From af86acb7a1ecd98a9be111cb574ca72ee7e743c3 Mon Sep 17 00:00:00 2001 From: Philip Wagner Date: Sun, 1 Sep 2024 10:47:15 +0200 Subject: [PATCH] downgrade to kirby v3 --- .envrc | 1 + README.md | 30 +- assets/style.css | 2 +- composer.json | 12 +- composer.lock | 1595 +++++ kirby/.editorconfig | 4 - kirby/CONTRIBUTING.md | 32 +- kirby/LICENSE.md | 147 +- kirby/README.md | 28 +- kirby/SECURITY.md | 26 +- kirby/bootstrap.php | 8 +- kirby/composer.json | 31 +- kirby/composer.lock | 526 +- kirby/config/aliases.php | 42 +- kirby/config/api/authentication.php | 8 +- kirby/config/api/collections.php | 22 +- kirby/config/api/models.php | 1 - kirby/config/api/models/File.php | 10 +- kirby/config/api/models/FileBlueprint.php | 5 +- kirby/config/api/models/FileVersion.php | 2 +- kirby/config/api/models/Language.php | 2 +- kirby/config/api/models/License.php | 17 - kirby/config/api/models/Page.php | 61 +- kirby/config/api/models/PageBlueprint.php | 5 +- kirby/config/api/models/Role.php | 2 +- kirby/config/api/models/Site.php | 2 +- kirby/config/api/models/SiteBlueprint.php | 2 +- kirby/config/api/models/System.php | 27 +- kirby/config/api/models/Translation.php | 2 +- kirby/config/api/models/User.php | 14 +- kirby/config/api/models/UserBlueprint.php | 5 +- kirby/config/api/routes.php | 5 +- kirby/config/api/routes/auth.php | 34 +- kirby/config/api/routes/files.php | 92 +- kirby/config/api/routes/kql.php | 35 - kirby/config/api/routes/languages.php | 8 +- kirby/config/api/routes/lock.php | 32 +- kirby/config/api/routes/pages.php | 30 +- kirby/config/api/routes/roles.php | 13 +- kirby/config/api/routes/site.php | 29 +- kirby/config/api/routes/system.php | 23 +- kirby/config/api/routes/users.php | 37 +- kirby/config/areas/account.php | 1 - kirby/config/areas/account/dialogs.php | 36 - kirby/config/areas/account/drawers.php | 19 - kirby/config/areas/account/views.php | 10 +- kirby/config/areas/fields/dialogs.php | 61 - kirby/config/areas/fields/drawers.php | 61 - kirby/config/areas/files/dialogs.php | 44 +- kirby/config/areas/lab.php | 11 - kirby/config/areas/lab/drawers.php | 30 - kirby/config/areas/lab/views.php | 148 - kirby/config/areas/languages.php | 2 +- kirby/config/areas/languages/dialogs.php | 121 +- kirby/config/areas/languages/views.php | 115 +- kirby/config/areas/search.php | 11 - kirby/config/areas/search/views.php | 17 - kirby/config/areas/site.php | 2 - kirby/config/areas/site/dialogs.php | 257 +- kirby/config/areas/site/drawers.php | 33 - kirby/config/areas/site/dropdowns.php | 5 + kirby/config/areas/site/requests.php | 66 - kirby/config/areas/site/searches.php | 51 +- kirby/config/areas/system/dialogs.php | 93 +- kirby/config/areas/system/views.php | 96 +- kirby/config/areas/users.php | 1 - kirby/config/areas/users/dialogs.php | 39 +- kirby/config/areas/users/drawers.php | 18 - kirby/config/areas/users/searches.php | 22 +- kirby/config/areas/users/views.php | 4 - kirby/config/blocks/gallery/gallery.php | 14 +- kirby/config/blocks/gallery/gallery.yml | 26 +- kirby/config/blocks/heading/heading.yml | 29 +- kirby/config/blocks/image/image.php | 2 +- kirby/config/blocks/image/image.yml | 4 +- kirby/config/blocks/video/video.php | 24 +- kirby/config/blocks/video/video.yml | 66 - kirby/config/blueprints/blocks/code.yml | 56 + kirby/config/blueprints/blocks/heading.yml | 20 + kirby/config/blueprints/blocks/image.yml | 16 + kirby/config/blueprints/blocks/quote.yml | 12 + kirby/config/blueprints/blocks/table.yml | 25 + kirby/config/blueprints/blocks/text.yml | 5 + kirby/config/blueprints/blocks/video.yml | 8 + kirby/config/blueprints/files/default.yml | 2 + kirby/config/blueprints/pages/default.yml | 3 + kirby/config/blueprints/site.yml | 7 + kirby/config/components.php | 279 +- kirby/config/fields/color.php | 145 - kirby/config/fields/date.php | 6 +- kirby/config/fields/files.php | 18 +- kirby/config/fields/headline.php | 9 +- kirby/config/fields/hidden.php | 4 +- kirby/config/fields/info.php | 1 + kirby/config/fields/link.php | 155 - kirby/config/fields/list.php | 6 - kirby/config/fields/mixins/layout.php | 2 +- kirby/config/fields/mixins/options.php | 23 +- kirby/config/fields/mixins/picker.php | 12 +- kirby/config/fields/mixins/upload.php | 50 +- kirby/config/fields/multiselect.php | 41 +- kirby/config/fields/number.php | 6 +- kirby/config/fields/object.php | 104 - kirby/config/fields/pages.php | 4 +- kirby/config/fields/range.php | 9 - kirby/config/fields/select.php | 13 - kirby/config/fields/structure.php | 120 +- kirby/config/fields/tags.php | 50 +- kirby/config/fields/text.php | 9 +- kirby/config/fields/time.php | 10 +- kirby/config/fields/toggle.php | 4 +- kirby/config/fields/users.php | 38 +- kirby/config/fields/writer.php | 63 +- kirby/config/helpers.php | 411 +- kirby/config/methods.php | 402 +- kirby/config/presets/files.php | 3 +- kirby/config/presets/page.php | 18 +- kirby/config/presets/pages.php | 14 +- kirby/config/routes.php | 68 +- kirby/config/sections/fields.php | 7 +- kirby/config/sections/files.php | 73 +- kirby/config/sections/info.php | 10 +- kirby/config/sections/mixins/headline.php | 16 +- kirby/config/sections/mixins/layout.php | 62 +- kirby/config/sections/mixins/parent.php | 12 +- kirby/config/sections/mixins/search.php | 2 +- kirby/config/sections/mixins/sort.php | 4 - kirby/config/sections/pages.php | 148 +- kirby/config/sections/stats.php | 24 +- kirby/config/setup.php | 5 + kirby/config/tags.php | 126 +- .../parsedown-extra/ParsedownExtra.php | 16 +- kirby/i18n/rules/{ro.json => rm.json} | 0 kirby/i18n/translations/bg.json | 1300 ++-- kirby/i18n/translations/ca.json | 1300 ++-- kirby/i18n/translations/cs.json | 1300 ++-- kirby/i18n/translations/da.json | 1300 ++-- kirby/i18n/translations/de.json | 1300 ++-- kirby/i18n/translations/el.json | 1300 ++-- kirby/i18n/translations/en.json | 1306 ++-- kirby/i18n/translations/eo.json | 1300 ++-- kirby/i18n/translations/es_419.json | 1300 ++-- kirby/i18n/translations/es_ES.json | 1300 ++-- kirby/i18n/translations/fa.json | 1300 ++-- kirby/i18n/translations/fi.json | 1300 ++-- kirby/i18n/translations/fr.json | 1300 ++-- kirby/i18n/translations/hu.json | 1300 ++-- kirby/i18n/translations/id.json | 1300 ++-- kirby/i18n/translations/is_IS.json | 1300 ++-- kirby/i18n/translations/it.json | 1300 ++-- kirby/i18n/translations/ko.json | 1300 ++-- kirby/i18n/translations/lt.json | 1300 ++-- kirby/i18n/translations/nb.json | 1300 ++-- kirby/i18n/translations/nl.json | 1300 ++-- kirby/i18n/translations/pl.json | 1300 ++-- kirby/i18n/translations/pt_BR.json | 1300 ++-- kirby/i18n/translations/pt_PT.json | 1300 ++-- kirby/i18n/translations/ro.json | 730 --- kirby/i18n/translations/ru.json | 1300 ++-- kirby/i18n/translations/sk.json | 1300 ++-- kirby/i18n/translations/sv_SE.json | 1300 ++-- kirby/i18n/translations/tr.json | 1300 ++-- kirby/package-lock.json | 6 - kirby/panel/.prettierignore | 2 - kirby/panel/dist/apple-touch-icon-dark.png | Bin 1148 -> 0 bytes kirby/panel/dist/css/style.css | 1 + kirby/panel/dist/css/style.min.css | 1 - kirby/panel/dist/favicon-dark.png | Bin 416 -> 0 bytes kirby/panel/dist/img/icons.svg | 1089 ++-- kirby/panel/dist/js/Docs.min.js | 1 - kirby/panel/dist/js/DocsView.min.js | 1 - kirby/panel/dist/js/Highlight.min.js | 1 - kirby/panel/dist/js/IndexView.min.js | 1 - kirby/panel/dist/js/PlaygroundView.min.js | 1 - .../js/container-query-polyfill.modern.min.js | 1 - kirby/panel/dist/js/index.js | 1 + kirby/panel/dist/js/index.min.js | 2 - kirby/panel/dist/js/plugins.js | 138 +- kirby/panel/dist/js/vendor.js | 12 + kirby/panel/dist/js/vendor.min.js | 16 - kirby/panel/dist/js/vue.min.js | 11 - kirby/panel/dist/js/vuedraggable.js | 7 + kirby/panel/dist/js/vuedraggable.min.js | 7 - kirby/panel/eslint.config.mjs | 28 - kirby/router.php | 9 +- kirby/src/Api/Api.php | 491 +- kirby/src/Api/Collection.php | 53 +- kirby/src/Api/Model.php | 81 +- kirby/src/Blueprint/Collection.php | 97 - kirby/src/Blueprint/Config.php | 75 - kirby/src/Blueprint/Extension.php | 65 - kirby/src/Blueprint/Factory.php | 119 - kirby/src/Blueprint/Node.php | 117 - kirby/src/Blueprint/NodeI18n.php | 44 - kirby/src/Blueprint/NodeIcon.php | 27 - kirby/src/Blueprint/NodeProperty.php | 27 - kirby/src/Blueprint/NodeString.php | 39 - kirby/src/Blueprint/NodeText.php | 30 - kirby/src/Cache/ApcuCache.php | 39 +- kirby/src/Cache/Cache.php | 234 +- kirby/src/Cache/FileCache.php | 63 +- kirby/src/Cache/MemCached.php | 47 +- kirby/src/Cache/MemoryCache.php | 31 +- kirby/src/Cache/NullCache.php | 24 +- kirby/src/Cache/Value.php | 51 +- kirby/src/Cms/Api.php | 199 +- kirby/src/Cms/App.php | 815 +-- kirby/src/Cms/AppCaches.php | 34 +- kirby/src/Cms/AppErrors.php | 81 +- kirby/src/Cms/AppPlugins.php | 306 +- kirby/src/Cms/AppTranslations.php | 71 +- kirby/src/Cms/AppUsers.php | 72 +- kirby/src/Cms/Auth.php | 331 +- kirby/src/Cms/Auth/Challenge.php | 16 +- kirby/src/Cms/Auth/EmailChallenge.php | 5 +- kirby/src/Cms/Auth/Status.php | 139 +- kirby/src/Cms/Auth/TotpChallenge.php | 65 - kirby/src/Cms/Block.php | 98 +- kirby/src/Cms/BlockConverter.php | 285 - kirby/src/Cms/Blocks.php | 92 +- kirby/src/Cms/Blueprint.php | 422 +- kirby/src/Cms/Collection.php | 114 +- kirby/src/Cms/Collections.php | 50 +- kirby/src/{Content => Cms}/Content.php | 105 +- kirby/src/Cms/ContentLock.php | 78 +- kirby/src/Cms/ContentLocks.php | 28 +- kirby/src/Cms/ContentTranslation.php | 248 + kirby/src/Cms/Core.php | 135 +- kirby/src/Cms/Email.php | 62 +- kirby/src/Cms/Event.php | 93 +- kirby/src/{Content => Cms}/Field.php | 109 +- kirby/src/Cms/Fieldset.php | 138 +- kirby/src/Cms/Fieldsets.php | 24 +- kirby/src/Cms/File.php | 563 +- kirby/src/Cms/FileActions.php | 334 +- kirby/src/Cms/FileBlueprint.php | 124 +- kirby/src/Cms/FileModifications.php | 86 +- kirby/src/Cms/FilePermissions.php | 11 +- kirby/src/Cms/FilePicker.php | 40 +- kirby/src/Cms/FileRules.php | 87 +- kirby/src/Cms/FileVersion.php | 64 +- kirby/src/Cms/Files.php | 65 +- kirby/src/Cms/Find.php | 86 +- kirby/src/Cms/HasChildren.php | 89 +- kirby/src/Cms/HasFiles.php | 85 +- kirby/src/Cms/HasMethods.php | 20 +- kirby/src/Cms/HasSiblings.php | 61 +- kirby/src/Cms/Helpers.php | 134 +- kirby/src/Cms/Html.php | 53 +- kirby/src/Cms/Ingredients.php | 25 +- kirby/src/Cms/Item.php | 65 +- kirby/src/Cms/Items.php | 69 +- kirby/src/Cms/Language.php | 520 +- kirby/src/Cms/LanguageRouter.php | 53 +- kirby/src/Cms/LanguageRoutes.php | 38 +- kirby/src/Cms/LanguageRules.php | 10 +- kirby/src/Cms/LanguageVariable.php | 122 - kirby/src/Cms/Languages.php | 39 +- kirby/src/Cms/Layout.php | 42 +- kirby/src/Cms/LayoutColumn.php | 36 +- kirby/src/Cms/LayoutColumns.php | 7 +- kirby/src/Cms/Layouts.php | 53 +- kirby/src/Cms/License.php | 529 -- kirby/src/Cms/LicenseStatus.php | 144 - kirby/src/Cms/LicenseType.php | 111 - kirby/src/Cms/Loader.php | 61 +- kirby/src/Cms/Media.php | 125 +- kirby/src/Cms/Model.php | 4 +- kirby/src/Cms/ModelPermissions.php | 76 +- kirby/src/Cms/ModelWithContent.php | 702 +-- kirby/src/Cms/Nest.php | 21 +- kirby/src/Cms/NestCollection.php | 3 + kirby/src/Cms/NestObject.php | 10 +- kirby/src/Cms/Page.php | 810 ++- kirby/src/Cms/PageActions.php | 462 +- kirby/src/Cms/PageBlueprint.php | 29 +- kirby/src/Cms/PagePermissions.php | 27 +- kirby/src/Cms/PagePicker.php | 93 +- kirby/src/Cms/PageRules.php | 241 +- kirby/src/Cms/PageSiblings.php | 13 +- kirby/src/Cms/Pages.php | 243 +- kirby/src/Cms/Pagination.php | 23 +- kirby/src/Cms/Permissions.php | 78 +- kirby/src/Cms/Picker.php | 47 +- kirby/src/Cms/Plugin.php | 253 +- kirby/src/Cms/PluginAsset.php | 120 - kirby/src/Cms/PluginAssets.php | 168 +- kirby/src/Cms/R.php | 6 +- kirby/src/Cms/Responder.php | 77 +- kirby/src/Cms/Response.php | 10 +- kirby/src/Cms/Role.php | 123 +- kirby/src/Cms/Roles.php | 23 +- kirby/src/Cms/S.php | 6 +- kirby/src/Cms/Search.php | 45 +- kirby/src/Cms/Section.php | 47 +- kirby/src/Cms/Site.php | 365 +- kirby/src/Cms/SiteActions.php | 66 +- kirby/src/Cms/SiteBlueprint.php | 6 +- kirby/src/Cms/SitePermissions.php | 2 +- kirby/src/Cms/SiteRules.php | 6 + kirby/src/Cms/Structure.php | 65 +- kirby/src/Cms/StructureObject.php | 188 +- kirby/src/Cms/System.php | 411 +- kirby/src/Cms/System/UpdateStatus.php | 838 --- kirby/src/Cms/Template.php | 205 + kirby/src/Cms/Translation.php | 63 +- kirby/src/Cms/Translations.php | 30 +- kirby/src/Cms/Url.php | 25 +- kirby/src/Cms/User.php | 562 +- kirby/src/Cms/UserActions.php | 191 +- kirby/src/Cms/UserBlueprint.php | 1 + kirby/src/Cms/UserPermissions.php | 26 +- kirby/src/Cms/UserPicker.php | 22 +- kirby/src/Cms/UserRules.php | 122 +- kirby/src/Cms/Users.php | 67 +- kirby/src/Cms/Visitor.php | 6 +- kirby/src/Content/ContentStorage.php | 314 - kirby/src/Content/ContentStorageHandler.php | 96 - kirby/src/Content/ContentTranslation.php | 173 - .../PlainTextContentStorageHandler.php | 253 - kirby/src/Data/Data.php | 77 +- kirby/src/Data/Handler.php | 20 +- kirby/src/Data/Json.php | 15 +- kirby/src/Data/PHP.php | 18 +- kirby/src/Data/Txt.php | 50 +- kirby/src/Data/Xml.php | 10 +- kirby/src/Data/Yaml.php | 53 +- kirby/src/Data/YamlSpyc.php | 43 - kirby/src/Data/YamlSymfony.php | 44 - kirby/src/Database/Database.php | 252 +- kirby/src/Database/Db.php | 142 +- kirby/src/Database/Query.php | 400 +- kirby/src/Database/Sql.php | 244 +- kirby/src/Database/Sql/Mysql.php | 3 + kirby/src/Database/Sql/Sqlite.php | 20 +- kirby/src/Email/Body.php | 64 +- kirby/src/Email/Email.php | 356 +- kirby/src/Email/PHPMailer.php | 7 +- kirby/src/Exception/AuthException.php | 21 - .../src/Exception/BadMethodCallException.php | 8 +- kirby/src/Exception/DuplicateException.php | 6 +- kirby/src/Exception/ErrorPageException.php | 6 +- kirby/src/Exception/Exception.php | 70 +- .../Exception/InvalidArgumentException.php | 8 +- kirby/src/Exception/LogicException.php | 6 +- kirby/src/Exception/NotFoundException.php | 6 +- kirby/src/Exception/PermissionException.php | 6 +- kirby/src/Field/FieldOptions.php | 108 - kirby/src/Filesystem/Asset.php | 69 +- kirby/src/Filesystem/Dir.php | 386 +- kirby/src/Filesystem/F.php | 366 +- kirby/src/Filesystem/File.php | 272 +- kirby/src/Filesystem/Filename.php | 102 +- kirby/src/Filesystem/IsFile.php | 105 +- kirby/src/Filesystem/Mime.php | 103 +- kirby/src/Form/Field.php | 187 +- kirby/src/Form/Field/BlocksField.php | 161 +- kirby/src/Form/Field/LayoutField.php | 170 +- kirby/src/Form/FieldClass.php | 460 +- kirby/src/Form/Fields.php | 5 + kirby/src/Form/Form.php | 132 +- kirby/src/Form/Mixin/EmptyState.php | 6 +- kirby/src/Form/Mixin/Max.php | 4 +- kirby/src/Form/Mixin/Min.php | 4 +- kirby/src/Form/Options.php | 210 + kirby/src/Form/OptionsApi.php | 242 + kirby/src/Form/OptionsQuery.php | 271 + kirby/src/Form/Validations.php | 88 +- kirby/src/Http/Cookie.php | 77 +- kirby/src/Http/Environment.php | 362 +- kirby/src/Http/Header.php | 77 +- kirby/src/Http/Idn.php | 16 +- kirby/src/Http/Params.php | 56 +- kirby/src/Http/Path.php | 8 +- kirby/src/Http/Query.php | 17 +- kirby/src/Http/Remote.php | 157 +- kirby/src/Http/Request.php | 180 +- kirby/src/Http/Request/Auth.php | 27 +- kirby/src/Http/Request/Auth/BasicAuth.php | 39 +- kirby/src/Http/Request/Auth/BearerAuth.php | 4 + kirby/src/Http/Request/Auth/SessionAuth.php | 9 +- kirby/src/Http/Request/Body.php | 36 +- kirby/src/Http/Request/Data.php | 15 +- kirby/src/Http/Request/Files.php | 16 +- kirby/src/Http/Request/Query.php | 20 +- kirby/src/Http/Response.php | 125 +- kirby/src/Http/Route.php | 70 +- kirby/src/Http/Router.php | 75 +- kirby/src/Http/Server.php | 38 + kirby/src/Http/Uri.php | 229 +- kirby/src/Http/Url.php | 140 +- kirby/src/Http/Visitor.php | 95 +- kirby/src/Image/Camera.php | 35 +- kirby/src/Image/Darkroom.php | 69 +- kirby/src/Image/Darkroom/GdLib.php | 79 +- kirby/src/Image/Darkroom/ImageMagick.php | 126 +- kirby/src/Image/Dimensions.php | 147 +- kirby/src/Image/Exif.php | 186 +- kirby/src/Image/Focus.php | 110 - kirby/src/Image/Image.php | 86 +- kirby/src/Image/Location.php | 54 +- kirby/src/Image/QrCode.php | 1611 ----- kirby/src/Option/Option.php | 64 - kirby/src/Option/Options.php | 57 - kirby/src/Option/OptionsApi.php | 148 - kirby/src/Option/OptionsProvider.php | 38 - kirby/src/Option/OptionsQuery.php | 186 - kirby/src/Panel/Assets.php | 324 - kirby/src/Panel/ChangesDialog.php | 71 - kirby/src/Panel/Dialog.php | 47 +- kirby/src/Panel/Document.php | 276 +- kirby/src/Panel/Drawer.php | 21 - kirby/src/Panel/Dropdown.php | 95 +- kirby/src/Panel/Field.php | 110 +- kirby/src/Panel/File.php | 273 +- kirby/src/Panel/Home.php | 61 +- kirby/src/Panel/Json.php | 75 +- kirby/src/Panel/Lab/Category.php | 134 - kirby/src/Panel/Lab/Docs.php | 340 -- kirby/src/Panel/Lab/Example.php | 296 - kirby/src/Panel/Lab/Snippet.php | 26 - kirby/src/Panel/Lab/Template.php | 34 - kirby/src/Panel/Menu.php | 221 - kirby/src/Panel/Model.php | 279 +- kirby/src/Panel/Page.php | 104 +- kirby/src/Panel/PageCreateDialog.php | 389 -- kirby/src/Panel/Panel.php | 289 +- kirby/src/Panel/Plugins.php | 14 +- kirby/src/Panel/Redirect.php | 4 + kirby/src/Panel/Request.php | 24 - kirby/src/Panel/Search.php | 23 +- kirby/src/Panel/Site.php | 26 +- kirby/src/Panel/User.php | 81 +- kirby/src/Panel/UserTotpDisableDialog.php | 114 - kirby/src/Panel/UserTotpEnableDialog.php | 95 - kirby/src/Panel/View.php | 203 +- kirby/src/Parsley/Element.php | 82 +- kirby/src/Parsley/Inline.php | 134 +- kirby/src/Parsley/Parsley.php | 137 +- kirby/src/Parsley/Schema.php | 11 +- kirby/src/Parsley/Schema/Blocks.php | 186 +- kirby/src/Parsley/Schema/Plain.php | 9 +- kirby/src/Query/Argument.php | 117 - kirby/src/Query/Arguments.php | 59 - kirby/src/Query/Expression.php | 119 - kirby/src/Query/Query.php | 142 - kirby/src/Query/Segment.php | 182 - kirby/src/Query/Segments.php | 100 - kirby/src/Sane/DomHandler.php | 90 +- kirby/src/Sane/Handler.php | 27 +- kirby/src/Sane/Html.php | 38 +- kirby/src/Sane/Sane.php | 82 +- kirby/src/Sane/Svg.php | 60 +- kirby/src/Sane/Svgz.php | 20 +- kirby/src/Sane/Xml.php | 14 +- kirby/src/Session/AutoSession.php | 37 +- kirby/src/Session/FileSessionStore.php | 81 +- kirby/src/Session/Session.php | 395 +- kirby/src/Session/SessionData.php | 222 +- kirby/src/Session/SessionStore.php | 17 +- kirby/src/Session/Sessions.php | 162 +- kirby/src/Template/Slot.php | 123 - kirby/src/Template/Slots.php | 54 - kirby/src/Template/Snippet.php | 308 - kirby/src/Template/Template.php | 216 - kirby/src/Text/KirbyTag.php | 117 +- kirby/src/Text/KirbyTags.php | 17 +- kirby/src/Text/Markdown.php | 27 +- kirby/src/Text/SmartyPants.php | 20 +- kirby/src/Toolkit/A.php | 1037 ++-- kirby/src/Toolkit/Collection.php | 141 +- kirby/src/Toolkit/Component.php | 186 +- kirby/src/Toolkit/Config.php | 5 +- kirby/src/Toolkit/Controller.php | 30 +- kirby/src/Toolkit/Date.php | 235 +- kirby/src/Toolkit/Dom.php | 227 +- kirby/src/Toolkit/Escape.php | 38 +- kirby/src/Toolkit/Facade.php | 6 + kirby/src/Toolkit/Html.php | 177 +- kirby/src/Toolkit/I18n.php | 317 +- kirby/src/Toolkit/Iterator.php | 64 +- kirby/src/Toolkit/LazyValue.php | 48 - kirby/src/Toolkit/Locale.php | 53 +- kirby/src/Toolkit/Obj.php | 35 +- kirby/src/Toolkit/Pagination.php | 223 +- kirby/src/Toolkit/Properties.php | 2 - kirby/src/Toolkit/Query.php | 244 + kirby/src/Toolkit/Silo.php | 29 +- kirby/src/Toolkit/Str.php | 817 ++- kirby/src/Toolkit/SymmetricCrypto.php | 216 - kirby/src/Toolkit/Totp.php | 144 - kirby/src/Toolkit/Tpl.php | 15 +- kirby/src/Toolkit/V.php | 163 +- kirby/src/Toolkit/View.php | 56 +- kirby/src/Toolkit/Xml.php | 131 +- kirby/src/Uuid/BlockUuid.php | 39 - kirby/src/Uuid/FieldUuid.php | 131 - kirby/src/Uuid/FileUuid.php | 86 - kirby/src/Uuid/HasUuids.php | 37 - kirby/src/Uuid/Identifiable.php | 21 - kirby/src/Uuid/ModelUuid.php | 124 - kirby/src/Uuid/PageUuid.php | 57 - kirby/src/Uuid/SiteUuid.php | 79 - kirby/src/Uuid/StructureUuid.php | 39 - kirby/src/Uuid/Uri.php | 94 - kirby/src/Uuid/UserUuid.php | 63 - kirby/src/Uuid/Uuid.php | 400 -- kirby/src/Uuid/Uuids.php | 122 - kirby/vendor/bin/yaml-lint | 119 - kirby/vendor/bin/yaml-lint.bat | 5 - .../christian-riesen/base32/src/Base32.php | 168 - .../christian-riesen/base32/src/Base32Hex.php | 68 - .../vendor/claviska/simpleimage/composer.lock | 209 - .../simpleimage/src/claviska/SimpleImage.php | 2409 -------- kirby/vendor/composer/autoload_classmap.php | 410 -- kirby/vendor/composer/autoload_psr4.php | 22 - kirby/vendor/composer/autoload_static.php | 543 -- kirby/vendor/composer/installed.json | 1136 ---- kirby/vendor/composer/installed.php | 179 - kirby/vendor/composer/semver/LICENSE | 19 - kirby/vendor/composer/semver/composer.json | 59 - .../composer/semver/phpstan-baseline.neon | 11 - .../vendor/composer/semver/src/Comparator.php | 113 - .../composer/semver/src/CompilingMatcher.php | 94 - .../composer/semver/src/Constraint/Bound.php | 122 - .../semver/src/Constraint/Constraint.php | 435 -- .../src/Constraint/ConstraintInterface.php | 75 - .../src/Constraint/MatchAllConstraint.php | 85 - .../src/Constraint/MatchNoneConstraint.php | 83 - .../semver/src/Constraint/MultiConstraint.php | 325 - kirby/vendor/composer/semver/src/Interval.php | 98 - .../vendor/composer/semver/src/Intervals.php | 478 -- kirby/vendor/composer/semver/src/Semver.php | 129 - .../composer/semver/src/VersionParser.php | 586 -- .../src/Whoops/Inspector/InspectorFactory.php | 21 - .../Inspector/InspectorFactoryInterface.php | 16 - .../Whoops/Inspector/InspectorInterface.php | 71 - .../whoops/src/Whoops/Resources/css/prism.css | 5 - .../whoops/src/Whoops/Resources/js/prism.js | 8 - .../phpmailer/language/phpmailer.lang-as.php | 35 - .../phpmailer/language/phpmailer.lang-bn.php | 35 - .../phpmailer/language/phpmailer.lang-nb.php | 33 - .../phpmailer/language/phpmailer.lang-si.php | 34 - .../phpmailer/src/DSNConfigurator.php | 245 - kirby/vendor/psr/log/src/AbstractLogger.php | 15 - .../deprecation-contracts/composer.json | 35 - .../deprecation-contracts/function.php | 27 - kirby/vendor/symfony/polyfill-ctype/Ctype.php | 232 - kirby/vendor/symfony/polyfill-ctype/LICENSE | 19 - .../symfony/polyfill-ctype/bootstrap.php | 50 - .../symfony/polyfill-ctype/bootstrap80.php | 46 - .../symfony/polyfill-ctype/composer.json | 38 - .../vendor/symfony/polyfill-intl-idn/LICENSE | 19 - .../Resources/unidata/caseFolding.php | 119 - .../symfony/yaml/Command/LintCommand.php | 276 - kirby/vendor/symfony/yaml/Dumper.php | 178 - kirby/vendor/symfony/yaml/Escaper.php | 95 - .../symfony/yaml/Exception/DumpException.php | 21 - .../yaml/Exception/ExceptionInterface.php | 21 - .../symfony/yaml/Exception/ParseException.php | 132 - .../yaml/Exception/RuntimeException.php | 21 - kirby/vendor/symfony/yaml/Inline.php | 828 --- kirby/vendor/symfony/yaml/LICENSE | 19 - kirby/vendor/symfony/yaml/Parser.php | 1249 ---- .../symfony/yaml/Resources/bin/yaml-lint | 49 - kirby/vendor/symfony/yaml/Tag/TaggedValue.php | 38 - kirby/vendor/symfony/yaml/Unescaper.php | 108 - kirby/vendor/symfony/yaml/Yaml.php | 97 - kirby/vendor/symfony/yaml/composer.json | 39 - kirby/views/panel.php | 13 +- site/blueprints/fields/block_settings.yml | 6 +- site/blueprints/pages/default.yml | 1 - site/plugins/color-palette/.editorconfig | 9 + site/plugins/color-palette/.gitignore | 3 + site/plugins/color-palette/README.md | 301 + site/plugins/color-palette/composer.json | 19 + site/plugins/color-palette/index.css | 1 + site/plugins/color-palette/index.js | 1 + site/plugins/color-palette/index.php | 18 + site/plugins/color-palette/lib/api.php | 68 + .../color-palette/lib/color-palette.php | 25 + site/plugins/color-palette/lib/fields.php | 79 + .../color-palette/lib/languages/de.php | 8 + .../color-palette/lib/languages/en.php | 8 + .../color-palette/lib/languages/fr.php | 8 + site/plugins/color-palette/package.json | 25 + .../color-palette/src/assets/css/styles.scss | 195 + .../color-palette/src/assets/svg/icons.js | 5 + .../color-palette/src/assets/svg/pipette.svg | 3 + .../src/components/field/ColorPalette.vue | 217 + site/plugins/color-palette/src/index.js | 8 + site/plugins/embed/vendor/autoload.php | 25 - .../embed/vendor/composer/ClassLoader.php | 581 -- .../vendor/composer/InstalledVersions.php | 352 -- site/plugins/embed/vendor/composer/LICENSE | 21 - .../vendor/composer/autoload_classmap.php | 10 - .../embed/vendor/composer/autoload_files.php | 11 - .../vendor/composer/autoload_namespaces.php | 10 - .../embed/vendor/composer/autoload_psr4.php | 17 - .../embed/vendor/composer/autoload_real.php | 50 - .../embed/vendor/composer/autoload_static.php | 106 - .../embed/vendor/composer/installed.json | 718 --- .../embed/vendor/composer/installed.php | 134 - site/plugins/kirby-fields-block/.gitignore | 12 + .../plugins/kirby-fields-block/LICENSE.md | 12 +- site/plugins/kirby-fields-block/README.md | 74 + site/plugins/kirby-fields-block/composer.json | 15 + site/plugins/kirby-fields-block/index.css | 42 + site/plugins/kirby-fields-block/index.js | 122 + site/plugins/kirby-fields-block/index.php | 3 + site/plugins/kirby-fields-block/package.json | 15 + .../kirby-fields-block/postcss.config.js | 3 + .../kirby-fields-block/src/FieldsBlock.vue | 94 + site/plugins/kirby-fields-block/src/index.js | 26 + site/plugins/my-helper/index.php | 17 +- {kirby/vendor => vendor}/autoload.php | 2 +- vendor/claviska/simpleimage/.editorconfig | 9 + .../claviska/simpleimage/.github/FUNDING.yml | 2 + vendor/claviska/simpleimage/.gitignore | 2 + .../claviska/simpleimage/LICENSE.md | 0 vendor/claviska/simpleimage/README.md | 779 +++ .../claviska/simpleimage/composer.json | 8 +- vendor/claviska/simpleimage/example/flag.png | Bin 0 -> 7821 bytes vendor/claviska/simpleimage/example/index.php | 25 + .../claviska/simpleimage/example/parrot.jpg | Bin 0 -> 56334 bytes .../simpleimage/src/claviska/SimpleImage.php | 2190 +++++++ .../composer/ClassLoader.php | 0 .../composer/InstalledVersions.php | 0 {kirby/vendor => vendor}/composer/LICENSE | 0 vendor/composer/autoload_classmap.php | 507 ++ .../composer/autoload_files.php | 8 +- .../composer/autoload_namespaces.php | 1 + vendor/composer/autoload_psr4.php | 25 + .../composer/autoload_real.php | 12 +- vendor/composer/autoload_static.php | 669 +++ .../composer/ca-bundle/LICENSE | 0 .../composer/ca-bundle/README.md | 0 .../composer/ca-bundle/composer.json | 10 +- .../composer/ca-bundle/res/cacert.pem | 289 +- .../composer/ca-bundle/src/CaBundle.php | 142 +- vendor/composer/installed.json | 1655 +++++ vendor/composer/installed.php | 272 + .../composer/platform_check.php | 0 .../embed/embed/CHANGELOG.md | 0 .../vendor => vendor}/embed/embed/LICENSE | 0 .../vendor => vendor}/embed/embed/README.md | 0 .../embed/embed/composer.json | 0 .../embed/embed/src/Adapters/Archive/Api.php | 0 .../Adapters/Archive/Detectors/AuthorName.php | 0 .../src/Adapters/Archive/Detectors/Code.php | 0 .../Archive/Detectors/Description.php | 0 .../Archive/Detectors/ProviderName.php | 0 .../Archive/Detectors/PublishedTime.php | 0 .../src/Adapters/Archive/Detectors/Title.php | 0 .../embed/src/Adapters/Archive/Extractor.php | 0 .../Bandcamp/Detectors/ProviderName.php | 0 .../embed/src/Adapters/Bandcamp/Extractor.php | 0 .../src/Adapters/CadenaSer/Detectors/Code.php | 0 .../src/Adapters/CadenaSer/Extractor.php | 0 .../src/Adapters/Facebook/Detectors/Title.php | 0 .../embed/src/Adapters/Facebook/Extractor.php | 0 .../embed/src/Adapters/Facebook/OEmbed.php | 0 .../src/Adapters/Flickr/Detectors/Code.php | 0 .../embed/src/Adapters/Flickr/Extractor.php | 0 .../embed/embed/src/Adapters/Gist/Api.php | 0 .../Adapters/Gist/Detectors/AuthorName.php | 0 .../src/Adapters/Gist/Detectors/AuthorUrl.php | 0 .../src/Adapters/Gist/Detectors/Code.php | 0 .../Adapters/Gist/Detectors/PublishedTime.php | 0 .../embed/src/Adapters/Gist/Extractor.php | 0 .../src/Adapters/Github/Detectors/Code.php | 0 .../embed/src/Adapters/Github/Extractor.php | 0 .../src/Adapters/Ideone/Detectors/Code.php | 0 .../embed/src/Adapters/Ideone/Extractor.php | 0 .../embed/src/Adapters/ImageShack/Api.php | 0 .../ImageShack/Detectors/AuthorName.php | 0 .../ImageShack/Detectors/AuthorUrl.php | 0 .../ImageShack/Detectors/Description.php | 0 .../Adapters/ImageShack/Detectors/Image.php | 0 .../ImageShack/Detectors/ProviderName.php | 0 .../ImageShack/Detectors/PublishedTime.php | 0 .../Adapters/ImageShack/Detectors/Title.php | 0 .../src/Adapters/ImageShack/Extractor.php | 0 .../src/Adapters/Instagram/Extractor.php | 0 .../embed/src/Adapters/Instagram/OEmbed.php | 0 .../src/Adapters/Pinterest/Detectors/Code.php | 0 .../src/Adapters/Pinterest/Extractor.php | 0 .../Adapters/Sassmeister/Detectors/Code.php | 0 .../src/Adapters/Sassmeister/Extractor.php | 0 .../src/Adapters/Slides/Detectors/Code.php | 0 .../embed/src/Adapters/Slides/Extractor.php | 0 .../src/Adapters/Snipplr/Detectors/Code.php | 0 .../embed/src/Adapters/Snipplr/Extractor.php | 0 .../src/Adapters/Twitch/Detectors/Code.php | 0 .../embed/src/Adapters/Twitch/Extractor.php | 0 .../embed/embed/src/Adapters/Twitter/Api.php | 0 .../Adapters/Twitter/Detectors/AuthorName.php | 0 .../Adapters/Twitter/Detectors/AuthorUrl.php | 0 .../Twitter/Detectors/Description.php | 0 .../src/Adapters/Twitter/Detectors/Image.php | 0 .../Twitter/Detectors/ProviderName.php | 0 .../Twitter/Detectors/PublishedTime.php | 0 .../src/Adapters/Twitter/Detectors/Title.php | 0 .../embed/src/Adapters/Twitter/Extractor.php | 0 .../embed/src/Adapters/Wikipedia/Api.php | 0 .../Wikipedia/Detectors/Description.php | 0 .../Adapters/Wikipedia/Detectors/Title.php | 0 .../src/Adapters/Wikipedia/Extractor.php | 0 .../src/Adapters/Youtube/Detectors/Feeds.php | 0 .../embed/src/Adapters/Youtube/Extractor.php | 0 .../embed/embed/src/ApiTrait.php | 0 .../embed/embed/src/Detectors/AuthorName.php | 0 .../embed/embed/src/Detectors/AuthorUrl.php | 0 .../embed/embed/src/Detectors/Cms.php | 0 .../embed/embed/src/Detectors/Code.php | 0 .../embed/embed/src/Detectors/Description.php | 0 .../embed/embed/src/Detectors/Detector.php | 0 .../embed/embed/src/Detectors/Favicon.php | 0 .../embed/embed/src/Detectors/Feeds.php | 0 .../embed/embed/src/Detectors/Icon.php | 0 .../embed/embed/src/Detectors/Image.php | 0 .../embed/embed/src/Detectors/Keywords.php | 0 .../embed/embed/src/Detectors/Language.php | 0 .../embed/embed/src/Detectors/Languages.php | 0 .../embed/embed/src/Detectors/License.php | 0 .../embed/src/Detectors/ProviderName.php | 0 .../embed/embed/src/Detectors/ProviderUrl.php | 0 .../embed/src/Detectors/PublishedTime.php | 0 .../embed/embed/src/Detectors/Redirect.php | 0 .../embed/embed/src/Detectors/Title.php | 0 .../embed/embed/src/Detectors/Url.php | 0 .../embed/embed/src/Document.php | 0 .../embed/embed/src/Embed.php | 0 .../embed/embed/src/EmbedCode.php | 0 .../embed/embed/src/Extractor.php | 0 .../embed/embed/src/ExtractorFactory.php | 0 .../embed/embed/src/Http/Crawler.php | 0 .../embed/embed/src/Http/CurlClient.php | 0 .../embed/embed/src/Http/CurlDispatcher.php | 0 .../embed/embed/src/Http/FactoryDiscovery.php | 0 .../embed/embed/src/Http/NetworkException.php | 0 .../embed/embed/src/Http/RequestException.php | 0 .../embed/embed/src/HttpApiTrait.php | 0 .../embed/embed/src/LinkedData.php | 0 .../embed/embed/src/Metas.php | 0 .../embed/embed/src/OEmbed.php | 0 .../embed/embed/src/QueryResult.php | 0 .../embed/embed/src/functions.php | 0 .../embed/embed/src/resources/oembed.php | 0 .../embed/embed/src/resources/suffix.php | 0 vendor/filp/whoops/.github/FUNDING.yml | 1 + .../filp/whoops/.github/workflows/tests.yml | 56 + vendor/filp/whoops/.mailmap | 2 + vendor/filp/whoops/CHANGELOG.md | 126 + .../vendor => vendor}/filp/whoops/LICENSE.md | 0 vendor/filp/whoops/SECURITY.md | 12 + .../filp/whoops/composer.json | 0 .../src/Whoops/Exception/ErrorException.php | 0 .../whoops/src/Whoops/Exception/Formatter.php | 13 +- .../whoops/src/Whoops/Exception/Frame.php | 3 + .../src/Whoops/Exception/FrameCollection.php | 3 + .../whoops/src/Whoops/Exception/Inspector.php | 28 +- .../src/Whoops/Handler/CallbackHandler.php | 0 .../whoops/src/Whoops/Handler/Handler.php | 10 +- .../src/Whoops/Handler/HandlerInterface.php | 6 +- .../Whoops/Handler/JsonResponseHandler.php | 6 +- .../src/Whoops/Handler/PlainTextHandler.php | 2 +- .../src/Whoops/Handler/PrettyPageHandler.php | 10 +- .../src/Whoops/Handler/XmlResponseHandler.php | 3 +- .../whoops/src/Whoops/Resources/css/prism.css | 237 + .../src/Whoops/Resources/css/whoops.base.css | 13 +- .../src/Whoops/Resources/js/clipboard.min.js | 0 .../whoops/src/Whoops/Resources/js/prism.js | 8 + .../src/Whoops/Resources/js/whoops.base.js | 8 +- .../src/Whoops/Resources/js/zepto.min.js | 0 .../Resources/views/env_details.html.php | 0 .../Resources/views/frame_code.html.php | 1 - .../Resources/views/frame_list.html.php | 0 .../Resources/views/frames_container.html.php | 0 .../views/frames_description.html.php | 0 .../Whoops/Resources/views/header.html.php | 0 .../Resources/views/header_outer.html.php | 0 .../Whoops/Resources/views/layout.html.php | 0 .../Resources/views/panel_details.html.php | 0 .../views/panel_details_outer.html.php | 0 .../Resources/views/panel_left.html.php | 0 .../Resources/views/panel_left_outer.html.php | 0 .../filp/whoops/src/Whoops/Run.php | 58 +- .../filp/whoops/src/Whoops/RunInterface.php | 18 - .../src/Whoops/Util/HtmlDumperOutput.php | 0 .../filp/whoops/src/Whoops/Util/Misc.php | 0 .../whoops/src/Whoops/Util/SystemFacade.php | 0 .../whoops/src/Whoops/Util/TemplateHelper.php | 3 + .../getkirby/composer-installer/composer.json | 0 .../getkirby/composer-installer/composer.lock | 1680 ++++++ .../getkirby/composer-installer/readme.md | 0 .../src/ComposerInstaller/CmsInstaller.php | 0 .../src/ComposerInstaller/Installer.php | 0 .../src/ComposerInstaller/Plugin.php | 0 .../src/ComposerInstaller/PluginInstaller.php | 0 .../guzzlehttp/psr7/CHANGELOG.md | 28 + .../vendor => vendor}/guzzlehttp/psr7/LICENSE | 0 .../guzzlehttp/psr7/README.md | 33 +- .../guzzlehttp/psr7/composer.json | 6 +- .../guzzlehttp/psr7/src/AppendStream.php | 0 .../guzzlehttp/psr7/src/BufferStream.php | 0 .../guzzlehttp/psr7/src/CachingStream.php | 2 +- .../guzzlehttp/psr7/src/DroppingStream.php | 0 .../src/Exception/MalformedUriException.php | 0 .../guzzlehttp/psr7/src/FnStream.php | 33 +- .../guzzlehttp/psr7/src/Header.php | 2 +- .../guzzlehttp/psr7/src/HttpFactory.php | 6 +- .../guzzlehttp/psr7/src/InflateStream.php | 8 +- .../guzzlehttp/psr7/src/LazyOpenStream.php | 0 .../guzzlehttp/psr7/src/LimitStream.php | 0 .../guzzlehttp/psr7/src/Message.php | 8 +- .../guzzlehttp/psr7/src/MessageTrait.php | 8 +- .../guzzlehttp/psr7/src/MimeType.php | 0 .../guzzlehttp/psr7/src/MultipartStream.php | 22 +- .../guzzlehttp/psr7/src/NoSeekStream.php | 0 .../guzzlehttp/psr7/src/PumpStream.php | 6 +- .../guzzlehttp/psr7/src/Query.php | 19 +- .../guzzlehttp/psr7/src/Request.php | 4 +- .../guzzlehttp/psr7/src/Response.php | 4 +- .../guzzlehttp/psr7/src/Rfc7230.php | 0 .../guzzlehttp/psr7/src/ServerRequest.php | 2 +- .../guzzlehttp/psr7/src/Stream.php | 4 +- .../psr7/src/StreamDecoratorTrait.php | 2 +- .../guzzlehttp/psr7/src/StreamWrapper.php | 40 +- .../guzzlehttp/psr7/src/UploadedFile.php | 8 +- .../guzzlehttp/psr7/src/Uri.php | 30 +- .../guzzlehttp/psr7/src/UriComparator.php | 0 .../guzzlehttp/psr7/src/UriNormalizer.php | 10 +- .../guzzlehttp/psr7/src/UriResolver.php | 6 +- .../guzzlehttp/psr7/src/Utils.php | 22 +- .../laminas/laminas-escaper/COPYRIGHT.md | 0 .../laminas/laminas-escaper/LICENSE.md | 0 vendor/laminas/laminas-escaper/README.md | 43 + .../laminas/laminas-escaper/composer.json | 14 +- vendor/laminas/laminas-escaper/composer.lock | 5327 +++++++++++++++++ .../laminas/laminas-escaper/src/Escaper.php | 18 +- .../src/Exception/ExceptionInterface.php | 4 +- .../Exception/InvalidArgumentException.php | 0 .../src/Exception/RuntimeException.php | 0 vendor/league/color-extractor/.gitignore | 5 + vendor/league/color-extractor/.php_cs | 13 + vendor/league/color-extractor/.travis.yml | 16 + vendor/league/color-extractor/CONTRIBUTING.md | 32 + .../league/color-extractor/LICENSE | 0 vendor/league/color-extractor/README.md | 79 + .../league/color-extractor/composer.json | 14 +- .../league/color-extractor/phpunit.xml.dist | 13 + .../src/League/ColorExtractor}/Color.php | 0 .../League/ColorExtractor}/ColorExtractor.php | 7 - .../src/League/ColorExtractor}/Palette.php | 86 +- .../ColorExtractor/Test/PaletteTest.php | 67 + .../color-extractor/tests/assets/google.png | Bin 0 -> 21801 bytes .../tests/assets/red-transparent-50.png | Bin 0 -> 70 bytes .../color-extractor/tests/assets/test.gif | Bin 0 -> 227287 bytes .../color-extractor/tests/assets/test.jpeg | Bin 0 -> 16432 bytes .../color-extractor/tests/assets/test.png | Bin 0 -> 296329 bytes .../color-extractor/tests/bootstrap.php | 4 + .../michelf/php-smartypants/License.md | 0 .../Michelf/SmartyPants.inc.php | 0 .../php-smartypants/Michelf/SmartyPants.php | 0 .../Michelf/SmartyPantsTypographer.inc.php | 0 .../Michelf/SmartyPantsTypographer.php | 0 vendor/michelf/php-smartypants/Readme.md | 246 + vendor/michelf/php-smartypants/Readme.php | 36 + .../michelf/php-smartypants/composer.json | 0 .../ml/iri/ML/IRI/.gitignore | 0 .../ml/iri/ML/IRI/.travis.yml | 0 .../vendor => vendor}/ml/iri/ML/IRI/IRI.php | 0 .../vendor => vendor}/ml/iri/ML/IRI/LICENSE | 0 .../vendor => vendor}/ml/iri/ML/IRI/README.md | 0 .../ml/iri/ML/IRI/Test/IriTest.php | 0 .../ml/iri/ML/IRI/Test/bootstrap.php | 0 .../ml/iri/ML/IRI/composer.json | 0 .../ml/iri/ML/IRI/phpunit.xml.dist | 0 .../ml/json-ld/.devcontainer/Dockerfile | 0 .../json-ld/.devcontainer/devcontainer.json | 0 .../ml/json-ld/.github/workflows/ci.yaml | 0 .../vendor => vendor}/ml/json-ld/.gitignore | 0 .../ml/json-ld/.vscode/launch.json | 0 .../ml/json-ld/DefaultDocumentFactory.php | 0 .../vendor => vendor}/ml/json-ld/Document.php | 0 .../ml/json-ld/DocumentFactoryInterface.php | 0 .../ml/json-ld/DocumentInterface.php | 0 .../ml/json-ld/DocumentLoaderInterface.php | 0 .../Exception/InvalidQuadException.php | 0 .../ml/json-ld/Exception/JsonLdException.php | 0 .../ml/json-ld/FileGetContentsLoader.php | 0 .../vendor => vendor}/ml/json-ld/Graph.php | 0 .../ml/json-ld/GraphInterface.php | 0 .../vendor => vendor}/ml/json-ld/JsonLD.php | 0 .../ml/json-ld/JsonLdSerializable.php | 0 .../vendor => vendor}/ml/json-ld/LICENSE | 0 .../ml/json-ld/LanguageTaggedString.php | 0 .../vendor => vendor}/ml/json-ld/NQuads.php | 0 .../vendor => vendor}/ml/json-ld/Node.php | 0 .../ml/json-ld/NodeInterface.php | 0 .../ml/json-ld/Processor.php | 0 .../vendor => vendor}/ml/json-ld/Quad.php | 0 .../ml/json-ld/QuadParserInterface.php | 0 .../ml/json-ld/QuadSerializerInterface.php | 0 .../vendor => vendor}/ml/json-ld/README.md | 0 .../ml/json-ld/RdfConstants.php | 0 .../ml/json-ld/RemoteDocument.php | 0 .../ml/json-ld/Test/DocumentTest.php | 0 .../ml/json-ld/Test/EarlReportGenerator.php | 0 .../Test/FileGetContentsLoaderTest.php | 0 .../ml/json-ld/Test/Fixtures/dataset.jsonld | 0 .../Test/Fixtures/sample-compacted.jsonld | 0 .../Test/Fixtures/sample-context.jsonld | 0 .../Test/Fixtures/sample-expanded.jsonld | 0 .../Test/Fixtures/sample-flattened.jsonld | 0 .../ml/json-ld/Test/Fixtures/sample-in.jsonld | 0 .../sample-serialized-document.jsonld | 0 .../ml/json-ld/Test/GraphTest.php | 0 .../ml/json-ld/Test/JsonLDApiTest.php | 0 .../ml/json-ld/Test/JsonTestCase.php | 0 .../ml/json-ld/Test/NQuadsTest.php | 0 .../ml/json-ld/Test/TestManifestIterator.php | 0 .../ml/json-ld/Test/ValueTest.php | 0 .../ml/json-ld/Test/W3CTestSuiteTest.php | 0 .../ml/json-ld/Test/bootstrap.php | 0 .../ml/json-ld/TypedValue.php | 0 .../vendor => vendor}/ml/json-ld/Value.php | 0 .../ml/json-ld/composer.json | 0 .../ml/json-ld/phpunit.xml.dist | 0 .../html-parser/.github/workflows/test.yml | 0 .../oscarotero/html-parser/CHANGELOG.md | 9 +- .../oscarotero/html-parser/LICENSE | 0 .../oscarotero/html-parser/README.md | 0 .../oscarotero/html-parser/composer.json | 0 .../oscarotero/html-parser/src/Parser.php | 4 + vendor/phpmailer/phpmailer/COMMITMENT | 46 + .../phpmailer/phpmailer/LICENSE | 0 vendor/phpmailer/phpmailer/README.md | 230 + vendor/phpmailer/phpmailer/SECURITY.md | 37 + vendor/phpmailer/phpmailer/VERSION | 1 + .../phpmailer/phpmailer/composer.json | 13 +- .../phpmailer/phpmailer/get_oauth_token.php | 20 - .../phpmailer/language/phpmailer.lang-af.php | 0 .../phpmailer/language/phpmailer.lang-ar.php | 0 .../phpmailer/language/phpmailer.lang-az.php | 0 .../phpmailer/language/phpmailer.lang-ba.php | 0 .../phpmailer/language/phpmailer.lang-be.php | 0 .../phpmailer/language/phpmailer.lang-bg.php | 0 .../phpmailer/language/phpmailer.lang-ca.php | 0 .../phpmailer/language/phpmailer.lang-cs.php | 0 .../phpmailer/language/phpmailer.lang-da.php | 11 +- .../phpmailer/language/phpmailer.lang-de.php | 0 .../phpmailer/language/phpmailer.lang-el.php | 0 .../phpmailer/language/phpmailer.lang-eo.php | 0 .../phpmailer/language/phpmailer.lang-es.php | 4 - .../phpmailer/language/phpmailer.lang-et.php | 0 .../phpmailer/language/phpmailer.lang-fa.php | 0 .../phpmailer/language/phpmailer.lang-fi.php | 1 + .../phpmailer/language/phpmailer.lang-fo.php | 0 .../phpmailer/language/phpmailer.lang-fr.php | 1 + .../phpmailer/language/phpmailer.lang-gl.php | 0 .../phpmailer/language/phpmailer.lang-he.php | 0 .../phpmailer/language/phpmailer.lang-hi.php | 12 +- .../phpmailer/language/phpmailer.lang-hr.php | 0 .../phpmailer/language/phpmailer.lang-hu.php | 0 .../phpmailer/language/phpmailer.lang-hy.php | 0 .../phpmailer/language/phpmailer.lang-id.php | 0 .../phpmailer/language/phpmailer.lang-it.php | 0 .../phpmailer/language/phpmailer.lang-ja.php | 0 .../phpmailer/language/phpmailer.lang-ka.php | 0 .../phpmailer/language/phpmailer.lang-ko.php | 0 .../phpmailer/language/phpmailer.lang-lt.php | 0 .../phpmailer/language/phpmailer.lang-lv.php | 0 .../phpmailer/language/phpmailer.lang-mg.php | 0 .../phpmailer/language/phpmailer.lang-mn.php | 0 .../phpmailer/language/phpmailer.lang-ms.php | 0 .../phpmailer/language/phpmailer.lang-nb.php | 26 + .../phpmailer/language/phpmailer.lang-nl.php | 0 .../phpmailer/language/phpmailer.lang-pl.php | 22 +- .../phpmailer/language/phpmailer.lang-pt.php | 0 .../language/phpmailer.lang-pt_br.php | 0 .../phpmailer/language/phpmailer.lang-ro.php | 0 .../phpmailer/language/phpmailer.lang-ru.php | 0 .../phpmailer/language/phpmailer.lang-sk.php | 0 .../phpmailer/language/phpmailer.lang-sl.php | 0 .../phpmailer/language/phpmailer.lang-sr.php | 0 .../language/phpmailer.lang-sr_latn.php | 0 .../phpmailer/language/phpmailer.lang-sv.php | 0 .../phpmailer/language/phpmailer.lang-tl.php | 0 .../phpmailer/language/phpmailer.lang-tr.php | 0 .../phpmailer/language/phpmailer.lang-uk.php | 0 .../phpmailer/language/phpmailer.lang-vi.php | 0 .../phpmailer/language/phpmailer.lang-zh.php | 0 .../language/phpmailer.lang-zh_cn.php | 11 +- .../phpmailer/phpmailer/src/Exception.php | 0 .../phpmailer/phpmailer/src/OAuth.php | 0 .../phpmailer/src/OAuthTokenProvider.php | 0 .../phpmailer/phpmailer/src/PHPMailer.php | 203 +- .../phpmailer/phpmailer/src/POP3.php | 9 +- .../phpmailer/phpmailer/src/SMTP.php | 46 +- .../psr/http-client/CHANGELOG.md | 0 .../vendor => vendor}/psr/http-client/LICENSE | 0 .../psr/http-client/README.md | 0 .../psr/http-client/composer.json | 0 .../src/ClientExceptionInterface.php | 0 .../psr/http-client/src/ClientInterface.php | 0 .../src/NetworkExceptionInterface.php | 0 .../src/RequestExceptionInterface.php | 0 .../psr/http-factory/LICENSE | 0 .../psr/http-factory/README.md | 0 .../psr/http-factory/composer.json | 7 +- .../src/RequestFactoryInterface.php | 0 .../src/ResponseFactoryInterface.php | 0 .../src/ServerRequestFactoryInterface.php | 0 .../src/StreamFactoryInterface.php | 0 .../src/UploadedFileFactoryInterface.php | 12 +- .../http-factory/src/UriFactoryInterface.php | 0 .../psr/http-message/CHANGELOG.md | 0 .../psr/http-message/LICENSE | 0 .../psr/http-message/README.md | 0 .../psr/http-message/composer.json | 0 .../psr/http-message/docs/PSR7-Interfaces.md | 0 .../psr/http-message/docs/PSR7-Usage.md | 0 .../psr/http-message/src/MessageInterface.php | 0 .../psr/http-message/src/RequestInterface.php | 0 .../http-message/src/ResponseInterface.php | 0 .../src/ServerRequestInterface.php | 0 .../psr/http-message/src/StreamInterface.php | 0 .../src/UploadedFileInterface.php | 0 .../psr/http-message/src/UriInterface.php | 0 {kirby/vendor => vendor}/psr/log/LICENSE | 0 vendor/psr/log/Psr/Log/AbstractLogger.php | 128 + .../log/Psr/Log}/InvalidArgumentException.php | 0 .../psr/log/Psr/Log}/LogLevel.php | 0 .../psr/log/Psr/Log}/LoggerAwareInterface.php | 2 +- .../psr/log/Psr/Log}/LoggerAwareTrait.php | 4 +- .../psr/log/Psr/Log}/LoggerInterface.php | 36 +- .../psr/log/Psr/Log}/LoggerTrait.php | 36 +- .../psr/log/Psr/Log}/NullLogger.php | 6 +- vendor/psr/log/Psr/Log/Test/DummyTest.php | 18 + .../log/Psr/Log/Test/LoggerInterfaceTest.php | 138 + vendor/psr/log/Psr/Log/Test/TestLogger.php | 147 + vendor/psr/log/README.md | 58 + .../vendor => vendor}/psr/log/composer.json | 6 +- .../ralouphie/getallheaders/LICENSE | 0 .../ralouphie/getallheaders/README.md | 0 .../ralouphie/getallheaders/composer.json | 0 .../getallheaders/src/getallheaders.php | 0 .../symfony/polyfill-intl-idn/Idn.php | 30 +- .../symfony/polyfill-intl-idn/Info.php | 0 .../symfony/polyfill-intl-idn}/LICENSE | 2 +- vendor/symfony/polyfill-intl-idn/README.md | 12 + .../Resources/unidata/DisallowedRanges.php | 9 - .../Resources/unidata/Regex.php | 9 - .../Resources/unidata/deviation.php | 0 .../Resources/unidata/disallowed.php | 0 .../unidata/disallowed_STD3_mapped.php | 0 .../unidata/disallowed_STD3_valid.php | 0 .../Resources/unidata/ignored.php | 0 .../Resources/unidata/mapped.php | 0 .../Resources/unidata/virama.php | 0 .../symfony/polyfill-intl-idn/bootstrap.php | 0 .../symfony/polyfill-intl-idn/bootstrap80.php | 0 .../symfony/polyfill-intl-idn/composer.json | 3 + .../symfony/polyfill-intl-normalizer/LICENSE | 0 .../polyfill-intl-normalizer/Normalizer.php | 0 .../polyfill-intl-normalizer/README.md | 14 + .../Resources/stubs/Normalizer.php | 0 .../unidata/canonicalComposition.php | 0 .../unidata/canonicalDecomposition.php | 0 .../Resources/unidata/combiningClass.php | 0 .../unidata/compatibilityDecomposition.php | 0 .../polyfill-intl-normalizer/bootstrap.php | 0 .../polyfill-intl-normalizer/bootstrap80.php | 0 .../polyfill-intl-normalizer/composer.json | 0 .../symfony/polyfill-mbstring}/LICENSE | 2 +- .../symfony/polyfill-mbstring/Mbstring.php | 146 +- vendor/symfony/polyfill-mbstring/README.md | 13 + .../Resources/unidata/lowerCase.php | 0 .../Resources/unidata/titleCaseRegexp.php | 0 .../Resources/unidata/upperCase.php | 0 .../symfony/polyfill-mbstring/bootstrap.php | 4 - .../symfony/polyfill-mbstring/bootstrap80.php | 4 - .../symfony/polyfill-mbstring/composer.json | 3 + 1085 files changed, 54743 insertions(+), 65042 deletions(-) create mode 100644 .envrc create mode 100644 composer.lock delete mode 100644 kirby/config/api/models/License.php delete mode 100644 kirby/config/api/routes/kql.php delete mode 100644 kirby/config/areas/account/drawers.php delete mode 100644 kirby/config/areas/fields/dialogs.php delete mode 100644 kirby/config/areas/fields/drawers.php delete mode 100644 kirby/config/areas/lab.php delete mode 100644 kirby/config/areas/lab/drawers.php delete mode 100644 kirby/config/areas/lab/views.php delete mode 100644 kirby/config/areas/search.php delete mode 100644 kirby/config/areas/search/views.php delete mode 100644 kirby/config/areas/site/drawers.php delete mode 100644 kirby/config/areas/site/requests.php delete mode 100644 kirby/config/areas/users/drawers.php create mode 100644 kirby/config/blueprints/blocks/code.yml create mode 100644 kirby/config/blueprints/blocks/heading.yml create mode 100644 kirby/config/blueprints/blocks/image.yml create mode 100644 kirby/config/blueprints/blocks/quote.yml create mode 100644 kirby/config/blueprints/blocks/table.yml create mode 100644 kirby/config/blueprints/blocks/text.yml create mode 100644 kirby/config/blueprints/blocks/video.yml create mode 100644 kirby/config/blueprints/files/default.yml create mode 100644 kirby/config/blueprints/pages/default.yml create mode 100644 kirby/config/blueprints/site.yml delete mode 100644 kirby/config/fields/color.php delete mode 100644 kirby/config/fields/link.php delete mode 100644 kirby/config/fields/object.php rename kirby/i18n/rules/{ro.json => rm.json} (100%) delete mode 100644 kirby/i18n/translations/ro.json delete mode 100644 kirby/package-lock.json delete mode 100644 kirby/panel/.prettierignore delete mode 100644 kirby/panel/dist/apple-touch-icon-dark.png create mode 100644 kirby/panel/dist/css/style.css delete mode 100644 kirby/panel/dist/css/style.min.css delete mode 100644 kirby/panel/dist/favicon-dark.png delete mode 100644 kirby/panel/dist/js/Docs.min.js delete mode 100644 kirby/panel/dist/js/DocsView.min.js delete mode 100644 kirby/panel/dist/js/Highlight.min.js delete mode 100644 kirby/panel/dist/js/IndexView.min.js delete mode 100644 kirby/panel/dist/js/PlaygroundView.min.js delete mode 100644 kirby/panel/dist/js/container-query-polyfill.modern.min.js create mode 100644 kirby/panel/dist/js/index.js delete mode 100644 kirby/panel/dist/js/index.min.js create mode 100644 kirby/panel/dist/js/vendor.js delete mode 100644 kirby/panel/dist/js/vendor.min.js delete mode 100644 kirby/panel/dist/js/vue.min.js create mode 100644 kirby/panel/dist/js/vuedraggable.js delete mode 100644 kirby/panel/dist/js/vuedraggable.min.js delete mode 100644 kirby/panel/eslint.config.mjs delete mode 100644 kirby/src/Blueprint/Collection.php delete mode 100644 kirby/src/Blueprint/Config.php delete mode 100644 kirby/src/Blueprint/Extension.php delete mode 100644 kirby/src/Blueprint/Factory.php delete mode 100644 kirby/src/Blueprint/Node.php delete mode 100644 kirby/src/Blueprint/NodeI18n.php delete mode 100644 kirby/src/Blueprint/NodeIcon.php delete mode 100644 kirby/src/Blueprint/NodeProperty.php delete mode 100644 kirby/src/Blueprint/NodeString.php delete mode 100644 kirby/src/Blueprint/NodeText.php delete mode 100644 kirby/src/Cms/Auth/TotpChallenge.php delete mode 100644 kirby/src/Cms/BlockConverter.php rename kirby/src/{Content => Cms}/Content.php (67%) create mode 100644 kirby/src/Cms/ContentTranslation.php rename kirby/src/{Content => Cms}/Field.php (66%) delete mode 100644 kirby/src/Cms/LanguageVariable.php delete mode 100644 kirby/src/Cms/License.php delete mode 100644 kirby/src/Cms/LicenseStatus.php delete mode 100644 kirby/src/Cms/LicenseType.php delete mode 100644 kirby/src/Cms/PluginAsset.php delete mode 100644 kirby/src/Cms/System/UpdateStatus.php create mode 100644 kirby/src/Cms/Template.php delete mode 100644 kirby/src/Content/ContentStorage.php delete mode 100644 kirby/src/Content/ContentStorageHandler.php delete mode 100644 kirby/src/Content/ContentTranslation.php delete mode 100644 kirby/src/Content/PlainTextContentStorageHandler.php delete mode 100644 kirby/src/Data/YamlSpyc.php delete mode 100644 kirby/src/Data/YamlSymfony.php delete mode 100644 kirby/src/Exception/AuthException.php delete mode 100644 kirby/src/Field/FieldOptions.php create mode 100644 kirby/src/Form/Options.php create mode 100644 kirby/src/Form/OptionsApi.php create mode 100644 kirby/src/Form/OptionsQuery.php create mode 100644 kirby/src/Http/Server.php delete mode 100644 kirby/src/Image/Focus.php delete mode 100644 kirby/src/Image/QrCode.php delete mode 100644 kirby/src/Option/Option.php delete mode 100644 kirby/src/Option/Options.php delete mode 100644 kirby/src/Option/OptionsApi.php delete mode 100644 kirby/src/Option/OptionsProvider.php delete mode 100644 kirby/src/Option/OptionsQuery.php delete mode 100644 kirby/src/Panel/Assets.php delete mode 100644 kirby/src/Panel/ChangesDialog.php delete mode 100644 kirby/src/Panel/Drawer.php delete mode 100644 kirby/src/Panel/Lab/Category.php delete mode 100644 kirby/src/Panel/Lab/Docs.php delete mode 100644 kirby/src/Panel/Lab/Example.php delete mode 100644 kirby/src/Panel/Lab/Snippet.php delete mode 100644 kirby/src/Panel/Lab/Template.php delete mode 100644 kirby/src/Panel/Menu.php delete mode 100644 kirby/src/Panel/PageCreateDialog.php delete mode 100644 kirby/src/Panel/Request.php delete mode 100644 kirby/src/Panel/UserTotpDisableDialog.php delete mode 100644 kirby/src/Panel/UserTotpEnableDialog.php delete mode 100644 kirby/src/Query/Argument.php delete mode 100644 kirby/src/Query/Arguments.php delete mode 100644 kirby/src/Query/Expression.php delete mode 100644 kirby/src/Query/Query.php delete mode 100644 kirby/src/Query/Segment.php delete mode 100644 kirby/src/Query/Segments.php delete mode 100644 kirby/src/Template/Slot.php delete mode 100644 kirby/src/Template/Slots.php delete mode 100644 kirby/src/Template/Snippet.php delete mode 100644 kirby/src/Template/Template.php delete mode 100644 kirby/src/Toolkit/LazyValue.php create mode 100644 kirby/src/Toolkit/Query.php delete mode 100644 kirby/src/Toolkit/SymmetricCrypto.php delete mode 100644 kirby/src/Toolkit/Totp.php delete mode 100644 kirby/src/Uuid/BlockUuid.php delete mode 100644 kirby/src/Uuid/FieldUuid.php delete mode 100644 kirby/src/Uuid/FileUuid.php delete mode 100644 kirby/src/Uuid/HasUuids.php delete mode 100644 kirby/src/Uuid/Identifiable.php delete mode 100644 kirby/src/Uuid/ModelUuid.php delete mode 100644 kirby/src/Uuid/PageUuid.php delete mode 100644 kirby/src/Uuid/SiteUuid.php delete mode 100644 kirby/src/Uuid/StructureUuid.php delete mode 100644 kirby/src/Uuid/Uri.php delete mode 100644 kirby/src/Uuid/UserUuid.php delete mode 100644 kirby/src/Uuid/Uuid.php delete mode 100644 kirby/src/Uuid/Uuids.php delete mode 100755 kirby/vendor/bin/yaml-lint delete mode 100644 kirby/vendor/bin/yaml-lint.bat delete mode 100644 kirby/vendor/christian-riesen/base32/src/Base32.php delete mode 100644 kirby/vendor/christian-riesen/base32/src/Base32Hex.php delete mode 100644 kirby/vendor/claviska/simpleimage/composer.lock delete mode 100644 kirby/vendor/claviska/simpleimage/src/claviska/SimpleImage.php delete mode 100644 kirby/vendor/composer/autoload_classmap.php delete mode 100644 kirby/vendor/composer/autoload_psr4.php delete mode 100644 kirby/vendor/composer/autoload_static.php delete mode 100644 kirby/vendor/composer/installed.json delete mode 100644 kirby/vendor/composer/installed.php delete mode 100644 kirby/vendor/composer/semver/LICENSE delete mode 100644 kirby/vendor/composer/semver/composer.json delete mode 100644 kirby/vendor/composer/semver/phpstan-baseline.neon delete mode 100644 kirby/vendor/composer/semver/src/Comparator.php delete mode 100644 kirby/vendor/composer/semver/src/CompilingMatcher.php delete mode 100644 kirby/vendor/composer/semver/src/Constraint/Bound.php delete mode 100644 kirby/vendor/composer/semver/src/Constraint/Constraint.php delete mode 100644 kirby/vendor/composer/semver/src/Constraint/ConstraintInterface.php delete mode 100644 kirby/vendor/composer/semver/src/Constraint/MatchAllConstraint.php delete mode 100644 kirby/vendor/composer/semver/src/Constraint/MatchNoneConstraint.php delete mode 100644 kirby/vendor/composer/semver/src/Constraint/MultiConstraint.php delete mode 100644 kirby/vendor/composer/semver/src/Interval.php delete mode 100644 kirby/vendor/composer/semver/src/Intervals.php delete mode 100644 kirby/vendor/composer/semver/src/Semver.php delete mode 100644 kirby/vendor/composer/semver/src/VersionParser.php delete mode 100644 kirby/vendor/filp/whoops/src/Whoops/Inspector/InspectorFactory.php delete mode 100644 kirby/vendor/filp/whoops/src/Whoops/Inspector/InspectorFactoryInterface.php delete mode 100644 kirby/vendor/filp/whoops/src/Whoops/Inspector/InspectorInterface.php delete mode 100644 kirby/vendor/filp/whoops/src/Whoops/Resources/css/prism.css delete mode 100644 kirby/vendor/filp/whoops/src/Whoops/Resources/js/prism.js delete mode 100644 kirby/vendor/phpmailer/phpmailer/language/phpmailer.lang-as.php delete mode 100644 kirby/vendor/phpmailer/phpmailer/language/phpmailer.lang-bn.php delete mode 100644 kirby/vendor/phpmailer/phpmailer/language/phpmailer.lang-nb.php delete mode 100644 kirby/vendor/phpmailer/phpmailer/language/phpmailer.lang-si.php delete mode 100644 kirby/vendor/phpmailer/phpmailer/src/DSNConfigurator.php delete mode 100644 kirby/vendor/psr/log/src/AbstractLogger.php delete mode 100644 kirby/vendor/symfony/deprecation-contracts/composer.json delete mode 100644 kirby/vendor/symfony/deprecation-contracts/function.php delete mode 100644 kirby/vendor/symfony/polyfill-ctype/Ctype.php delete mode 100644 kirby/vendor/symfony/polyfill-ctype/LICENSE delete mode 100644 kirby/vendor/symfony/polyfill-ctype/bootstrap.php delete mode 100644 kirby/vendor/symfony/polyfill-ctype/bootstrap80.php delete mode 100644 kirby/vendor/symfony/polyfill-ctype/composer.json delete mode 100644 kirby/vendor/symfony/polyfill-intl-idn/LICENSE delete mode 100644 kirby/vendor/symfony/polyfill-mbstring/Resources/unidata/caseFolding.php delete mode 100644 kirby/vendor/symfony/yaml/Command/LintCommand.php delete mode 100644 kirby/vendor/symfony/yaml/Dumper.php delete mode 100644 kirby/vendor/symfony/yaml/Escaper.php delete mode 100644 kirby/vendor/symfony/yaml/Exception/DumpException.php delete mode 100644 kirby/vendor/symfony/yaml/Exception/ExceptionInterface.php delete mode 100644 kirby/vendor/symfony/yaml/Exception/ParseException.php delete mode 100644 kirby/vendor/symfony/yaml/Exception/RuntimeException.php delete mode 100644 kirby/vendor/symfony/yaml/Inline.php delete mode 100644 kirby/vendor/symfony/yaml/LICENSE delete mode 100644 kirby/vendor/symfony/yaml/Parser.php delete mode 100755 kirby/vendor/symfony/yaml/Resources/bin/yaml-lint delete mode 100644 kirby/vendor/symfony/yaml/Tag/TaggedValue.php delete mode 100644 kirby/vendor/symfony/yaml/Unescaper.php delete mode 100644 kirby/vendor/symfony/yaml/Yaml.php delete mode 100644 kirby/vendor/symfony/yaml/composer.json create mode 100644 site/plugins/color-palette/.editorconfig create mode 100644 site/plugins/color-palette/.gitignore create mode 100644 site/plugins/color-palette/README.md create mode 100644 site/plugins/color-palette/composer.json create mode 100644 site/plugins/color-palette/index.css create mode 100644 site/plugins/color-palette/index.js create mode 100644 site/plugins/color-palette/index.php create mode 100644 site/plugins/color-palette/lib/api.php create mode 100644 site/plugins/color-palette/lib/color-palette.php create mode 100644 site/plugins/color-palette/lib/fields.php create mode 100644 site/plugins/color-palette/lib/languages/de.php create mode 100644 site/plugins/color-palette/lib/languages/en.php create mode 100644 site/plugins/color-palette/lib/languages/fr.php create mode 100644 site/plugins/color-palette/package.json create mode 100644 site/plugins/color-palette/src/assets/css/styles.scss create mode 100644 site/plugins/color-palette/src/assets/svg/icons.js create mode 100644 site/plugins/color-palette/src/assets/svg/pipette.svg create mode 100644 site/plugins/color-palette/src/components/field/ColorPalette.vue create mode 100644 site/plugins/color-palette/src/index.js delete mode 100644 site/plugins/embed/vendor/autoload.php delete mode 100644 site/plugins/embed/vendor/composer/ClassLoader.php delete mode 100644 site/plugins/embed/vendor/composer/InstalledVersions.php delete mode 100644 site/plugins/embed/vendor/composer/LICENSE delete mode 100644 site/plugins/embed/vendor/composer/autoload_classmap.php delete mode 100644 site/plugins/embed/vendor/composer/autoload_files.php delete mode 100644 site/plugins/embed/vendor/composer/autoload_namespaces.php delete mode 100644 site/plugins/embed/vendor/composer/autoload_psr4.php delete mode 100644 site/plugins/embed/vendor/composer/autoload_real.php delete mode 100644 site/plugins/embed/vendor/composer/autoload_static.php delete mode 100644 site/plugins/embed/vendor/composer/installed.json delete mode 100644 site/plugins/embed/vendor/composer/installed.php create mode 100644 site/plugins/kirby-fields-block/.gitignore rename kirby/vendor/symfony/deprecation-contracts/LICENSE => site/plugins/kirby-fields-block/LICENSE.md (87%) mode change 100644 => 100755 create mode 100755 site/plugins/kirby-fields-block/README.md create mode 100755 site/plugins/kirby-fields-block/composer.json create mode 100644 site/plugins/kirby-fields-block/index.css create mode 100644 site/plugins/kirby-fields-block/index.js create mode 100644 site/plugins/kirby-fields-block/index.php create mode 100644 site/plugins/kirby-fields-block/package.json create mode 100644 site/plugins/kirby-fields-block/postcss.config.js create mode 100644 site/plugins/kirby-fields-block/src/FieldsBlock.vue create mode 100644 site/plugins/kirby-fields-block/src/index.js rename {kirby/vendor => vendor}/autoload.php (91%) create mode 100644 vendor/claviska/simpleimage/.editorconfig create mode 100644 vendor/claviska/simpleimage/.github/FUNDING.yml create mode 100644 vendor/claviska/simpleimage/.gitignore rename {kirby/vendor => vendor}/claviska/simpleimage/LICENSE.md (100%) create mode 100644 vendor/claviska/simpleimage/README.md rename {kirby/vendor => vendor}/claviska/simpleimage/composer.json (73%) create mode 100644 vendor/claviska/simpleimage/example/flag.png create mode 100644 vendor/claviska/simpleimage/example/index.php create mode 100644 vendor/claviska/simpleimage/example/parrot.jpg create mode 100644 vendor/claviska/simpleimage/src/claviska/SimpleImage.php rename {kirby/vendor => vendor}/composer/ClassLoader.php (100%) rename {kirby/vendor => vendor}/composer/InstalledVersions.php (100%) rename {kirby/vendor => vendor}/composer/LICENSE (100%) create mode 100644 vendor/composer/autoload_classmap.php rename {kirby/vendor => vendor}/composer/autoload_files.php (55%) rename {kirby/vendor => vendor}/composer/autoload_namespaces.php (84%) create mode 100644 vendor/composer/autoload_psr4.php rename {kirby/vendor => vendor}/composer/autoload_real.php (65%) create mode 100644 vendor/composer/autoload_static.php rename {site/plugins/embed/vendor => vendor}/composer/ca-bundle/LICENSE (100%) rename {site/plugins/embed/vendor => vendor}/composer/ca-bundle/README.md (100%) rename {site/plugins/embed/vendor => vendor}/composer/ca-bundle/composer.json (81%) rename {site/plugins/embed/vendor => vendor}/composer/ca-bundle/res/cacert.pem (94%) rename {site/plugins/embed/vendor => vendor}/composer/ca-bundle/src/CaBundle.php (56%) create mode 100644 vendor/composer/installed.json create mode 100644 vendor/composer/installed.php rename {site/plugins/embed/vendor => vendor}/composer/platform_check.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/CHANGELOG.md (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/LICENSE (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/README.md (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/composer.json (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/Adapters/Archive/Api.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/Adapters/Archive/Detectors/AuthorName.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/Adapters/Archive/Detectors/Code.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/Adapters/Archive/Detectors/Description.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/Adapters/Archive/Detectors/ProviderName.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/Adapters/Archive/Detectors/PublishedTime.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/Adapters/Archive/Detectors/Title.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/Adapters/Archive/Extractor.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/Adapters/Bandcamp/Detectors/ProviderName.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/Adapters/Bandcamp/Extractor.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/Adapters/CadenaSer/Detectors/Code.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/Adapters/CadenaSer/Extractor.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/Adapters/Facebook/Detectors/Title.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/Adapters/Facebook/Extractor.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/Adapters/Facebook/OEmbed.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/Adapters/Flickr/Detectors/Code.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/Adapters/Flickr/Extractor.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/Adapters/Gist/Api.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/Adapters/Gist/Detectors/AuthorName.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/Adapters/Gist/Detectors/AuthorUrl.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/Adapters/Gist/Detectors/Code.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/Adapters/Gist/Detectors/PublishedTime.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/Adapters/Gist/Extractor.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/Adapters/Github/Detectors/Code.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/Adapters/Github/Extractor.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/Adapters/Ideone/Detectors/Code.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/Adapters/Ideone/Extractor.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/Adapters/ImageShack/Api.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/Adapters/ImageShack/Detectors/AuthorName.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/Adapters/ImageShack/Detectors/AuthorUrl.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/Adapters/ImageShack/Detectors/Description.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/Adapters/ImageShack/Detectors/Image.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/Adapters/ImageShack/Detectors/ProviderName.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/Adapters/ImageShack/Detectors/PublishedTime.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/Adapters/ImageShack/Detectors/Title.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/Adapters/ImageShack/Extractor.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/Adapters/Instagram/Extractor.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/Adapters/Instagram/OEmbed.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/Adapters/Pinterest/Detectors/Code.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/Adapters/Pinterest/Extractor.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/Adapters/Sassmeister/Detectors/Code.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/Adapters/Sassmeister/Extractor.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/Adapters/Slides/Detectors/Code.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/Adapters/Slides/Extractor.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/Adapters/Snipplr/Detectors/Code.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/Adapters/Snipplr/Extractor.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/Adapters/Twitch/Detectors/Code.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/Adapters/Twitch/Extractor.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/Adapters/Twitter/Api.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/Adapters/Twitter/Detectors/AuthorName.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/Adapters/Twitter/Detectors/AuthorUrl.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/Adapters/Twitter/Detectors/Description.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/Adapters/Twitter/Detectors/Image.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/Adapters/Twitter/Detectors/ProviderName.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/Adapters/Twitter/Detectors/PublishedTime.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/Adapters/Twitter/Detectors/Title.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/Adapters/Twitter/Extractor.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/Adapters/Wikipedia/Api.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/Adapters/Wikipedia/Detectors/Description.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/Adapters/Wikipedia/Detectors/Title.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/Adapters/Wikipedia/Extractor.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/Adapters/Youtube/Detectors/Feeds.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/Adapters/Youtube/Extractor.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/ApiTrait.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/Detectors/AuthorName.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/Detectors/AuthorUrl.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/Detectors/Cms.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/Detectors/Code.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/Detectors/Description.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/Detectors/Detector.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/Detectors/Favicon.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/Detectors/Feeds.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/Detectors/Icon.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/Detectors/Image.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/Detectors/Keywords.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/Detectors/Language.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/Detectors/Languages.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/Detectors/License.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/Detectors/ProviderName.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/Detectors/ProviderUrl.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/Detectors/PublishedTime.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/Detectors/Redirect.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/Detectors/Title.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/Detectors/Url.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/Document.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/Embed.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/EmbedCode.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/Extractor.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/ExtractorFactory.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/Http/Crawler.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/Http/CurlClient.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/Http/CurlDispatcher.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/Http/FactoryDiscovery.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/Http/NetworkException.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/Http/RequestException.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/HttpApiTrait.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/LinkedData.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/Metas.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/OEmbed.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/QueryResult.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/functions.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/resources/oembed.php (100%) rename {site/plugins/embed/vendor => vendor}/embed/embed/src/resources/suffix.php (100%) create mode 100644 vendor/filp/whoops/.github/FUNDING.yml create mode 100644 vendor/filp/whoops/.github/workflows/tests.yml create mode 100644 vendor/filp/whoops/.mailmap create mode 100644 vendor/filp/whoops/CHANGELOG.md rename {kirby/vendor => vendor}/filp/whoops/LICENSE.md (100%) create mode 100644 vendor/filp/whoops/SECURITY.md rename {kirby/vendor => vendor}/filp/whoops/composer.json (100%) rename {kirby/vendor => vendor}/filp/whoops/src/Whoops/Exception/ErrorException.php (100%) rename {kirby/vendor => vendor}/filp/whoops/src/Whoops/Exception/Formatter.php (81%) rename {kirby/vendor => vendor}/filp/whoops/src/Whoops/Exception/Frame.php (99%) rename {kirby/vendor => vendor}/filp/whoops/src/Whoops/Exception/FrameCollection.php (99%) rename {kirby/vendor => vendor}/filp/whoops/src/Whoops/Exception/Inspector.php (90%) rename {kirby/vendor => vendor}/filp/whoops/src/Whoops/Handler/CallbackHandler.php (100%) rename {kirby/vendor => vendor}/filp/whoops/src/Whoops/Handler/Handler.php (88%) rename {kirby/vendor => vendor}/filp/whoops/src/Whoops/Handler/HandlerInterface.php (79%) rename {kirby/vendor => vendor}/filp/whoops/src/Whoops/Handler/JsonResponseHandler.php (89%) rename {kirby/vendor => vendor}/filp/whoops/src/Whoops/Handler/PlainTextHandler.php (99%) rename {kirby/vendor => vendor}/filp/whoops/src/Whoops/Handler/PrettyPageHandler.php (98%) rename {kirby/vendor => vendor}/filp/whoops/src/Whoops/Handler/XmlResponseHandler.php (96%) create mode 100644 vendor/filp/whoops/src/Whoops/Resources/css/prism.css rename {kirby/vendor => vendor}/filp/whoops/src/Whoops/Resources/css/whoops.base.css (98%) rename {kirby/vendor => vendor}/filp/whoops/src/Whoops/Resources/js/clipboard.min.js (100%) create mode 100644 vendor/filp/whoops/src/Whoops/Resources/js/prism.js rename {kirby/vendor => vendor}/filp/whoops/src/Whoops/Resources/js/whoops.base.js (98%) rename {kirby/vendor => vendor}/filp/whoops/src/Whoops/Resources/js/zepto.min.js (100%) rename {kirby/vendor => vendor}/filp/whoops/src/Whoops/Resources/views/env_details.html.php (100%) rename {kirby/vendor => vendor}/filp/whoops/src/Whoops/Resources/views/frame_code.html.php (98%) rename {kirby/vendor => vendor}/filp/whoops/src/Whoops/Resources/views/frame_list.html.php (100%) rename {kirby/vendor => vendor}/filp/whoops/src/Whoops/Resources/views/frames_container.html.php (100%) rename {kirby/vendor => vendor}/filp/whoops/src/Whoops/Resources/views/frames_description.html.php (100%) rename {kirby/vendor => vendor}/filp/whoops/src/Whoops/Resources/views/header.html.php (100%) rename {kirby/vendor => vendor}/filp/whoops/src/Whoops/Resources/views/header_outer.html.php (100%) rename {kirby/vendor => vendor}/filp/whoops/src/Whoops/Resources/views/layout.html.php (100%) rename {kirby/vendor => vendor}/filp/whoops/src/Whoops/Resources/views/panel_details.html.php (100%) rename {kirby/vendor => vendor}/filp/whoops/src/Whoops/Resources/views/panel_details_outer.html.php (100%) rename {kirby/vendor => vendor}/filp/whoops/src/Whoops/Resources/views/panel_left.html.php (100%) rename {kirby/vendor => vendor}/filp/whoops/src/Whoops/Resources/views/panel_left_outer.html.php (100%) rename {kirby/vendor => vendor}/filp/whoops/src/Whoops/Run.php (91%) rename {kirby/vendor => vendor}/filp/whoops/src/Whoops/RunInterface.php (90%) rename {kirby/vendor => vendor}/filp/whoops/src/Whoops/Util/HtmlDumperOutput.php (100%) rename {kirby/vendor => vendor}/filp/whoops/src/Whoops/Util/Misc.php (100%) rename {kirby/vendor => vendor}/filp/whoops/src/Whoops/Util/SystemFacade.php (100%) rename {kirby/vendor => vendor}/filp/whoops/src/Whoops/Util/TemplateHelper.php (99%) rename {site/plugins/embed/vendor => vendor}/getkirby/composer-installer/composer.json (100%) create mode 100644 vendor/getkirby/composer-installer/composer.lock rename {site/plugins/embed/vendor => vendor}/getkirby/composer-installer/readme.md (100%) rename {site/plugins/embed/vendor => vendor}/getkirby/composer-installer/src/ComposerInstaller/CmsInstaller.php (100%) rename {site/plugins/embed/vendor => vendor}/getkirby/composer-installer/src/ComposerInstaller/Installer.php (100%) rename {site/plugins/embed/vendor => vendor}/getkirby/composer-installer/src/ComposerInstaller/Plugin.php (100%) rename {site/plugins/embed/vendor => vendor}/getkirby/composer-installer/src/ComposerInstaller/PluginInstaller.php (100%) rename {site/plugins/embed/vendor => vendor}/guzzlehttp/psr7/CHANGELOG.md (95%) rename {site/plugins/embed/vendor => vendor}/guzzlehttp/psr7/LICENSE (100%) rename {site/plugins/embed/vendor => vendor}/guzzlehttp/psr7/README.md (96%) rename {site/plugins/embed/vendor => vendor}/guzzlehttp/psr7/composer.json (94%) rename {site/plugins/embed/vendor => vendor}/guzzlehttp/psr7/src/AppendStream.php (100%) rename {site/plugins/embed/vendor => vendor}/guzzlehttp/psr7/src/BufferStream.php (100%) rename {site/plugins/embed/vendor => vendor}/guzzlehttp/psr7/src/CachingStream.php (99%) rename {site/plugins/embed/vendor => vendor}/guzzlehttp/psr7/src/DroppingStream.php (100%) rename {site/plugins/embed/vendor => vendor}/guzzlehttp/psr7/src/Exception/MalformedUriException.php (100%) rename {site/plugins/embed/vendor => vendor}/guzzlehttp/psr7/src/FnStream.php (81%) rename {site/plugins/embed/vendor => vendor}/guzzlehttp/psr7/src/Header.php (99%) rename {site/plugins/embed/vendor => vendor}/guzzlehttp/psr7/src/HttpFactory.php (96%) rename {site/plugins/embed/vendor => vendor}/guzzlehttp/psr7/src/InflateStream.php (82%) rename {site/plugins/embed/vendor => vendor}/guzzlehttp/psr7/src/LazyOpenStream.php (100%) rename {site/plugins/embed/vendor => vendor}/guzzlehttp/psr7/src/LimitStream.php (100%) rename {site/plugins/embed/vendor => vendor}/guzzlehttp/psr7/src/Message.php (96%) rename {site/plugins/embed/vendor => vendor}/guzzlehttp/psr7/src/MessageTrait.php (96%) rename {site/plugins/embed/vendor => vendor}/guzzlehttp/psr7/src/MimeType.php (100%) rename {site/plugins/embed/vendor => vendor}/guzzlehttp/psr7/src/MultipartStream.php (88%) rename {site/plugins/embed/vendor => vendor}/guzzlehttp/psr7/src/NoSeekStream.php (100%) rename {site/plugins/embed/vendor => vendor}/guzzlehttp/psr7/src/PumpStream.php (96%) rename {site/plugins/embed/vendor => vendor}/guzzlehttp/psr7/src/Query.php (80%) rename {site/plugins/embed/vendor => vendor}/guzzlehttp/psr7/src/Request.php (96%) rename {site/plugins/embed/vendor => vendor}/guzzlehttp/psr7/src/Response.php (98%) rename {site/plugins/embed/vendor => vendor}/guzzlehttp/psr7/src/Rfc7230.php (100%) rename {site/plugins/embed/vendor => vendor}/guzzlehttp/psr7/src/ServerRequest.php (99%) rename {site/plugins/embed/vendor => vendor}/guzzlehttp/psr7/src/Stream.php (98%) rename {site/plugins/embed/vendor => vendor}/guzzlehttp/psr7/src/StreamDecoratorTrait.php (98%) rename {site/plugins/embed/vendor => vendor}/guzzlehttp/psr7/src/StreamWrapper.php (83%) rename {site/plugins/embed/vendor => vendor}/guzzlehttp/psr7/src/UploadedFile.php (95%) rename {site/plugins/embed/vendor => vendor}/guzzlehttp/psr7/src/Uri.php (95%) rename {site/plugins/embed/vendor => vendor}/guzzlehttp/psr7/src/UriComparator.php (100%) rename {site/plugins/embed/vendor => vendor}/guzzlehttp/psr7/src/UriNormalizer.php (96%) rename {site/plugins/embed/vendor => vendor}/guzzlehttp/psr7/src/UriResolver.php (97%) rename {site/plugins/embed/vendor => vendor}/guzzlehttp/psr7/src/Utils.php (96%) rename {kirby/vendor => vendor}/laminas/laminas-escaper/COPYRIGHT.md (100%) rename {kirby/vendor => vendor}/laminas/laminas-escaper/LICENSE.md (100%) create mode 100644 vendor/laminas/laminas-escaper/README.md rename {kirby/vendor => vendor}/laminas/laminas-escaper/composer.json (86%) create mode 100644 vendor/laminas/laminas-escaper/composer.lock rename {kirby/vendor => vendor}/laminas/laminas-escaper/src/Escaper.php (94%) rename {kirby/vendor => vendor}/laminas/laminas-escaper/src/Exception/ExceptionInterface.php (54%) rename {kirby/vendor => vendor}/laminas/laminas-escaper/src/Exception/InvalidArgumentException.php (100%) rename {kirby/vendor => vendor}/laminas/laminas-escaper/src/Exception/RuntimeException.php (100%) create mode 100644 vendor/league/color-extractor/.gitignore create mode 100644 vendor/league/color-extractor/.php_cs create mode 100644 vendor/league/color-extractor/.travis.yml create mode 100644 vendor/league/color-extractor/CONTRIBUTING.md rename {kirby/vendor => vendor}/league/color-extractor/LICENSE (100%) create mode 100644 vendor/league/color-extractor/README.md rename {kirby/vendor => vendor}/league/color-extractor/composer.json (67%) create mode 100644 vendor/league/color-extractor/phpunit.xml.dist rename {kirby/vendor/league/color-extractor/src => vendor/league/color-extractor/src/League/ColorExtractor}/Color.php (100%) rename {kirby/vendor/league/color-extractor/src => vendor/league/color-extractor/src/League/ColorExtractor}/ColorExtractor.php (98%) rename {kirby/vendor/league/color-extractor/src => vendor/league/color-extractor/src/League/ColorExtractor}/Palette.php (62%) create mode 100644 vendor/league/color-extractor/tests/League/ColorExtractor/Test/PaletteTest.php create mode 100644 vendor/league/color-extractor/tests/assets/google.png create mode 100644 vendor/league/color-extractor/tests/assets/red-transparent-50.png create mode 100644 vendor/league/color-extractor/tests/assets/test.gif create mode 100644 vendor/league/color-extractor/tests/assets/test.jpeg create mode 100644 vendor/league/color-extractor/tests/assets/test.png create mode 100644 vendor/league/color-extractor/tests/bootstrap.php rename {kirby/vendor => vendor}/michelf/php-smartypants/License.md (100%) rename {kirby/vendor => vendor}/michelf/php-smartypants/Michelf/SmartyPants.inc.php (100%) rename {kirby/vendor => vendor}/michelf/php-smartypants/Michelf/SmartyPants.php (100%) rename {kirby/vendor => vendor}/michelf/php-smartypants/Michelf/SmartyPantsTypographer.inc.php (100%) rename {kirby/vendor => vendor}/michelf/php-smartypants/Michelf/SmartyPantsTypographer.php (100%) create mode 100644 vendor/michelf/php-smartypants/Readme.md create mode 100644 vendor/michelf/php-smartypants/Readme.php rename {kirby/vendor => vendor}/michelf/php-smartypants/composer.json (100%) rename {site/plugins/embed/vendor => vendor}/ml/iri/ML/IRI/.gitignore (100%) rename {site/plugins/embed/vendor => vendor}/ml/iri/ML/IRI/.travis.yml (100%) rename {site/plugins/embed/vendor => vendor}/ml/iri/ML/IRI/IRI.php (100%) rename {site/plugins/embed/vendor => vendor}/ml/iri/ML/IRI/LICENSE (100%) rename {site/plugins/embed/vendor => vendor}/ml/iri/ML/IRI/README.md (100%) rename {site/plugins/embed/vendor => vendor}/ml/iri/ML/IRI/Test/IriTest.php (100%) rename {site/plugins/embed/vendor => vendor}/ml/iri/ML/IRI/Test/bootstrap.php (100%) rename {site/plugins/embed/vendor => vendor}/ml/iri/ML/IRI/composer.json (100%) rename {site/plugins/embed/vendor => vendor}/ml/iri/ML/IRI/phpunit.xml.dist (100%) rename {site/plugins/embed/vendor => vendor}/ml/json-ld/.devcontainer/Dockerfile (100%) rename {site/plugins/embed/vendor => vendor}/ml/json-ld/.devcontainer/devcontainer.json (100%) rename {site/plugins/embed/vendor => vendor}/ml/json-ld/.github/workflows/ci.yaml (100%) rename {site/plugins/embed/vendor => vendor}/ml/json-ld/.gitignore (100%) rename {site/plugins/embed/vendor => vendor}/ml/json-ld/.vscode/launch.json (100%) rename {site/plugins/embed/vendor => vendor}/ml/json-ld/DefaultDocumentFactory.php (100%) rename {site/plugins/embed/vendor => vendor}/ml/json-ld/Document.php (100%) rename {site/plugins/embed/vendor => vendor}/ml/json-ld/DocumentFactoryInterface.php (100%) rename {site/plugins/embed/vendor => vendor}/ml/json-ld/DocumentInterface.php (100%) rename {site/plugins/embed/vendor => vendor}/ml/json-ld/DocumentLoaderInterface.php (100%) rename {site/plugins/embed/vendor => vendor}/ml/json-ld/Exception/InvalidQuadException.php (100%) rename {site/plugins/embed/vendor => vendor}/ml/json-ld/Exception/JsonLdException.php (100%) rename {site/plugins/embed/vendor => vendor}/ml/json-ld/FileGetContentsLoader.php (100%) rename {site/plugins/embed/vendor => vendor}/ml/json-ld/Graph.php (100%) rename {site/plugins/embed/vendor => vendor}/ml/json-ld/GraphInterface.php (100%) rename {site/plugins/embed/vendor => vendor}/ml/json-ld/JsonLD.php (100%) rename {site/plugins/embed/vendor => vendor}/ml/json-ld/JsonLdSerializable.php (100%) rename {site/plugins/embed/vendor => vendor}/ml/json-ld/LICENSE (100%) rename {site/plugins/embed/vendor => vendor}/ml/json-ld/LanguageTaggedString.php (100%) rename {site/plugins/embed/vendor => vendor}/ml/json-ld/NQuads.php (100%) rename {site/plugins/embed/vendor => vendor}/ml/json-ld/Node.php (100%) rename {site/plugins/embed/vendor => vendor}/ml/json-ld/NodeInterface.php (100%) rename {site/plugins/embed/vendor => vendor}/ml/json-ld/Processor.php (100%) rename {site/plugins/embed/vendor => vendor}/ml/json-ld/Quad.php (100%) rename {site/plugins/embed/vendor => vendor}/ml/json-ld/QuadParserInterface.php (100%) rename {site/plugins/embed/vendor => vendor}/ml/json-ld/QuadSerializerInterface.php (100%) rename {site/plugins/embed/vendor => vendor}/ml/json-ld/README.md (100%) rename {site/plugins/embed/vendor => vendor}/ml/json-ld/RdfConstants.php (100%) rename {site/plugins/embed/vendor => vendor}/ml/json-ld/RemoteDocument.php (100%) rename {site/plugins/embed/vendor => vendor}/ml/json-ld/Test/DocumentTest.php (100%) rename {site/plugins/embed/vendor => vendor}/ml/json-ld/Test/EarlReportGenerator.php (100%) rename {site/plugins/embed/vendor => vendor}/ml/json-ld/Test/FileGetContentsLoaderTest.php (100%) rename {site/plugins/embed/vendor => vendor}/ml/json-ld/Test/Fixtures/dataset.jsonld (100%) rename {site/plugins/embed/vendor => vendor}/ml/json-ld/Test/Fixtures/sample-compacted.jsonld (100%) rename {site/plugins/embed/vendor => vendor}/ml/json-ld/Test/Fixtures/sample-context.jsonld (100%) rename {site/plugins/embed/vendor => vendor}/ml/json-ld/Test/Fixtures/sample-expanded.jsonld (100%) rename {site/plugins/embed/vendor => vendor}/ml/json-ld/Test/Fixtures/sample-flattened.jsonld (100%) rename {site/plugins/embed/vendor => vendor}/ml/json-ld/Test/Fixtures/sample-in.jsonld (100%) rename {site/plugins/embed/vendor => vendor}/ml/json-ld/Test/Fixtures/sample-serialized-document.jsonld (100%) rename {site/plugins/embed/vendor => vendor}/ml/json-ld/Test/GraphTest.php (100%) rename {site/plugins/embed/vendor => vendor}/ml/json-ld/Test/JsonLDApiTest.php (100%) rename {site/plugins/embed/vendor => vendor}/ml/json-ld/Test/JsonTestCase.php (100%) rename {site/plugins/embed/vendor => vendor}/ml/json-ld/Test/NQuadsTest.php (100%) rename {site/plugins/embed/vendor => vendor}/ml/json-ld/Test/TestManifestIterator.php (100%) rename {site/plugins/embed/vendor => vendor}/ml/json-ld/Test/ValueTest.php (100%) rename {site/plugins/embed/vendor => vendor}/ml/json-ld/Test/W3CTestSuiteTest.php (100%) rename {site/plugins/embed/vendor => vendor}/ml/json-ld/Test/bootstrap.php (100%) rename {site/plugins/embed/vendor => vendor}/ml/json-ld/TypedValue.php (100%) rename {site/plugins/embed/vendor => vendor}/ml/json-ld/Value.php (100%) rename {site/plugins/embed/vendor => vendor}/ml/json-ld/composer.json (100%) rename {site/plugins/embed/vendor => vendor}/ml/json-ld/phpunit.xml.dist (100%) rename {site/plugins/embed/vendor => vendor}/oscarotero/html-parser/.github/workflows/test.yml (100%) rename {site/plugins/embed/vendor => vendor}/oscarotero/html-parser/CHANGELOG.md (88%) rename {site/plugins/embed/vendor => vendor}/oscarotero/html-parser/LICENSE (100%) rename {site/plugins/embed/vendor => vendor}/oscarotero/html-parser/README.md (100%) rename {site/plugins/embed/vendor => vendor}/oscarotero/html-parser/composer.json (100%) rename {site/plugins/embed/vendor => vendor}/oscarotero/html-parser/src/Parser.php (96%) create mode 100644 vendor/phpmailer/phpmailer/COMMITMENT rename {kirby/vendor => vendor}/phpmailer/phpmailer/LICENSE (100%) create mode 100644 vendor/phpmailer/phpmailer/README.md create mode 100644 vendor/phpmailer/phpmailer/SECURITY.md create mode 100644 vendor/phpmailer/phpmailer/VERSION rename {kirby/vendor => vendor}/phpmailer/phpmailer/composer.json (80%) rename {kirby/vendor => vendor}/phpmailer/phpmailer/get_oauth_token.php (88%) rename {kirby/vendor => vendor}/phpmailer/phpmailer/language/phpmailer.lang-af.php (100%) rename {kirby/vendor => vendor}/phpmailer/phpmailer/language/phpmailer.lang-ar.php (100%) rename {kirby/vendor => vendor}/phpmailer/phpmailer/language/phpmailer.lang-az.php (100%) rename {kirby/vendor => vendor}/phpmailer/phpmailer/language/phpmailer.lang-ba.php (100%) rename {kirby/vendor => vendor}/phpmailer/phpmailer/language/phpmailer.lang-be.php (100%) rename {kirby/vendor => vendor}/phpmailer/phpmailer/language/phpmailer.lang-bg.php (100%) rename {kirby/vendor => vendor}/phpmailer/phpmailer/language/phpmailer.lang-ca.php (100%) rename {kirby/vendor => vendor}/phpmailer/phpmailer/language/phpmailer.lang-cs.php (100%) rename {kirby/vendor => vendor}/phpmailer/phpmailer/language/phpmailer.lang-da.php (69%) rename {kirby/vendor => vendor}/phpmailer/phpmailer/language/phpmailer.lang-de.php (100%) rename {kirby/vendor => vendor}/phpmailer/phpmailer/language/phpmailer.lang-el.php (100%) rename {kirby/vendor => vendor}/phpmailer/phpmailer/language/phpmailer.lang-eo.php (100%) rename {kirby/vendor => vendor}/phpmailer/phpmailer/language/phpmailer.lang-es.php (84%) rename {kirby/vendor => vendor}/phpmailer/phpmailer/language/phpmailer.lang-et.php (100%) rename {kirby/vendor => vendor}/phpmailer/phpmailer/language/phpmailer.lang-fa.php (100%) rename {kirby/vendor => vendor}/phpmailer/phpmailer/language/phpmailer.lang-fi.php (95%) rename {kirby/vendor => vendor}/phpmailer/phpmailer/language/phpmailer.lang-fo.php (100%) rename {kirby/vendor => vendor}/phpmailer/phpmailer/language/phpmailer.lang-fr.php (97%) rename {kirby/vendor => vendor}/phpmailer/phpmailer/language/phpmailer.lang-gl.php (100%) rename {kirby/vendor => vendor}/phpmailer/phpmailer/language/phpmailer.lang-he.php (100%) rename {kirby/vendor => vendor}/phpmailer/phpmailer/language/phpmailer.lang-hi.php (68%) rename {kirby/vendor => vendor}/phpmailer/phpmailer/language/phpmailer.lang-hr.php (100%) rename {kirby/vendor => vendor}/phpmailer/phpmailer/language/phpmailer.lang-hu.php (100%) rename {kirby/vendor => vendor}/phpmailer/phpmailer/language/phpmailer.lang-hy.php (100%) rename {kirby/vendor => vendor}/phpmailer/phpmailer/language/phpmailer.lang-id.php (100%) rename {kirby/vendor => vendor}/phpmailer/phpmailer/language/phpmailer.lang-it.php (100%) rename {kirby/vendor => vendor}/phpmailer/phpmailer/language/phpmailer.lang-ja.php (100%) rename {kirby/vendor => vendor}/phpmailer/phpmailer/language/phpmailer.lang-ka.php (100%) rename {kirby/vendor => vendor}/phpmailer/phpmailer/language/phpmailer.lang-ko.php (100%) rename {kirby/vendor => vendor}/phpmailer/phpmailer/language/phpmailer.lang-lt.php (100%) rename {kirby/vendor => vendor}/phpmailer/phpmailer/language/phpmailer.lang-lv.php (100%) rename {kirby/vendor => vendor}/phpmailer/phpmailer/language/phpmailer.lang-mg.php (100%) rename {kirby/vendor => vendor}/phpmailer/phpmailer/language/phpmailer.lang-mn.php (100%) rename {kirby/vendor => vendor}/phpmailer/phpmailer/language/phpmailer.lang-ms.php (100%) create mode 100644 vendor/phpmailer/phpmailer/language/phpmailer.lang-nb.php rename {kirby/vendor => vendor}/phpmailer/phpmailer/language/phpmailer.lang-nl.php (100%) rename {kirby/vendor => vendor}/phpmailer/phpmailer/language/phpmailer.lang-pl.php (54%) rename {kirby/vendor => vendor}/phpmailer/phpmailer/language/phpmailer.lang-pt.php (100%) rename {kirby/vendor => vendor}/phpmailer/phpmailer/language/phpmailer.lang-pt_br.php (100%) rename {kirby/vendor => vendor}/phpmailer/phpmailer/language/phpmailer.lang-ro.php (100%) rename {kirby/vendor => vendor}/phpmailer/phpmailer/language/phpmailer.lang-ru.php (100%) rename {kirby/vendor => vendor}/phpmailer/phpmailer/language/phpmailer.lang-sk.php (100%) rename {kirby/vendor => vendor}/phpmailer/phpmailer/language/phpmailer.lang-sl.php (100%) rename {kirby/vendor => vendor}/phpmailer/phpmailer/language/phpmailer.lang-sr.php (100%) rename {kirby/vendor => vendor}/phpmailer/phpmailer/language/phpmailer.lang-sr_latn.php (100%) rename {kirby/vendor => vendor}/phpmailer/phpmailer/language/phpmailer.lang-sv.php (100%) rename {kirby/vendor => vendor}/phpmailer/phpmailer/language/phpmailer.lang-tl.php (100%) rename {kirby/vendor => vendor}/phpmailer/phpmailer/language/phpmailer.lang-tr.php (100%) rename {kirby/vendor => vendor}/phpmailer/phpmailer/language/phpmailer.lang-uk.php (100%) rename {kirby/vendor => vendor}/phpmailer/phpmailer/language/phpmailer.lang-vi.php (100%) rename {kirby/vendor => vendor}/phpmailer/phpmailer/language/phpmailer.lang-zh.php (100%) rename {kirby/vendor => vendor}/phpmailer/phpmailer/language/phpmailer.lang-zh_cn.php (65%) rename {kirby/vendor => vendor}/phpmailer/phpmailer/src/Exception.php (100%) rename {kirby/vendor => vendor}/phpmailer/phpmailer/src/OAuth.php (100%) rename {kirby/vendor => vendor}/phpmailer/phpmailer/src/OAuthTokenProvider.php (100%) rename {kirby/vendor => vendor}/phpmailer/phpmailer/src/PHPMailer.php (96%) rename {kirby/vendor => vendor}/phpmailer/phpmailer/src/POP3.php (98%) rename {kirby/vendor => vendor}/phpmailer/phpmailer/src/SMTP.php (97%) rename {site/plugins/embed/vendor => vendor}/psr/http-client/CHANGELOG.md (100%) rename {site/plugins/embed/vendor => vendor}/psr/http-client/LICENSE (100%) rename {site/plugins/embed/vendor => vendor}/psr/http-client/README.md (100%) rename {site/plugins/embed/vendor => vendor}/psr/http-client/composer.json (100%) rename {site/plugins/embed/vendor => vendor}/psr/http-client/src/ClientExceptionInterface.php (100%) rename {site/plugins/embed/vendor => vendor}/psr/http-client/src/ClientInterface.php (100%) rename {site/plugins/embed/vendor => vendor}/psr/http-client/src/NetworkExceptionInterface.php (100%) rename {site/plugins/embed/vendor => vendor}/psr/http-client/src/RequestExceptionInterface.php (100%) rename {site/plugins/embed/vendor => vendor}/psr/http-factory/LICENSE (100%) rename {site/plugins/embed/vendor => vendor}/psr/http-factory/README.md (100%) rename {site/plugins/embed/vendor => vendor}/psr/http-factory/composer.json (76%) rename {site/plugins/embed/vendor => vendor}/psr/http-factory/src/RequestFactoryInterface.php (100%) rename {site/plugins/embed/vendor => vendor}/psr/http-factory/src/ResponseFactoryInterface.php (100%) rename {site/plugins/embed/vendor => vendor}/psr/http-factory/src/ServerRequestFactoryInterface.php (100%) rename {site/plugins/embed/vendor => vendor}/psr/http-factory/src/StreamFactoryInterface.php (100%) rename {site/plugins/embed/vendor => vendor}/psr/http-factory/src/UploadedFileFactoryInterface.php (71%) rename {site/plugins/embed/vendor => vendor}/psr/http-factory/src/UriFactoryInterface.php (100%) rename {site/plugins/embed/vendor => vendor}/psr/http-message/CHANGELOG.md (100%) rename {site/plugins/embed/vendor => vendor}/psr/http-message/LICENSE (100%) rename {site/plugins/embed/vendor => vendor}/psr/http-message/README.md (100%) rename {site/plugins/embed/vendor => vendor}/psr/http-message/composer.json (100%) rename {site/plugins/embed/vendor => vendor}/psr/http-message/docs/PSR7-Interfaces.md (100%) rename {site/plugins/embed/vendor => vendor}/psr/http-message/docs/PSR7-Usage.md (100%) rename {site/plugins/embed/vendor => vendor}/psr/http-message/src/MessageInterface.php (100%) rename {site/plugins/embed/vendor => vendor}/psr/http-message/src/RequestInterface.php (100%) rename {site/plugins/embed/vendor => vendor}/psr/http-message/src/ResponseInterface.php (100%) rename {site/plugins/embed/vendor => vendor}/psr/http-message/src/ServerRequestInterface.php (100%) rename {site/plugins/embed/vendor => vendor}/psr/http-message/src/StreamInterface.php (100%) rename {site/plugins/embed/vendor => vendor}/psr/http-message/src/UploadedFileInterface.php (100%) rename {site/plugins/embed/vendor => vendor}/psr/http-message/src/UriInterface.php (100%) rename {kirby/vendor => vendor}/psr/log/LICENSE (100%) create mode 100644 vendor/psr/log/Psr/Log/AbstractLogger.php rename {kirby/vendor/psr/log/src => vendor/psr/log/Psr/Log}/InvalidArgumentException.php (100%) rename {kirby/vendor/psr/log/src => vendor/psr/log/Psr/Log}/LogLevel.php (100%) rename {kirby/vendor/psr/log/src => vendor/psr/log/Psr/Log}/LoggerAwareInterface.php (79%) rename {kirby/vendor/psr/log/src => vendor/psr/log/Psr/Log}/LoggerAwareTrait.php (75%) rename {kirby/vendor/psr/log/src => vendor/psr/log/Psr/Log}/LoggerInterface.php (66%) rename {kirby/vendor/psr/log/src => vendor/psr/log/Psr/Log}/LoggerTrait.php (69%) rename {kirby/vendor/psr/log/src => vendor/psr/log/Psr/Log}/NullLogger.php (78%) create mode 100644 vendor/psr/log/Psr/Log/Test/DummyTest.php create mode 100644 vendor/psr/log/Psr/Log/Test/LoggerInterfaceTest.php create mode 100644 vendor/psr/log/Psr/Log/Test/TestLogger.php create mode 100644 vendor/psr/log/README.md rename {kirby/vendor => vendor}/psr/log/composer.json (82%) rename {site/plugins/embed/vendor => vendor}/ralouphie/getallheaders/LICENSE (100%) rename {site/plugins/embed/vendor => vendor}/ralouphie/getallheaders/README.md (100%) rename {site/plugins/embed/vendor => vendor}/ralouphie/getallheaders/composer.json (100%) rename {site/plugins/embed/vendor => vendor}/ralouphie/getallheaders/src/getallheaders.php (100%) rename {kirby/vendor => vendor}/symfony/polyfill-intl-idn/Idn.php (97%) rename {kirby/vendor => vendor}/symfony/polyfill-intl-idn/Info.php (100%) rename {kirby/vendor/symfony/polyfill-mbstring => vendor/symfony/polyfill-intl-idn}/LICENSE (92%) create mode 100644 vendor/symfony/polyfill-intl-idn/README.md rename {kirby/vendor => vendor}/symfony/polyfill-intl-idn/Resources/unidata/DisallowedRanges.php (97%) rename {kirby/vendor => vendor}/symfony/polyfill-intl-idn/Resources/unidata/Regex.php (99%) rename {kirby/vendor => vendor}/symfony/polyfill-intl-idn/Resources/unidata/deviation.php (100%) rename {kirby/vendor => vendor}/symfony/polyfill-intl-idn/Resources/unidata/disallowed.php (100%) rename {kirby/vendor => vendor}/symfony/polyfill-intl-idn/Resources/unidata/disallowed_STD3_mapped.php (100%) rename {kirby/vendor => vendor}/symfony/polyfill-intl-idn/Resources/unidata/disallowed_STD3_valid.php (100%) rename {kirby/vendor => vendor}/symfony/polyfill-intl-idn/Resources/unidata/ignored.php (100%) rename {kirby/vendor => vendor}/symfony/polyfill-intl-idn/Resources/unidata/mapped.php (100%) rename {kirby/vendor => vendor}/symfony/polyfill-intl-idn/Resources/unidata/virama.php (100%) rename {kirby/vendor => vendor}/symfony/polyfill-intl-idn/bootstrap.php (100%) rename {kirby/vendor => vendor}/symfony/polyfill-intl-idn/bootstrap80.php (100%) rename {kirby/vendor => vendor}/symfony/polyfill-intl-idn/composer.json (94%) rename {kirby/vendor => vendor}/symfony/polyfill-intl-normalizer/LICENSE (100%) rename {kirby/vendor => vendor}/symfony/polyfill-intl-normalizer/Normalizer.php (100%) create mode 100644 vendor/symfony/polyfill-intl-normalizer/README.md rename {kirby/vendor => vendor}/symfony/polyfill-intl-normalizer/Resources/stubs/Normalizer.php (100%) rename {kirby/vendor => vendor}/symfony/polyfill-intl-normalizer/Resources/unidata/canonicalComposition.php (100%) rename {kirby/vendor => vendor}/symfony/polyfill-intl-normalizer/Resources/unidata/canonicalDecomposition.php (100%) rename {kirby/vendor => vendor}/symfony/polyfill-intl-normalizer/Resources/unidata/combiningClass.php (100%) rename {kirby/vendor => vendor}/symfony/polyfill-intl-normalizer/Resources/unidata/compatibilityDecomposition.php (100%) rename {kirby/vendor => vendor}/symfony/polyfill-intl-normalizer/bootstrap.php (100%) rename {kirby/vendor => vendor}/symfony/polyfill-intl-normalizer/bootstrap80.php (100%) rename {kirby/vendor => vendor}/symfony/polyfill-intl-normalizer/composer.json (100%) rename {kirby/vendor/christian-riesen/base32 => vendor/symfony/polyfill-mbstring}/LICENSE (96%) rename {kirby/vendor => vendor}/symfony/polyfill-mbstring/Mbstring.php (82%) create mode 100644 vendor/symfony/polyfill-mbstring/README.md rename {kirby/vendor => vendor}/symfony/polyfill-mbstring/Resources/unidata/lowerCase.php (100%) rename {kirby/vendor => vendor}/symfony/polyfill-mbstring/Resources/unidata/titleCaseRegexp.php (100%) rename {kirby/vendor => vendor}/symfony/polyfill-mbstring/Resources/unidata/upperCase.php (100%) rename {kirby/vendor => vendor}/symfony/polyfill-mbstring/bootstrap.php (96%) rename {kirby/vendor => vendor}/symfony/polyfill-mbstring/bootstrap80.php (96%) rename {kirby/vendor => vendor}/symfony/polyfill-mbstring/composer.json (93%) diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..51627fa --- /dev/null +++ b/.envrc @@ -0,0 +1 @@ +PATH_add /opt/homebrew/opt/php@7.4/bin diff --git a/README.md b/README.md index 80e633e..420b6f3 100644 --- a/README.md +++ b/README.md @@ -1,36 +1,34 @@ -**Kirby: the CMS that adapts to any project, loved by developers and editors alike.** + +**Kirby: the CMS that adapts to any project, loved by developers and editors alike.** The Plainkit is a minimal Kirby setup with the basics you need to start a project from scratch. It is the ideal choice if you are already familiar with Kirby and want to start step-by-step. You can learn more about Kirby at [getkirby.com](https://getkirby.com). -### Try Kirby for free - +### Try Kirby for free You can try Kirby and the Plainkit on your local machine or on a test server as long as you need to make sure it is the right tool for your next project. … and when you’re convinced, [buy your license](https://getkirby.com/buy). ### Get going - Read our guide on [how to get started with Kirby](https://getkirby.com/docs/guide/quickstart). -You can [download the latest version](https://github.com/getkirby/plainkit/archive/main.zip) of the Plainkit. +You can [download the latest version](https://github.com/getkirby/plainkit/archive/main.zip) of the Plainkit. If you are familiar with Git, you can clone Kirby's Plainkit repository from Github. git clone https://github.com/getkirby/plainkit.git ## What's Kirby? - -- **[getkirby.com](https://getkirby.com)** – Get to know the CMS. -- **[Try it](https://getkirby.com/try)** – Take a test ride with our online demo. Or download one of our kits to get started. -- **[Documentation](https://getkirby.com/docs/guide)** – Read the official guide, reference and cookbook recipes. -- **[Issues](https://github.com/getkirby/kirby/issues)** – Report bugs and other problems. -- **[Feedback](https://feedback.getkirby.com)** – You have an idea for Kirby? Share it. -- **[Forum](https://forum.getkirby.com)** – Whenever you get stuck, don't hesitate to reach out for questions and support. -- **[Discord](https://chat.getkirby.com)** – Hang out and meet the community. -- **[Mastodon](https://mastodon.social/@getkirby)** – Spread the word. -- **[Instagram](https://www.instagram.com/getkirby/)** – Share your creations: #madewithkirby. +- **[getkirby.com](https://getkirby.com)** – Get to know the CMS. +- **[Try it](https://getkirby.com/try)** – Take a test ride with our online demo. Or download one of our kits to get started. +- **[Documentation](https://getkirby.com/docs/guide)** – Read the official guide, reference and cookbook recipes. +- **[Issues](https://github.com/getkirby/kirby/issues)** – Report bugs and other problems. +- **[Feedback](https://feedback.getkirby.com)** – You have an idea for Kirby? Share it. +- **[Forum](https://forum.getkirby.com)** – Whenever you get stuck, don't hesitate to reach out for questions and support. +- **[Discord](https://chat.getkirby.com)** – Hang out and meet the community. +- **[Twitter](https://twitter.com/getkirby)** – Spread the word. +- **[Instagram](https://www.instagram.com/getkirby/)** – Share your creations: #madewithkirby. --- -© 2009 Bastian Allgeier +© 2009-2022 Bastian Allgeier [getkirby.com](https://getkirby.com) · [License agreement](https://getkirby.com/license) diff --git a/assets/style.css b/assets/style.css index 590fb04..6055e61 100644 --- a/assets/style.css +++ b/assets/style.css @@ -12,7 +12,7 @@ h1, .text-40 { font-size: 40pt; line-height: 58pt; font-weight: normal } h2, .text-30 { font-size: 30pt; line-height: 29pt; font-weight: normal } h3, .text-22 { font-size: 22pt; line-height: 29pt; font-weight: normal } h4, .text-16, html { font-size: 16pt; line-height: 29pt; font-weight: normal } -h5, .text-12 { font-size: 12pt; line-height: 15pt; font-weight: normal } +h5, h6, .text-12 { font-size: 12pt; line-height: 15pt; font-weight: normal } h2 { margin-top: 16pt } diff --git a/composer.json b/composer.json index 5b92331..639e889 100644 --- a/composer.json +++ b/composer.json @@ -5,7 +5,7 @@ "keywords": [ "kirby", "cms", - "plainkit" + "starterkit" ], "authors": [ { @@ -17,12 +17,16 @@ "homepage": "https://getkirby.com", "support": { "email": "support@getkirby.com", + "issues": "https://github.com/getkirby/starterkit/issues", "forum": "https://forum.getkirby.com", - "source": "https://github.com/getkirby/plainkit" + "source": "https://github.com/getkirby/starterkit" }, "require": { - "php": "~8.1.0 || ~8.2.0 || ~8.3.0", - "getkirby/cms": "^4.0" + "php": ">=7.4.0 <8.0.0", + "getkirby/cms": "^3.6", + "sylvainjule/embed": "^1.0", + "jg/kirby-fields-block": "^1.1", + "sylvainjule/color-palette": "^1.0" }, "config": { "allow-plugins": { diff --git a/composer.lock b/composer.lock new file mode 100644 index 0000000..861bcd3 --- /dev/null +++ b/composer.lock @@ -0,0 +1,1595 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "74776b9954f7c7164160efc4281c70dc", + "packages": [ + { + "name": "claviska/simpleimage", + "version": "3.7.0", + "source": { + "type": "git", + "url": "https://github.com/claviska/SimpleImage.git", + "reference": "abd15ced313c7b8041d7d73d8d2398b4f2510cf1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/claviska/SimpleImage/zipball/abd15ced313c7b8041d7d73d8d2398b4f2510cf1", + "reference": "abd15ced313c7b8041d7d73d8d2398b4f2510cf1", + "shasum": "" + }, + "require": { + "ext-gd": "*", + "league/color-extractor": "0.3.*", + "php": ">=5.6.0" + }, + "type": "library", + "autoload": { + "psr-0": { + "claviska": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Cory LaViska", + "homepage": "http://www.abeautifulsite.net/", + "role": "Developer" + } + ], + "description": "A PHP class that makes working with images as simple as possible.", + "support": { + "issues": "https://github.com/claviska/SimpleImage/issues", + "source": "https://github.com/claviska/SimpleImage/tree/3.7.0" + }, + "funding": [ + { + "url": "https://github.com/claviska", + "type": "github" + } + ], + "time": "2022-07-05T13:18:44+00:00" + }, + { + "name": "composer/ca-bundle", + "version": "1.5.1", + "source": { + "type": "git", + "url": "https://github.com/composer/ca-bundle.git", + "reference": "063d9aa8696582f5a41dffbbaf3c81024f0a604a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/ca-bundle/zipball/063d9aa8696582f5a41dffbbaf3c81024f0a604a", + "reference": "063d9aa8696582f5a41dffbbaf3c81024f0a604a", + "shasum": "" + }, + "require": { + "ext-openssl": "*", + "ext-pcre": "*", + "php": "^7.2 || ^8.0" + }, + "require-dev": { + "phpstan/phpstan": "^1.10", + "psr/log": "^1.0 || ^2.0 || ^3.0", + "symfony/phpunit-bridge": "^4.2 || ^5", + "symfony/process": "^4.0 || ^5.0 || ^6.0 || ^7.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Composer\\CaBundle\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + } + ], + "description": "Lets you find a path to the system CA bundle, and includes a fallback to the Mozilla CA bundle.", + "keywords": [ + "cabundle", + "cacert", + "certificate", + "ssl", + "tls" + ], + "support": { + "irc": "irc://irc.freenode.org/composer", + "issues": "https://github.com/composer/ca-bundle/issues", + "source": "https://github.com/composer/ca-bundle/tree/1.5.1" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], + "time": "2024-07-08T15:28:20+00:00" + }, + { + "name": "embed/embed", + "version": "v4.4.8", + "source": { + "type": "git", + "url": "https://github.com/oscarotero/Embed.git", + "reference": "49134080764018bc6b8a2488dd1c8cc2c47d15fc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/oscarotero/Embed/zipball/49134080764018bc6b8a2488dd1c8cc2c47d15fc", + "reference": "49134080764018bc6b8a2488dd1c8cc2c47d15fc", + "shasum": "" + }, + "require": { + "composer/ca-bundle": "^1.0", + "ext-curl": "*", + "ext-dom": "*", + "ext-json": "*", + "ext-mbstring": "*", + "ml/json-ld": "^1.1", + "oscarotero/html-parser": "^0.1.4", + "php": "^7.4|^8", + "psr/http-client": "^1.0", + "psr/http-factory": "^1.0", + "psr/http-message": "^1.0|^2.0" + }, + "require-dev": { + "brick/varexporter": "^0.3.1", + "friendsofphp/php-cs-fixer": "^2.0", + "nyholm/psr7": "^1.2", + "oscarotero/php-cs-fixer-config": "^1.0", + "phpunit/phpunit": "^9.0", + "symfony/css-selector": "^5.0" + }, + "suggest": { + "symfony/css-selector": "If you want to get elements using css selectors" + }, + "type": "library", + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "Embed\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Oscar Otero", + "email": "oom@oscarotero.com", + "homepage": "http://oscarotero.com", + "role": "Developer" + } + ], + "description": "PHP library to retrieve page info using oembed, opengraph, etc", + "homepage": "https://github.com/oscarotero/Embed", + "keywords": [ + "embed", + "embedly", + "oembed", + "opengraph", + "twitter cards" + ], + "support": { + "email": "oom@oscarotero.com", + "issues": "https://github.com/oscarotero/Embed/issues", + "source": "https://github.com/oscarotero/Embed/tree/v4.4.8" + }, + "funding": [ + { + "url": "https://paypal.me/oscarotero", + "type": "custom" + }, + { + "url": "https://github.com/oscarotero", + "type": "github" + }, + { + "url": "https://www.patreon.com/misteroom", + "type": "patreon" + } + ], + "time": "2023-05-22T18:48:30+00:00" + }, + { + "name": "filp/whoops", + "version": "2.14.5", + "source": { + "type": "git", + "url": "https://github.com/filp/whoops.git", + "reference": "a63e5e8f26ebbebf8ed3c5c691637325512eb0dc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/filp/whoops/zipball/a63e5e8f26ebbebf8ed3c5c691637325512eb0dc", + "reference": "a63e5e8f26ebbebf8ed3c5c691637325512eb0dc", + "shasum": "" + }, + "require": { + "php": "^5.5.9 || ^7.0 || ^8.0", + "psr/log": "^1.0.1 || ^2.0 || ^3.0" + }, + "require-dev": { + "mockery/mockery": "^0.9 || ^1.0", + "phpunit/phpunit": "^4.8.36 || ^5.7.27 || ^6.5.14 || ^7.5.20 || ^8.5.8 || ^9.3.3", + "symfony/var-dumper": "^2.6 || ^3.0 || ^4.0 || ^5.0" + }, + "suggest": { + "symfony/var-dumper": "Pretty print complex values better with var-dumper available", + "whoops/soap": "Formats errors as SOAP responses" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.7-dev" + } + }, + "autoload": { + "psr-4": { + "Whoops\\": "src/Whoops/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Filipe Dobreira", + "homepage": "https://github.com/filp", + "role": "Developer" + } + ], + "description": "php error handling for cool kids", + "homepage": "https://filp.github.io/whoops/", + "keywords": [ + "error", + "exception", + "handling", + "library", + "throwable", + "whoops" + ], + "support": { + "issues": "https://github.com/filp/whoops/issues", + "source": "https://github.com/filp/whoops/tree/2.14.5" + }, + "funding": [ + { + "url": "https://github.com/denis-sokolov", + "type": "github" + } + ], + "time": "2022-01-07T12:00:00+00:00" + }, + { + "name": "getkirby/cms", + "version": "3.7.5.5", + "source": { + "type": "git", + "url": "https://github.com/getkirby/kirby.git", + "reference": "a645ec70bc0152cc3caa07df303dd57ac25b30db" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/getkirby/kirby/zipball/a645ec70bc0152cc3caa07df303dd57ac25b30db", + "reference": "a645ec70bc0152cc3caa07df303dd57ac25b30db", + "shasum": "" + }, + "require": { + "claviska/simpleimage": "3.7.0", + "ext-ctype": "*", + "ext-curl": "*", + "ext-dom": "*", + "ext-filter": "*", + "ext-hash": "*", + "ext-iconv": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-openssl": "*", + "ext-simplexml": "*", + "filp/whoops": "2.14.5", + "getkirby/composer-installer": "^1.2.1", + "laminas/laminas-escaper": "2.10.0", + "michelf/php-smartypants": "1.8.1", + "php": ">=7.4.0 <8.2.0", + "phpmailer/phpmailer": "6.6.4", + "symfony/polyfill-intl-idn": "1.26.0", + "symfony/polyfill-mbstring": "1.26.0" + }, + "replace": { + "symfony/polyfill-php72": "*" + }, + "suggest": { + "ext-PDO": "Support for using databases", + "ext-apcu": "Support for the Apcu cache driver", + "ext-exif": "Support for exif information from images", + "ext-fileinfo": "Improved mime type detection for files", + "ext-intl": "Improved i18n number formatting", + "ext-memcached": "Support for the Memcached cache driver", + "ext-zip": "Support for ZIP archive file functions", + "ext-zlib": "Sanitization and validation for svgz files" + }, + "type": "kirby-cms", + "extra": { + "unused": [ + "symfony/polyfill-intl-idn" + ] + }, + "autoload": { + "files": [ + "config/setup.php", + "config/helpers.php" + ], + "psr-4": { + "Kirby\\": "src/" + }, + "classmap": [ + "dependencies/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "proprietary" + ], + "authors": [ + { + "name": "Kirby Team", + "email": "support@getkirby.com", + "homepage": "https://getkirby.com" + } + ], + "description": "The Kirby 3 core", + "homepage": "https://getkirby.com", + "keywords": [ + "cms", + "core", + "kirby" + ], + "support": { + "email": "support@getkirby.com", + "forum": "https://forum.getkirby.com", + "issues": "https://github.com/getkirby/kirby/issues", + "source": "https://github.com/getkirby/kirby" + }, + "funding": [ + { + "url": "https://getkirby.com/buy", + "type": "custom" + } + ], + "time": "2024-08-24T20:23:32+00:00" + }, + { + "name": "getkirby/composer-installer", + "version": "1.2.1", + "source": { + "type": "git", + "url": "https://github.com/getkirby/composer-installer.git", + "reference": "c98ece30bfba45be7ce457e1102d1b169d922f3d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/getkirby/composer-installer/zipball/c98ece30bfba45be7ce457e1102d1b169d922f3d", + "reference": "c98ece30bfba45be7ce457e1102d1b169d922f3d", + "shasum": "" + }, + "require": { + "composer-plugin-api": "^1.0 || ^2.0" + }, + "require-dev": { + "composer/composer": "^1.8 || ^2.0" + }, + "type": "composer-plugin", + "extra": { + "class": "Kirby\\ComposerInstaller\\Plugin" + }, + "autoload": { + "psr-4": { + "Kirby\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Kirby's custom Composer installer for the Kirby CMS and for Kirby plugins", + "homepage": "https://getkirby.com", + "support": { + "issues": "https://github.com/getkirby/composer-installer/issues", + "source": "https://github.com/getkirby/composer-installer/tree/1.2.1" + }, + "funding": [ + { + "url": "https://getkirby.com/buy", + "type": "custom" + } + ], + "time": "2020-12-28T12:54:39+00:00" + }, + { + "name": "guzzlehttp/psr7", + "version": "2.7.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/psr7.git", + "reference": "a70f5c95fb43bc83f07c9c948baa0dc1829bf201" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/a70f5c95fb43bc83f07c9c948baa0dc1829bf201", + "reference": "a70f5c95fb43bc83f07c9c948baa0dc1829bf201", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0", + "psr/http-factory": "^1.0", + "psr/http-message": "^1.1 || ^2.0", + "ralouphie/getallheaders": "^3.0" + }, + "provide": { + "psr/http-factory-implementation": "1.0", + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "http-interop/http-factory-tests": "0.9.0", + "phpunit/phpunit": "^8.5.39 || ^9.6.20" + }, + "suggest": { + "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Psr7\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://sagikazarmark.hu" + } + ], + "description": "PSR-7 message implementation that also provides common utility methods", + "keywords": [ + "http", + "message", + "psr-7", + "request", + "response", + "stream", + "uri", + "url" + ], + "support": { + "issues": "https://github.com/guzzle/psr7/issues", + "source": "https://github.com/guzzle/psr7/tree/2.7.0" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/psr7", + "type": "tidelift" + } + ], + "time": "2024-07-18T11:15:46+00:00" + }, + { + "name": "jg/kirby-fields-block", + "version": "v1.2.1", + "source": { + "type": "git", + "url": "https://github.com/jongacnik/kirby-fields-block.git", + "reference": "e56c4d109edd921a1b4436e3df0e64b1117f1b83" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/jongacnik/kirby-fields-block/zipball/e56c4d109edd921a1b4436e3df0e64b1117f1b83", + "reference": "e56c4d109edd921a1b4436e3df0e64b1117f1b83", + "shasum": "" + }, + "require": { + "getkirby/composer-installer": "^1.1" + }, + "type": "kirby-plugin", + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jon Gacnik", + "email": "jon@folderstudio.com" + } + ], + "description": "Kirby Fields Block", + "support": { + "issues": "https://github.com/jongacnik/kirby-fields-block/issues", + "source": "https://github.com/jongacnik/kirby-fields-block/tree/v1.2.1" + }, + "time": "2023-01-22T19:02:00+00:00" + }, + { + "name": "laminas/laminas-escaper", + "version": "2.10.0", + "source": { + "type": "git", + "url": "https://github.com/laminas/laminas-escaper.git", + "reference": "58af67282db37d24e584a837a94ee55b9c7552be" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laminas/laminas-escaper/zipball/58af67282db37d24e584a837a94ee55b9c7552be", + "reference": "58af67282db37d24e584a837a94ee55b9c7552be", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "ext-mbstring": "*", + "php": "^7.4 || ~8.0.0 || ~8.1.0" + }, + "conflict": { + "zendframework/zend-escaper": "*" + }, + "require-dev": { + "infection/infection": "^0.26.6", + "laminas/laminas-coding-standard": "~2.3.0", + "maglnet/composer-require-checker": "^3.8.0", + "phpunit/phpunit": "^9.5.18", + "psalm/plugin-phpunit": "^0.16.1", + "vimeo/psalm": "^4.22.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Laminas\\Escaper\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "description": "Securely and safely escape HTML, HTML attributes, JavaScript, CSS, and URLs", + "homepage": "https://laminas.dev", + "keywords": [ + "escaper", + "laminas" + ], + "support": { + "chat": "https://laminas.dev/chat", + "docs": "https://docs.laminas.dev/laminas-escaper/", + "forum": "https://discourse.laminas.dev", + "issues": "https://github.com/laminas/laminas-escaper/issues", + "rss": "https://github.com/laminas/laminas-escaper/releases.atom", + "source": "https://github.com/laminas/laminas-escaper" + }, + "funding": [ + { + "url": "https://funding.communitybridge.org/projects/laminas-project", + "type": "community_bridge" + } + ], + "time": "2022-03-08T20:15:36+00:00" + }, + { + "name": "league/color-extractor", + "version": "0.3.2", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/color-extractor.git", + "reference": "837086ec60f50c84c611c613963e4ad2e2aec806" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/color-extractor/zipball/837086ec60f50c84c611c613963e4ad2e2aec806", + "reference": "837086ec60f50c84c611c613963e4ad2e2aec806", + "shasum": "" + }, + "require": { + "ext-gd": "*", + "php": ">=5.4.0" + }, + "replace": { + "matthecat/colorextractor": "*" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "~2", + "phpunit/phpunit": "~5" + }, + "type": "library", + "autoload": { + "psr-4": { + "": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mathieu Lechat", + "email": "math.lechat@gmail.com", + "homepage": "http://matthecat.com", + "role": "Developer" + } + ], + "description": "Extract colors from an image as a human would do.", + "homepage": "https://github.com/thephpleague/color-extractor", + "keywords": [ + "color", + "extract", + "human", + "image", + "palette" + ], + "support": { + "issues": "https://github.com/thephpleague/color-extractor/issues", + "source": "https://github.com/thephpleague/color-extractor/tree/master" + }, + "time": "2016-12-15T09:30:02+00:00" + }, + { + "name": "michelf/php-smartypants", + "version": "1.8.1", + "source": { + "type": "git", + "url": "https://github.com/michelf/php-smartypants.git", + "reference": "47d17c90a4dfd0ccf1f87e25c65e6c8012415aad" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/michelf/php-smartypants/zipball/47d17c90a4dfd0ccf1f87e25c65e6c8012415aad", + "reference": "47d17c90a4dfd0ccf1f87e25c65e6c8012415aad", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "autoload": { + "psr-0": { + "Michelf": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Michel Fortin", + "email": "michel.fortin@michelf.ca", + "homepage": "https://michelf.ca/", + "role": "Developer" + }, + { + "name": "John Gruber", + "homepage": "https://daringfireball.net/" + } + ], + "description": "PHP SmartyPants", + "homepage": "https://michelf.ca/projects/php-smartypants/", + "keywords": [ + "dashes", + "quotes", + "spaces", + "typographer", + "typography" + ], + "support": { + "issues": "https://github.com/michelf/php-smartypants/issues", + "source": "https://github.com/michelf/php-smartypants/tree/1.8.1" + }, + "time": "2016-12-13T01:01:17+00:00" + }, + { + "name": "ml/iri", + "version": "1.1.4", + "target-dir": "ML/IRI", + "source": { + "type": "git", + "url": "https://github.com/lanthaler/IRI.git", + "reference": "cbd44fa913e00ea624241b38cefaa99da8d71341" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/lanthaler/IRI/zipball/cbd44fa913e00ea624241b38cefaa99da8d71341", + "reference": "cbd44fa913e00ea624241b38cefaa99da8d71341", + "shasum": "" + }, + "require": { + "lib-pcre": ">=4.0", + "php": ">=5.3.0" + }, + "type": "library", + "autoload": { + "psr-0": { + "ML\\IRI": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Markus Lanthaler", + "email": "mail@markus-lanthaler.com", + "homepage": "http://www.markus-lanthaler.com", + "role": "Developer" + } + ], + "description": "IRI handling for PHP", + "homepage": "http://www.markus-lanthaler.com", + "keywords": [ + "URN", + "iri", + "uri", + "url" + ], + "support": { + "issues": "https://github.com/lanthaler/IRI/issues", + "source": "https://github.com/lanthaler/IRI/tree/master" + }, + "time": "2014-01-21T13:43:39+00:00" + }, + { + "name": "ml/json-ld", + "version": "1.2.1", + "source": { + "type": "git", + "url": "https://github.com/lanthaler/JsonLD.git", + "reference": "537e68e87a6bce23e57c575cd5dcac1f67ce25d8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/lanthaler/JsonLD/zipball/537e68e87a6bce23e57c575cd5dcac1f67ce25d8", + "reference": "537e68e87a6bce23e57c575cd5dcac1f67ce25d8", + "shasum": "" + }, + "require": { + "ext-json": "*", + "ml/iri": "^1.1.1", + "php": ">=5.3.0" + }, + "require-dev": { + "json-ld/tests": "1.0", + "phpunit/phpunit": "^4" + }, + "type": "library", + "autoload": { + "psr-4": { + "ML\\JsonLD\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Markus Lanthaler", + "email": "mail@markus-lanthaler.com", + "homepage": "http://www.markus-lanthaler.com", + "role": "Developer" + } + ], + "description": "JSON-LD Processor for PHP", + "homepage": "http://www.markus-lanthaler.com", + "keywords": [ + "JSON-LD", + "jsonld" + ], + "support": { + "issues": "https://github.com/lanthaler/JsonLD/issues", + "source": "https://github.com/lanthaler/JsonLD/tree/1.2.1" + }, + "time": "2022-09-29T08:45:17+00:00" + }, + { + "name": "oscarotero/html-parser", + "version": "v0.1.8", + "source": { + "type": "git", + "url": "https://github.com/oscarotero/html-parser.git", + "reference": "10f3219267a365d9433f2f7d1694209c9d436c8d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/oscarotero/html-parser/zipball/10f3219267a365d9433f2f7d1694209c9d436c8d", + "reference": "10f3219267a365d9433f2f7d1694209c9d436c8d", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^2.11", + "phpunit/phpunit": "^8.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "HtmlParser\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Oscar Otero", + "email": "oom@oscarotero.com", + "homepage": "http://oscarotero.com", + "role": "Developer" + } + ], + "description": "Parse html strings to DOMDocument", + "homepage": "https://github.com/oscarotero/html-parser", + "keywords": [ + "dom", + "html", + "parser" + ], + "support": { + "email": "oom@oscarotero.com", + "issues": "https://github.com/oscarotero/html-parser/issues", + "source": "https://github.com/oscarotero/html-parser/tree/v0.1.8" + }, + "time": "2023-11-29T20:28:41+00:00" + }, + { + "name": "phpmailer/phpmailer", + "version": "v6.6.4", + "source": { + "type": "git", + "url": "https://github.com/PHPMailer/PHPMailer.git", + "reference": "a94fdebaea6bd17f51be0c2373ab80d3d681269b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/a94fdebaea6bd17f51be0c2373ab80d3d681269b", + "reference": "a94fdebaea6bd17f51be0c2373ab80d3d681269b", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "ext-filter": "*", + "ext-hash": "*", + "php": ">=5.5.0" + }, + "require-dev": { + "dealerdirect/phpcodesniffer-composer-installer": "^0.7.0", + "doctrine/annotations": "^1.2", + "php-parallel-lint/php-console-highlighter": "^1.0.0", + "php-parallel-lint/php-parallel-lint": "^1.3.2", + "phpcompatibility/php-compatibility": "^9.3.5", + "roave/security-advisories": "dev-latest", + "squizlabs/php_codesniffer": "^3.6.2", + "yoast/phpunit-polyfills": "^1.0.0" + }, + "suggest": { + "ext-mbstring": "Needed to send email in multibyte encoding charset or decode encoded addresses", + "hayageek/oauth2-yahoo": "Needed for Yahoo XOAUTH2 authentication", + "league/oauth2-google": "Needed for Google XOAUTH2 authentication", + "psr/log": "For optional PSR-3 debug logging", + "stevenmaguire/oauth2-microsoft": "Needed for Microsoft XOAUTH2 authentication", + "symfony/polyfill-mbstring": "To support UTF-8 if the Mbstring PHP extension is not enabled (^1.2)" + }, + "type": "library", + "autoload": { + "psr-4": { + "PHPMailer\\PHPMailer\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-2.1-only" + ], + "authors": [ + { + "name": "Marcus Bointon", + "email": "phpmailer@synchromedia.co.uk" + }, + { + "name": "Jim Jagielski", + "email": "jimjag@gmail.com" + }, + { + "name": "Andy Prevost", + "email": "codeworxtech@users.sourceforge.net" + }, + { + "name": "Brent R. Matzelle" + } + ], + "description": "PHPMailer is a full-featured email creation and transfer class for PHP", + "support": { + "issues": "https://github.com/PHPMailer/PHPMailer/issues", + "source": "https://github.com/PHPMailer/PHPMailer/tree/v6.6.4" + }, + "funding": [ + { + "url": "https://github.com/Synchro", + "type": "github" + } + ], + "time": "2022-08-22T09:22:00+00:00" + }, + { + "name": "psr/http-client", + "version": "1.0.3", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-client.git", + "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-client/zipball/bb5906edc1c324c9a05aa0873d40117941e5fa90", + "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90", + "shasum": "" + }, + "require": { + "php": "^7.0 || ^8.0", + "psr/http-message": "^1.0 || ^2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Client\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP clients", + "homepage": "https://github.com/php-fig/http-client", + "keywords": [ + "http", + "http-client", + "psr", + "psr-18" + ], + "support": { + "source": "https://github.com/php-fig/http-client" + }, + "time": "2023-09-23T14:17:50+00:00" + }, + { + "name": "psr/http-factory", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-factory.git", + "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-factory/zipball/2b4765fddfe3b508ac62f829e852b1501d3f6e8a", + "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a", + "shasum": "" + }, + "require": { + "php": ">=7.1", + "psr/http-message": "^1.0 || ^2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "PSR-17: Common interfaces for PSR-7 HTTP message factories", + "keywords": [ + "factory", + "http", + "message", + "psr", + "psr-17", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-factory" + }, + "time": "2024-04-15T12:06:14+00:00" + }, + { + "name": "psr/http-message", + "version": "2.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message.git", + "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/402d35bcb92c70c026d1a6a9883f06b2ead23d71", + "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP messages", + "homepage": "https://github.com/php-fig/http-message", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-message/tree/2.0" + }, + "time": "2023-04-04T09:54:51+00:00" + }, + { + "name": "psr/log", + "version": "1.1.4", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "d49695b909c3b7628b6289db5479a1c204601f11" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/d49695b909c3b7628b6289db5479a1c204601f11", + "reference": "d49695b909c3b7628b6289db5479a1c204601f11", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Log\\": "Psr/Log/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "support": { + "source": "https://github.com/php-fig/log/tree/1.1.4" + }, + "time": "2021-05-03T11:20:27+00:00" + }, + { + "name": "ralouphie/getallheaders", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/ralouphie/getallheaders.git", + "reference": "120b605dfeb996808c31b6477290a714d356e822" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", + "reference": "120b605dfeb996808c31b6477290a714d356e822", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.1", + "phpunit/phpunit": "^5 || ^6.5" + }, + "type": "library", + "autoload": { + "files": [ + "src/getallheaders.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ralph Khattar", + "email": "ralph.khattar@gmail.com" + } + ], + "description": "A polyfill for getallheaders.", + "support": { + "issues": "https://github.com/ralouphie/getallheaders/issues", + "source": "https://github.com/ralouphie/getallheaders/tree/develop" + }, + "time": "2019-03-08T08:55:37+00:00" + }, + { + "name": "sylvainjule/color-palette", + "version": "1.0.4", + "source": { + "type": "git", + "url": "https://github.com/sylvainjule/kirby-color-palette.git", + "reference": "290da479c5bddf55a61974119243987504085223" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sylvainjule/kirby-color-palette/zipball/290da479c5bddf55a61974119243987504085223", + "reference": "290da479c5bddf55a61974119243987504085223", + "shasum": "" + }, + "require": { + "getkirby/composer-installer": "^1.1" + }, + "type": "kirby-plugin", + "extra": { + "installer-name": "color-palette" + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Sylvain Julé", + "email": "contact@sylvain-jule.fr" + } + ], + "description": "A color palette to pick colors from for Kirby", + "support": { + "issues": "https://github.com/sylvainjule/kirby-color-palette/issues", + "source": "https://github.com/sylvainjule/kirby-color-palette/tree/master" + }, + "time": "2020-04-11T10:05:01+00:00" + }, + { + "name": "sylvainjule/embed", + "version": "1.1.2", + "source": { + "type": "git", + "url": "https://github.com/sylvainjule/kirby-embed.git", + "reference": "19a586d64883790b7c5f2366bf5ea128e63d47b3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sylvainjule/kirby-embed/zipball/19a586d64883790b7c5f2366bf5ea128e63d47b3", + "reference": "19a586d64883790b7c5f2366bf5ea128e63d47b3", + "shasum": "" + }, + "require": { + "embed/embed": "4.4.8", + "getkirby/composer-installer": "^1.1", + "guzzlehttp/psr7": "^2.6" + }, + "type": "kirby-plugin", + "extra": { + "installer-name": "embed" + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Sylvain Julé", + "email": "contact@sylvain-jule.fr" + } + ], + "description": "Embed field for Kirby 3", + "support": { + "issues": "https://github.com/sylvainjule/kirby-embed/issues", + "source": "https://github.com/sylvainjule/kirby-embed/tree/1.1.2" + }, + "time": "2024-03-08T14:51:01+00:00" + }, + { + "name": "symfony/polyfill-intl-idn", + "version": "v1.26.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-idn.git", + "reference": "59a8d271f00dd0e4c2e518104cc7963f655a1aa8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/59a8d271f00dd0e4c2e518104cc7963f655a1aa8", + "reference": "59a8d271f00dd0e4c2e518104cc7963f655a1aa8", + "shasum": "" + }, + "require": { + "php": ">=7.1", + "symfony/polyfill-intl-normalizer": "^1.10", + "symfony/polyfill-php72": "^1.10" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.26-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Idn\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Laurent Bassin", + "email": "laurent@bassin.info" + }, + { + "name": "Trevor Rowbotham", + "email": "trevor.rowbotham@pm.me" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's idn_to_ascii and idn_to_utf8 functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "idn", + "intl", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.26.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-05-24T11:49:31+00:00" + }, + { + "name": "symfony/polyfill-intl-normalizer", + "version": "v1.30.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-normalizer.git", + "reference": "a95281b0be0d9ab48050ebd988b967875cdb9fdb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/a95281b0be0d9ab48050ebd988b967875cdb9fdb", + "reference": "a95281b0be0d9ab48050ebd988b967875cdb9fdb", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Normalizer\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's Normalizer class and related functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "intl", + "normalizer", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.30.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-05-31T15:07:36+00:00" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.26.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "9344f9cb97f3b19424af1a21a3b0e75b0a7d8d7e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/9344f9cb97f3b19424af1a21a3b0e75b0a7d8d7e", + "reference": "9344f9cb97f3b19424af1a21a3b0e75b0a7d8d7e", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "provide": { + "ext-mbstring": "*" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.26-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the Mbstring extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.26.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-05-24T11:49:31+00:00" + } + ], + "packages-dev": [], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": { + "php": ">=7.4.0 <8.0.0" + }, + "platform-dev": [], + "plugin-api-version": "2.6.0" +} diff --git a/kirby/.editorconfig b/kirby/.editorconfig index 10fd327..76df047 100644 --- a/kirby/.editorconfig +++ b/kirby/.editorconfig @@ -17,10 +17,6 @@ trim_trailing_whitespace = true indent_size = 4 insert_final_newline = true -[*.vue.php] -indent_size = 2 -insert_final_newline = false - [*.yml] indent_style = space diff --git a/kirby/CONTRIBUTING.md b/kirby/CONTRIBUTING.md index a4c299a..0b8af3a 100644 --- a/kirby/CONTRIBUTING.md +++ b/kirby/CONTRIBUTING.md @@ -6,47 +6,43 @@ To keep track of different states of our code (current release, bugfixes, features) we use branches: -| Branch | Used for | PRs allowed? | -| --------------- | ------------------------------------------------------------------------ | --------------------------- | -| `main` | Latest released version | ❌ | -| `develop-patch` | Working branch for next patch release, e.g. `4.0.x` | ✅ | -| `develop-minor` | Working branch for next minor release, e.g. `4.x.0` | ✅ | -| `v5/develop` | Working branch for next major release, e.g. `5.0.0` | ✅ | -| `fix/*` | Temporary branches for single bugfix | - | -| `feature/*` | Temporary branches for single feature | - | -| `release/*` | Pre-releases in testing before they are merged into `main` when released | only during release testing | +| Branch | Used for | PRs allowed? | +| ----------- | ------------------------------------------------------------------------ | --------------------------- | +| `main` | Latest released version | - | +| `develop` | Working branch for next release, e.g. `3.7.x` | ✅ | +| `fix/*` | Temporary branches for single patch | - | +| `feature/*` | Temporary branches for single feature | - | +| `release/*` | Pre-releases in testing before they are merged into `main` when released | only during release testing | -We will review all pull requests (PRs) to `develop-patch`, `develop-minor` and `v5/develop` and merge them if accepted, once an appropriate version is upcoming. Please understand that this might not be the immediate next release and might take some time. +We will review all pull requests (PRs) to `develop` and merge them if accepted, once an appropriate version is upcoming. Please understand that this might not be the immediate next release and might take some time. ## How you can contribute ### Report a bug -When you find a bug, the first step to fixing it is to help us understand and reproduce the bug as best as possible. When you create a bug report, please include as many details as possible. Fill out [the template](https://github.com/getkirby/kirby/issues/new?template=bug_report.md) because the requested information helps us resolve issues so much faster. +When you find a bug, the first step to fixing it is to help us understand and reproduce the bug as best as possible. When you create a bug report, please include as many details as possible. Fill out [the template](ISSUE_TEMPLATE/bug_report.md) because the requested information helps us resolve issues so much faster. ### Bug fixes For bug fixes, please create a new branch following the name scheme: `fix/issue_number-bug-x`, e.g. `fix/234-this-nasty-bug`. Limit bug fix PRs to a single bug. **Do not mix multiple bug fixes in a single PR.** This will make it easier for us to review the fix and merge it. -- Always send bug fix PRs against the `develop-patch` branch––not `main`. +- Always send bug fix PRs against the `develop` branch––not `main`. - Add a helpful description of what the PR does if it is not 100% self-explanatory. - Every bug fix should include a [unit test](#tests) to avoid future regressions. Let us know if you need help with that. - Make sure your code [style](#style) matches ours and includes [comments/in-code documentation](#documentation). -- Make sure your branch is up to date with the latest state on the `develop-patch` branch. [Rebase](https://help.github.com/articles/about-pull-request-merges/) changes before you send the PR. -- Please *don't* commit updated dist files in the `panel/dist` folder to avoid merge conflicts. We only build the dist files on release. Your branch should only contain changes to the source files. +- Make sure your branch is up to date with the latest state on the `develop` branch. [Rebase](https://help.github.com/articles/about-pull-request-merges/) changes before you send the PR. ### Features For features create a new branch following the name scheme: `feature/issue_number-feature-x`, e.g. `feature/123-awesome-function`. Our [feedback platform](https://feedback.getkirby.com) can be a good source of highly requested features. Maybe your feature idea already exists and you can get valuable feedback from other Kirby users. Focus on a single feature per PR. Don't mix features! -- Always send feature PRs against the `develop-minor` branch––not `main`. +- Always send feature PRs against the `develop` branch––not `main`. - Add a helpful description of what the PR does. - New features should include [unit tests](#tests). Let us know if you need help with that. - Make your code [style](#style) matches ours and includes [comments/in-code documentation](#documentation). -- Make sure your branch is up to date with the latest state on the `develop-minor` branch. [Rebase](https://help.github.com/articles/about-pull-request-merges/) changes before you send the PR. -- Please *don't* commit updated dist files in the `panel/dist` folder to avoid merge conflicts. We only build the dist files on release. Your branch should only contain changes to the source files. +- Make sure your branch is up to date with the latest state on the `develop` branch. [Rebase](https://help.github.com/articles/about-pull-request-merges/) changes before you send the PR. -We try to bundle features in our major releases, e.g. `5.0`. That is why we might only review and, if accepted, merge your PR once an appropriate release is upcoming. Please understand that we cannot merge all feature ideas or that it might take a while. Check out the [roadmap](https://roadmap.getkirby.com) to see upcoming releases. +We try to bundle features in our major releases, e.g. `3.x`. That is why we might only review and, if accepted, merge your PR once an appropriate release is upcoming. Please understand that we cannot merge all feature ideas or that it might take a while. Check out the [roadmap](https://roadmap.getkirby.com) to see upcoming releases. ### Translations diff --git a/kirby/LICENSE.md b/kirby/LICENSE.md index f7514fd..eb852a4 100644 --- a/kirby/LICENSE.md +++ b/kirby/LICENSE.md @@ -1,7 +1,7 @@ # Kirby License Agreement -Published: November 28, 2023 -Source: https://getkirby.com/license/2023-11-28 +Published: March 15, 2022 +Source: https://getkirby.com/license/2022-03-15 ## About this Agreement @@ -11,86 +11,49 @@ This End User License Agreement (the **"Agreement"**) is fundamental to the rela If you do not agree to this Agreement, please do not download, install or use Kirby. Installation or use of Kirby signifies that you have read, understood, and agreed to be bound by this Agreement. -## Summary - -This section summarizes the most important conditions of this Agreement to give you a quick overview: - -- With your purchase you obtain a license. A license allows you to use Kirby according to this Agreement. -- Each project (defined by its URL) needs its own license. You need to purchase the right license for your project and/or client. You can find our license variants on . In some explicitly listed cases, you can use Kirby without having to purchase a license. -- Each license includes any Kirby version that gets released within three years from the date when you first activated your license. We also provide free security updates for older versions that may protect your project beyond three years. -- After those three years, you can continue to use Kirby for your project with any of these versions as long as you want. -- To use any newer version released after this time, you will need to upgrade your license. -- Upgrading your license extends the timeframe for an additional three years during which you can use new releases. You can perform the upgrade at any time. -- You have the right to transfer or reassign a license to another person or project if needed. -- There are some restrictions for use of Kirby that you can find below. - -For the full license details, please read the Agreement in full. Only the following sections are legally binding. - ## Definitions Before we get started with the conditions of the Agreement, let's define the terms that will be used throughout it: -- When we refer to **"You"**, we mean the licensee. Before purchasing Kirby, that's the individual or company that has downloaded and/or installed Kirby for a Development Installation, Private Installation or Extension Demo. When used for a Public Site, the licensee is the individual or company that has purchased the Kirby license. If you work on a client project and have purchased the Kirby license for your client, you (and _not_ the client) are the licensee. -- When we refer to **"We"**/**"Us"**/**"Our"**, we mean the licensor, the Content Folder GmbH & Co. KG. You can find Our company and contact information on Our [contact page](https://getkirby.com/contact). -- **"Client"** is the individual or company on whose behalf You create or work on a Website. This only applies if the client is not the licensee. +- When we refer to **"You"**, we mean the licensee. Before purchasing Kirby, that's the individual or company that has downloaded and/or installed Kirby for a Development Installation, Private Installation or Extension Demo. When used for a Public Site, the licensee is the individual or company that has purchased the Kirby license. If you work on a client project and have purchased the Kirby license for your client, you (and _not_ the client) are the licensee. +- When we refer to **"We"**/**"Us"**/**"Our"**, we mean the licensor, the Content Folder GmbH & Co. KG. You can find Our company and contact information on Our [contact page](https://getkirby.com/contact). - A **"Website"** is a single Kirby project that is defined by its domain name and root directory (e.g. `https://sub.example.com` or `https://example.com/example/`). Each (sub)domain and root directory is a separate Website, even if the projects are related in any way. Exception: If You use the cross-domain multi-language feature with the same `content` folder, these domains count as the same Website. You may use Kirby as a headless backend or as a static site generator. In these cases the Website is defined by the domain and root directory of the user- or visitor-facing frontend(s). - A **"Development Installation"** is a Website that is installed purely for the purposes of development and client preview. It must only be accessible by a restricted number of users (like on a personal computer, on a server in a network with restricted access or when protecting a staging website with a password that only a restricted number of users know). - A **"Private Installation"** is a Website that is installed purely for personal use. It must only be accessible by You and Your family. - An **"Extension Demo"** is a Website with the single purpose to showcase a free or commercial Kirby theme or Kirby plugin, as long as that Website only contains demo content. If the showcased extension is a Kirby theme, the demo content must be exactly as shipped with the theme. Demos for Kirby plugins may _not_ contain any additional content that is not needed to showcase the plugin in use. - A **"Public Site"** is a Website that is _neither_ a Development Installation, a Private Installation nor an Extension Demo. -- A **"Minor Release"** is a stable Kirby release which adds smaller new features, minor functionality enhancements or bug fixes. This class of release is identified by the change of the revision to the right of the first decimal point, e.g. 4.1 to 4.2, 4.X.1 to 4.X.2. -- A **"Major Release"** is a stable Kirby release which incorporates major new features or enhancements that increase or change the core functionality of Kirby to a larger extent. It may also deprecate existing parts of the Source Code or change them in a breaking way. This class of release is identified by the change of the revision to the left of the first decimal point, e.g. 4.X to 5.0. -- A **"Major Generation"** is defined as all releases that share the revision to the left of the first decimal point, e.g. 4.0.0, 4.0.X, 4.X.0 and 4.X.X. +- An **"Update"** is defined as a Kirby release which adds smaller new features, minor functionality enhancements or bug fixes. This class of release is identified by the change of the revision to the right of the first decimal point, e.g. 3.1 to 3.2, 3.X.1 to 3.X.2 or 3.X.X.1 to 3.X.X.2. +- An **"Upgrade"** is a major Kirby release which incorporates major new features or enhancements that increase the core functionality of Kirby to a larger extent. This class of release is identified by the change of the revision to the left of the first decimal point, e.g. 3.X to 4.0. - The **"Source Code"** is defined as the contents of all files that are provided with Kirby and that make Kirby work. This includes (but is not limited to) all PHP, JavaScript, JSON, HTML and CSS files as well as all related image and other media files. -- The **"Activation Date"** determines the included updates. It is defined like this: - - For a newly purchased license, it is the date when the license was first activated for use with a Public Site. - - When You upgrade an already activated license, it is the date on which the upgrade was performed in Our license hub. If the license is still within the Included Updates Period, the Activation Date of the upgrade license will be set to the end of the Included Updates Period of the existing license. - - When You upgrade a license that had _not_ been activated before, the upgrade license adopts the unactivated state of the existing license. The Activation Date is set on first activation for use with a Public Site. -- The **"Included Updates Period"** is the time span of three (3) years after the Activation Date. -- Licensees (You), Clients and Websites are **"Qualified"** if they satisfy the purchase requirements from the ["Order Process" section](#order-process) of this Agreement. Every time you see one of these capitalized terms in the following text, it has the meaning that has been explained above. ## Usage for a Public Site -Installing Kirby on or using it for a Public Site requires a [paid license](https://getkirby.com/buy). Once a paid license is needed, the license must be immediately activated to the Public Site’s domain name and root directory via our license hub or the activation feature in the Kirby Panel. +Installing Kirby on or using it for a Public Site requires a [paid license](https://getkirby.com/buy). As Kirby is software and software is intangible, We don't sell it as such. Instead, this Agreement grants a license for each purchase to install and use a single instance of Kirby on a **specific Website**. Additional Kirby licenses must be purchased in order to install and use Kirby on **additional Websites**. -The license is **non-exclusive** (meaning that You are not the only one to whom We will issue a license) and **generally non-transferable** (meaning that the one who purchases the license is the licensee). +The license is **non-exclusive** (meaning that You are not the only one who We will issue a license) and **generally non-transferable** (meaning that the one who purchases the license is the licensee). -On request, We will **transfer** a license to anyone who would be allowed and Qualified to purchase the license by law and this Agreement. The new licensee will take over all rights and obligations of this Agreement from You at the moment We confirm the license transfer. +On request, We will **transfer** a license to anyone who is also allowed to buy Kirby licenses by law and this Agreement. -We will also **reassign** a license to another Qualified Website domain and root directory, if You confirm that the previous Website is no longer in operation and will not be operated with the same license in the future. +We will also **reassign** a license to another Website domain and root directory of Your choice, provided that You confirm that the previous Website is no longer in operation and will not be operated with the same license in the future. -If the new licensee, Website or Client in a transfer or reassignment is not Qualified for the existing license, You or the new licensee need to **upgrade the license to the qualifying terms and conditions** before the transfer or reassignment can be performed. +If you need to transfer your Kirby license to another individual or company (for example to your client or a new agency) or reassign it to a different project, please get in touch directly at . -> [!NOTE] -> If you need to transfer your Kirby license to another individual or company (for example to your client or a new agency) or reassign it to a different project, please get in touch directly at . - -A license is valid for all Major Releases that We publish before the end of the Included Updates Period. It is also valid for all releases in those Major Generations independent of their release date. Whether a release is a Minor Release or Major Release is at Our sole discretion. - -The use of releases in Major Generations that We publish after the Included Updates Period requires a **paid license upgrade**. An upgrade license replaces the existing license. +A license is valid for all Updates of the same major Kirby release. We reserve the right to charge an **upgrade fee for Upgrade releases**. Whether a release is an Update or Upgrade is at Our sole discretion. ## Order Process Our order process is conducted by Our online reseller [Paddle.com](https://paddle.com). Paddle.com is the Merchant of Record for all Our orders. Paddle provides all customer service inquiries and handles returns. -When purchasing a license, You are **responsible to choose the right license** based on You and the Website project. Different license variants can come with certain requirements towards You and/or the Website project. We publish all such requirements on in a way that makes them clearly visible before the purchase. With Your purchase, You confirm that You and the Website project qualify for the selected license variant. - -If the Website is created for a Client, You need to make sure that the **Client qualifies for the selected license**. - -If You purchase licenses **in advance**, You need to ensure to only use the license(s) for projects that satisfy the requirements for the selected license variant(s). - -We **reserve the right to verify** at any time after the purchase whether You, the Website and (if applicable) the Client are Qualified. Changes to the situation of You, the Website or the Client as well as changes to the published information on Our "Buy" page after the purchase or after the assignment to a Client do _not_ take effect on an existing license unless You upgrade the license or We transfer or reassign the license on Your request. - ## Free Licenses Kirby can be used **for free in the following cases**. -> [!NOTE] -> Please note that the restrictions and all other clauses of this Agreement also apply to free licenses. You may especially _not_ alter or circumvent the licensing features. +Please note that the restrictions and all other clauses of this Agreement also apply to free licenses. You may especially _not_ alter or circumvent the licensing features. ### Usage for a Development Installation @@ -98,28 +61,26 @@ We believe that it should be possible to test and evaluate software before havin Therefore, installing and using Kirby on a personal computer (like a desktop PC, notebook or tablet) or server for a Development Installation is **free** for as long as You need. -> [!NOTE] -> The usage of Kirby in production (with the intention to handle production data or content) is _never_ considered a Development Installation, even in internal apps or systems. +The usage of Kirby in production (with the intention to handle production data or content) is _never_ considered a Development Installation, even in internal apps or systems. ### Usage for a Private Installation You may also install and use Kirby for **free** in Private Installations as long as they are not accessible by anyone except You and Your family. -> [!NOTE] -> Our [definition](#definitions) of a Private Installation allows the following use cases: -> -> - Private sites for personal use, for example: -> - Apps for You personally (like a personal diary) -> - Apps for You as a freelancer (like a bookkeeping, invoicing or project management app) -> - Apps for Your family (like a private photo gallery) -> - Experimental local Kirby setups for Your personal use (for example to try out Kirby features) -> -> However, the following use cases are _not_ covered and need a **[paid license](#usage-for-a-public-site)**: -> -> - Intranets for companies, authorities or organizations, no matter if on a local or public server -> - (Internal) apps for teams or entire companies, authorities or organizations -> - Websites that are accessible by the public, even for personal/non-commercial purposes -> - Use of Kirby as a local CMS for a static or headless site without a license for the frontend domain(s) +Our [definition](#definitions) of a Private Installation allows the following use cases: + +- Private sites for personal use, for example: + - Apps for You personally (like a personal diary) + - Apps for You as a freelancer (like a bookkeeping, invoicing or project management app) + - Apps for Your family (like a private photo gallery) +- Experimental local Kirby setups for Your personal use (for example to try out Kirby features) + +However, the following use cases are _not_ covered and need a **[paid license](#usage-for-a-public-site)**: + +- Intranets for companies, authorities or organizations, no matter if on a local or public server +- (Internal) apps for teams or entire companies, authorities or organizations +- Websites that are accessible by the public, even for personal/non-commercial purposes +- Use of Kirby as a local CMS for a static or headless site without a license for the frontend domain(s) ### Usage for an Extension Demo @@ -127,8 +88,7 @@ Extension Demos are not real Websites. We want to encourage you to build and sho Therefore, You may **operate Extension Demos without purchasing a license**. -> [!NOTE] -> Please note that this does _not_ apply to store fronts or other types of sites used to promote free or commercial themes or plugins. If such a site is built with Kirby as well, it is a Public Site and needs a **[paid license](#usage-for-a-public-site)**. +Please note that this does _not_ apply to store fronts or other types of sites used to promote free or commercial themes or plugins. If such a site is built with Kirby as well, it is a Public Site and needs a **[paid license](#usage-for-a-public-site)**. ## Restrictions @@ -138,26 +98,20 @@ You may only use Kirby in a manner that complies with any and all **applicable l ### Making Copies -You may make **copies of Kirby** in any machine readable form solely for the **following purposes**, provided that You reproduce Kirby in its original form and with all proprietary notices on the copy: - -- when deploying a Website to a server, -- when developing a Website on a personal computer or server, -- when working on code contributions to Kirby or -- as a backup. +You may make **copies of Kirby** in any machine readable form solely for purposes of **deploying a Website to a server, developing a Website on a personal computer or server or as a backup**, provided that You reproduce Kirby in its original form and with all proprietary notices on the copy. You may _not_ reproduce Kirby or its Source Code, in whole or in part, for **any other purpose**. ### Modification of the Source Code -You may **alter, modify or extend the Source Code** for Your own use or with the intention to contribute Your changes back to Kirby. You may also **commission a third party** to perform those modifications for You. +You may **alter, modify or extend the Source Code** for Your own use. You may also **commission a third party** to perform those modifications for You. However You may _not_: - **alter or circumvent the licensing features**, including (but not limited to) the license validation and payment prompts or - **resell, redistribute or transfer** the modified or derivative version. -> [!NOTE] -> Please note that We **can't provide technical support** for modified or derivative versions of the Source Code. +Please note that We **can't provide technical support** for modified or derivative versions of the Source Code. ### Your Relationship to Third Parties @@ -171,13 +125,12 @@ The following cases are exempted from this restriction: - You may make a Kirby installation available to employees or partners of You or Your Website client. You may also disclose and distribute Kirby’s Source Code to Your client together with the source code of the Website You created for them. - You may disclose the Source Code to individuals or companies that are involved in the development or operation of Your Website (e.g. agencies, design or development freelancers, hosting providers or administrators). -> [!NOTE] -> E.g. the following cases are explicitly **_not_ allowed**: -> -> - Selling, licensing or distributing a new product based on Kirby that modifies or hides Kirby’s identity as a Content Management System (CMS) -> - Forking Kirby and selling the modified version ([see above](#modification-of-the-source-code)) -> - Buying licenses in bulk and reselling them in your own shop -> - Bundling or including Kirby’s Source Code in the publication and/or distribution of a Website’s source code or a (free or paid) theme or plugin (please use Git submodules or Composer or provide a link to Our repository or website instead) +E.g. the following cases are explicitly **_not_ allowed**: + +- Selling, licensing or distributing a new product based on Kirby that modifies or hides Kirby’s identity as a Content Management System (CMS) +- Forking Kirby and selling the modified version ([see above](#restrictions__modification-of-the-source-code)) +- Buying licenses in bulk and reselling them in your own shop +- Bundling or including Kirby’s Source Code in the publication and/or distribution of a Website’s source code or a (free or paid) theme or plugin (please use Git submodules or Composer or provide a link to Our repository or website instead) ### Disallowed Uses @@ -210,23 +163,13 @@ You may also _not_: Technical support is **provided as described on Our website** at . **No representations or guarantees** are made regarding the response time in which support questions are answered, however We will do Our best to respond quickly. -For each Major Generation, We aim to provide **security support for three (3) years** after the Major Release. Security support means that We will provide free security updates for the supported releases, which will include fixes for security vulnerabilities according to the following rules: - - We published a security advisory on within the respective security support period. We will publish vulnerabilities on this page as soon as they are known to Us and an official fix for any supported release is available. - - The latest release of the supported Major Generation is affected by the vulnerability. - -With each vulnerability, We aim to publish the security advisory and security updates for all supported Major Generations at the same time. - -> [!NOTE] -> You can find up-to-date information on our currently supported versions in our [public security policy](https://getkirby.com/security). - We reserve the right to **limit technical support for free licenses**. ## Refund Policy We offer a **14-day**, money back refund policy if Kirby didn't work out for Your project. -> [!NOTE] -> If you need a refund, please get in touch directly at . +If you need a refund, please get in touch directly at . ## No Warranty @@ -234,13 +177,7 @@ KIRBY IS OFFERED ON AN **"AS-IS" BASIS** AND **NO WARRANTY**, EITHER EXPRESSED O ## Term, Termination and Modification -You may **indefinitely use** all Kirby versions that are covered by Your license under this Agreement until either party **terminates this Agreement** as described in this section. - -**You** may terminate the Agreement at any time. - -**We** may only terminate the Agreement if You or any individual or company who works with Kirby or uses it on Your behalf has violated or failed to comply with terms of this Agreement. If Your compliance with the Agreement can be restored by fixing the violation or non-compliance, We will first contact You with information on the specific term that was violated or not complied with and will allow reasonable time of at least 14 days before We will decide on a license termination. Should We be in the position to terminate a license according to this paragraph, other or all licenses granted to You may be terminated for the same reason(s) at the same time or at any later date. - -Termination takes effect upon notice to the other party in textual form (via email or letter). Upon termination, the specified **licenses granted to You will terminate**, and You will **immediately uninstall and cease all use** of Kirby. If not all licenses are terminated, You may continue to use Kirby for the Websites with active licenses. The sections entitled "No Warranty", "Indemnification" and "Limitation of Liability" will **survive any termination** of this Agreement. +You may use Kirby under this Agreement until either party terminates this Agreement as described in this paragraph. Either party may **terminate the Agreement** at any time, upon notice to the other party in textual form (via email or letter). Upon termination, all or the specified **licenses granted to You will terminate**, and You will **immediately uninstall and cease all use** of Kirby. If not all licenses are terminated, You may continue to use Kirby for the Websites with active licenses. The sections entitled "No Warranty", "Indemnification" and "Limitation of Liability" will **survive any termination** of this Agreement. We may **modify Kirby and this Agreement** with notice to You either via email or by publishing content on the Kirby website at https://getkirby.com, including but not limited to changing the functionality or appearance of Kirby. Any such modification will **become binding on You** unless You terminate this Agreement. Changes to this Agreement that constrain Your rights to a great extent will only become effective with Your approval in textual or electronic form. @@ -256,8 +193,6 @@ YOU EXPRESSLY UNDERSTAND AND AGREE THAT **WE SHALL NOT BE LIABLE** FOR ANY DIREC Bastian Allgeier **owns all rights**, title and interest to Kirby (including all intellectual property rights) and **reserves all rights to Kirby** that are not expressly granted in this Agreement. -In the event that Kirby will no longer be actively maintained, Bastian Allgeier will provide the Source Code under the terms of a free and open source software (FOSS) license as far as legally and contractually possible. - ## Applicable Law & Place of Jurisdiction 1. For all disputes arising out of or in connection with this Agreement, the courts competent for Neckargemünd, Germany, shall have exclusive jurisdiction. However, We shall have the choice to file lawsuits against You before the courts competent for Your place of business. @@ -273,4 +208,4 @@ Should any provision of this Agreement be or become invalid, void or unenforceab Due to Kirby's flexibility, you may have special use cases or requirements that don't fit this Agreement. -If that's the case or if you have any questions, feel free to [get in touch](mailto:support@getkirby.com). We are happy to think outside the box and find custom license solutions for your creative application of Kirby. +If that's the case or if you have any questions, feel free to get in touch: . We are happy to think outside the box and find custom license solutions for your creative application of Kirby. diff --git a/kirby/README.md b/kirby/README.md index 4ef329d..2075a4f 100644 --- a/kirby/README.md +++ b/kirby/README.md @@ -1,28 +1,28 @@ -[](https://getkirby.com) +[](https://getkirby.com) -[![Release](https://img.shields.io/github/v/release/getkirby/kirby)](https://github.com/getkirby/kirby/releases/latest) -[![CI Status](https://img.shields.io/github/actions/workflow/status/getkirby/kirby/ci.yml?branch=main&label=CI)](https://github.com/getkirby/kirby/actions?query=workflow%3ACI+branch%3Amain) -[![Coverage Status](https://img.shields.io/codecov/c/gh/getkirby/kirby?token=ROZ2RVA0OF)](https://codecov.io/gh/getkirby/kirby) -[![Downloads](https://img.shields.io/packagist/dt/getkirby/cms?color=red)](https://github.com/getkirby/kirby/releases/latest) +[![Release](https://badgen.net/github/release/getkirby/kirby/stable?color=yellow)](https://github.com/getkirby/kirby/releases/latest) +[![CI Status](https://github.com/getkirby/kirby/workflows/CI/badge.svg)](https://github.com/getkirby/kirby/actions?query=workflow%3ACI) +[![Coverage Status](https://badgen.net/codecov/c/gh/getkirby/kirby/main?label=coverage)](https://codecov.io/gh/getkirby/kirby) +[![Downloads](https://badgen.net/packagist/dt/getkirby/cms?color=red)](https://github.com/getkirby/kirby/releases/latest) +[![Twitter](https://badgen.net/twitter/follow/getkirby?color=cyan)](https://twitter.com/getkirby) **Kirby: the CMS that adapts to any project, loved by developers and editors alike.** -With Kirby, you build your own ideal interface. Combine forms, galleries, articles, spreadsheets and more into an amazing editing experience. You can learn more about Kirby at [getkirby.com](https://getkirby.com). +With Kirby, you build your own ideal interface. Combine forms, galleries, articles, spreadsheets and more into an amazing editing experience. You can learn more about Kirby at [getkirby.com](https://getkirby.com). This is Kirby's core application folder. Get started with one of the following repositories instead: - [Starterkit](https://github.com/getkirby/starterkit) - [Plainkit](https://github.com/getkirby/plainkit) - - -### Try Kirby for free + +### Try Kirby for free Kirby is not free software. However, you can try Kirby and the Starterkit on your local machine or on a test server as long as you need to make sure it is the right tool for your next project. … and when you’re convinced, [buy your license](https://getkirby.com/buy). ### Contribute **Found a bug?** -Please post all bugs as individual reports in our [issue tracker](https://github.com/getkirby/kirby/issues). +Please post all bug reports in our [issue tracker](https://github.com/getkirby/kirby/issues). **Suggest a feature** If you have ideas for a feature or enhancement for Kirby, please use our [feedback platform](https://feedback.getkirby.com). @@ -30,8 +30,9 @@ If you have ideas for a feature or enhancement for Kirby, please use our [feedba **Translations, bug fixes, code contributions ...** Read about how to contribute to the development in our [contributing guide](/CONTRIBUTING.md). -## What's Kirby? + +## What's Kirby? - **[getkirby.com](https://getkirby.com)** – Get to know the CMS. - **[Try it](https://getkirby.com/try)** – Take a test ride with our online demo. Or download one of our kits to get started. - **[Documentation](https://getkirby.com/docs/guide)** – Read the official guide, reference and cookbook recipes. @@ -39,11 +40,10 @@ Read about how to contribute to the development in our [contributing guide](/CON - **[Feedback](https://feedback.getkirby.com)** – You have an idea for Kirby? Share it. - **[Forum](https://forum.getkirby.com)** – Whenever you get stuck, don't hesitate to reach out for questions and support. - **[Discord](https://chat.getkirby.com)** – Hang out and meet the community. -- **[YouTube](https://youtube.com/kirbyCasts)** - Watch the latest video tutorials visually with Bastian. -- **[Mastodon](https://mastodon.social/@getkirby)** – Spread the word. +- **[Twitter](https://twitter.com/getkirby)** – Spread the word. - **[Instagram](https://www.instagram.com/getkirby/)** – Share your creations: #madewithkirby. --- -© 2009 Bastian Allgeier +© 2009-2022 Bastian Allgeier [getkirby.com](https://getkirby.com) · [License agreement](https://getkirby.com/license) diff --git a/kirby/SECURITY.md b/kirby/SECURITY.md index ffc6ad0..ae42a38 100644 --- a/kirby/SECURITY.md +++ b/kirby/SECURITY.md @@ -1,27 +1,3 @@ # Security Policy -## Supported versions and past security incidents - -You can find up-to-date information on the security status of each version on . - -## Security of your Kirby site - -We have a detailed [security guide](https://getkirby.com/docs/guide/security) with information on how to keep your Kirby installation secure. - -## Reporting a vulnerability - -If you have spotted a vulnerability in Kirby's core or the Panel, please make sure to let us know immediately. We appreciate your efforts to responsibly disclose your findings, and will make every effort to acknowledge your contributions. - -You can always contact us directly at ****. -If you want to encrypt your message, our GPG key is [6E6B 057A F491 FFAD 363F 6F49 9101 10FA A459 E120](https://getkirby.com/pgp.asc). - -You can also use the [security advisory form on GitHub](https://github.com/getkirby/kirby/security/advisories/new) to securely and privately report a vulnerability to us. - -We will send you a response as soon as possible and will keep you informed on our progress towards a fix and announcement. - -> [!IMPORTANT] -> Please do not write to us publicly, e.g. in the forum, on Discord or in a GitHub issue. A public report can give attackers valuable time to exploit the issue before it is fixed. -> -> By letting us know directly and coordinating the disclosure with us, you can help to protect other Kirby users from such attacks. -> -> Also please do *not* request a CVE ID from organizations like MITRE. The responsible CVE Numbering Authority (CNA) for Kirby is GitHub. We can and will request a CVE ID for each confirmed vulnerability and will provide it to you in advance of the coordinated release. +Please see the [Security Policy on the Kirby website](https://getkirby.com/security) for a list of the currently supported Kirby versions and of past security incidents as well as for information on how to report security vulnerabilities in the Kirby core or in the Panel. diff --git a/kirby/bootstrap.php b/kirby/bootstrap.php index 9a419de..b4c1fa3 100644 --- a/kirby/bootstrap.php +++ b/kirby/bootstrap.php @@ -5,8 +5,8 @@ * stop at older or too recent versions */ if ( - version_compare(PHP_VERSION, '8.1.0', '>=') === false || - version_compare(PHP_VERSION, '8.4.0', '<') === false + version_compare(PHP_VERSION, '7.4.0', '>=') === false || + version_compare(PHP_VERSION, '8.2.0', '<') === false ) { die(include __DIR__ . '/views/php.php'); } @@ -16,15 +16,11 @@ if (is_file($autoloader = dirname(__DIR__) . '/vendor/autoload.php')) { * Always prefer a site-wide Composer autoloader * if it exists, it means that the user has probably * installed additional packages - * - * @psalm-suppress MissingFile */ include $autoloader; } elseif (is_file($autoloader = __DIR__ . '/vendor/autoload.php')) { /** * Fall back to the local autoloader if that exists - * - * @psalm-suppress MissingFile */ include $autoloader; } else { diff --git a/kirby/composer.json b/kirby/composer.json index 59cbfb6..30c796d 100644 --- a/kirby/composer.json +++ b/kirby/composer.json @@ -1,9 +1,9 @@ { "name": "getkirby/cms", - "description": "The Kirby core", + "description": "The Kirby 3 core", "license": "proprietary", "type": "kirby-cms", - "version": "4.3.1", + "version": "3.7.5.5", "keywords": [ "kirby", "cms", @@ -24,7 +24,7 @@ "source": "https://github.com/getkirby/kirby" }, "require": { - "php": "~8.1.0 || ~8.2.0 || ~8.3.0", + "php": ">=7.4.0 <8.2.0", "ext-SimpleXML": "*", "ext-ctype": "*", "ext-curl": "*", @@ -36,17 +36,14 @@ "ext-libxml": "*", "ext-mbstring": "*", "ext-openssl": "*", - "christian-riesen/base32": "1.6.0", - "claviska/simpleimage": "4.2.0", - "composer/semver": "3.4.0", - "filp/whoops": "2.15.4", + "claviska/simpleimage": "3.7.0", + "filp/whoops": "2.14.5", "getkirby/composer-installer": "^1.2.1", - "laminas/laminas-escaper": "2.13.0", + "laminas/laminas-escaper": "2.10.0", "michelf/php-smartypants": "1.8.1", - "phpmailer/phpmailer": "6.9.1", - "symfony/polyfill-intl-idn": "1.29.0", - "symfony/polyfill-mbstring": "1.29.0", - "symfony/yaml": "6.4.8" + "phpmailer/phpmailer": "6.6.4", + "symfony/polyfill-intl-idn": "1.26.0", + "symfony/polyfill-mbstring": "1.26.0" }, "replace": { "symfony/polyfill-php72": "*" @@ -58,7 +55,6 @@ "ext-fileinfo": "Improved mime type detection for files", "ext-intl": "Improved i18n number formatting", "ext-memcached": "Support for the Memcached cache driver", - "ext-sodium": "Support for the crypto class and more robust session handling", "ext-zip": "Support for ZIP archive file functions", "ext-zlib": "Sanitization and validation for svgz files" }, @@ -80,7 +76,7 @@ }, "optimize-autoloader": true, "platform": { - "php": "8.1.0" + "php": "7.4.0" }, "platform-check": false }, @@ -94,13 +90,13 @@ "analyze": [ "@analyze:composer", "@analyze:psalm", + "@analyze:phpcpd", "@analyze:phpmd" ], "analyze:composer": "composer validate --strict --no-check-version --no-check-all", + "analyze:phpcpd": "phpcpd --fuzzy --exclude tests --exclude vendor .", "analyze:phpmd": "phpmd . ansi phpmd.xml.dist --exclude 'dependencies/*,tests/*,vendor/*'", "analyze:psalm": "psalm", - "bench": "phpbench run --report=aggregate --ref baseline", - "bench:baseline": "phpbench run --report=aggregate --tag baseline", "build": "./scripts/build", "ci": [ "@fix", @@ -108,8 +104,7 @@ "@test" ], "fix": "php-cs-fixer fix", - "test": "phpunit", - "test:coverage": "XDEBUG_MODE=coverage phpunit --coverage-html=tests/coverage", + "test": "phpunit --stderr --coverage-html=tests/coverage", "zip": "composer archive --format=zip --file=dist" } } diff --git a/kirby/composer.lock b/kirby/composer.lock index d648e89..2046ac4 100644 --- a/kirby/composer.lock +++ b/kirby/composer.lock @@ -4,89 +4,26 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "5c5a02ed090776d3c703adfc737f316b", + "content-hash": "615bb9a6346016f0be80b1805212a9df", "packages": [ - { - "name": "christian-riesen/base32", - "version": "1.6.0", - "source": { - "type": "git", - "url": "https://github.com/ChristianRiesen/base32.git", - "reference": "2e82dab3baa008e24a505649b0d583c31d31e894" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/ChristianRiesen/base32/zipball/2e82dab3baa008e24a505649b0d583c31d31e894", - "reference": "2e82dab3baa008e24a505649b0d583c31d31e894", - "shasum": "" - }, - "require": { - "php": "^7.2 || ^8.0" - }, - "require-dev": { - "friendsofphp/php-cs-fixer": "^2.17", - "phpstan/phpstan": "^0.12", - "phpunit/phpunit": "^8.5.13 || ^9.5" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "Base32\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Christian Riesen", - "email": "chris.riesen@gmail.com", - "homepage": "http://christianriesen.com", - "role": "Developer" - } - ], - "description": "Base32 encoder/decoder according to RFC 4648", - "homepage": "https://github.com/ChristianRiesen/base32", - "keywords": [ - "base32", - "decode", - "encode", - "rfc4648" - ], - "support": { - "issues": "https://github.com/ChristianRiesen/base32/issues", - "source": "https://github.com/ChristianRiesen/base32/tree/1.6.0" - }, - "time": "2021-02-26T10:19:33+00:00" - }, { "name": "claviska/simpleimage", - "version": "4.2.0", + "version": "3.7.0", "source": { "type": "git", "url": "https://github.com/claviska/SimpleImage.git", - "reference": "dfbe53c01dae8467468ef2b817c09b786a7839d2" + "reference": "abd15ced313c7b8041d7d73d8d2398b4f2510cf1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/claviska/SimpleImage/zipball/dfbe53c01dae8467468ef2b817c09b786a7839d2", - "reference": "dfbe53c01dae8467468ef2b817c09b786a7839d2", + "url": "https://api.github.com/repos/claviska/SimpleImage/zipball/abd15ced313c7b8041d7d73d8d2398b4f2510cf1", + "reference": "abd15ced313c7b8041d7d73d8d2398b4f2510cf1", "shasum": "" }, "require": { "ext-gd": "*", - "league/color-extractor": "0.4.*", - "php": ">=8.0" - }, - "require-dev": { - "laravel/pint": "^1.5", - "phpstan/phpstan": "^1.10" + "league/color-extractor": "0.3.*", + "php": ">=5.6.0" }, "type": "library", "autoload": { @@ -108,7 +45,7 @@ "description": "A PHP class that makes working with images as simple as possible.", "support": { "issues": "https://github.com/claviska/SimpleImage/issues", - "source": "https://github.com/claviska/SimpleImage/tree/4.2.0" + "source": "https://github.com/claviska/SimpleImage/tree/3.7.0" }, "funding": [ { @@ -116,101 +53,20 @@ "type": "github" } ], - "time": "2024-04-15T16:07:16+00:00" - }, - { - "name": "composer/semver", - "version": "3.4.0", - "source": { - "type": "git", - "url": "https://github.com/composer/semver.git", - "reference": "35e8d0af4486141bc745f23a29cc2091eb624a32" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/composer/semver/zipball/35e8d0af4486141bc745f23a29cc2091eb624a32", - "reference": "35e8d0af4486141bc745f23a29cc2091eb624a32", - "shasum": "" - }, - "require": { - "php": "^5.3.2 || ^7.0 || ^8.0" - }, - "require-dev": { - "phpstan/phpstan": "^1.4", - "symfony/phpunit-bridge": "^4.2 || ^5" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "3.x-dev" - } - }, - "autoload": { - "psr-4": { - "Composer\\Semver\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nils Adermann", - "email": "naderman@naderman.de", - "homepage": "http://www.naderman.de" - }, - { - "name": "Jordi Boggiano", - "email": "j.boggiano@seld.be", - "homepage": "http://seld.be" - }, - { - "name": "Rob Bast", - "email": "rob.bast@gmail.com", - "homepage": "http://robbast.nl" - } - ], - "description": "Semver library that offers utilities, version constraint parsing and validation.", - "keywords": [ - "semantic", - "semver", - "validation", - "versioning" - ], - "support": { - "irc": "ircs://irc.libera.chat:6697/composer", - "issues": "https://github.com/composer/semver/issues", - "source": "https://github.com/composer/semver/tree/3.4.0" - }, - "funding": [ - { - "url": "https://packagist.com", - "type": "custom" - }, - { - "url": "https://github.com/composer", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/composer/composer", - "type": "tidelift" - } - ], - "time": "2023-08-31T09:50:34+00:00" + "time": "2022-07-05T13:18:44+00:00" }, { "name": "filp/whoops", - "version": "2.15.4", + "version": "2.14.5", "source": { "type": "git", "url": "https://github.com/filp/whoops.git", - "reference": "a139776fa3f5985a50b509f2a02ff0f709d2a546" + "reference": "a63e5e8f26ebbebf8ed3c5c691637325512eb0dc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/filp/whoops/zipball/a139776fa3f5985a50b509f2a02ff0f709d2a546", - "reference": "a139776fa3f5985a50b509f2a02ff0f709d2a546", + "url": "https://api.github.com/repos/filp/whoops/zipball/a63e5e8f26ebbebf8ed3c5c691637325512eb0dc", + "reference": "a63e5e8f26ebbebf8ed3c5c691637325512eb0dc", "shasum": "" }, "require": { @@ -260,7 +116,7 @@ ], "support": { "issues": "https://github.com/filp/whoops/issues", - "source": "https://github.com/filp/whoops/tree/2.15.4" + "source": "https://github.com/filp/whoops/tree/2.14.5" }, "funding": [ { @@ -268,7 +124,7 @@ "type": "github" } ], - "time": "2023-11-03T12:00:00+00:00" + "time": "2022-01-07T12:00:00+00:00" }, { "name": "getkirby/composer-installer", @@ -319,33 +175,33 @@ }, { "name": "laminas/laminas-escaper", - "version": "2.13.0", + "version": "2.10.0", "source": { "type": "git", "url": "https://github.com/laminas/laminas-escaper.git", - "reference": "af459883f4018d0f8a0c69c7a209daef3bf973ba" + "reference": "58af67282db37d24e584a837a94ee55b9c7552be" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laminas/laminas-escaper/zipball/af459883f4018d0f8a0c69c7a209daef3bf973ba", - "reference": "af459883f4018d0f8a0c69c7a209daef3bf973ba", + "url": "https://api.github.com/repos/laminas/laminas-escaper/zipball/58af67282db37d24e584a837a94ee55b9c7552be", + "reference": "58af67282db37d24e584a837a94ee55b9c7552be", "shasum": "" }, "require": { "ext-ctype": "*", "ext-mbstring": "*", - "php": "~8.1.0 || ~8.2.0 || ~8.3.0" + "php": "^7.4 || ~8.0.0 || ~8.1.0" }, "conflict": { "zendframework/zend-escaper": "*" }, "require-dev": { - "infection/infection": "^0.27.0", - "laminas/laminas-coding-standard": "~2.5.0", + "infection/infection": "^0.26.6", + "laminas/laminas-coding-standard": "~2.3.0", "maglnet/composer-require-checker": "^3.8.0", - "phpunit/phpunit": "^9.6.7", - "psalm/plugin-phpunit": "^0.18.4", - "vimeo/psalm": "^5.9" + "phpunit/phpunit": "^9.5.18", + "psalm/plugin-phpunit": "^0.16.1", + "vimeo/psalm": "^4.22.0" }, "type": "library", "autoload": { @@ -377,40 +233,37 @@ "type": "community_bridge" } ], - "time": "2023-10-10T08:35:13+00:00" + "time": "2022-03-08T20:15:36+00:00" }, { "name": "league/color-extractor", - "version": "0.4.0", + "version": "0.3.2", "source": { "type": "git", "url": "https://github.com/thephpleague/color-extractor.git", - "reference": "21fcac6249c5ef7d00eb83e128743ee6678fe505" + "reference": "837086ec60f50c84c611c613963e4ad2e2aec806" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/color-extractor/zipball/21fcac6249c5ef7d00eb83e128743ee6678fe505", - "reference": "21fcac6249c5ef7d00eb83e128743ee6678fe505", + "url": "https://api.github.com/repos/thephpleague/color-extractor/zipball/837086ec60f50c84c611c613963e4ad2e2aec806", + "reference": "837086ec60f50c84c611c613963e4ad2e2aec806", "shasum": "" }, "require": { "ext-gd": "*", - "php": "^7.3 || ^8.0" + "php": ">=5.4.0" }, "replace": { "matthecat/colorextractor": "*" }, "require-dev": { "friendsofphp/php-cs-fixer": "~2", - "phpunit/phpunit": "^9.5" - }, - "suggest": { - "ext-curl": "To download images from remote URLs if allow_url_fopen is disabled for security reasons" + "phpunit/phpunit": "~5" }, "type": "library", "autoload": { "psr-4": { - "League\\ColorExtractor\\": "src" + "": "src" } }, "notification-url": "https://packagist.org/downloads/", @@ -436,9 +289,9 @@ ], "support": { "issues": "https://github.com/thephpleague/color-extractor/issues", - "source": "https://github.com/thephpleague/color-extractor/tree/0.4.0" + "source": "https://github.com/thephpleague/color-extractor/tree/master" }, - "time": "2022-09-24T15:57:16+00:00" + "time": "2016-12-15T09:30:02+00:00" }, { "name": "michelf/php-smartypants", @@ -496,16 +349,16 @@ }, { "name": "phpmailer/phpmailer", - "version": "v6.9.1", + "version": "v6.6.4", "source": { "type": "git", "url": "https://github.com/PHPMailer/PHPMailer.git", - "reference": "039de174cd9c17a8389754d3b877a2ed22743e18" + "reference": "a94fdebaea6bd17f51be0c2373ab80d3d681269b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/039de174cd9c17a8389754d3b877a2ed22743e18", - "reference": "039de174cd9c17a8389754d3b877a2ed22743e18", + "url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/a94fdebaea6bd17f51be0c2373ab80d3d681269b", + "reference": "a94fdebaea6bd17f51be0c2373ab80d3d681269b", "shasum": "" }, "require": { @@ -515,25 +368,22 @@ "php": ">=5.5.0" }, "require-dev": { - "dealerdirect/phpcodesniffer-composer-installer": "^1.0", - "doctrine/annotations": "^1.2.6 || ^1.13.3", + "dealerdirect/phpcodesniffer-composer-installer": "^0.7.0", + "doctrine/annotations": "^1.2", "php-parallel-lint/php-console-highlighter": "^1.0.0", "php-parallel-lint/php-parallel-lint": "^1.3.2", "phpcompatibility/php-compatibility": "^9.3.5", "roave/security-advisories": "dev-latest", - "squizlabs/php_codesniffer": "^3.7.2", - "yoast/phpunit-polyfills": "^1.0.4" + "squizlabs/php_codesniffer": "^3.6.2", + "yoast/phpunit-polyfills": "^1.0.0" }, "suggest": { - "decomplexity/SendOauth2": "Adapter for using XOAUTH2 authentication", "ext-mbstring": "Needed to send email in multibyte encoding charset or decode encoded addresses", - "ext-openssl": "Needed for secure SMTP sending and DKIM signing", - "greew/oauth2-azure-provider": "Needed for Microsoft Azure XOAUTH2 authentication", "hayageek/oauth2-yahoo": "Needed for Yahoo XOAUTH2 authentication", "league/oauth2-google": "Needed for Google XOAUTH2 authentication", "psr/log": "For optional PSR-3 debug logging", - "symfony/polyfill-mbstring": "To support UTF-8 if the Mbstring PHP extension is not enabled (^1.2)", - "thenetworg/oauth2-azure": "Needed for Microsoft XOAUTH2 authentication" + "stevenmaguire/oauth2-microsoft": "Needed for Microsoft XOAUTH2 authentication", + "symfony/polyfill-mbstring": "To support UTF-8 if the Mbstring PHP extension is not enabled (^1.2)" }, "type": "library", "autoload": { @@ -565,7 +415,7 @@ "description": "PHPMailer is a full-featured email creation and transfer class for PHP", "support": { "issues": "https://github.com/PHPMailer/PHPMailer/issues", - "source": "https://github.com/PHPMailer/PHPMailer/tree/v6.9.1" + "source": "https://github.com/PHPMailer/PHPMailer/tree/v6.6.4" }, "funding": [ { @@ -573,34 +423,34 @@ "type": "github" } ], - "time": "2023-11-25T22:23:28+00:00" + "time": "2022-08-22T09:22:00+00:00" }, { "name": "psr/log", - "version": "3.0.0", + "version": "1.1.4", "source": { "type": "git", "url": "https://github.com/php-fig/log.git", - "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001" + "reference": "d49695b909c3b7628b6289db5479a1c204601f11" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/log/zipball/fe5ea303b0887d5caefd3d431c3e61ad47037001", - "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001", + "url": "https://api.github.com/repos/php-fig/log/zipball/d49695b909c3b7628b6289db5479a1c204601f11", + "reference": "d49695b909c3b7628b6289db5479a1c204601f11", "shasum": "" }, "require": { - "php": ">=8.0.0" + "php": ">=5.3.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.x-dev" + "dev-master": "1.1.x-dev" } }, "autoload": { "psr-4": { - "Psr\\Log\\": "src" + "Psr\\Log\\": "Psr/Log/" } }, "notification-url": "https://packagist.org/downloads/", @@ -621,168 +471,22 @@ "psr-3" ], "support": { - "source": "https://github.com/php-fig/log/tree/3.0.0" + "source": "https://github.com/php-fig/log/tree/1.1.4" }, - "time": "2021-07-14T16:46:02+00:00" - }, - { - "name": "symfony/deprecation-contracts", - "version": "v3.5.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1", - "reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1", - "shasum": "" - }, - "require": { - "php": ">=8.1" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "3.5-dev" - }, - "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" - } - }, - "autoload": { - "files": [ - "function.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "A generic function and convention to trigger deprecation notices", - "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v3.5.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2024-04-18T09:32:20+00:00" - }, - { - "name": "symfony/polyfill-ctype", - "version": "v1.29.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "ef4d7e442ca910c4764bce785146269b30cb5fc4" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/ef4d7e442ca910c4764bce785146269b30cb5fc4", - "reference": "ef4d7e442ca910c4764bce785146269b30cb5fc4", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "provide": { - "ext-ctype": "*" - }, - "suggest": { - "ext-ctype": "For best performance" - }, - "type": "library", - "extra": { - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, - "autoload": { - "files": [ - "bootstrap.php" - ], - "psr-4": { - "Symfony\\Polyfill\\Ctype\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Gert de Pagter", - "email": "BackEndTea@gmail.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill for ctype functions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "ctype", - "polyfill", - "portable" - ], - "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.29.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2024-01-29T20:11:03+00:00" + "time": "2021-05-03T11:20:27+00:00" }, { "name": "symfony/polyfill-intl-idn", - "version": "v1.29.0", + "version": "v1.26.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-idn.git", - "reference": "a287ed7475f85bf6f61890146edbc932c0fff919" + "reference": "59a8d271f00dd0e4c2e518104cc7963f655a1aa8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/a287ed7475f85bf6f61890146edbc932c0fff919", - "reference": "a287ed7475f85bf6f61890146edbc932c0fff919", + "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/59a8d271f00dd0e4c2e518104cc7963f655a1aa8", + "reference": "59a8d271f00dd0e4c2e518104cc7963f655a1aa8", "shasum": "" }, "require": { @@ -795,6 +499,9 @@ }, "type": "library", "extra": { + "branch-alias": { + "dev-main": "1.26-dev" + }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" @@ -837,7 +544,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.29.0" + "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.26.0" }, "funding": [ { @@ -853,20 +560,20 @@ "type": "tidelift" } ], - "time": "2024-01-29T20:11:03+00:00" + "time": "2022-05-24T11:49:31+00:00" }, { "name": "symfony/polyfill-intl-normalizer", - "version": "v1.29.0", + "version": "v1.30.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git", - "reference": "bc45c394692b948b4d383a08d7753968bed9a83d" + "reference": "a95281b0be0d9ab48050ebd988b967875cdb9fdb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/bc45c394692b948b4d383a08d7753968bed9a83d", - "reference": "bc45c394692b948b4d383a08d7753968bed9a83d", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/a95281b0be0d9ab48050ebd988b967875cdb9fdb", + "reference": "a95281b0be0d9ab48050ebd988b967875cdb9fdb", "shasum": "" }, "require": { @@ -918,7 +625,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.29.0" + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.30.0" }, "funding": [ { @@ -934,20 +641,20 @@ "type": "tidelift" } ], - "time": "2024-01-29T20:11:03+00:00" + "time": "2024-05-31T15:07:36+00:00" }, { "name": "symfony/polyfill-mbstring", - "version": "v1.29.0", + "version": "v1.26.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "9773676c8a1bb1f8d4340a62efe641cf76eda7ec" + "reference": "9344f9cb97f3b19424af1a21a3b0e75b0a7d8d7e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/9773676c8a1bb1f8d4340a62efe641cf76eda7ec", - "reference": "9773676c8a1bb1f8d4340a62efe641cf76eda7ec", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/9344f9cb97f3b19424af1a21a3b0e75b0a7d8d7e", + "reference": "9344f9cb97f3b19424af1a21a3b0e75b0a7d8d7e", "shasum": "" }, "require": { @@ -961,6 +668,9 @@ }, "type": "library", "extra": { + "branch-alias": { + "dev-main": "1.26-dev" + }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" @@ -998,7 +708,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.29.0" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.26.0" }, "funding": [ { @@ -1014,79 +724,7 @@ "type": "tidelift" } ], - "time": "2024-01-29T20:11:03+00:00" - }, - { - "name": "symfony/yaml", - "version": "v6.4.8", - "source": { - "type": "git", - "url": "https://github.com/symfony/yaml.git", - "reference": "52903de178d542850f6f341ba92995d3d63e60c9" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/52903de178d542850f6f341ba92995d3d63e60c9", - "reference": "52903de178d542850f6f341ba92995d3d63e60c9", - "shasum": "" - }, - "require": { - "php": ">=8.1", - "symfony/deprecation-contracts": "^2.5|^3", - "symfony/polyfill-ctype": "^1.8" - }, - "conflict": { - "symfony/console": "<5.4" - }, - "require-dev": { - "symfony/console": "^5.4|^6.0|^7.0" - }, - "bin": [ - "Resources/bin/yaml-lint" - ], - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\Yaml\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Loads and dumps YAML files", - "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/yaml/tree/v6.4.8" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2024-05-31T14:49:08+00:00" + "time": "2022-05-24T11:49:31+00:00" } ], "packages-dev": [], @@ -1096,7 +734,7 @@ "prefer-stable": false, "prefer-lowest": false, "platform": { - "php": "~8.1.0 || ~8.2.0 || ~8.3.0", + "php": ">=7.4.0 <8.2.0", "ext-simplexml": "*", "ext-ctype": "*", "ext-curl": "*", @@ -1111,7 +749,7 @@ }, "platform-dev": [], "platform-overrides": { - "php": "8.1.0" + "php": "7.4.0" }, "plugin-api-version": "2.6.0" } diff --git a/kirby/config/aliases.php b/kirby/config/aliases.php index 206d3b4..ee795a3 100644 --- a/kirby/config/aliases.php +++ b/kirby/config/aliases.php @@ -3,6 +3,7 @@ return [ // cms classes 'collection' => 'Kirby\Cms\Collection', + 'field' => 'Kirby\Cms\Field', 'file' => 'Kirby\Cms\File', 'files' => 'Kirby\Cms\Files', 'find' => 'Kirby\Cms\Find', @@ -23,9 +24,6 @@ return [ 'users' => 'Kirby\Cms\Users', 'visitor' => 'Kirby\Cms\Visitor', - // content classes - 'field' => 'Kirby\Content\Field', - // data handler 'data' => 'Kirby\Data\Data', 'json' => 'Kirby\Data\Json', @@ -48,6 +46,7 @@ return [ 'cookie' => 'Kirby\Http\Cookie', 'header' => 'Kirby\Http\Header', 'remote' => 'Kirby\Http\Remote', + 'server' => 'Kirby\Http\Server', // image classes 'dimensions' => 'Kirby\Image\Dimensions', @@ -55,10 +54,6 @@ return [ // panel classes 'panel' => 'Kirby\Panel\Panel', - // template classes - 'snippet' => 'Kirby\Template\Snippet', - 'slot' => 'Kirby\Template\Slot', - // toolkit classes 'a' => 'Kirby\Toolkit\A', 'c' => 'Kirby\Toolkit\Config', @@ -71,25 +66,16 @@ return [ 'v' => 'Kirby\Toolkit\V', 'xml' => 'Kirby\Toolkit\Xml', - // Deprecated aliases: - // Any of these might be removed at any point in the future - 'kirby\cms\asset' => 'Kirby\Filesystem\Asset', - 'kirby\cms\content' => 'Kirby\Content\Content', - 'kirby\cms\contenttranslation' => 'Kirby\Content\ContentTranslation', - 'kirby\cms\dir' => 'Kirby\Filesystem\Dir', - 'kirby\cms\filename' => 'Kirby\Filesystem\Filename', - 'kirby\cms\filefoundation' => 'Kirby\Filesystem\IsFile', - 'kirby\cms\field' => 'Kirby\Content\Field', - 'kirby\cms\form' => 'Kirby\Form\Form', - 'kirby\cms\kirbytag' => 'Kirby\Text\KirbyTag', - 'kirby\cms\kirbytags' => 'Kirby\Text\KirbyTags', - 'kirby\cms\template' => 'Kirby\Template\Template', - 'kirby\form\options' => 'Kirby\Option\Options', - 'kirby\form\optionsapi' => 'Kirby\Option\OptionsApi', - 'kirby\form\optionsquery' => 'Kirby\Option\OptionsQuery', - 'kirby\toolkit\dir' => 'Kirby\Filesystem\Dir', - 'kirby\toolkit\f' => 'Kirby\Filesystem\F', - 'kirby\toolkit\file' => 'Kirby\Filesystem\File', - 'kirby\toolkit\mime' => 'Kirby\Filesystem\Mime', - 'kirby\toolkit\query' => 'Kirby\Query\Query', + // TODO: remove in 4.0.0 + 'kirby\cms\asset' => 'Kirby\Filesystem\Asset', + 'kirby\cms\dir' => 'Kirby\Filesystem\Dir', + 'kirby\cms\filename' => 'Kirby\Filesystem\Filename', + 'kirby\cms\filefoundation' => 'Kirby\Filesystem\IsFile', + 'kirby\cms\form' => 'Kirby\Form\Form', + 'kirby\cms\kirbytag' => 'Kirby\Text\KirbyTag', + 'kirby\cms\kirbytags' => 'Kirby\Text\KirbyTags', + 'kirby\toolkit\dir' => 'Kirby\Filesystem\Dir', + 'kirby\toolkit\f' => 'Kirby\Filesystem\F', + 'kirby\toolkit\file' => 'Kirby\Filesystem\File', + 'kirby\toolkit\mime' => 'Kirby\Filesystem\Mime', ]; diff --git a/kirby/config/api/authentication.php b/kirby/config/api/authentication.php index 15f3bbd..4758599 100644 --- a/kirby/config/api/authentication.php +++ b/kirby/config/api/authentication.php @@ -1,6 +1,6 @@ kirby()->auth(); @@ -11,17 +11,17 @@ return function () { $auth->type($allowImpersonation) === 'session' && $auth->csrf() === false ) { - throw new AuthException('Unauthenticated'); + throw new PermissionException('Unauthenticated'); } // get user from session or basic auth if ($user = $auth->user(null, $allowImpersonation)) { if ($user->role()->permissions()->for('access', 'panel') === false) { - throw new AuthException(['key' => 'access.panel']); + throw new PermissionException(['key' => 'access.panel']); } return $user; } - throw new AuthException('Unauthenticated'); + throw new PermissionException('Unauthenticated'); }; diff --git a/kirby/config/api/collections.php b/kirby/config/api/collections.php index 97b2180..3a34927 100644 --- a/kirby/config/api/collections.php +++ b/kirby/config/api/collections.php @@ -3,14 +3,6 @@ /** * Api Collection Definitions */ - -use Kirby\Cms\Files; -use Kirby\Cms\Languages; -use Kirby\Cms\Pages; -use Kirby\Cms\Roles; -use Kirby\Cms\Translations; -use Kirby\Cms\Users; - return [ /** @@ -18,7 +10,7 @@ return [ */ 'children' => [ 'model' => 'page', - 'type' => Pages::class, + 'type' => 'Kirby\Cms\Pages', 'view' => 'compact' ], @@ -27,7 +19,7 @@ return [ */ 'files' => [ 'model' => 'file', - 'type' => Files::class, + 'type' => 'Kirby\Cms\Files' ], /** @@ -35,7 +27,7 @@ return [ */ 'languages' => [ 'model' => 'language', - 'type' => Languages::class, + 'type' => 'Kirby\Cms\Languages' ], /** @@ -43,7 +35,7 @@ return [ */ 'pages' => [ 'model' => 'page', - 'type' => Pages::class, + 'type' => 'Kirby\Cms\Pages', 'view' => 'compact' ], @@ -52,7 +44,7 @@ return [ */ 'roles' => [ 'model' => 'role', - 'type' => Roles::class, + 'type' => 'Kirby\Cms\Roles', 'view' => 'compact' ], @@ -61,7 +53,7 @@ return [ */ 'translations' => [ 'model' => 'translation', - 'type' => Translations::class, + 'type' => 'Kirby\Cms\Translations', 'view' => 'compact' ], @@ -71,7 +63,7 @@ return [ 'users' => [ 'default' => fn () => $this->users(), 'model' => 'user', - 'type' => Users::class, + 'type' => 'Kirby\Cms\Users', 'view' => 'compact' ] diff --git a/kirby/config/api/models.php b/kirby/config/api/models.php index 9e6fc18..075442f 100644 --- a/kirby/config/api/models.php +++ b/kirby/config/api/models.php @@ -8,7 +8,6 @@ return [ 'FileBlueprint' => include __DIR__ . '/models/FileBlueprint.php', 'FileVersion' => include __DIR__ . '/models/FileVersion.php', 'Language' => include __DIR__ . '/models/Language.php', - 'License' => include __DIR__ . '/models/License.php', 'Page' => include __DIR__ . '/models/Page.php', 'PageBlueprint' => include __DIR__ . '/models/PageBlueprint.php', 'Role' => include __DIR__ . '/models/Role.php', diff --git a/kirby/config/api/models/File.php b/kirby/config/api/models/File.php index b70919a..dac185d 100644 --- a/kirby/config/api/models/File.php +++ b/kirby/config/api/models/File.php @@ -57,9 +57,8 @@ return [ }, 'type' => fn (File $file) => $file->type(), 'url' => fn (File $file) => $file->url(), - 'uuid' => fn (File $file) => $file->uuid()?->toString() ], - 'type' => File::class, + 'type' => 'Kirby\Cms\File', 'views' => [ 'default' => [ 'content', @@ -80,8 +79,7 @@ return [ 'size', 'template', 'type', - 'url', - 'uuid' + 'url' ], 'compact' => [ 'filename', @@ -89,7 +87,6 @@ return [ 'link', 'type', 'url', - 'uuid' ], 'panel' => [ 'blueprint', @@ -112,8 +109,7 @@ return [ 'prevWithTemplate' => 'compact', 'template', 'type', - 'url', - 'uuid' + 'url' ] ], ]; diff --git a/kirby/config/api/models/FileBlueprint.php b/kirby/config/api/models/FileBlueprint.php index f255c14..e781e45 100644 --- a/kirby/config/api/models/FileBlueprint.php +++ b/kirby/config/api/models/FileBlueprint.php @@ -12,6 +12,7 @@ return [ 'tabs' => fn (FileBlueprint $blueprint) => $blueprint->tabs(), 'title' => fn (FileBlueprint $blueprint) => $blueprint->title(), ], - 'type' => FileBlueprint::class, - 'views' => [], + 'type' => 'Kirby\Cms\FileBlueprint', + 'views' => [ + ], ]; diff --git a/kirby/config/api/models/FileVersion.php b/kirby/config/api/models/FileVersion.php index 063e10b..df2aac0 100644 --- a/kirby/config/api/models/FileVersion.php +++ b/kirby/config/api/models/FileVersion.php @@ -20,7 +20,7 @@ return [ 'type' => fn (FileVersion $file) => $file->type(), 'url' => fn (FileVersion $file) => $file->url(), ], - 'type' => FileVersion::class, + 'type' => 'Kirby\Cms\FileVersion', 'views' => [ 'default' => [ 'dimensions', diff --git a/kirby/config/api/models/Language.php b/kirby/config/api/models/Language.php index fcebad1..362d6f5 100644 --- a/kirby/config/api/models/Language.php +++ b/kirby/config/api/models/Language.php @@ -15,7 +15,7 @@ return [ 'rules' => fn (Language $language) => $language->rules(), 'url' => fn (Language $language) => $language->url(), ], - 'type' => Language::class, + 'type' => 'Kirby\Cms\Language', 'views' => [ 'default' => [ 'code', diff --git a/kirby/config/api/models/License.php b/kirby/config/api/models/License.php deleted file mode 100644 index 3a56556..0000000 --- a/kirby/config/api/models/License.php +++ /dev/null @@ -1,17 +0,0 @@ - [ - 'status' => fn (License $license) => $license->status()->value(), - 'code' => function (License $license) { - return $this->kirby()->user()->isAdmin() ? $license->code() : $license->code(true); - }, - 'type' => fn (License $license) => $license->type()->label(), - ], - 'type' => License::class, -]; diff --git a/kirby/config/api/models/Page.php b/kirby/config/api/models/Page.php index 4ff6dbc..03b6c7d 100644 --- a/kirby/config/api/models/Page.php +++ b/kirby/config/api/models/Page.php @@ -1,5 +1,6 @@ fn (Page $page) => $page->hasFiles(), 'id' => fn (Page $page) => $page->id(), 'isSortable' => fn (Page $page) => $page->isSortable(), - 'num' => fn (Page $page) => $page->num(), - 'options' => fn (Page $page) => $page->panel()->options(['preview']), - 'panelImage' => fn (Page $page) => $page->panel()->image(), - 'parent' => fn (Page $page) => $page->parent(), - 'parents' => fn (Page $page) => $page->parents()->flip(), - 'previewUrl' => fn (Page $page) => $page->previewUrl(), - 'siblings' => function (Page $page) { + /** + * @deprecated 3.6.0 + * @todo Remove in 3.8.0 + * @codeCoverageIgnore + */ + 'next' => function (Page $page) { + Helpers::deprecated('The API field page.next has been deprecated and will be removed in 3.8.0.'); + + return $page + ->nextAll() + ->filter('intendedTemplate', $page->intendedTemplate()) + ->filter('status', $page->status()) + ->filter('isReadable', true) + ->first(); + }, + 'num' => fn (Page $page) => $page->num(), + 'options' => fn (Page $page) => $page->panel()->options(['preview']), + 'panelImage' => fn (Page $page) => $page->panel()->image(), + 'parent' => fn (Page $page) => $page->parent(), + 'parents' => fn (Page $page) => $page->parents()->flip(), + /** + * @deprecated 3.6.0 + * @todo Remove in 3.8.0 + * @codeCoverageIgnore + */ + 'prev' => function (Page $page) { + Helpers::deprecated('The API field page.prev has been deprecated and will be removed in 3.8.0.'); + + return $page + ->prevAll() + ->filter('intendedTemplate', $page->intendedTemplate()) + ->filter('status', $page->status()) + ->filter('isReadable', true) + ->last(); + }, + 'previewUrl' => fn (Page $page) => $page->previewUrl(), + 'siblings' => function (Page $page) { if ($page->isDraft() === true) { return $page->parentModel()->children()->not($page); + } else { + return $page->siblings(); } - - return $page->siblings(); }, 'slug' => fn (Page $page) => $page->slug(), 'status' => fn (Page $page) => $page->status(), 'template' => fn (Page $page) => $page->intendedTemplate()->name(), 'title' => fn (Page $page) => $page->title()->value(), 'url' => fn (Page $page) => $page->url(), - 'uuid' => fn (Page $page) => $page->uuid()?->toString() ], - 'type' => Page::class, + 'type' => 'Kirby\Cms\Page', 'views' => [ 'compact' => [ 'id', 'title', 'url', - 'num', - 'uuid' + 'num' ], 'default' => [ 'content', @@ -59,8 +88,7 @@ return [ 'slug', 'template', 'title', - 'url', - 'uuid' + 'url' ], 'panel' => [ 'id', @@ -74,8 +102,7 @@ return [ 'previewUrl', 'slug', 'title', - 'url', - 'uuid' + 'url' ], 'selector' => [ 'id', diff --git a/kirby/config/api/models/PageBlueprint.php b/kirby/config/api/models/PageBlueprint.php index e993b91..dc240ed 100644 --- a/kirby/config/api/models/PageBlueprint.php +++ b/kirby/config/api/models/PageBlueprint.php @@ -15,6 +15,7 @@ return [ 'tabs' => fn (PageBlueprint $blueprint) => $blueprint->tabs(), 'title' => fn (PageBlueprint $blueprint) => $blueprint->title(), ], - 'type' => PageBlueprint::class, - 'views' => [], + 'type' => 'Kirby\Cms\PageBlueprint', + 'views' => [ + ], ]; diff --git a/kirby/config/api/models/Role.php b/kirby/config/api/models/Role.php index 3c2b468..e1d27c3 100644 --- a/kirby/config/api/models/Role.php +++ b/kirby/config/api/models/Role.php @@ -12,7 +12,7 @@ return [ 'permissions' => fn (Role $role) => $role->permissions()->toArray(), 'title' => fn (Role $role) => $role->title(), ], - 'type' => Role::class, + 'type' => 'Kirby\Cms\Role', 'views' => [ 'compact' => [ 'description', diff --git a/kirby/config/api/models/Site.php b/kirby/config/api/models/Site.php index 81cab62..c312ef4 100644 --- a/kirby/config/api/models/Site.php +++ b/kirby/config/api/models/Site.php @@ -19,7 +19,7 @@ return [ 'title' => fn (Site $site) => $site->title()->value(), 'url' => fn (Site $site) => $site->url(), ], - 'type' => Site::class, + 'type' => 'Kirby\Cms\Site', 'views' => [ 'compact' => [ 'title', diff --git a/kirby/config/api/models/SiteBlueprint.php b/kirby/config/api/models/SiteBlueprint.php index 69aad5b..7841841 100644 --- a/kirby/config/api/models/SiteBlueprint.php +++ b/kirby/config/api/models/SiteBlueprint.php @@ -12,6 +12,6 @@ return [ 'tabs' => fn (SiteBlueprint $blueprint) => $blueprint->tabs(), 'title' => fn (SiteBlueprint $blueprint) => $blueprint->title(), ], - 'type' => SiteBlueprint::class, + 'type' => 'Kirby\Cms\SiteBlueprint', 'views' => [], ]; diff --git a/kirby/config/api/models/System.php b/kirby/config/api/models/System.php index 4627226..260aa45 100644 --- a/kirby/config/api/models/System.php +++ b/kirby/config/api/models/System.php @@ -32,24 +32,31 @@ return [ 'slugs' => fn () => Str::$language, 'title' => fn () => $this->site()->title()->value(), 'translation' => function () { - $code = $this->user()?->language() ?? - $this->kirby()->panelLanguage(); + if ($user = $this->user()) { + $translationCode = $user->language(); + } else { + $translationCode = $this->kirby()->panelLanguage(); + } - return - $this->kirby()->translation($code) ?? - $this->kirby()->translation('en'); + if ($translation = $this->kirby()->translation($translationCode)) { + return $translation; + } else { + return $this->kirby()->translation('en'); + } }, 'kirbytext' => fn () => $this->kirby()->option('panel.kirbytext') ?? true, 'user' => fn () => $this->user(), 'version' => function () { - if ($this->user()?->role()->permissions()->for('access', 'system') === true) { - return $this->kirby()->version(); - } + $user = $this->user(); - return null; + if ($user && $user->role()->permissions()->for('access', 'system') === true) { + return $this->kirby()->version(); + } else { + return null; + } } ], - 'type' => System::class, + 'type' => 'Kirby\Cms\System', 'views' => [ 'login' => [ 'authStatus', diff --git a/kirby/config/api/models/Translation.php b/kirby/config/api/models/Translation.php index 94f9c02..faf51e7 100644 --- a/kirby/config/api/models/Translation.php +++ b/kirby/config/api/models/Translation.php @@ -13,7 +13,7 @@ return [ 'id' => fn (Translation $translation) => $translation->id(), 'name' => fn (Translation $translation) => $translation->name(), ], - 'type' => Translation::class, + 'type' => 'Kirby\Cms\Translation', 'views' => [ 'compact' => [ 'direction', diff --git a/kirby/config/api/models/User.php b/kirby/config/api/models/User.php index 0da32e9..5354e3a 100644 --- a/kirby/config/api/models/User.php +++ b/kirby/config/api/models/User.php @@ -9,7 +9,7 @@ use Kirby\Form\Form; return [ 'default' => fn () => $this->user(), 'fields' => [ - 'avatar' => fn (User $user) => $user->avatar()?->crop(512), + 'avatar' => fn (User $user) => $user->avatar() ? $user->avatar()->crop(512) : null, 'blueprint' => fn (User $user) => $user->blueprint(), 'content' => fn (User $user) => Form::for($user)->values(), 'email' => fn (User $user) => $user->email(), @@ -24,10 +24,9 @@ return [ 'prev' => fn (User $user) => $user->prev(), 'role' => fn (User $user) => $user->role(), 'roles' => fn (User $user) => $user->roles(), - 'username' => fn (User $user) => $user->username(), - 'uuid' => fn (User $user) => $user->uuid()?->toString() + 'username' => fn (User $user) => $user->username() ], - 'type' => User::class, + 'type' => 'Kirby\Cms\User', 'views' => [ 'default' => [ 'avatar', @@ -40,8 +39,7 @@ return [ 'options', 'prev' => 'compact', 'role', - 'username', - 'uuid' + 'username' ], 'compact' => [ 'avatar' => 'compact', @@ -50,8 +48,7 @@ return [ 'language', 'name', 'role' => 'compact', - 'username', - 'uuid' + 'username' ], 'auth' => [ 'avatar' => 'compact', @@ -75,7 +72,6 @@ return [ 'prev' => ['id', 'name'], 'role', 'username', - 'uuid' ], ] ]; diff --git a/kirby/config/api/models/UserBlueprint.php b/kirby/config/api/models/UserBlueprint.php index 2fa83e9..099a177 100644 --- a/kirby/config/api/models/UserBlueprint.php +++ b/kirby/config/api/models/UserBlueprint.php @@ -12,6 +12,7 @@ return [ 'tabs' => fn (UserBlueprint $blueprint) => $blueprint->tabs(), 'title' => fn (UserBlueprint $blueprint) => $blueprint->title(), ], - 'type' => UserBlueprint::class, - 'views' => [], + 'type' => 'Kirby\Cms\UserBlueprint', + 'views' => [ + ], ]; diff --git a/kirby/config/api/routes.php b/kirby/config/api/routes.php index aca9e79..749fbad 100644 --- a/kirby/config/api/routes.php +++ b/kirby/config/api/routes.php @@ -19,10 +19,7 @@ return function ($kirby) { // only add the language routes if the // multi language setup is activated if ($kirby->option('languages', false) !== false) { - $routes = array_merge( - $routes, - include __DIR__ . '/routes/languages.php' - ); + $routes = array_merge($routes, include __DIR__ . '/routes/languages.php'); } return $routes; diff --git a/kirby/config/api/routes/auth.php b/kirby/config/api/routes/auth.php index 97b81a1..a4fcbb4 100644 --- a/kirby/config/api/routes/auth.php +++ b/kirby/config/api/routes/auth.php @@ -70,11 +70,13 @@ return [ $user = $auth->login($email, $password, $long); } } else { - $mode = match (true) { - isset($methods['code']) => 'login', - isset($methods['password-reset']) => 'password-reset', - default => throw new InvalidArgumentException('Login without password is not enabled') - }; + if (isset($methods['code']) === true) { + $mode = 'login'; + } elseif (isset($methods['password-reset']) === true) { + $mode = 'password-reset'; + } else { + throw new InvalidArgumentException('Login without password is not enabled'); + } $status = $auth->createChallenge($email, $long, $mode); } @@ -85,13 +87,13 @@ return [ 'status' => 'ok', 'user' => $this->resolve($user)->view('auth')->toArray() ]; + } else { + return [ + 'code' => 200, + 'status' => 'ok', + 'challenge' => $status->challenge() + ]; } - - return [ - 'code' => 200, - 'status' => 'ok', - 'challenge' => $status->challenge() - ]; } ], [ @@ -103,14 +105,4 @@ return [ return true; } ], - [ - 'pattern' => 'auth/ping', - 'method' => 'POST', - 'auth' => false, - 'action' => function () { - // refresh the session timeout - $this->kirby()->session(); - return true; - } - ], ]; diff --git a/kirby/config/api/routes/files.php b/kirby/config/api/routes/files.php index 7cf1073..c1b755b 100644 --- a/kirby/config/api/routes/files.php +++ b/kirby/config/api/routes/files.php @@ -1,148 +1,132 @@ $filePattern . '/fields/(:any)/(:all?)', + 'pattern' => $pattern . '/files/(:any)/sections/(:any)', + 'method' => 'GET', + 'action' => function (string $path, string $filename, string $sectionName) { + if ($section = $this->file($path, $filename)->blueprint()->section($sectionName)) { + return $section->toResponse(); + } + } + ], + [ + 'pattern' => $pattern . '/files/(:any)/fields/(:any)/(:all?)', 'method' => 'ALL', - 'action' => function (string $parent, string $filename, string $fieldName, string|null $path = null) { + 'action' => function (string $parent, string $filename, string $fieldName, string $path = null) { if ($file = $this->file($parent, $filename)) { return $this->fieldApi($file, $fieldName, $path); } } ], [ - 'pattern' => $filePattern . '/sections/(:any)', - 'method' => 'GET', - 'action' => function (string $path, string $filename, string $sectionName) { - return $this->file($path, $filename)->blueprint()->section($sectionName)?->toResponse(); - } - ], - [ - 'pattern' => $filePattern . '/sections/(:any)/(:all?)', - 'method' => 'ALL', - 'action' => function (string $parent, string $filename, string $sectionName, string|null $path = null) { - if ($file = $this->file($parent, $filename)) { - return $this->sectionApi($file, $sectionName, $path); - } - } - ], - [ - 'pattern' => $parentPattern, + 'pattern' => $pattern . '/files', 'method' => 'GET', 'action' => function (string $path) { - return $this->files($path)->sorted(); + return $this->parent($path)->files()->sorted(); } ], [ - 'pattern' => $parentPattern, + 'pattern' => $pattern . '/files', 'method' => 'POST', 'action' => function (string $path) { // move_uploaded_file() not working with unit test // @codeCoverageIgnoreStart return $this->upload(function ($source, $filename) use ($path) { - $props = [ + return $this->parent($path)->createFile([ 'content' => [ 'sort' => $this->requestBody('sort') ], 'source' => $source, 'template' => $this->requestBody('template'), 'filename' => $filename - ]; - - // move the source file from the temp dir - return $this->parent($path)->createFile($props, true); + ]); }); // @codeCoverageIgnoreEnd } ], [ - 'pattern' => $parentPattern . '/search', + 'pattern' => $pattern . '/files/search', 'method' => 'GET|POST', 'action' => function (string $path) { - $files = $this->files($path); + $files = $this->parent($path)->files(); if ($this->requestMethod() === 'GET') { return $files->search($this->requestQuery('q')); + } else { + return $files->query($this->requestBody()); } - - return $files->query($this->requestBody()); } ], [ - 'pattern' => $parentPattern . '/sort', + 'pattern' => $pattern . '/files/sort', 'method' => 'PATCH', 'action' => function (string $path) { - return $this->files($path)->changeSort( + return $this->parent($path)->files()->changeSort( $this->requestBody('files'), $this->requestBody('index') ); } ], [ - 'pattern' => $filePattern, + 'pattern' => $pattern . '/files/(:any)', 'method' => 'GET', 'action' => function (string $path, string $filename) { return $this->file($path, $filename); } ], [ - 'pattern' => $filePattern, + 'pattern' => $pattern . '/files/(:any)', 'method' => 'PATCH', 'action' => function (string $path, string $filename) { - return $this->file($path, $filename)->update( - $this->requestBody(), - $this->language(), - true - ); + return $this->file($path, $filename)->update($this->requestBody(), $this->language(), true); } ], [ - 'pattern' => $filePattern, + 'pattern' => $pattern . '/files/(:any)', 'method' => 'POST', 'action' => function (string $path, string $filename) { - // move the source file from the temp dir - return $this->upload( - fn ($source) => $this->file($path, $filename)->replace($source, true) - ); + return $this->upload(function ($source) use ($path, $filename) { + return $this->file($path, $filename)->replace($source); + }); } ], [ - 'pattern' => $filePattern, + 'pattern' => $pattern . '/files/(:any)', 'method' => 'DELETE', 'action' => function (string $path, string $filename) { return $this->file($path, $filename)->delete(); } ], [ - 'pattern' => $filePattern . '/name', + 'pattern' => $pattern . '/files/(:any)/name', 'method' => 'PATCH', 'action' => function (string $path, string $filename) { return $this->file($path, $filename)->changeName($this->requestBody('name')); } ], [ - 'pattern' => $parentPattern . '/search', + 'pattern' => 'files/search', 'method' => 'GET|POST', 'action' => function () { $files = $this ->site() ->index(true) - ->filter('isListable', true) - ->files() - ->filter('isListable', true); + ->filter('isReadable', true) + ->files(); if ($this->requestMethod() === 'GET') { return $files->search($this->requestQuery('q')); + } else { + return $files->query($this->requestBody()); } - - return $files->query($this->requestBody()); } ], ]; diff --git a/kirby/config/api/routes/kql.php b/kirby/config/api/routes/kql.php deleted file mode 100644 index 68710ec..0000000 --- a/kirby/config/api/routes/kql.php +++ /dev/null @@ -1,35 +0,0 @@ - function ($kirby) { - return [ - [ - 'pattern' => 'query', - 'method' => 'POST|GET', - 'auth' => $kirby->option('kql.auth') !== false, - 'action' => function () use ($kirby) { - $kql = '\Kirby\Kql\Kql'; - - if (class_exists($kql) === false) { - return [ - 'code' => 500, - 'status' => 'error', - 'message' => 'KQL plugin is not installed', - ]; - } - - $input = $kirby->request()->get(); - $result = $kql::run($input); - - return [ - 'code' => 200, - 'result' => $result, - 'status' => 'ok', - ]; - } - ] - ]; - } -]; -// @codeCoverageIgnoreEnd diff --git a/kirby/config/api/routes/languages.php b/kirby/config/api/routes/languages.php index e2d4f6b..4105ef2 100644 --- a/kirby/config/api/routes/languages.php +++ b/kirby/config/api/routes/languages.php @@ -29,14 +29,18 @@ return [ 'pattern' => 'languages/(:any)', 'method' => 'PATCH', 'action' => function (string $code) { - return $this->kirby()->languages()->find($code)?->update($this->requestBody()); + if ($language = $this->kirby()->languages()->find($code)) { + return $language->update($this->requestBody()); + } } ], [ 'pattern' => 'languages/(:any)', 'method' => 'DELETE', 'action' => function (string $code) { - return $this->kirby()->languages()->find($code)?->delete(); + if ($language = $this->kirby()->languages()->find($code)) { + return $language->delete(); + } } ] ]; diff --git a/kirby/config/api/routes/lock.php b/kirby/config/api/routes/lock.php index c7095d9..c5b2da4 100644 --- a/kirby/config/api/routes/lock.php +++ b/kirby/config/api/routes/lock.php @@ -4,34 +4,22 @@ /** * Content Lock Routes */ - -use Kirby\Exception\NotFoundException; - return [ - [ - 'pattern' => '(:all)/lock', - 'method' => 'GET', - 'action' => function (string $path) { - return [ - 'lock' => $this->parent($path)->lock()?->toArray() ?? false - ]; - } - ], [ 'pattern' => '(:all)/lock', 'method' => 'PATCH', 'action' => function (string $path) { - return $this->parent($path)->lock()?->create(); + if ($lock = $this->parent($path)->lock()) { + return $lock->create(); + } } ], [ 'pattern' => '(:all)/lock', 'method' => 'DELETE', 'action' => function (string $path) { - try { - return $this->parent($path)->lock()?->remove(); - } catch (NotFoundException) { - return true; + if ($lock = $this->parent($path)->lock()) { + return $lock->remove(); } } ], @@ -39,17 +27,17 @@ return [ 'pattern' => '(:all)/unlock', 'method' => 'PATCH', 'action' => function (string $path) { - return $this->parent($path)->lock()?->unlock(); + if ($lock = $this->parent($path)->lock()) { + return $lock->unlock(); + } } ], [ 'pattern' => '(:all)/unlock', 'method' => 'DELETE', 'action' => function (string $path) { - try { - return $this->parent($path)->lock()?->resolve(); - } catch (NotFoundException) { - return true; + if ($lock = $this->parent($path)->lock()) { + return $lock->resolve(); } } ], diff --git a/kirby/config/api/routes/pages.php b/kirby/config/api/routes/pages.php index 6de9c1a..3ff255c 100644 --- a/kirby/config/api/routes/pages.php +++ b/kirby/config/api/routes/pages.php @@ -5,7 +5,7 @@ * Page Routes */ return [ - // @codeCoverageIgnoreStart + [ 'pattern' => 'pages/(:any)', 'method' => 'GET', @@ -100,30 +100,22 @@ return [ return $this->page($id)->changeTitle($this->requestBody('title')); } ], + [ + 'pattern' => 'pages/(:any)/sections/(:any)', + 'method' => 'GET', + 'action' => function (string $id, string $sectionName) { + if ($section = $this->page($id)->blueprint()->section($sectionName)) { + return $section->toResponse(); + } + } + ], [ 'pattern' => 'pages/(:any)/fields/(:any)/(:all?)', 'method' => 'ALL', - 'action' => function (string $id, string $fieldName, string|null $path = null) { + 'action' => function (string $id, string $fieldName, string $path = null) { if ($page = $this->page($id)) { return $this->fieldApi($page, $fieldName, $path); } } ], - [ - 'pattern' => 'pages/(:any)/sections/(:any)', - 'method' => 'GET', - 'action' => function (string $id, string $sectionName) { - return $this->page($id)->blueprint()->section($sectionName)?->toResponse(); - } - ], - [ - 'pattern' => 'pages/(:any)/sections/(:any)/(:all?)', - 'method' => 'ALL', - 'action' => function (string $id, string $sectionName, string|null $path = null) { - if ($page = $this->page($id)) { - return $this->sectionApi($page, $sectionName, $path); - } - } - ], - // @codeCoverageIgnoreEnd ]; diff --git a/kirby/config/api/routes/roles.php b/kirby/config/api/routes/roles.php index 56ecfea..7dbe45f 100644 --- a/kirby/config/api/routes/roles.php +++ b/kirby/config/api/routes/roles.php @@ -10,11 +10,14 @@ return [ 'action' => function () { $kirby = $this->kirby(); - return match ($kirby->request()->get('canBe')) { - 'changed' => $kirby->roles()->canBeChanged(), - 'created' => $kirby->roles()->canBeCreated(), - default => $kirby->roles() - }; + switch ($kirby->request()->get('canBe')) { + case 'changed': + return $kirby->roles()->canBeChanged(); + case 'created': + return $kirby->roles()->canBeCreated(); + default: + return $kirby->roles(); + } } ], [ diff --git a/kirby/config/api/routes/site.php b/kirby/config/api/routes/site.php index abc2ac5..3f2601c 100644 --- a/kirby/config/api/routes/site.php +++ b/kirby/config/api/routes/site.php @@ -5,7 +5,7 @@ * Site Routes */ return [ - // @codeCoverageIgnoreStart + [ 'pattern' => 'site', 'action' => function () { @@ -75,35 +75,30 @@ return [ $pages = $this ->site() ->index(true) - ->filter('isListable', true); + ->filter('isReadable', true); if ($this->requestMethod() === 'GET') { return $pages->search($this->requestQuery('q')); + } else { + return $pages->query($this->requestBody()); } - - return $pages->query($this->requestBody()); - } - ], - [ - 'pattern' => 'site/fields/(:any)/(:all?)', - 'method' => 'ALL', - 'action' => function (string $fieldName, string|null $path = null) { - return $this->fieldApi($this->site(), $fieldName, $path); } ], [ 'pattern' => 'site/sections/(:any)', 'method' => 'GET', 'action' => function (string $sectionName) { - return $this->site()->blueprint()->section($sectionName)?->toResponse(); + if ($section = $this->site()->blueprint()->section($sectionName)) { + return $section->toResponse(); + } } ], [ - 'pattern' => 'site/sections/(:any)/(:all?)', + 'pattern' => 'site/fields/(:any)/(:all?)', 'method' => 'ALL', - 'action' => function (string $sectionName, string|null $path = null) { - return $this->sectionApi($this->site(), $sectionName, $path); + 'action' => function (string $fieldName, string $path = null) { + return $this->fieldApi($this->site(), $fieldName, $path); } - ], - // @codeCoverageIgnoreEnd + ] + ]; diff --git a/kirby/config/api/routes/system.php b/kirby/config/api/routes/system.php index 103e826..0f6ba46 100644 --- a/kirby/config/api/routes/system.php +++ b/kirby/config/api/routes/system.php @@ -17,18 +17,19 @@ return [ if ($this->kirby()->user()) { return $system; + } else { + if ($system->isOk() === true) { + $info = $this->resolve($system)->view('login')->toArray(); + } else { + $info = $this->resolve($system)->view('troubleshooting')->toArray(); + } + + return [ + 'status' => 'ok', + 'data' => $info, + 'type' => 'model' + ]; } - - $info = match ($system->isOk()) { - true => $this->resolve($system)->view('login')->toArray(), - false => $this->resolve($system)->view('troubleshooting')->toArray() - }; - - return [ - 'status' => 'ok', - 'data' => $info, - 'type' => 'model' - ]; } ], [ diff --git a/kirby/config/api/routes/users.php b/kirby/config/api/routes/users.php index 88658d8..90fea4d 100644 --- a/kirby/config/api/routes/users.php +++ b/kirby/config/api/routes/users.php @@ -8,7 +8,6 @@ use Kirby\Toolkit\Str; * User Routes */ return [ - // @codeCoverageIgnoreStart [ 'pattern' => 'users', 'method' => 'GET', @@ -29,9 +28,9 @@ return [ 'action' => function () { if ($this->requestMethod() === 'GET') { return $this->users()->search($this->requestQuery('q')); + } else { + return $this->users()->query($this->requestBody()); } - - return $this->users()->query($this->requestBody()); } ], [ @@ -101,18 +100,17 @@ return [ } // delete the old avatar - $this->user($id)->avatar()?->delete(); + if ($avatar = $this->user($id)->avatar()) { + $avatar->delete(); + } - $props = [ + return $this->user($id)->createFile([ 'filename' => 'profile.' . F::extension($filename), 'template' => 'avatar', 'source' => $source - ]; - - // move the source file from the temp dir - return $this->user($id)->createFile($props, true); + ]); }, - single: true + $single = true ); } ], @@ -206,16 +204,6 @@ return [ return $this->user($id)->roles(); } ], - [ - 'pattern' => [ - '(account)/fields/(:any)/(:all?)', - 'users/(:any)/fields/(:any)/(:all?)', - ], - 'method' => 'ALL', - 'action' => function (string $id, string $fieldName, string|null $path = null) { - return $this->fieldApi($this->user($id), $fieldName, $path); - } - ], [ 'pattern' => [ '(account)/sections/(:any)', @@ -230,13 +218,12 @@ return [ ], [ 'pattern' => [ - '(account)/sections/(:any)/(:all?)', - 'users/(:any)/sections/(:any)/(:all?)', + '(account)/fields/(:any)/(:all?)', + 'users/(:any)/fields/(:any)/(:all?)', ], 'method' => 'ALL', - 'action' => function (string $id, string $sectionName, string|null $path = null) { - return $this->sectionApi($this->user($id), $sectionName, $path); + 'action' => function (string $id, string $fieldName, string $path = null) { + return $this->fieldApi($this->user($id), $fieldName, $path); } ], - // @codeCoverageIgnoreEnd ]; diff --git a/kirby/config/areas/account.php b/kirby/config/areas/account.php index e138cab..738a839 100644 --- a/kirby/config/areas/account.php +++ b/kirby/config/areas/account.php @@ -8,7 +8,6 @@ return function () { 'label' => I18n::translate('view.account'), 'search' => 'users', 'dialogs' => require __DIR__ . '/account/dialogs.php', - 'drawers' => require __DIR__ . '/account/drawers.php', 'dropdowns' => require __DIR__ . '/account/dropdowns.php', 'views' => require __DIR__ . '/account/views.php' ]; diff --git a/kirby/config/areas/account/dialogs.php b/kirby/config/areas/account/dialogs.php index 93635ce..7c13062 100644 --- a/kirby/config/areas/account/dialogs.php +++ b/kirby/config/areas/account/dialogs.php @@ -1,7 +1,5 @@ $dialogs['user.delete']['submit'], ], - // account fields dialogs - 'account.fields' => [ - 'pattern' => '(account)/files/(:any)/fields/(:any)/(:all?)', - 'load' => $dialogs['user.fields']['load'], - 'submit' => $dialogs['user.fields']['submit'] - ], - // change file name 'account.file.changeName' => [ 'pattern' => '(account)/files/(:any)/changeName', @@ -69,13 +60,6 @@ return [ 'submit' => $dialogs['user.file.changeSort']['submit'], ], - // change file template - 'account.file.changeTemplate' => [ - 'pattern' => '(account)/files/(:any)/changeTemplate', - 'load' => $dialogs['user.file.changeTemplate']['load'], - 'submit' => $dialogs['user.file.changeTemplate']['submit'], - ], - // delete 'account.file.delete' => [ 'pattern' => '(account)/files/(:any)/delete', @@ -83,24 +67,4 @@ return [ 'submit' => $dialogs['user.file.delete']['submit'], ], - // account file fields dialogs - 'account.file.fields' => [ - 'pattern' => '(account)/files/(:any)/fields/(:any)/(:all?)', - 'load' => $dialogs['user.file.fields']['load'], - 'submit' => $dialogs['user.file.fields']['submit'] - ], - - // account enable TOTP - 'account.totp.enable' => [ - 'pattern' => '(account)/totp/enable', - 'load' => fn () => (new UserTotpEnableDialog())->load(), - 'submit' => fn () => (new UserTotpEnableDialog())->submit() - ], - - // account disable TOTP - 'account.totp.disable' => [ - 'pattern' => '(account)/totp/disable', - 'load' => $dialogs['user.totp.disable']['load'], - 'submit' => $dialogs['user.totp.disable']['submit'] - ], ]; diff --git a/kirby/config/areas/account/drawers.php b/kirby/config/areas/account/drawers.php deleted file mode 100644 index 01bb0b6..0000000 --- a/kirby/config/areas/account/drawers.php +++ /dev/null @@ -1,19 +0,0 @@ - [ - 'pattern' => '(account)/files/(:any)/fields/(:any)/(:all?)', - 'load' => $drawers['user.fields']['load'], - 'submit' => $drawers['user.fields']['submit'] - ], - - // account file fields drawers - 'account.file.fields' => [ - 'pattern' => '(account)/files/(:any)/fields/(:any)/(:all?)', - 'load' => $drawers['user.file.fields']['load'], - 'submit' => $drawers['user.file.fields']['submit'] - ], -]; diff --git a/kirby/config/areas/account/views.php b/kirby/config/areas/account/views.php index 933e0a4..264edf9 100644 --- a/kirby/config/areas/account/views.php +++ b/kirby/config/areas/account/views.php @@ -2,7 +2,6 @@ use Kirby\Cms\App; use Kirby\Cms\Find; -use Kirby\Toolkit\I18n; return [ 'account' => [ @@ -20,13 +19,6 @@ return [ ], 'account.password' => [ 'pattern' => 'reset-password', - 'action' => fn () => [ - 'component' => 'k-reset-password-view', - 'breadcrumb' => [ - [ - 'label' => I18n::translate('view.resetPassword') - ] - ] - ] + 'action' => fn () => ['component' => 'k-reset-password-view'] ] ]; diff --git a/kirby/config/areas/fields/dialogs.php b/kirby/config/areas/fields/dialogs.php deleted file mode 100644 index ca14e08..0000000 --- a/kirby/config/areas/fields/dialogs.php +++ /dev/null @@ -1,61 +0,0 @@ - [ - 'load' => function ( - string $modelPath, - string $fieldName, - string|null $path = null - ) { - return Field::dialog( - model: Find::parent($modelPath), - fieldName: $fieldName, - path: $path, - method: 'GET' - ); - }, - 'submit' => function ( - string $modelPath, - string $fieldName, - string|null $path = null - ) { - return Field::dialog( - model: Find::parent($modelPath), - fieldName: $fieldName, - path: $path, - method: 'POST' - ); - } - ], - 'file' => [ - 'load' => function ( - string $modelPath, - string $filename, - string $fieldName, - string|null $path = null - ) { - return Field::dialog( - model: Find::file($modelPath, $filename), - fieldName: $fieldName, - path: $path, - method: 'GET' - ); - }, - 'submit' => function ( - string $modelPath, - string $filename, - string $fieldName, - string|null $path = null - ) { - return Field::dialog( - model: Find::file($modelPath, $filename), - fieldName: $fieldName, - path: $path, - method: 'POST' - ); - } - ], -]; diff --git a/kirby/config/areas/fields/drawers.php b/kirby/config/areas/fields/drawers.php deleted file mode 100644 index 1280a68..0000000 --- a/kirby/config/areas/fields/drawers.php +++ /dev/null @@ -1,61 +0,0 @@ - [ - 'load' => function ( - string $modelPath, - string $fieldName, - string|null $path = null - ) { - return Field::drawer( - model: Find::parent($modelPath), - fieldName: $fieldName, - path: $path, - method: 'GET' - ); - }, - 'submit' => function ( - string $modelPath, - string $fieldName, - string|null $path = null - ) { - return Field::drawer( - model: Find::parent($modelPath), - fieldName: $fieldName, - path: $path, - method: 'POST' - ); - } - ], - 'file' => [ - 'load' => function ( - string $modelPath, - string $filename, - string $fieldName, - string|null $path = null - ) { - return Field::drawer( - model: Find::file($modelPath, $filename), - fieldName: $fieldName, - path: $path, - method: 'GET' - ); - }, - 'submit' => function ( - string $modelPath, - string $filename, - string $fieldName, - string|null $path = null - ) { - return Field::drawer( - model: Find::file($modelPath, $filename), - fieldName: $fieldName, - path: $path, - method: 'POST' - ); - } - ], -]; diff --git a/kirby/config/areas/files/dialogs.php b/kirby/config/areas/files/dialogs.php index 8707bd0..44625eb 100644 --- a/kirby/config/areas/files/dialogs.php +++ b/kirby/config/areas/files/dialogs.php @@ -26,7 +26,7 @@ return [ 'type' => 'slug', 'required' => true, 'icon' => 'title', - 'allow' => 'a-z0-9@._-', + 'allow' => '@._-', 'after' => '.' . $file->extension(), 'preselect' => true ] @@ -40,8 +40,7 @@ return [ }, 'submit' => function (string $path, string $filename) { $file = Find::file($path, $filename); - $name = $file->kirby()->request()->get('name'); - $renamed = $file->changeName($name); + $renamed = $file->changeName($file->kirby()->request()->get('name')); $oldUrl = $file->panel()->url(true); $newUrl = $renamed->panel()->url(true); $response = [ @@ -97,44 +96,6 @@ return [ } ], - 'changeTemplate' => [ - 'load' => function (string $path, string $filename) { - $file = Find::file($path, $filename); - $blueprints = $file->blueprints(); - - return [ - 'component' => 'k-form-dialog', - 'props' => [ - 'fields' => [ - 'warning' => [ - 'type' => 'info', - 'theme' => 'notice', - 'text' => I18n::translate('file.changeTemplate.notice') - ], - 'template' => Field::template($blueprints, [ - 'required' => true - ]) - ], - 'theme' => 'notice', - 'submitButton' => I18n::translate('change'), - 'value' => [ - 'template' => $file->template() - ] - ] - ]; - }, - 'submit' => function (string $path, string $filename) { - $file = Find::file($path, $filename); - $template = $file->kirby()->request()->get('template'); - - $file->changeTemplate($template); - - return [ - 'event' => 'file.changeTemplate', - ]; - } - ], - 'delete' => [ 'load' => function (string $path, string $filename) { $file = Find::file($path, $filename); @@ -168,5 +129,4 @@ return [ ]; } ], - ]; diff --git a/kirby/config/areas/lab.php b/kirby/config/areas/lab.php deleted file mode 100644 index 580a9fb..0000000 --- a/kirby/config/areas/lab.php +++ /dev/null @@ -1,11 +0,0 @@ - 'lab', - 'label' => 'Lab', - 'menu' => false, - 'drawers' => require __DIR__ . '/lab/drawers.php', - 'views' => require __DIR__ . '/lab/views.php' - ]; -}; diff --git a/kirby/config/areas/lab/drawers.php b/kirby/config/areas/lab/drawers.php deleted file mode 100644 index 9d16d81..0000000 --- a/kirby/config/areas/lab/drawers.php +++ /dev/null @@ -1,30 +0,0 @@ - [ - 'pattern' => 'lab/docs/(:any)', - 'load' => function (string $component) { - if (Docs::installed() === false) { - return [ - 'component' => 'k-text-drawer', - 'props' => [ - 'text' => 'The UI docs are not installed.' - ] - ]; - } - - $docs = new Docs($component); - - return [ - 'component' => 'k-lab-docs-drawer', - 'props' => [ - 'icon' => 'book', - 'title' => $component, - 'docs' => $docs->toArray() - ] - ]; - }, - ], -]; diff --git a/kirby/config/areas/lab/views.php b/kirby/config/areas/lab/views.php deleted file mode 100644 index c1cf42d..0000000 --- a/kirby/config/areas/lab/views.php +++ /dev/null @@ -1,148 +0,0 @@ - [ - 'pattern' => 'lab', - 'action' => function () { - return [ - 'component' => 'k-lab-index-view', - 'props' => [ - 'categories' => Category::all(), - 'info' => Category::installed() ? null : 'The default Lab examples are not installed.', - 'tab' => 'examples', - ], - ]; - } - ], - 'lab.docs' => [ - 'pattern' => 'lab/docs', - 'action' => function () { - $props = match (Docs::installed()) { - true => [ - 'categories' => [['examples' => Docs::all()]], - 'tab' => 'docs', - ], - false => [ - 'info' => 'The UI docs are not installed.', - 'tab' => 'docs', - ] - }; - - return [ - 'component' => 'k-lab-index-view', - 'title' => 'Docs', - 'breadcrumb' => [ - [ - 'label' => 'Docs', - 'link' => 'lab/docs' - ] - ], - 'props' => $props, - ]; - } - ], - 'lab.doc' => [ - 'pattern' => 'lab/docs/(:any)', - 'action' => function (string $component) { - $crumbs = [ - [ - 'label' => 'Docs', - 'link' => 'lab/docs' - ], - [ - 'label' => $component, - 'link' => 'lab/docs/' . $component - ] - ]; - - if (Docs::installed() === false) { - return [ - 'component' => 'k-lab-index-view', - 'title' => $component, - 'breadcrumb' => $crumbs, - 'props' => [ - 'info' => 'The UI docs are not installed.', - 'tab' => 'docs', - ], - ]; - } - - $docs = new Docs($component); - - return [ - 'component' => 'k-lab-docs-view', - 'title' => $component, - 'breadcrumb' => $crumbs, - 'props' => [ - 'component' => $component, - 'docs' => $docs->toArray(), - 'lab' => $docs->lab() - ] - ]; - } - ], - 'lab.vue' => [ - 'pattern' => [ - 'lab/(:any)/(:any)/index.vue', - 'lab/(:any)/(:any)/(:any)/index.vue' - ], - 'action' => function ( - string $category, - string $id, - string|null $tab = null - ) { - return Category::factory($category)->example($id, $tab)->serve(); - } - ], - 'lab.example' => [ - 'pattern' => 'lab/(:any)/(:any)/(:any?)', - 'action' => function ( - string $category, - string $id, - string|null $tab = null - ) { - $category = Category::factory($category); - $example = $category->example($id, $tab); - $props = $example->props(); - $vue = $example->vue(); - - if (Docs::installed() === true && $docs = $props['docs'] ?? null) { - $docs = new Docs($docs); - } - - $github = $docs?->github(); - - if ($source = $props['source'] ?? null) { - $github ??= 'https://github.com/getkirby/kirby/tree/main/' . $source; - } - - return [ - 'component' => 'k-lab-playground-view', - 'breadcrumb' => [ - [ - 'label' => $category->name(), - ], - [ - 'label' => $example->title(), - 'link' => $example->url() - ] - ], - 'props' => [ - 'docs' => $docs?->name(), - 'examples' => $vue['examples'], - 'file' => $example->module(), - 'github' => $github, - 'props' => $props, - 'styles' => $vue['style'], - 'tab' => $example->tab(), - 'tabs' => array_values($example->tabs()), - 'template' => $vue['template'], - 'title' => $example->title(), - ], - ]; - } - ] -]; diff --git a/kirby/config/areas/languages.php b/kirby/config/areas/languages.php index 263ffd7..d464c58 100644 --- a/kirby/config/areas/languages.php +++ b/kirby/config/areas/languages.php @@ -4,7 +4,7 @@ use Kirby\Toolkit\I18n; return function ($kirby) { return [ - 'icon' => 'translate', + 'icon' => 'globe', 'label' => I18n::translate('view.languages'), 'menu' => true, 'dialogs' => require __DIR__ . '/languages/dialogs.php', diff --git a/kirby/config/areas/languages/dialogs.php b/kirby/config/areas/languages/dialogs.php index fe88ff3..a38b148 100644 --- a/kirby/config/areas/languages/dialogs.php +++ b/kirby/config/areas/languages/dialogs.php @@ -2,15 +2,13 @@ use Kirby\Cms\App; use Kirby\Cms\Find; -use Kirby\Cms\LanguageVariable; -use Kirby\Exception\NotFoundException; +use Kirby\Panel\Field; use Kirby\Toolkit\A; use Kirby\Toolkit\Escape; use Kirby\Toolkit\I18n; $languageDialogFields = [ 'name' => [ - 'counter' => false, 'label' => I18n::translate('language.name'), 'type' => 'text', 'required' => true, @@ -21,7 +19,7 @@ $languageDialogFields = [ 'type' => 'text', 'required' => true, 'counter' => false, - 'icon' => 'translate', + 'icon' => 'globe', 'width' => '1/2' ], 'direction' => [ @@ -36,27 +34,11 @@ $languageDialogFields = [ 'width' => '1/2' ], 'locale' => [ - 'counter' => false, - 'label' => I18n::translate('language.locale'), - 'type' => 'text', + 'label' => I18n::translate('language.locale'), + 'type' => 'text', ], ]; -$translationDialogFields = [ - 'key' => [ - 'counter' => false, - 'icon' => null, - 'label' => I18n::translate('language.variable.key'), - 'type' => 'text' - ], - 'value' => [ - 'buttons' => false, - 'counter' => false, - 'label' => I18n::translate('language.variable.value'), - 'type' => 'textarea' - ] -]; - return [ // create language @@ -110,10 +92,8 @@ return [ }, 'submit' => function (string $id) { Find::language($id)->delete(); - return [ - 'event' => 'language.delete', - 'redirect' => 'languages' + 'event' => 'language.delete', ]; } ], @@ -172,95 +152,4 @@ return [ ]; } ], - - 'language.translation.create' => [ - 'pattern' => 'languages/(:any)/translations/create', - 'load' => function (string $languageCode) use ($translationDialogFields) { - // find the language to make sure it exists - Find::language($languageCode); - - return [ - 'component' => 'k-form-dialog', - 'props' => [ - 'fields' => $translationDialogFields, - 'size' => 'large', - ], - ]; - }, - 'submit' => function (string $languageCode) { - $request = App::instance()->request(); - $language = Find::language($languageCode); - - $key = $request->get('key', ''); - $value = $request->get('value', ''); - - LanguageVariable::create($key, $value); - - if ($language->isDefault() === false) { - $language->variable($key)->update($value); - } - - return true; - } - ], - 'language.translation.delete' => [ - 'pattern' => 'languages/(:any)/translations/(:any)/delete', - 'load' => function (string $languageCode, string $translationKey) { - $variable = Find::language($languageCode)->variable($translationKey, true); - - if ($variable->exists() === false) { - throw new NotFoundException([ - 'key' => 'language.variable.notFound' - ]); - } - - return [ - 'component' => 'k-remove-dialog', - 'props' => [ - 'text' => I18n::template('language.variable.delete.confirm', [ - 'key' => Escape::html($variable->key()) - ]) - ], - ]; - }, - 'submit' => function (string $languageCode, string $translationKey) { - return Find::language($languageCode)->variable($translationKey, true)->delete(); - } - ], - 'language.translation.update' => [ - 'pattern' => 'languages/(:any)/translations/(:any)/update', - 'load' => function (string $languageCode, string $translationKey) use ($translationDialogFields) { - $variable = Find::language($languageCode)->variable($translationKey, true); - - if ($variable->exists() === false) { - throw new NotFoundException([ - 'key' => 'language.variable.notFound' - ]); - } - - $fields = $translationDialogFields; - $fields['key']['disabled'] = true; - $fields['value']['autofocus'] = true; - - return [ - 'component' => 'k-form-dialog', - 'props' => [ - 'fields' => $fields, - 'size' => 'large', - 'value' => [ - 'key' => $variable->key(), - 'value' => $variable->value() - ] - ], - ]; - }, - 'submit' => function (string $languageCode, string $translationKey) { - Find::language($languageCode)->variable($translationKey, true)->update( - App::instance()->request()->get('value') - ); - - return true; - } - ] - ]; diff --git a/kirby/config/areas/languages/views.php b/kirby/config/areas/languages/views.php index ac2d6d4..0eee9da 100644 --- a/kirby/config/areas/languages/views.php +++ b/kirby/config/areas/languages/views.php @@ -1,110 +1,9 @@ [ - 'pattern' => 'languages/(:any)', - 'when' => function (): bool { - return App::instance()->option('languages.variables', true) !== false; - }, - 'action' => function (string $code) { - $kirby = App::instance(); - $language = Find::language($code); - $link = '/languages/' . $language->code(); - $strings = []; - $foundation = $kirby->defaultLanguage()->translations(); - $translations = $language->translations(); - - // TODO: update following line and adapt for update and delete options - // when new `languageVariables.*` permissions available - $canUpdate = $kirby->user()?->role()->permissions()->for('languages', 'update') === true; - - ksort($foundation); - - foreach ($foundation as $key => $value) { - $strings[] = [ - 'key' => $key, - 'value' => $translations[$key] ?? null, - 'options' => [ - [ - 'click' => 'update', - 'disabled' => $canUpdate === false, - 'icon' => 'edit', - 'text' => I18n::translate('edit'), - ], - [ - 'click' => 'delete', - 'disabled' => $canUpdate === false || $language->isDefault() === false, - 'icon' => 'trash', - 'text' => I18n::translate('delete'), - ] - ] - ]; - } - - $next = function () use ($language) { - if ($next = $language->next()) { - return [ - 'link' => '/languages/' . $next->code(), - 'title' => $next->name(), - ]; - } - }; - - $prev = function () use ($language) { - if ($prev = $language->prev()) { - return [ - 'link' => '/languages/' . $prev->code(), - 'title' => $prev->name(), - ]; - } - }; - - return [ - 'component' => 'k-language-view', - 'breadcrumb' => [ - [ - 'label' => $name = $language->name(), - 'link' => $link, - ] - ], - 'props' => [ - 'deletable' => $language->isDeletable(), - 'code' => Escape::html($language->code()), - 'default' => $language->isDefault(), - 'direction' => $language->direction(), - 'id' => $language->code(), - 'info' => [ - [ - 'label' => 'Status', - 'value' => I18n::translate('language.' . ($language->isDefault() ? 'default' : 'secondary')), - ], - [ - 'label' => I18n::translate('language.code'), - 'value' => $language->code(), - ], - [ - 'label' => I18n::translate('language.locale'), - 'value' => $language->locale(LC_ALL) - ], - [ - 'label' => I18n::translate('language.direction'), - 'value' => I18n::translate('language.direction.' . $language->direction()), - ], - ], - 'name' => $name, - 'next' => $next, - 'prev' => $prev, - 'translations' => $strings, - 'url' => $language->url(), - ] - ]; - } - ], 'languages' => [ 'pattern' => 'languages', 'action' => function () { @@ -114,15 +13,13 @@ return [ 'component' => 'k-languages-view', 'props' => [ 'languages' => $kirby->languages()->values(fn ($language) => [ - 'deletable' => $language->isDeletable(), - 'default' => $language->isDefault(), - 'id' => $language->code(), - 'info' => Escape::html($language->code()), - 'text' => Escape::html($language->name()), - ]), - 'variables' => $kirby->option('languages.variables', true) + 'default' => $language->isDefault(), + 'id' => $language->code(), + 'info' => Escape::html($language->code()), + 'text' => Escape::html($language->name()), + ]) ] ]; } - ] + ], ]; diff --git a/kirby/config/areas/search.php b/kirby/config/areas/search.php deleted file mode 100644 index 2f7474e..0000000 --- a/kirby/config/areas/search.php +++ /dev/null @@ -1,11 +0,0 @@ - 'search', - 'label' => I18n::translate('search'), - 'views' => require __DIR__ . '/search/views.php' - ]; -}; diff --git a/kirby/config/areas/search/views.php b/kirby/config/areas/search/views.php deleted file mode 100644 index 365e834..0000000 --- a/kirby/config/areas/search/views.php +++ /dev/null @@ -1,17 +0,0 @@ - [ - 'pattern' => 'search', - 'action' => function () { - return [ - 'component' => 'k-search-view', - 'props' => [ - 'type' => App::instance()->request()->get('type'), - ] - ]; - } - ], -]; diff --git a/kirby/config/areas/site.php b/kirby/config/areas/site.php index ab2eb78..3f082be 100644 --- a/kirby/config/areas/site.php +++ b/kirby/config/areas/site.php @@ -11,9 +11,7 @@ return function ($kirby) { 'label' => $kirby->site()->blueprint()->title() ?? I18n::translate('view.site'), 'menu' => true, 'dialogs' => require __DIR__ . '/site/dialogs.php', - 'drawers' => require __DIR__ . '/site/drawers.php', 'dropdowns' => require __DIR__ . '/site/dropdowns.php', - 'requests' => require __DIR__ . '/site/requests.php', 'searches' => require __DIR__ . '/site/searches.php', 'views' => require __DIR__ . '/site/views.php', ]; diff --git a/kirby/config/areas/site/dialogs.php b/kirby/config/areas/site/dialogs.php index f797139..3101464 100644 --- a/kirby/config/areas/site/dialogs.php +++ b/kirby/config/areas/site/dialogs.php @@ -2,20 +2,14 @@ use Kirby\Cms\App; use Kirby\Cms\Find; -use Kirby\Cms\PageRules; use Kirby\Exception\Exception; use Kirby\Exception\InvalidArgumentException; use Kirby\Exception\PermissionException; -use Kirby\Panel\ChangesDialog; use Kirby\Panel\Field; -use Kirby\Panel\PageCreateDialog; use Kirby\Panel\Panel; -use Kirby\Toolkit\Escape; use Kirby\Toolkit\I18n; use Kirby\Toolkit\Str; -use Kirby\Uuid\Uuids; -$fields = require __DIR__ . '/../fields/dialogs.php'; $files = require __DIR__ . '/../files/dialogs.php'; return [ @@ -161,16 +155,10 @@ return [ 'component' => 'k-form-dialog', 'props' => [ 'fields' => [ - 'notice' => [ - 'type' => 'info', - 'theme' => 'notice', - 'text' => I18n::translate('page.changeTemplate.notice') - ], 'template' => Field::template($blueprints, [ 'required' => true ]) ], - 'theme' => 'notice', 'submitButton' => I18n::translate('change'), 'value' => [ 'template' => $page->intendedTemplate()->name() @@ -179,10 +167,9 @@ return [ ]; }, 'submit' => function (string $id) { - $page = Find::page($id); - $template = App::instance()->request()->get('template'); + $request = App::instance()->request(); - $page->changeTemplate($template); + Find::page($id)->changeTemplate($request->get('template')); return [ 'event' => 'page.changeTemplate', @@ -212,7 +199,7 @@ return [ 'slug' => Field::slug([ 'required' => true, 'preselect' => $select === 'slug', - 'path' => $page->parent() ? '/' . $page->parent()->uri() . '/' : '/', + 'path' => $page->parent() ? '/' . $page->parent()->id() . '/' : '/', 'disabled' => $permissions->can('changeSlug') === false, 'wizard' => [ 'text' => I18n::translate('page.changeSlug.fromTitle'), @@ -237,8 +224,17 @@ return [ $slug = trim($request->get('slug', '')); // basic input validation before we move on - PageRules::validateTitleLength($title); - PageRules::validateSlugLength($slug); + if (Str::length($title) === 0) { + throw new InvalidArgumentException([ + 'key' => 'page.changeTitle.empty' + ]); + } + + if (Str::length($slug) === 0) { + throw new InvalidArgumentException([ + 'key' => 'page.slug.invalid' + ]); + } // nothing changed if ($page->title()->value() === $title && $page->slug() === $slug) { @@ -281,30 +277,93 @@ return [ 'page.create' => [ 'pattern' => 'pages/create', 'load' => function () { - $request = App::instance()->request(); - $dialog = new PageCreateDialog( - parentId: $request->get('parent'), - sectionId: $request->get('section'), - slug: $request->get('slug'), - template: $request->get('template'), - title: $request->get('title'), - viewId: $request->get('view'), - ); + $kirby = App::instance(); + $request = $kirby->request(); - return $dialog->load(); + // the parent model for the new page + $parent = $request->get('parent', 'site'); + + // the view on which the add button is located + // this is important to find the right section + // and provide the correct templates for the new page + $view = $request->get('view', $parent); + + // templates will be fetched depending on the + // section settings in the blueprint + $section = $request->get('section'); + + // this is the parent model + $model = Find::parent($parent); + + // this is the view model + // i.e. site if the add button is on + // the dashboard + $view = Find::parent($view); + + // available blueprints/templates for the new page + // are always loaded depending on the matching section + // in the view model blueprint + $blueprints = $view->blueprints($section); + + // the pre-selected template + $template = $blueprints[0]['name'] ?? $blueprints[0]['value'] ?? null; + + $fields = [ + 'parent' => Field::hidden(), + 'title' => Field::title([ + 'required' => true, + 'preselect' => true + ]), + 'slug' => Field::slug([ + 'required' => true, + 'sync' => 'title', + 'path' => empty($model->id()) === false ? '/' . $model->id() . '/' : '/' + ]), + 'template' => Field::hidden() + ]; + + // only show template field if > 1 templates available + // or when in debug mode + if (count($blueprints) > 1 || $kirby->option('debug') === true) { + $fields['template'] = Field::template($blueprints, [ + 'required' => true + ]); + } + + return [ + 'component' => 'k-form-dialog', + 'props' => [ + 'fields' => $fields, + 'submitButton' => I18n::translate('page.draft.create'), + 'value' => [ + 'parent' => $parent, + 'slug' => '', + 'template' => $template, + 'title' => '', + ] + ] + ]; }, 'submit' => function () { $request = App::instance()->request(); - $dialog = new PageCreateDialog( - parentId: $request->get('parent'), - sectionId: $request->get('section'), - slug: $request->get('slug'), - template: $request->get('template'), - title: $request->get('title'), - viewId: $request->get('view'), - ); + $title = trim($request->get('title', '')); - return $dialog->submit($request->get()); + if (Str::length($title) === 0) { + throw new InvalidArgumentException([ + 'key' => 'page.changeTitle.empty' + ]); + } + + $page = Find::parent($request->get('parent', 'site'))->createChild([ + 'content' => ['title' => $title], + 'slug' => $request->get('slug'), + 'template' => $request->get('template'), + ]); + + return [ + 'event' => 'page.create', + 'redirect' => $page->panel()->url(true) + ]; } ], @@ -420,26 +479,6 @@ return [ ]; } - $slugAppendix = Str::slug(I18n::translate('page.duplicate.appendix')); - $titleAppendix = I18n::translate('page.duplicate.appendix'); - - // if the item to be duplicated already exists - // add a suffix at the end of slug and title - $duplicateSlug = $page->slug() . '-' . $slugAppendix; - $siblingKeys = $page->parentModel()->childrenAndDrafts()->pluck('uid'); - - if (in_array($duplicateSlug, $siblingKeys) === true) { - $suffixCounter = 2; - $newSlug = $duplicateSlug . $suffixCounter; - - while (in_array($newSlug, $siblingKeys) === true) { - $newSlug = $duplicateSlug . ++$suffixCounter; - } - - $slugAppendix .= $suffixCounter; - $titleAppendix .= ' ' . $suffixCounter; - } - return [ 'component' => 'k-form-dialog', 'props' => [ @@ -448,8 +487,8 @@ return [ 'value' => [ 'children' => false, 'files' => false, - 'slug' => $page->slug() . '-' . $slugAppendix, - 'title' => $page->title() . ' ' . $titleAppendix + 'slug' => $page->slug() . '-' . Str::slug(I18n::translate('page.duplicate.appendix')), + 'title' => $page->title() . ' ' . I18n::translate('page.duplicate.appendix') ] ] ]; @@ -470,13 +509,6 @@ return [ } ], - // page field dialogs - 'page.fields' => [ - 'pattern' => '(pages/.*?)/fields/(:any)/(:all?)', - 'load' => $fields['model']['load'], - 'submit' => $fields['model']['submit'] - ], - // change filename 'page.file.changeName' => [ 'pattern' => '(pages/.*?)/files/(:any)/changeName', @@ -491,13 +523,6 @@ return [ 'submit' => $files['changeSort']['submit'], ], - // change template - 'page.file.changeTemplate' => [ - 'pattern' => '(pages/.*?)/files/(:any)/changeTemplate', - 'load' => $files['changeTemplate']['load'], - 'submit' => $files['changeTemplate']['submit'], - ], - // delete 'page.file.delete' => [ 'pattern' => '(pages/.*?)/files/(:any)/delete', @@ -505,56 +530,6 @@ return [ 'submit' => $files['delete']['submit'], ], - // page file field dialogs - 'page.file.fields' => [ - 'pattern' => '(pages/.*?)/files/(:any)/fields/(:any)/(:all?)', - 'load' => $fields['file']['load'], - 'submit' => $fields['file']['submit'], - ], - - // move page - 'page.move' => [ - 'pattern' => 'pages/(:any)/move', - 'load' => function (string $id) { - $page = Find::page($id); - $parent = $page->parentModel(); - - if (Uuids::enabled() === false) { - $parentId = $parent?->id() ?? '/'; - } else { - $parentId = $parent?->uuid()->toString() ?? 'site://'; - } - - return [ - 'component' => 'k-page-move-dialog', - 'props' => [ - 'value' => [ - 'move' => $page->panel()->url(true), - 'parent' => $parentId - ] - ] - ]; - }, - 'submit' => function (string $id) { - $kirby = App::instance(); - $parentId = $kirby->request()->get('parent'); - $parent = (empty($parentId) === true || $parentId === '/' || $parentId === 'site://') ? $kirby->site() : Find::page($parentId); - $oldPage = Find::page($id); - $newPage = $oldPage->move($parent); - - return [ - 'event' => 'page.move', - 'redirect' => $newPage->panel()->url(true), - 'dispatch' => [ - 'content/move' => [ - $oldPage->panel()->url(true), - $newPage->panel()->url(true) - ] - ], - ]; - } - ], - // change site title 'site.changeTitle' => [ 'pattern' => 'site/changeTitle', @@ -577,21 +552,14 @@ return [ }, 'submit' => function () { $kirby = App::instance(); - $kirby->site()->changeTitle($kirby->request()->get('title')); + $kirby->site()->changeTitle($kirby->request()->get('title')); return [ 'event' => 'site.changeTitle', ]; } ], - // site field dialogs - 'site.fields' => [ - 'pattern' => '(site)/fields/(:any)/(:all?)', - 'load' => $fields['model']['load'], - 'submit' => $fields['model']['submit'], - ], - // change filename 'site.file.changeName' => [ 'pattern' => '(site)/files/(:any)/changeName', @@ -606,13 +574,6 @@ return [ 'submit' => $files['changeSort']['submit'], ], - // change template - 'site.file.changeTemplate' => [ - 'pattern' => '(site)/files/(:any)/changeTemplate', - 'load' => $files['changeTemplate']['load'], - 'submit' => $files['changeTemplate']['submit'], - ], - // delete 'site.file.delete' => [ 'pattern' => '(site)/files/(:any)/delete', @@ -620,24 +581,4 @@ return [ 'submit' => $files['delete']['submit'], ], - // site file field dialogs - 'site.file.fields' => [ - 'pattern' => '(site)/files/(:any)/fields/(:any)/(:all?)', - 'load' => $fields['file']['load'], - 'submit' => $fields['file']['submit'], - ], - - // content changes - 'changes' => [ - 'pattern' => 'changes', - 'load' => function () { - $dialog = new ChangesDialog(); - return $dialog->load(); - }, - 'submit' => function () { - $dialog = new ChangesDialog(); - $ids = App::instance()->request()->get('ids'); - return $dialog->submit($ids); - } - ], ]; diff --git a/kirby/config/areas/site/drawers.php b/kirby/config/areas/site/drawers.php deleted file mode 100644 index 7bdf4da..0000000 --- a/kirby/config/areas/site/drawers.php +++ /dev/null @@ -1,33 +0,0 @@ - [ - 'pattern' => '(pages/.*?)/fields/(:any)/(:all?)', - 'load' => $fields['model']['load'], - 'submit' => $fields['model']['submit'] - ], - - // page file field drawers - 'page.file.fields' => [ - 'pattern' => '(pages/.*?)/files/(:any)/fields/(:any)/(:all?)', - 'load' => $fields['file']['load'], - 'submit' => $fields['file']['submit'], - ], - - // site field drawers - 'site.fields' => [ - 'pattern' => '(site)/fields/(:any)/(:all?)', - 'load' => $fields['model']['load'], - 'submit' => $fields['model']['submit'], - ], - - // site file field drawers - 'site.file.fields' => [ - 'pattern' => '(site)/files/(:any)/fields/(:any)/(:all?)', - 'load' => $fields['file']['load'], - 'submit' => $fields['file']['submit'], - ], -]; diff --git a/kirby/config/areas/site/dropdowns.php b/kirby/config/areas/site/dropdowns.php index b756cf4..c08853b 100644 --- a/kirby/config/areas/site/dropdowns.php +++ b/kirby/config/areas/site/dropdowns.php @@ -1,9 +1,14 @@ [ + 'pattern' => 'changes', + 'options' => fn () => Dropdown::changes() + ], 'page' => [ 'pattern' => 'pages/(:any)', 'options' => function (string $path) { diff --git a/kirby/config/areas/site/requests.php b/kirby/config/areas/site/requests.php deleted file mode 100644 index 352334a..0000000 --- a/kirby/config/areas/site/requests.php +++ /dev/null @@ -1,66 +0,0 @@ - [ - 'pattern' => 'site/tree', - 'action' => function () { - $kirby = App::instance(); - $request = $kirby->request(); - $move = $request->get('move'); - $move = $move ? Find::parent($move) : null; - $parent = $request->get('parent'); - - if ($parent === null) { - $site = $kirby->site(); - $panel = $site->panel(); - $uuid = $site->uuid()?->toString(); - $url = $site->url(); - $value = $uuid ?? '/'; - - return [ - [ - 'children' => $panel->url(true), - 'disabled' => $move?->isMovableTo($site) === false, - 'hasChildren' => true, - 'icon' => 'home', - 'id' => '/', - 'label' => I18n::translate('view.site'), - 'open' => false, - 'url' => $url, - 'uuid' => $uuid, - 'value' => $value - ] - ]; - } - - $parent = Find::parent($parent); - $pages = []; - - foreach ($parent->childrenAndDrafts()->filterBy('isListable', true) as $child) { - $panel = $child->panel(); - $uuid = $child->uuid()?->toString(); - $url = $child->url(); - $value = $uuid ?? $child->id(); - - $pages[] = [ - 'children' => $panel->url(true), - 'disabled' => $move?->isMovableTo($child) === false, - 'hasChildren' => $child->hasChildren() === true || $child->hasDrafts() === true, - 'icon' => $panel->image()['icon'] ?? null, - 'id' => $child->id(), - 'open' => false, - 'label' => $child->title()->value(), - 'url' => $url, - 'uuid' => $uuid, - 'value' => $value - ]; - } - - return $pages; - } - ] -]; diff --git a/kirby/config/areas/site/searches.php b/kirby/config/areas/site/searches.php index 4cefefe..6719bb2 100644 --- a/kirby/config/areas/site/searches.php +++ b/kirby/config/areas/site/searches.php @@ -8,49 +8,50 @@ return [ 'pages' => [ 'label' => I18n::translate('pages'), 'icon' => 'page', - 'query' => function (string $query = null, int $limit, int $page) { - $kirby = App::instance(); - $pages = $kirby->site() + 'query' => function (string $query = null) { + $pages = App::instance()->site() ->index(true) ->search($query) - ->filter('isListable', true) - ->paginate($limit, $page); + ->filter('isReadable', true) + ->limit(10); - return [ - 'results' => $pages->values(fn ($page) => [ + $results = []; + + foreach ($pages as $page) { + $results[] = [ 'image' => $page->panel()->image(), 'text' => Escape::html($page->title()->value()), 'link' => $page->panel()->url(true), - 'info' => Escape::html($page->id()), - 'uuid' => $page->uuid()?->toString(), - ]), - 'pagination' => $pages->pagination()->toArray() - ]; + 'info' => Escape::html($page->id()) + ]; + } + + return $results; } ], 'files' => [ 'label' => I18n::translate('files'), 'icon' => 'image', - 'query' => function (string $query = null, int $limit, int $page) { - $kirby = App::instance(); - $files = $kirby->site() + 'query' => function (string $query = null) { + $files = App::instance()->site() ->index(true) - ->filter('isListable', true) + ->filter('isReadable', true) ->files() - ->filter('isListable', true) ->search($query) - ->paginate($limit, $page); + ->limit(10); - return [ - 'results' => $files->values(fn ($file) => [ + $results = []; + + foreach ($files as $file) { + $results[] = [ 'image' => $file->panel()->image(), 'text' => Escape::html($file->filename()), 'link' => $file->panel()->url(true), - 'info' => Escape::html($file->id()), - 'uuid' => $file->uuid()->toString(), - ]), - 'pagination' => $files->pagination()->toArray() - ]; + 'info' => Escape::html($file->id()) + ]; + } + + return $results; } ] ]; diff --git a/kirby/config/areas/system/dialogs.php b/kirby/config/areas/system/dialogs.php index e8dd694..35a3f9a 100644 --- a/kirby/config/areas/system/dialogs.php +++ b/kirby/config/areas/system/dialogs.php @@ -1,7 +1,6 @@ [ 'load' => function () { - $kirby = App::instance(); - $license = $kirby->system()->license(); - $obfuscated = $kirby->user()->isAdmin() === false; - $status = $license->status(); - $renewable = $status->renewable(); + $license = App::instance()->system()->license(); + + // @codeCoverageIgnoreStart + // the system is registered but the license + // key is only visible for admins + if ($license === true) { + $license = 'Kirby 3'; + } + // @codeCoverageIgnoreEnd return [ - 'component' => 'k-license-dialog', + 'component' => 'k-form-dialog', 'props' => [ - 'license' => [ - 'code' => $license->code($obfuscated), - 'icon' => $status->icon(), - 'info' => $status->info($license->renewal('Y-m-d', 'date')), - 'theme' => $status->theme(), - 'type' => $license->label(), + 'size' => 'medium', + 'fields' => [ + 'license' => [ + 'type' => 'info', + 'label' => I18n::translate('license'), + 'text' => $license ? $license : I18n::translate('license.unregistered.label'), + 'theme' => $license ? 'code' : 'negative', + 'help' => $license ? + // @codeCoverageIgnoreStart + '' . I18n::translate('license.manage') . ' →' : + // @codeCoverageIgnoreEnd + '' . I18n::translate('license.buy') . ' →' + ] ], - 'cancelButton' => $renewable, - 'submitButton' => $renewable ? [ - 'icon' => 'refresh', - 'text' => I18n::translate('renew'), - 'theme' => 'love', - ] : false, + 'submitButton' => false, + 'cancelButton' => false, ] ]; - }, - 'submit' => function () { - // @codeCoverageIgnoreStart - $response = App::instance()->system()->license()->upgrade(); - - // the upgrade is still needed - if ($response['status'] === 'upgrade') { - return [ - 'redirect' => $response['url'] - ]; - } - - // the upgrade has already been completed - if ($response['status'] === 'complete') { - return [ - 'event' => 'system.renew', - 'message' => I18n::translate('license.success') - ]; - } - - throw new LogicException('The upgrade failed'); - // @codeCoverageIgnoreEnd } ], // license registration 'registration' => [ 'load' => function () { - $system = App::instance()->system(); - $local = $system->isLocal(); - return [ 'component' => 'k-form-dialog', 'props' => [ 'fields' => [ - 'domain' => [ - 'label' => I18n::translate('license.activate.label'), - 'type' => 'info', - 'theme' => $local ? 'warning' : 'info', - 'text' => I18n::template('license.activate.' . ($local ? 'local' : 'domain'), ['host' => $system->indexUrl()]) - ], 'license' => [ - 'label' => I18n::translate('license.code.label'), + 'label' => I18n::translate('license.register.label'), 'type' => 'text', 'required' => true, 'counter' => false, - 'placeholder' => 'K-', - 'help' => I18n::translate('license.code.help') . ' ' . '' . I18n::translate('license.buy') . ' →' + 'placeholder' => 'K3-', + 'help' => I18n::translate('license.register.help') ], - 'email' => Field::email(['required' => true]) - ], - 'submitButton' => [ - 'icon' => 'key', - 'text' => I18n::translate('activate'), - 'theme' => 'love', + 'email' => Field::email([ + 'required' => true + ]) ], + 'submitButton' => I18n::translate('license.register'), 'value' => [ 'license' => null, 'email' => null @@ -105,7 +78,7 @@ return [ return [ 'event' => 'system.register', - 'message' => I18n::translate('license.success') + 'message' => I18n::translate('license.register.success') ]; // @codeCoverageIgnoreEnd } diff --git a/kirby/config/areas/system/views.php b/kirby/config/areas/system/views.php index a24d1bc..8bab2a2 100644 --- a/kirby/config/areas/system/views.php +++ b/kirby/config/areas/system/views.php @@ -1,94 +1,48 @@ [ 'pattern' => 'system', 'action' => function () { - $kirby = App::instance(); - $system = $kirby->system(); - $updateStatus = $system->updateStatus(); - $license = $system->license(); + $kirby = App::instance(); + $system = $kirby->system(); + $license = $system->license(); - $environment = [ - [ - 'label' => $license->status()->label(), - 'value' => $license->label(), - 'theme' => $license->status()->theme(), - 'icon' => $license->status()->icon(), - 'dialog' => $license->status()->dialog() - ], - [ - 'label' => $updateStatus?->label() ?? I18n::translate('version'), - 'value' => $kirby->version(), - 'link' => $updateStatus?->url() ?? - 'https://github.com/getkirby/kirby/releases/tag/' . $kirby->version(), - 'theme' => $updateStatus?->theme(), - 'icon' => $updateStatus?->icon() ?? 'info' - ], - [ - 'label' => 'PHP', - 'value' => phpversion(), - 'icon' => 'code' - ], - [ - 'label' => I18n::translate('server'), - 'value' => $system->serverSoftware() ?? '?', - 'icon' => 'server' - ] - ]; - - $exceptions = $updateStatus?->exceptionMessages() ?? []; - - $plugins = $system->plugins()->values(function ($plugin) use (&$exceptions) { - $authors = $plugin->authorsNames(); - $updateStatus = $plugin->updateStatus(); - $version = $updateStatus?->toArray() ?? $plugin->version() ?? '–'; - - if ($updateStatus !== null) { - $exceptions = array_merge($exceptions, $updateStatus->exceptionMessages()); - } + // @codeCoverageIgnoreStart + if ($license === true) { + // valid license, but user is not admin + $license = 'Kirby 3'; + } elseif ($license === false) { + // no valid license + $license = null; + } + // @codeCoverageIgnoreEnd + $plugins = $system->plugins()->values(function ($plugin) { return [ - 'author' => empty($authors) ? '–' : $authors, - 'license' => $plugin->license() ?? '–', + 'author' => $plugin->authorsNames(), + 'license' => $plugin->license(), 'name' => [ - 'text' => $plugin->name() ?? '–', + 'text' => $plugin->name(), 'href' => $plugin->link(), ], - 'version' => $version, + 'version' => $plugin->version(), ]; }); - $security = $updateStatus?->messages() ?? []; - - if ($kirby->option('debug', false) === true) { - $security[] = [ - 'id' => 'debug', - 'text' => I18n::translate('system.issues.debug'), - 'link' => 'https://getkirby.com/security/debug' - ]; - } - - if ($kirby->environment()->https() !== true) { - $security[] = [ - 'id' => 'https', - 'text' => I18n::translate('system.issues.https'), - 'link' => 'https://getkirby.com/security/https' - ]; - } - return [ 'component' => 'k-system-view', 'props' => [ - 'environment' => $environment, - 'exceptions' => $kirby->option('debug') === true ? $exceptions : [], - 'info' => $system->info(), - 'plugins' => $plugins, - 'security' => $security, - 'urls' => [ + 'debug' => $kirby->option('debug', false), + 'license' => $license, + 'plugins' => $plugins, + 'php' => phpversion(), + 'server' => $system->serverSoftware(), + 'https' => $kirby->environment()->https(), + 'version' => $kirby->version(), + 'urls' => [ 'content' => $system->exposedFileUrl('content'), 'git' => $system->exposedFileUrl('git'), 'kirby' => $system->exposedFileUrl('kirby'), diff --git a/kirby/config/areas/users.php b/kirby/config/areas/users.php index dbccc5f..ff7e130 100644 --- a/kirby/config/areas/users.php +++ b/kirby/config/areas/users.php @@ -9,7 +9,6 @@ return function ($kirby) { 'search' => 'users', 'menu' => true, 'dialogs' => require __DIR__ . '/users/dialogs.php', - 'drawers' => require __DIR__ . '/users/drawers.php', 'dropdowns' => require __DIR__ . '/users/dropdowns.php', 'searches' => require __DIR__ . '/users/searches.php', 'views' => require __DIR__ . '/users/views.php' diff --git a/kirby/config/areas/users/dialogs.php b/kirby/config/areas/users/dialogs.php index 1f1da96..291abb3 100644 --- a/kirby/config/areas/users/dialogs.php +++ b/kirby/config/areas/users/dialogs.php @@ -6,11 +6,9 @@ use Kirby\Cms\UserRules; use Kirby\Exception\InvalidArgumentException; use Kirby\Panel\Field; use Kirby\Panel\Panel; -use Kirby\Panel\UserTotpDisableDialog; use Kirby\Toolkit\Escape; use Kirby\Toolkit\I18n; -$fields = require __DIR__ . '/../fields/dialogs.php'; $files = require __DIR__ . '/../files/dialogs.php'; return [ @@ -20,12 +18,6 @@ return [ 'pattern' => 'users/create', 'load' => function () { $kirby = App::instance(); - - // get default value for role - if ($role = $kirby->request()->get('role')) { - $role = $kirby->roles()->find($role)?->id(); - } - return [ 'component' => 'k-form-dialog', 'props' => [ @@ -49,7 +41,7 @@ return [ 'email' => '', 'password' => '', 'translation' => $kirby->panelLanguage(), - 'role' => $role ?? $kirby->user()->role()->name() + 'role' => $kirby->user()->role()->name() ] ] ]; @@ -295,13 +287,6 @@ return [ } ], - // user field dialogs - 'user.fields' => [ - 'pattern' => '(users/.*?)/fields/(:any)/(:all?)', - 'load' => $fields['model']['load'], - 'submit' => $fields['model']['submit'] - ], - // change file name 'user.file.changeName' => [ 'pattern' => '(users/.*?)/files/(:any)/changeName', @@ -316,31 +301,11 @@ return [ 'submit' => $files['changeSort']['submit'], ], - // change file template - 'user.file.changeTemplate' => [ - 'pattern' => '(users/.*?)/files/(:any)/changeTemplate', - 'load' => $files['changeTemplate']['load'], - 'submit' => $files['changeTemplate']['submit'], - ], - // delete file 'user.file.delete' => [ 'pattern' => '(users/.*?)/files/(:any)/delete', 'load' => $files['delete']['load'], 'submit' => $files['delete']['submit'], - ], + ] - // user file fields dialogs - 'user.file.fields' => [ - 'pattern' => '(users/.*?)/files/(:any)/fields/(:any)/(:all?)', - 'load' => $fields['file']['load'], - 'submit' => $fields['file']['submit'] - ], - - // user disable TOTP - 'user.totp.disable' => [ - 'pattern' => 'users/(:any)/totp/disable', - 'load' => fn (string $id) => (new UserTotpDisableDialog($id))->load(), - 'submit' => fn (string $id) => (new UserTotpDisableDialog($id))->submit() - ], ]; diff --git a/kirby/config/areas/users/drawers.php b/kirby/config/areas/users/drawers.php deleted file mode 100644 index 10d6bd1..0000000 --- a/kirby/config/areas/users/drawers.php +++ /dev/null @@ -1,18 +0,0 @@ - [ - 'pattern' => '(users/.*?)/fields/(:any)/(:all?)', - 'load' => $fields['model']['load'], - 'submit' => $fields['model']['submit'] - ], - // user file fields drawers - 'user.file.fields' => [ - 'pattern' => '(users/.*?)/files/(:any)/fields/(:any)/(:all?)', - 'load' => $fields['file']['load'], - 'submit' => $fields['file']['submit'] - ], -]; diff --git a/kirby/config/areas/users/searches.php b/kirby/config/areas/users/searches.php index 82bce90..25a5702 100644 --- a/kirby/config/areas/users/searches.php +++ b/kirby/config/areas/users/searches.php @@ -8,22 +8,20 @@ return [ 'users' => [ 'label' => I18n::translate('users'), 'icon' => 'users', - 'query' => function (string $query = null, int $limit, int $page) { - $kirby = App::instance(); - $users = $kirby->users() - ->search($query) - ->paginate($limit, $page); + 'query' => function (string $query = null) { + $users = App::instance()->users()->search($query)->limit(10); + $results = []; - return [ - 'results' => $users->values(fn ($user) => [ + foreach ($users as $user) { + $results[] = [ 'image' => $user->panel()->image(), 'text' => Escape::html($user->username()), 'link' => $user->panel()->url(true), - 'info' => Escape::html($user->role()->title()), - 'uuid' => $user->uuid()->toString(), - ]), - 'pagination' => $users->pagination()->toArray() - ]; + 'info' => Escape::html($user->role()->title()) + ]; + } + + return $results; } ] ]; diff --git a/kirby/config/areas/users/views.php b/kirby/config/areas/users/views.php index 5f0ce9d..a03a5d6 100644 --- a/kirby/config/areas/users/views.php +++ b/kirby/config/areas/users/views.php @@ -31,10 +31,6 @@ return [ $users = $users->role($role); } - // sort users alphabetically - $users = $users->sortBy('username', 'asc'); - - // paginate $users = $users->paginate([ 'limit' => 20, 'page' => $kirby->request()->get('page') diff --git a/kirby/config/blocks/gallery/gallery.php b/kirby/config/blocks/gallery/gallery.php index 033575b..77ab465 100644 --- a/kirby/config/blocks/gallery/gallery.php +++ b/kirby/config/blocks/gallery/gallery.php @@ -1,10 +1,5 @@ -caption(); -$crop = $block->crop()->isTrue(); -$ratio = $block->ratio()->or('auto'); -?> - $ratio, 'data-crop' => $crop], null, ' ') ?>> + +
    images()->toFiles() as $image): ?>
  • @@ -12,9 +7,4 @@ $ratio = $block->ratio()->or('auto');
- isNotEmpty()): ?> -
- -
-
diff --git a/kirby/config/blocks/gallery/gallery.yml b/kirby/config/blocks/gallery/gallery.yml index 3c6aad9..168dbe9 100644 --- a/kirby/config/blocks/gallery/gallery.yml +++ b/kirby/config/blocks/gallery/gallery.yml @@ -8,33 +8,9 @@ fields: query: model.images multiple: true layout: cards - size: small + size: tiny empty: field.blocks.gallery.images.empty uploads: template: blocks/image image: ratio: 1/1 - caption: - label: field.blocks.image.caption - type: writer - icon: text - inline: true - ratio: - label: field.blocks.image.ratio - type: select - placeholder: Auto - width: 1/2 - options: - 1/1: "1:1" - 16/9: "16:9" - 10/8: "10:8" - 21/9: "21:9" - 7/5: "7:5" - 4/3: "4:3" - 5/3: "5:3" - 3/2: "3:2" - 3/1: "3:1" - crop: - label: field.blocks.image.crop - type: toggle - width: 1/2 diff --git a/kirby/config/blocks/heading/heading.yml b/kirby/config/blocks/heading/heading.yml index f34fe53..d7ee4f0 100644 --- a/kirby/config/blocks/heading/heading.yml +++ b/kirby/config/blocks/heading/heading.yml @@ -5,31 +5,20 @@ preview: heading fields: level: label: field.blocks.heading.level - type: toggles + type: select empty: false default: "h2" - labels: false + width: 1/6 options: - - value: h1 - icon: h1 - text: H1 - - value: h2 - icon: h2 - text: H2 - - value: h3 - icon: h3 - text: H3 - - value: h4 - icon: h4 - text: H4 - - value: h5 - icon: h5 - text: H5 - - value: h6 - icon: h6 - text: H6 + - h1 + - h2 + - h3 + - h4 + - h5 + - h6 text: label: field.blocks.heading.text type: writer inline: true + width: 5/6 placeholder: field.blocks.heading.placeholder diff --git a/kirby/config/blocks/image/image.php b/kirby/config/blocks/image/image.php index 1638744..3e3e3df 100644 --- a/kirby/config/blocks/image/image.php +++ b/kirby/config/blocks/image/image.php @@ -11,7 +11,7 @@ $src = null; if ($block->location() == 'web') { $src = $block->src()->esc(); } elseif ($image = $block->image()->toFile()) { - $alt = $alt->or($image->alt()); + $alt = $alt ?? $image->alt(); $src = $image->url(); } diff --git a/kirby/config/blocks/image/image.yml b/kirby/config/blocks/image/image.yml index ada9313..5909f8b 100644 --- a/kirby/config/blocks/image/image.yml +++ b/kirby/config/blocks/image/image.yml @@ -8,8 +8,8 @@ fields: columns: 2 default: "kirby" options: - kirby: "{{ t('field.blocks.image.location.internal') }}" - web: "{{ t('field.blocks.image.location.external') }}" + kirby: Kirby + web: Web image: label: field.blocks.image.name type: files diff --git a/kirby/config/blocks/video/video.php b/kirby/config/blocks/video/video.php index a1b1a31..1808946 100644 --- a/kirby/config/blocks/video/video.php +++ b/kirby/config/blocks/video/video.php @@ -2,30 +2,12 @@ use Kirby\Cms\Html; /** @var \Kirby\Cms\Block $block */ -$caption = $block->caption(); - -if ( - $block->location() == 'kirby' && - $video = $block->video()->toFile() -) { - $url = $video->url(); - $attrs = array_filter([ - 'autoplay' => $block->autoplay()->toBool(), - 'controls' => $block->controls()->toBool(), - 'loop' => $block->loop()->toBool(), - 'muted' => $block->muted()->toBool(), - 'poster' => $block->poster()->toFile()?->url(), - 'preload' => $block->preload()->value(), - ]); -} else { - $url = $block->url(); -} ?> - +url())): ?>
- isNotEmpty()): ?> -
+ caption()->isNotEmpty()): ?> +
caption() ?>
diff --git a/kirby/config/blocks/video/video.yml b/kirby/config/blocks/video/video.yml index b5fc104..6b5223a 100644 --- a/kirby/config/blocks/video/video.yml +++ b/kirby/config/blocks/video/video.yml @@ -2,77 +2,11 @@ name: field.blocks.video.name icon: video preview: video fields: - location: - label: field.blocks.video.location - type: radio - columns: 2 - default: "web" - options: - kirby: "{{ t('field.blocks.image.location.internal') }}" - web: "{{ t('field.blocks.image.location.external') }}" url: label: field.blocks.video.url.label type: url placeholder: field.blocks.video.url.placeholder - when: - location: web - video: - label: field.blocks.video.name - type: files - query: model.videos - multiple: false - # you might want to add a template for videos here - when: - location: kirby - poster: - label: field.blocks.video.poster - type: files - query: model.images - multiple: false - image: - back: black - uploads: - template: blocks/image - when: - location: kirby caption: label: field.blocks.video.caption type: writer inline: true - autoplay: - label: field.blocks.video.autoplay - type: toggle - width: 1/3 - when: - location: kirby - muted: - label: field.blocks.video.muted - type: toggle - width: 1/3 - default: true - when: - location: kirby - loop: - label: field.blocks.video.loop - type: toggle - width: 1/3 - when: - location: kirby - controls: - label: field.blocks.video.controls - type: toggle - width: 1/3 - default: true - when: - location: kirby - preload: - label: field.blocks.video.preload - type: select - width: 2/3 - default: auto - options: - - auto - - metadata - - none - when: - location: kirby diff --git a/kirby/config/blueprints/blocks/code.yml b/kirby/config/blueprints/blocks/code.yml new file mode 100644 index 0000000..a103422 --- /dev/null +++ b/kirby/config/blueprints/blocks/code.yml @@ -0,0 +1,56 @@ +name: Code +icon: code +fields: + code: + label: Code + type: textarea + buttons: false + font: monospace + language: + label: Language + type: select + default: text + options: + bash: Bash + basic: BASIC + c: C + clojure: Clojure + cpp: C++ + csharp: C# + css: CSS + diff: Diff + elixir: Elixir + elm: Elm + erlang: Erlang + go: Go + graphql: GraphQL + haskell: Haskell + html: HTML + java: Java + js: JavaScript + json: JSON + latext: LaTeX + less: Less + lisp: Lisp + lua: Lua + makefile: Makefile + markdown: Markdown + markup: Markup + objectivec: Objective-C + pascal: Pascal + perl: Perl + php: PHP + text: Plain Text + python: Python + r: R + ruby: Ruby + rust: Rust + sass: Sass + scss: SCSS + shell: Shell + sql: SQL + swift: Swift + typescript: TypeScript + vbnet: VB.net + xml: XML + yaml: YAML diff --git a/kirby/config/blueprints/blocks/heading.yml b/kirby/config/blueprints/blocks/heading.yml new file mode 100644 index 0000000..aa42575 --- /dev/null +++ b/kirby/config/blueprints/blocks/heading.yml @@ -0,0 +1,20 @@ +icon: title +fields: + text: + type: text + level: + type: select + width: 1/2 + empty: false + default: "2" + options: + - value: "1" + text: Heading 1 + - value: "2" + text: Heading 2 + - value: "3" + text: Heading 3 + id: + type: text + label: ID + width: 1/2 diff --git a/kirby/config/blueprints/blocks/image.yml b/kirby/config/blueprints/blocks/image.yml new file mode 100644 index 0000000..31b1ef1 --- /dev/null +++ b/kirby/config/blueprints/blocks/image.yml @@ -0,0 +1,16 @@ +name: Image +icon: image +fields: + image: + type: files + multiple: false + alt: + type: text + icon: title + caption: + type: writer + inline: true + icon: text + link: + type: text + icon: url diff --git a/kirby/config/blueprints/blocks/quote.yml b/kirby/config/blueprints/blocks/quote.yml new file mode 100644 index 0000000..78bf681 --- /dev/null +++ b/kirby/config/blueprints/blocks/quote.yml @@ -0,0 +1,12 @@ +name: Quote +icon: quote +fields: + text: + label: Quote Text + type: writer + inline: true + citation: + label: Citation + type: writer + inline: true + placeholder: by … diff --git a/kirby/config/blueprints/blocks/table.yml b/kirby/config/blueprints/blocks/table.yml new file mode 100644 index 0000000..a8513ba --- /dev/null +++ b/kirby/config/blueprints/blocks/table.yml @@ -0,0 +1,25 @@ +name: Table +icon: menu +fields: + rows: + label: Menu + type: structure + columns: + dish: true + description: true + price: + before: € + width: 1/4 + align: right + fields: + dish: + label: Dish + type: text + description: + label: Description + type: text + price: + label: Price + type: number + before: € + step: 0.01 diff --git a/kirby/config/blueprints/blocks/text.yml b/kirby/config/blueprints/blocks/text.yml new file mode 100644 index 0000000..c251959 --- /dev/null +++ b/kirby/config/blueprints/blocks/text.yml @@ -0,0 +1,5 @@ +name: Text +icon: text +fields: + text: + type: writer diff --git a/kirby/config/blueprints/blocks/video.yml b/kirby/config/blueprints/blocks/video.yml new file mode 100644 index 0000000..9131ace --- /dev/null +++ b/kirby/config/blueprints/blocks/video.yml @@ -0,0 +1,8 @@ +name: Video +icon: video +label: "{{ url }}" +fields: + url: + type: url + caption: + type: writer diff --git a/kirby/config/blueprints/files/default.yml b/kirby/config/blueprints/files/default.yml new file mode 100644 index 0000000..d5ef1df --- /dev/null +++ b/kirby/config/blueprints/files/default.yml @@ -0,0 +1,2 @@ +name: File +title: file diff --git a/kirby/config/blueprints/pages/default.yml b/kirby/config/blueprints/pages/default.yml new file mode 100644 index 0000000..ceb895a --- /dev/null +++ b/kirby/config/blueprints/pages/default.yml @@ -0,0 +1,3 @@ +name: Page +title: Page + diff --git a/kirby/config/blueprints/site.yml b/kirby/config/blueprints/site.yml new file mode 100644 index 0000000..04718f3 --- /dev/null +++ b/kirby/config/blueprints/site.yml @@ -0,0 +1,7 @@ +name: Site +title: Site +sections: + pages: + headline: Pages + type: pages + diff --git a/kirby/config/components.php b/kirby/config/components.php index 637e96f..914cc36 100644 --- a/kirby/config/components.php +++ b/kirby/config/components.php @@ -4,69 +4,90 @@ use Kirby\Cms\App; use Kirby\Cms\Collection; use Kirby\Cms\File; use Kirby\Cms\FileVersion; -use Kirby\Cms\Page; -use Kirby\Cms\User; +use Kirby\Cms\Helpers; +use Kirby\Cms\Template; use Kirby\Data\Data; use Kirby\Email\PHPMailer as Emailer; -use Kirby\Exception\NotFoundException; use Kirby\Filesystem\F; use Kirby\Filesystem\Filename; use Kirby\Http\Uri; use Kirby\Http\Url; use Kirby\Image\Darkroom; -use Kirby\Template\Snippet; -use Kirby\Template\Template; use Kirby\Text\Markdown; use Kirby\Text\SmartyPants; use Kirby\Toolkit\A; use Kirby\Toolkit\Str; -use Kirby\Uuid\Uuid; +use Kirby\Toolkit\Tpl as Snippet; return [ /** * Used by the `css()` helper * + * @param \Kirby\Cms\App $kirby Kirby instance * @param string $url Relative or absolute URL * @param string|array $options An array of attributes for the link tag or a media attribute string */ 'css' => fn (App $kirby, string $url, $options = null): string => $url, + + /** + * Object and variable dumper + * to help with debugging. + * + * @param \Kirby\Cms\App $kirby Kirby instance + * @param mixed $variable + * @param bool $echo + * @return string + * + * @deprecated 3.7.0 Disable `dump()` via `KIRBY_HELPER_DUMP` instead and create your own function + * @todo move to `Helpers::dump()`, remove component in 3.8.0 + */ + 'dump' => function (App $kirby, $variable, bool $echo = true) { + if ($kirby->environment()->cli() === true) { + $output = print_r($variable, true) . PHP_EOL; + } else { + $output = '
' . print_r($variable, true) . '
'; + } + + if ($echo === true) { + echo $output; + } + + return $output; + }, + /** * Add your own email provider + * + * @param \Kirby\Cms\App $kirby Kirby instance + * @param array $props + * @param bool $debug */ - 'email' => function ( - App $kirby, - array $props = [], - bool $debug = false - ) { + 'email' => function (App $kirby, array $props = [], bool $debug = false) { return new Emailer($props, $debug); }, /** * Modify URLs for file objects * + * @param \Kirby\Cms\App $kirby Kirby instance * @param \Kirby\Cms\File $file The original file object + * @return string */ - 'file::url' => function ( - App $kirby, - File $file - ): string { + 'file::url' => function (App $kirby, File $file): string { return $file->mediaUrl(); }, /** * Adapt file characteristics * + * @param \Kirby\Cms\App $kirby Kirby instance * @param \Kirby\Cms\File|\Kirby\Filesystem\Asset $file The file object * @param array $options All thumb options (width, height, crop, blur, grayscale) * @return \Kirby\Cms\File|\Kirby\Cms\FileVersion|\Kirby\Filesystem\Asset */ - 'file::version' => function ( - App $kirby, - $file, - array $options = [] - ) { + 'file::version' => function (App $kirby, $file, array $options = []) { // if file is not resizable, return if ($file->isResizable() === false) { return $file; @@ -87,7 +108,7 @@ return [ Data::write($job, array_merge($options, [ 'filename' => $file->filename() ])); - } catch (Throwable) { + } catch (Throwable $e) { // if thumb doesn't exist yet and job file cannot // be created, return return $file; @@ -105,6 +126,7 @@ return [ /** * Used by the `js()` helper * + * @param \Kirby\Cms\App $kirby Kirby instance * @param string $url Relative or absolute URL * @param string|array $options An array of attributes for the link tag or a media attribute string */ @@ -113,17 +135,27 @@ return [ /** * Add your own Markdown parser * + * @param \Kirby\Cms\App $kirby Kirby instance * @param string $text Text to parse * @param array $options Markdown options + * @param bool $inline Whether to wrap the text in `

` tags (deprecated: set via $options['inline'] instead) + * @return string + * @todo remove $inline parameter in in 3.8.0 */ - 'markdown' => function ( - App $kirby, - string $text = null, - array $options = [] - ): string { + 'markdown' => function (App $kirby, string $text = null, array $options = [], bool $inline = false): string { static $markdown; static $config; + // warning for deprecated fourth parameter + if (func_num_args() === 4 && isset($options['inline']) === false) { + // @codeCoverageIgnoreStart + Helpers::deprecated('markdown component: the $inline parameter is deprecated and will be removed in Kirby 3.8.0. Use $options[\'inline\'] instead.'); + // @codeCoverageIgnoreEnd + } + + // support for the deprecated fourth argument + $options['inline'] ??= $inline; + // if the config options have changed or the component is called for the first time, // (re-)initialize the parser object if ($config !== $options) { @@ -137,14 +169,17 @@ return [ /** * Add your own search engine * + * @param \Kirby\Cms\App $kirby Kirby instance * @param \Kirby\Cms\Collection $collection Collection of searchable models + * @param string $query + * @param mixed $params + * @return \Kirby\Cms\Collection|bool */ - 'search' => function ( - App $kirby, - Collection $collection, - string|null $query = null, - string|array $params = [] - ): Collection { + 'search' => function (App $kirby, Collection $collection, string $query = null, $params = []) { + if (empty(trim($query ?? '')) === true) { + return $collection->limit(0); + } + if (is_string($params) === true) { $params = ['fields' => Str::split($params, '|')]; } @@ -156,57 +191,37 @@ return [ 'words' => false, ]; - $collection = clone $collection; $options = array_merge($defaults, $params); - $query = trim($query ?? ''); - - // empty or too short search query - if (Str::length($query) < $options['minlength']) { - return $collection->limit(0); - } - - $words = preg_replace('/(\s)/u', ',', $query); - $words = Str::split($words, ',', $options['minlength']); + $collection = clone $collection; + $searchWords = preg_replace('/(\s)/u', ',', $query); + $searchWords = Str::split($searchWords, ',', $options['minlength']); + $lowerQuery = Str::lower($query); + $exactQuery = $options['words'] ? '(\b' . preg_quote($query) . '\b)' : preg_quote($query); if (empty($options['stopwords']) === false) { - $words = array_diff($words, $options['stopwords']); + $searchWords = array_diff($searchWords, $options['stopwords']); } - // returns an empty collection if there is no search word - if (empty($words) === true) { - return $collection->limit(0); - } + $searchWords = array_map(function ($value) use ($options) { + return $options['words'] ? '\b' . preg_quote($value) . '\b' : preg_quote($value); + }, $searchWords); - $words = A::map( - $words, - fn ($value) => Str::wrap(preg_quote($value), $options['words'] ? '\b' : '') - ); - - $exact = preg_quote($query); - - if ($options['words']) { - $exact = '(\b' . $exact . '\b)'; - } - - $query = Str::lower($query); - $preg = '!(' . implode('|', $words) . ')!iu'; - $scores = []; - - $results = $collection->filter(function ($item) use ($query, $exact, $preg, $options, &$scores) { - $data = $item->content()->toArray(); - $keys = array_keys($data); + $preg = '!(' . implode('|', $searchWords) . ')!i'; + $results = $collection->filter(function ($item) use ($query, $preg, $options, $lowerQuery, $exactQuery) { + $data = $item->content()->toArray(); + $keys = array_keys($data); $keys[] = 'id'; - if ($item instanceof User) { + if (is_a($item, 'Kirby\Cms\User') === true) { $keys[] = 'name'; $keys[] = 'email'; $keys[] = 'role'; - } elseif ($item instanceof Page) { + } elseif (is_a($item, 'Kirby\Cms\Page') === true) { // apply the default score for pages - $options['score'] = array_merge( - ['id' => 64, 'title' => 64], - $options['score'] - ); + $options['score'] = array_merge([ + 'id' => 64, + 'title' => 64, + ], $options['score']); } if (empty($options['fields']) === false) { @@ -214,10 +229,8 @@ return [ $keys = array_intersect($keys, $fields); } - $scoring = [ - 'hits' => 0, - 'score' => 0 - ]; + $item->searchHits = 0; + $item->searchScore = 0; foreach ($keys as $key) { $score = $options['score'][$key] ?? 1; @@ -226,53 +239,43 @@ return [ $lowerValue = Str::lower($value); // check for exact matches - if ($query == $lowerValue) { - $scoring['score'] += 16 * $score; - $scoring['hits'] += 1; + if ($lowerQuery == $lowerValue) { + $item->searchScore += 16 * $score; + $item->searchHits += 1; // check for exact beginning matches - } elseif ( - $options['words'] === false && - Str::startsWith($lowerValue, $query) === true - ) { - $scoring['score'] += 8 * $score; - $scoring['hits'] += 1; + } elseif ($options['words'] === false && Str::startsWith($lowerValue, $lowerQuery) === true) { + $item->searchScore += 8 * $score; + $item->searchHits += 1; // check for exact query matches - } elseif ($matches = preg_match_all('!' . $exact . '!ui', $value, $r)) { - $scoring['score'] += 2 * $score; - $scoring['hits'] += $matches; + } elseif ($matches = preg_match_all('!' . $exactQuery . '!i', $value, $r)) { + $item->searchScore += 2 * $score; + $item->searchHits += $matches; } // check for any match if ($matches = preg_match_all($preg, $value, $r)) { - $scoring['score'] += $matches * $score; - $scoring['hits'] += $matches; + $item->searchHits += $matches; + $item->searchScore += $matches * $score; } } - $scores[$item->id()] = $scoring; - - return $scoring['hits'] > 0; + return $item->searchHits > 0; }); - return $results->sort( - fn ($item) => $scores[$item->id()]['score'], - 'desc' - ); + return $results->sort('searchScore', 'desc'); }, /** * Add your own SmartyPants parser * + * @param \Kirby\Cms\App $kirby Kirby instance * @param string $text Text to parse * @param array $options SmartyPants options + * @return string */ - 'smartypants' => function ( - App $kirby, - string $text = null, - array $options = [] - ): string { + 'smartypants' => function (App $kirby, string $text = null, array $options = []): string { static $smartypants; static $config; @@ -289,55 +292,59 @@ return [ /** * Add your own snippet loader * + * @param \Kirby\Cms\App $kirby Kirby instance * @param string|array $name Snippet name * @param array $data Data array for the snippet + * @return string|null */ - 'snippet' => function ( - App $kirby, - string|array|null $name, - array $data = [], - bool $slots = false - ): Snippet|string { - return Snippet::factory($name, $data, $slots); + 'snippet' => function (App $kirby, $name, array $data = []): ?string { + $snippets = A::wrap($name); + + foreach ($snippets as $name) { + $name = (string)$name; + $file = $kirby->root('snippets') . '/' . $name . '.php'; + + if (file_exists($file) === false) { + $file = $kirby->extensions('snippets')[$name] ?? null; + } + + if ($file) { + break; + } + } + + return Snippet::load($file, $data); }, /** * Add your own template engine * + * @param \Kirby\Cms\App $kirby Kirby instance * @param string $name Template name * @param string $type Extension type * @param string $defaultType Default extension type - * @return \Kirby\Template\Template + * @return \Kirby\Cms\Template */ - 'template' => function ( - App $kirby, - string $name, - string $type = 'html', - string $defaultType = 'html' - ) { + 'template' => function (App $kirby, string $name, string $type = 'html', string $defaultType = 'html') { return new Template($name, $type, $defaultType); }, /** * Add your own thumb generator * + * @param \Kirby\Cms\App $kirby Kirby instance * @param string $src Root of the original file * @param string $dst Template string for the root to the desired destination * @param array $options All thumb options that should be applied: `width`, `height`, `crop`, `blur`, `grayscale` * @return string */ - 'thumb' => function ( - App $kirby, - string $src, - string $dst, - array $options - ): string { + 'thumb' => function (App $kirby, string $src, string $dst, array $options): string { $darkroom = Darkroom::factory( $kirby->option('thumbs.driver', 'gd'), $kirby->option('thumbs', []) ); - $options = $darkroom->preprocess($src, $options); - $root = (new Filename($src, $dst, $options))->toString(); + $options = $darkroom->preprocess($src, $options); + $root = (new Filename($src, $dst, $options))->toString(); F::copy($src, $root, true); $darkroom->process($root, $options); @@ -348,15 +355,12 @@ return [ /** * Modify all URLs * + * @param \Kirby\Cms\App $kirby Kirby instance * @param string|null $path URL path * @param array|string|null $options Array of options for the Uri class - * @throws \Kirby\Exception\NotFoundException If an invalid UUID was passed + * @return string */ - 'url' => function ( - App $kirby, - string $path = null, - $options = null - ): string { + 'url' => function (App $kirby, string $path = null, $options = null): string { $language = null; // get language from simple string option @@ -398,23 +402,6 @@ return [ return $path; } - // support UUIDs - if ( - $path !== null && - ( - Uuid::is($path, 'page') === true || - Uuid::is($path, 'file') === true - ) - ) { - $model = Uuid::for($path)->model(); - - if ($model === null) { - throw new NotFoundException('The model could not be found for "' . $path . '" uuid'); - } - - $path = $model->url(); - } - $url = Url::makeAbsolute($path, $kirby->url()); if ($options === null) { diff --git a/kirby/config/fields/color.php b/kirby/config/fields/color.php deleted file mode 100644 index 8d473f1..0000000 --- a/kirby/config/fields/color.php +++ /dev/null @@ -1,145 +0,0 @@ - [ - /** - * Unset inherited props - */ - 'after' => null, - 'before' => null, - - /** - * Whether to allow alpha transparency in the color - */ - 'alpha' => function (bool $alpha = false) { - return $alpha; - }, - /** - * The CSS format (hex, rgb, hsl) to display and store the value - */ - 'format' => function (string $format = 'hex'): string { - if (in_array($format, ['hex', 'hsl', 'rgb']) === false) { - throw new InvalidArgumentException('Unsupported format for color field (supported: hex, rgb, hsl)'); - } - - return $format; - }, - /** - * Change mode to disable the color picker (`input`) or to only - * show the `options` as toggles - */ - 'mode' => function (string $mode = 'picker'): string { - if (in_array($mode, ['picker', 'input', 'options']) === false) { - throw new InvalidArgumentException('Unsupported mode for color field (supported: picker, input, options)'); - } - - return $mode; - }, - /** - * List of colors that will be shown as buttons - * to directly select them - */ - 'options' => function (array $options = []): array { - return $options; - } - ], - 'computed' => [ - 'default' => function (): string { - return Str::lower($this->default); - }, - 'options' => function (): array { - // resolve options to support manual arrays - // alongside api and query options - $props = FieldOptions::polyfill($this->props); - $options = FieldOptions::factory([ - 'text' => '{{ item.value }}', - 'value' => '{{ item.key }}', - ...$props['options'] - ]); - - $options = $options->render($this->model()); - - if (empty($options) === true) { - return []; - } - - $options = match (true) { - // simple array of values - // or value=text (from Options class) - is_numeric($options[0]['value']) || - $options[0]['value'] === $options[0]['text'] - => A::map($options, fn ($option) => [ - 'value' => $option['text'] - ]), - - // deprecated: name => value, flipping - // TODO: start throwing in warning in v5 - $this->isColor($options[0]['text']) - => A::map($options, fn ($option) => [ - 'value' => $option['text'], - // ensure that any HTML in the new text is escaped - 'text' => Escape::html($option['value']) - ]), - - default - => A::map($options, fn ($option) => [ - 'value' => $option['value'], - 'text' => $option['text'] - ]), - }; - - return $options; - } - ], - 'methods' => [ - 'isColor' => function (string $value): bool { - return - $this->isHex($value) || - $this->isRgb($value) || - $this->isHsl($value); - }, - 'isHex' => function (string $value): bool { - return preg_match('/^#([\da-f]{3,4}){1,2}$/i', $value) === 1; - }, - 'isHsl' => function (string $value): bool { - return preg_match('/^hsla?\(\s*(\d{1,3}\.?\d*)(deg|rad|grad|turn)?(?:,|\s)+(\d{1,3})%(?:,|\s)+(\d{1,3})%(?:,|\s|\/)*(\d*(?:\.\d+)?)(%?)\s*\)?$/i', $value) === 1; - }, - 'isRgb' => function (string $value): bool { - return preg_match('/^rgba?\(\s*(\d{1,3})(%?)(?:,|\s)+(\d{1,3})(%?)(?:,|\s)+(\d{1,3})(%?)(?:,|\s|\/)*(\d*(?:\.\d+)?)(%?)\s*\)?$/i', $value) === 1; - }, - ], - 'validations' => [ - 'color' => function ($value) { - if (empty($value) === true) { - return true; - } - - if ($this->format === 'hex' && $this->isHex($value) === false) { - throw new InvalidArgumentException([ - 'key' => 'validation.color', - 'data' => ['format' => 'hex'] - ]); - } - - if ($this->format === 'rgb' && $this->isRgb($value) === false) { - throw new InvalidArgumentException([ - 'key' => 'validation.color', - 'data' => ['format' => 'rgb'] - ]); - } - - if ($this->format === 'hsl' && $this->isHsl($value) === false) { - throw new InvalidArgumentException([ - 'key' => 'validation.color', - 'data' => ['format' => 'hsl'] - ]); - } - } - ] -]; diff --git a/kirby/config/fields/date.php b/kirby/config/fields/date.php index 1cfa41c..ffb6dc4 100644 --- a/kirby/config/fields/date.php +++ b/kirby/config/fields/date.php @@ -46,13 +46,13 @@ return [ /** * Latest date, which can be selected/saved (Y-m-d) */ - 'max' => function (string $max = null): string|null { + 'max' => function (string $max = null): ?string { return Date::optional($max); }, /** * Earliest date, which can be selected/saved (Y-m-d) */ - 'min' => function (string $min = null): string|null { + 'min' => function (string $min = null): ?string { return Date::optional($min); }, @@ -129,7 +129,7 @@ return [ 'key' => 'validation.date.between', 'data' => [ 'min' => $min->format($format), - 'max' => $max->format($format) + 'max' => $min->format($format) ] ]); } elseif ($min && $value->isMin($min) === false) { diff --git a/kirby/config/fields/files.php b/kirby/config/fields/files.php index 4f37765..5fef3e2 100644 --- a/kirby/config/fields/files.php +++ b/kirby/config/fields/files.php @@ -1,6 +1,5 @@ [ 'parentModel' => function () { - if ( - is_string($this->parent) === true && - $model = $this->model()->query( - $this->parent, - ModelWithContent::class - ) - ) { + if (is_string($this->parent) === true && $model = $this->model()->query($this->parent, 'Kirby\Cms\Model')) { return $model; } @@ -75,13 +68,10 @@ return [ foreach (Data::decode($value, 'yaml') as $id) { if (is_array($id) === true) { - $id = $id['uuid'] ?? $id['id'] ?? null; + $id = $id['id'] ?? null; } - if ( - $id !== null && - ($file = $this->kirby()->file($id, $this->model())) - ) { + if ($id !== null && ($file = $this->kirby()->file($id, $this->model()))) { $files[] = $this->fileResponse($file); } } @@ -132,7 +122,7 @@ return [ ]; }, 'save' => function ($value = null) { - return A::pluck($value, $this->store); + return A::pluck($value, 'uuid'); }, 'validations' => [ 'max', diff --git a/kirby/config/fields/headline.php b/kirby/config/fields/headline.php index 3a4509e..01994ad 100644 --- a/kirby/config/fields/headline.php +++ b/kirby/config/fields/headline.php @@ -14,6 +14,13 @@ return [ 'icon' => null, 'placeholder' => null, 'required' => null, - 'translate' => null + 'translate' => null, + + /** + * If `false`, the prepended number will be hidden + */ + 'numbered' => function (bool $numbered = true) { + return $numbered; + } ] ]; diff --git a/kirby/config/fields/hidden.php b/kirby/config/fields/hidden.php index 4b40df5..0b67a5f 100644 --- a/kirby/config/fields/hidden.php +++ b/kirby/config/fields/hidden.php @@ -1,5 +1,3 @@ true -]; +return []; diff --git a/kirby/config/fields/info.php b/kirby/config/fields/info.php index e65dc83..4df8ed3 100644 --- a/kirby/config/fields/info.php +++ b/kirby/config/fields/info.php @@ -12,6 +12,7 @@ return [ 'before' => null, 'default' => null, 'disabled' => null, + 'icon' => null, 'placeholder' => null, 'required' => null, 'translate' => null, diff --git a/kirby/config/fields/link.php b/kirby/config/fields/link.php deleted file mode 100644 index 885eb87..0000000 --- a/kirby/config/fields/link.php +++ /dev/null @@ -1,155 +0,0 @@ - [ - 'after' => null, - 'before' => null, - 'icon' => null, - 'placeholder' => null, - - /** - * @values 'anchor', 'url, 'page, 'file', 'email', 'tel', 'custom' - */ - 'options' => function (array|null $options = null): array { - return $options ?? [ - 'url', - 'page', - 'file', - 'email', - 'tel', - 'anchor' - ]; - }, - 'value' => function (string|null $value = null) { - return $value ?? ''; - } - ], - 'methods' => [ - 'activeTypes' => function () { - return array_filter($this->availableTypes(), function (string $type) { - return in_array($type, $this->props['options']) === true; - }, ARRAY_FILTER_USE_KEY); - }, - 'availableTypes' => function () { - return [ - 'anchor' => [ - 'detect' => function (string $value): bool { - return Str::startsWith($value, '#') === true; - }, - 'link' => function (string $value): string { - return $value; - }, - 'validate' => function (string $value): bool { - return Str::startsWith($value, '#') === true; - }, - ], - 'email' => [ - 'detect' => function (string $value): bool { - return Str::startsWith($value, 'mailto:') === true; - }, - 'link' => function (string $value): string { - return str_replace('mailto:', '', $value); - }, - 'validate' => function (string $value): bool { - return V::email($value); - }, - ], - 'file' => [ - 'detect' => function (string $value): bool { - return Str::startsWith($value, 'file://') === true; - }, - 'link' => function (string $value): string { - return $value; - }, - 'validate' => function (string $value): bool { - return V::uuid($value, 'file'); - }, - ], - 'page' => [ - 'detect' => function (string $value): bool { - return Str::startsWith($value, 'page://') === true; - }, - 'link' => function (string $value): string { - return $value; - }, - 'validate' => function (string $value): bool { - return V::uuid($value, 'page'); - }, - ], - 'tel' => [ - 'detect' => function (string $value): bool { - return Str::startsWith($value, 'tel:') === true; - }, - 'link' => function (string $value): string { - return str_replace('tel:', '', $value); - }, - 'validate' => function (string $value): bool { - return V::tel($value); - }, - ], - 'url' => [ - 'detect' => function (string $value): bool { - return Str::startsWith($value, 'http://') === true || Str::startsWith($value, 'https://') === true; - }, - 'link' => function (string $value): string { - return $value; - }, - 'validate' => function (string $value): bool { - return V::url($value); - }, - ], - - // needs to come last - 'custom' => [ - 'detect' => function (string $value): bool { - return true; - }, - 'link' => function (string $value): string { - return $value; - }, - 'validate' => function (): bool { - return true; - }, - ] - ]; - }, - ], - 'validations' => [ - 'value' => function (string|null $value) { - if (empty($value) === true) { - return true; - } - - $detected = false; - - foreach ($this->activeTypes() as $type => $options) { - if ($options['detect']($value) !== true) { - continue; - } - - $link = $options['link']($value); - $detected = true; - - if ($options['validate']($link) === false) { - throw new InvalidArgumentException([ - 'key' => 'validation.' . $type - ]); - } - } - - // none of the configured types has been detected - if ($detected === false) { - throw new InvalidArgumentException([ - 'key' => 'validation.linkType' - ]); - } - - return true; - }, - ] -]; diff --git a/kirby/config/fields/list.php b/kirby/config/fields/list.php index d1917f2..74493a7 100644 --- a/kirby/config/fields/list.php +++ b/kirby/config/fields/list.php @@ -7,12 +7,6 @@ return [ */ 'marks' => function ($marks = true) { return $marks; - }, - /** - * Sets the allowed nodes. Available nodes: `bulletList`, `orderedList` - */ - 'nodes' => function ($nodes = null) { - return $nodes; } ], 'computed' => [ diff --git a/kirby/config/fields/mixins/layout.php b/kirby/config/fields/mixins/layout.php index 4f94b0f..4ac0138 100644 --- a/kirby/config/fields/mixins/layout.php +++ b/kirby/config/fields/mixins/layout.php @@ -12,7 +12,7 @@ return [ }, /** - * Layout size for cards: `tiny`, `small`, `medium`, `large`, `huge`, `full` + * Layout size for cards: `tiny`, `small`, `medium`, `large` or `huge` */ 'size' => function (string $size = 'auto') { return $size; diff --git a/kirby/config/fields/mixins/options.php b/kirby/config/fields/mixins/options.php index a3625f3..465ac50 100644 --- a/kirby/config/fields/mixins/options.php +++ b/kirby/config/fields/mixins/options.php @@ -1,6 +1,6 @@ [ @@ -30,18 +30,19 @@ return [ ], 'methods' => [ 'getOptions' => function () { - $props = FieldOptions::polyfill($this->props); - $options = FieldOptions::factory($props['options']); - return $options->render($this->model()); + return Options::factory( + $this->options(), + $this->props, + $this->model() + ); }, - 'sanitizeOption' => function ($value) { - $options = array_column($this->options(), 'value'); - return in_array($value, $options) === true ? $value : null; + 'sanitizeOption' => function ($option) { + $allowed = array_column($this->options(), 'value'); + return in_array($option, $allowed, true) === true ? $option : null; }, - 'sanitizeOptions' => function ($values) { - $options = array_column($this->options(), 'value'); - $options = array_intersect($values, $options); - return array_values($options); + 'sanitizeOptions' => function ($options) { + $allowed = array_column($this->options(), 'value'); + return array_intersect($options, $allowed); }, ] ]; diff --git a/kirby/config/fields/mixins/picker.php b/kirby/config/fields/mixins/picker.php index 5d95e45..97b4f8a 100644 --- a/kirby/config/fields/mixins/picker.php +++ b/kirby/config/fields/mixins/picker.php @@ -1,7 +1,6 @@ [ @@ -68,21 +67,12 @@ return [ return $search; }, - /** - * Whether to store UUID or ID in the - * content file of the model - * - * @param string $store 'uuid'|'id' - */ - 'store' => function (string $store = 'uuid') { - return Str::lower($store); - }, - /** * Main text for each item */ 'text' => function (string $text = null) { return $text; }, + ], ]; diff --git a/kirby/config/fields/mixins/upload.php b/kirby/config/fields/mixins/upload.php index aad3933..166aeb1 100644 --- a/kirby/config/fields/mixins/upload.php +++ b/kirby/config/fields/mixins/upload.php @@ -3,7 +3,6 @@ use Kirby\Cms\Api; use Kirby\Cms\File; use Kirby\Exception\Exception; -use Kirby\Exception\InvalidArgumentException; return [ 'props' => [ @@ -23,23 +22,18 @@ return [ $uploads = []; } - $uploads['accept'] = '*'; - - if ($template = $uploads['template'] ?? null) { - // get parent object for upload target - $parent = $this->uploadParent($uploads['parent'] ?? null); - - if ($parent === null) { - throw new InvalidArgumentException('"' . $uploads['parent'] . '" could not be resolved as a valid parent for the upload'); - } + $template = $uploads['template'] ?? null; + if ($template) { $file = new File([ 'filename' => 'tmp', - 'parent' => $parent, + 'parent' => $this->model(), 'template' => $template ]); - $uploads['accept'] = $file->blueprint()->acceptAttribute(); + $uploads['accept'] = $file->blueprint()->acceptMime(); + } else { + $uploads['accept'] = '*'; } return $uploads; @@ -51,37 +45,29 @@ return [ throw new Exception('Uploads are disabled for this field'); } - $parent = $this->uploadParent($params['parent'] ?? null); + if ($parentQuery = ($params['parent'] ?? null)) { + $parent = $this->model()->query($parentQuery); + } else { + $parent = $this->model(); + } + + if (is_a($parent, 'Kirby\Cms\File') === true) { + $parent = $parent->parent(); + } return $api->upload(function ($source, $filename) use ($parent, $params, $map) { - $props = [ + $file = $parent->createFile([ 'source' => $source, 'template' => $params['template'] ?? null, 'filename' => $filename, - ]; + ]); - // move the source file from the temp dir - $file = $parent->createFile($props, true); - - if ($file instanceof File === false) { + if (is_a($file, 'Kirby\Cms\File') === false) { throw new Exception('The file could not be uploaded'); } return $map($file, $parent); }); - }, - 'uploadParent' => function (string $parentQuery = null) { - $parent = $this->model(); - - if ($parentQuery) { - $parent = $parent->query($parentQuery); - } - - if ($parent instanceof File) { - $parent = $parent->parent(); - } - - return $parent; } ] ]; diff --git a/kirby/config/fields/multiselect.php b/kirby/config/fields/multiselect.php index 6633ee3..37ab356 100644 --- a/kirby/config/fields/multiselect.php +++ b/kirby/config/fields/multiselect.php @@ -1,35 +1,32 @@ 'tags', 'props' => [ /** - * If set to `all`, any type of input is accepted. If set to `options` only the predefined options are accepted as input. + * Unset inherited props */ - 'accept' => function ($value = 'options') { - return V::in($value, ['all', 'options']) ? $value : 'all'; - }, + 'accept' => null, /** * Custom icon to replace the arrow down. */ - 'icon' => function (string $icon = 'checklist') { + 'icon' => function (string $icon = null) { return $icon; }, - ], - 'methods' => [ - 'toValues' => function ($value) { - if (is_null($value) === true) { - return []; - } - - if (is_array($value) === false) { - $value = Str::split($value, $this->separator()); - } - - return $this->sanitizeOptions($value); - } - ], + /** + * Enable/disable the search in the dropdown + * Also limit displayed items (display: 20) + * and set minimum number of characters to search (min: 3) + */ + 'search' => function ($search = true) { + return $search; + }, + /** + * If `true`, selected entries will be sorted + * according to their position in the dropdown + */ + 'sort' => function (bool $sort = false) { + return $sort; + }, + ] ]; diff --git a/kirby/config/fields/number.php b/kirby/config/fields/number.php index 11334e8..62470ed 100644 --- a/kirby/config/fields/number.php +++ b/kirby/config/fields/number.php @@ -8,7 +8,7 @@ return [ * Default number that will be saved when a new page/user/file is created */ 'default' => function ($default = null) { - return $this->toNumber($default) ?? ''; + return $this->toNumber($default); }, /** * The lowest allowed number @@ -26,10 +26,10 @@ return [ * Allowed incremental steps between numbers (i.e `0.5`) */ 'step' => function ($step = null) { - return $this->toNumber($step) ?? ''; + return $this->toNumber($step); }, 'value' => function ($value = null) { - return $this->toNumber($value) ?? ''; + return $this->toNumber($value); } ], 'methods' => [ diff --git a/kirby/config/fields/object.php b/kirby/config/fields/object.php deleted file mode 100644 index 57cd2e4..0000000 --- a/kirby/config/fields/object.php +++ /dev/null @@ -1,104 +0,0 @@ - [ - /** - * Unset inherited props - */ - 'after' => null, - 'before' => null, - 'autofocus' => null, - 'icon' => null, - 'placeholder' => null, - - /** - * Set the default values for the object - */ - 'default' => function ($default = null) { - return $default; - }, - - /** - * The placeholder text if no information has been added yet - */ - 'empty' => function ($empty = null) { - return I18n::translate($empty, $empty); - }, - - /** - * Fields setup for the object form. Works just like fields in regular forms. - */ - 'fields' => function (array $fields = []) { - return $fields; - } - ], - 'computed' => [ - 'default' => function () { - if (empty($this->default) === true) { - return ''; - } - - return $this->form($this->default)->values(); - }, - 'fields' => function () { - if (empty($this->fields) === true) { - return []; - } - - return $this->form()->fields()->toArray(); - }, - 'value' => function () { - $data = Data::decode($this->value, 'yaml'); - - if (empty($data) === true) { - return ''; - } - - return $this->form($data)->values(); - } - ], - 'methods' => [ - 'form' => function (array $values = []) { - return new Form([ - 'fields' => $this->attrs['fields'], - 'values' => $values, - 'model' => $this->model - ]); - }, - ], - 'save' => function ($value) { - if (empty($value) === true) { - return ''; - } - - return $this->form($value)->content(); - }, - 'validations' => [ - 'object' => function ($value) { - if (empty($value) === true) { - return true; - } - - $errors = $this->form($value)->errors(); - - if (empty($errors) === false) { - // use the first error for details - $name = array_key_first($errors); - $error = $errors[$name]; - - throw new InvalidArgumentException([ - 'key' => 'object.validation', - 'data' => [ - 'label' => $error['label'] ?? $name, - 'message' => implode("\n", $error['message']) - ] - ]); - } - } - ] -]; diff --git a/kirby/config/fields/pages.php b/kirby/config/fields/pages.php index 54d9aa8..8eaa70d 100644 --- a/kirby/config/fields/pages.php +++ b/kirby/config/fields/pages.php @@ -67,7 +67,7 @@ return [ foreach (Data::decode($value, 'yaml') as $id) { if (is_array($id) === true) { - $id = $id['uuid'] ?? $id['id'] ?? null; + $id = $id['id'] ?? null; } if ($id !== null && ($page = $kirby->page($id))) { @@ -102,7 +102,7 @@ return [ ]; }, 'save' => function ($value = null) { - return A::pluck($value, $this->store); + return A::pluck($value, 'id'); }, 'validations' => [ 'max', diff --git a/kirby/config/fields/range.php b/kirby/config/fields/range.php index d203a7e..04221f1 100644 --- a/kirby/config/fields/range.php +++ b/kirby/config/fields/range.php @@ -1,7 +1,5 @@ 'number', 'props' => [ @@ -20,13 +18,6 @@ return [ * Enables/disables the tooltip and set the before and after values */ 'tooltip' => function ($tooltip = true) { - if (is_array($tooltip) === true) { - $after = $tooltip['after'] ?? null; - $before = $tooltip['before'] ?? null; - $tooltip['after'] = I18n::translate($after, $after); - $tooltip['before'] = I18n::translate($before, $before); - } - return $tooltip; }, ] diff --git a/kirby/config/fields/select.php b/kirby/config/fields/select.php index 4c06b5b..04b468d 100644 --- a/kirby/config/fields/select.php +++ b/kirby/config/fields/select.php @@ -1,7 +1,5 @@ 'radio', 'props' => [ @@ -22,16 +20,5 @@ return [ 'placeholder' => function (string $placeholder = '—') { return $placeholder; }, - ], - 'methods' => [ - 'getOptions' => function () { - $props = FieldOptions::polyfill($this->props); - - // disable safe mode as the select field does not - // render HTML for the option text - $options = FieldOptions::factory($props['options'], false); - - return $options->render($this->model()); - } ] ]; diff --git a/kirby/config/fields/structure.php b/kirby/config/fields/structure.php index 510459b..ee74703 100644 --- a/kirby/config/fields/structure.php +++ b/kirby/config/fields/structure.php @@ -1,11 +1,8 @@ ['min'], @@ -52,7 +49,7 @@ return [ /** * Fields setup for the structure form. Works just like fields in regular forms. */ - 'fields' => function (array $fields = []) { + 'fields' => function (array $fields) { return $fields; }, /** @@ -102,54 +99,54 @@ return [ }, 'fields' => function () { if (empty($this->fields) === true) { - return []; + throw new Exception('Please provide some fields for the structure'); } return $this->form()->fields()->toArray(); }, 'columns' => function () { - $columns = []; - $blueprint = $this->columns; + $columns = []; + $mobile = 0; - // if no custom columns have been defined, - // gather all fields as columns - if (empty($blueprint) === true) { - // skip hidden fields - $fields = array_filter( - $this->fields, - fn ($field) => - $field['type'] !== 'hidden' && $field['hidden'] !== true - ); - $fields = array_column($fields, 'name'); - $blueprint = array_fill_keys($fields, true); - } + if (empty($this->columns)) { + foreach ($this->fields as $field) { + // Skip hidden and unsaveable fields + // They should never be included as column + if ($field['type'] === 'hidden' || $field['saveable'] === false) { + continue; + } - foreach ($blueprint as $name => $column) { - $field = $this->fields[$name] ?? null; - - // Skip empty and unsaveable fields - // They should never be included as column - if ( - empty($field) === true || - $field['saveable'] === false - ) { - continue; + $columns[$field['name']] = [ + 'type' => $field['type'], + 'label' => $field['label'] ?? $field['name'] + ]; } + } else { + foreach ($this->columns as $columnName => $columnProps) { + if (is_array($columnProps) === false) { + $columnProps = []; + } - if (is_array($column) === false) { - $column = []; + $field = $this->fields[$columnName] ?? null; + + if (empty($field) === true || $field['saveable'] === false) { + continue; + } + + if (($columnProps['mobile'] ?? false) === true) { + $mobile++; + } + + $columns[$columnName] = array_merge($columnProps, [ + 'type' => $field['type'], + 'label' => $field['label'] ?? $field['name'] + ]); } - - $column['type'] ??= $field['type']; - $column['label'] ??= $field['label'] ?? $name; - $column['label'] = I18n::translate($column['label'], $column['label']); - - $columns[$name] = $column; } // make the first column visible on mobile // if no other mobile columns are defined - if (in_array(true, array_column($columns, 'mobile')) === false) { + if ($mobile === 0) { $columns[array_key_first($columns)]['mobile'] = true; } @@ -173,53 +170,34 @@ return [ }, 'form' => function (array $values = []) { return new Form([ - 'fields' => $this->attrs['fields'] ?? [], + 'fields' => $this->attrs['fields'], 'values' => $values, 'model' => $this->model ]); }, ], + 'api' => function () { + return [ + [ + 'pattern' => 'validate', + 'method' => 'ALL', + 'action' => function () { + return array_values($this->field()->form($this->requestBody())->errors()); + } + ] + ]; + }, 'save' => function ($value) { $data = []; foreach ($value as $row) { - $row = $this->form($row)->content(); - - // remove frontend helper id - unset($row['_id']); - - $data[] = $row; + $data[] = $this->form($row)->content(); } return $data; }, 'validations' => [ 'min', - 'max', - 'structure' => function ($value) { - if (empty($value) === true) { - return true; - } - - $values = A::wrap($value); - - foreach ($values as $index => $value) { - $form = $this->form($value); - - foreach ($form->fields() as $field) { - $errors = $field->errors(); - - if (empty($errors) === false) { - throw new InvalidArgumentException([ - 'key' => 'structure.validation', - 'data' => [ - 'field' => $field->label() ?? Str::ucfirst($field->name()), - 'index' => $index + 1 - ] - ]); - } - } - } - } + 'max' ] ]; diff --git a/kirby/config/fields/tags.php b/kirby/config/fields/tags.php index b5b6c9e..ab8121a 100644 --- a/kirby/config/fields/tags.php +++ b/kirby/config/fields/tags.php @@ -31,7 +31,7 @@ return [ * Set to `list` to display each tag with 100% width, * otherwise the tags are displayed inline */ - 'layout' => function (string|null $layout = null) { + 'layout' => function (?string $layout = null) { return $layout; }, /** @@ -46,56 +46,52 @@ return [ 'max' => function (int $max = null) { return $max; }, - /** - * Enable/disable the search in the dropdown - * Also limit displayed items (display: 20) - * and set minimum number of characters to search (min: 3) - */ - 'search' => function (bool|array $search = true) { - return $search; - }, /** * Custom tags separator, which will be used to store tags in the content file */ 'separator' => function (string $separator = ',') { return $separator; }, - /** - * If `true`, selected entries will be sorted - * according to their position in the dropdown - */ - 'sort' => function (bool $sort = false) { - return $sort; - }, ], 'computed' => [ 'default' => function (): array { - return $this->toValues($this->default); + return $this->toTags($this->default); }, 'value' => function (): array { - return $this->toValues($this->value); + return $this->toTags($this->value); } ], 'methods' => [ - 'toValues' => function ($value) { + 'toTags' => function ($value) { if (is_null($value) === true) { return []; } - if (is_array($value) === false) { - $value = Str::split($value, $this->separator()); - } + $options = $this->options(); - if ($this->accept === 'options') { - $value = $this->sanitizeOptions($value); - } + // transform into value-text objects + return array_map(function ($option) use ($options) { + // already a valid object + if (is_array($option) === true && isset($option['value'], $option['text']) === true) { + return $option; + } - return $value; + $index = array_search($option, array_column($options, 'value')); + + if ($index !== false) { + return $options[$index]; + } + + return [ + 'value' => $option, + 'text' => $option, + ]; + }, Str::split($value, $this->separator())); } ], 'save' => function (array $value = null): string { return A::join( - $value, + A::pluck($value, 'value'), $this->separator() . ' ' ); }, diff --git a/kirby/config/fields/text.php b/kirby/config/fields/text.php index 574a4ec..7abd86f 100644 --- a/kirby/config/fields/text.php +++ b/kirby/config/fields/text.php @@ -10,7 +10,7 @@ return [ * The field value will be converted with the selected converter before the value gets saved. Available converters: `lower`, `upper`, `ucfirst`, `slug` */ 'converter' => function ($value = null) { - if ($value !== null && array_key_exists($value, $this->converters()) === false) { + if ($value !== null && in_array($value, array_keys($this->converters())) === false) { throw new InvalidArgumentException([ 'key' => 'field.converter.invalid', 'data' => ['converter' => $value] @@ -27,13 +27,6 @@ return [ return $counter; }, - /** - * Sets the font family (sans or monospace) - */ - 'font' => function (string $font = null) { - return $font === 'monospace' ? 'monospace' : 'sans-serif'; - }, - /** * Maximum number of allowed characters */ diff --git a/kirby/config/fields/time.php b/kirby/config/fields/time.php index 4a0b6fc..69a2da9 100644 --- a/kirby/config/fields/time.php +++ b/kirby/config/fields/time.php @@ -15,7 +15,7 @@ return [ /** * Sets the default time when a new page/file/user is created */ - 'default' => function ($default = null): string|null { + 'default' => function ($default = null): ?string { return $default; }, @@ -36,13 +36,13 @@ return [ /** * Latest time, which can be selected/saved (H:i or H:i:s) */ - 'max' => function (string $max = null): string|null { + 'max' => function (string $max = null): ?string { return Date::optional($max); }, /** * Earliest time, which can be selected/saved (H:i or H:i:s) */ - 'min' => function (string $min = null): string|null { + 'min' => function (string $min = null): ?string { return Date::optional($min); }, @@ -62,7 +62,7 @@ return [ 'unit' => 'minute', ]); }, - 'value' => function ($value = null): string|null { + 'value' => function ($value = null): ?string { return $value; } ], @@ -80,7 +80,7 @@ return [ 'format' => function () { return $this->props['format'] ?? 'H:i:s'; }, - 'value' => function (): string|null { + 'value' => function (): ?string { return $this->toDatetime($this->value, 'H:i:s') ?? ''; } ], diff --git a/kirby/config/fields/toggle.php b/kirby/config/fields/toggle.php index a9b7897..4cb8a6e 100644 --- a/kirby/config/fields/toggle.php +++ b/kirby/config/fields/toggle.php @@ -49,9 +49,9 @@ return [ 'value' => function () { if ($this->props['value'] === null) { return $this->default(); + } else { + return $this->toBool($this->props['value']); } - - return $this->toBool($this->props['value']); } ], 'methods' => [ diff --git a/kirby/config/fields/users.php b/kirby/config/fields/users.php index f30f6ab..8641eee 100644 --- a/kirby/config/fields/users.php +++ b/kirby/config/fields/users.php @@ -24,8 +24,18 @@ return [ /** * Default selected user(s) when a new page/file/user is created */ - 'default' => function (string|array|bool|null $default = null) { - return $default; + 'default' => function ($default = null) { + if ($default === false) { + return []; + } + + if ($default === null && $user = $this->kirby()->user()) { + return [ + $this->userResponse($user) + ]; + } + + return $this->toUsers($default); }, 'value' => function ($value = null) { @@ -33,22 +43,10 @@ return [ }, ], 'computed' => [ - 'default' => function (): array { - if ($this->default === false) { - return []; - } - - if ( - $this->default === true && - $user = $this->kirby()->user() - ) { - return [ - $this->userResponse($user) - ]; - } - - return $this->toUsers($this->default); - } + /** + * Unset inherited computed + */ + 'default' => null ], 'methods' => [ 'userResponse' => function ($user) { @@ -59,7 +57,7 @@ return [ 'text' => $this->text, ]); }, - 'toUsers' => function ($value = null): array { + 'toUsers' => function ($value = null) { $users = []; $kirby = App::instance(); @@ -98,7 +96,7 @@ return [ ]; }, 'save' => function ($value = null) { - return A::pluck($value, $this->store); + return A::pluck($value, 'id'); }, 'validations' => [ 'max', diff --git a/kirby/config/fields/writer.php b/kirby/config/fields/writer.php index fc4a393..73c4976 100644 --- a/kirby/config/fields/writer.php +++ b/kirby/config/fields/writer.php @@ -1,23 +1,9 @@ [ - /** - * Enables/disables the character counter in the top right corner - */ - 'counter' => function (bool $counter = true) { - return $counter; - }, - /** - * Available heading levels - */ - 'headings' => function (array|null $headings = null) { - return array_intersect($headings ?? range(1, 6), range(1, 6)); - }, /** * Enables inline mode, which will not wrap new lines in paragraphs and creates hard breaks instead. * @@ -27,37 +13,18 @@ return [ return $inline; }, /** - * Sets the allowed HTML formats. Available formats: `bold`, `italic`, `underline`, `strike`, `code`, `link`, `email`. Activate/deactivate them all by passing `true`/`false`. Default marks are `bold`, `italic`, `underline`, `strike`, `link`, `email` + * Sets the allowed HTML formats. Available formats: `bold`, `italic`, `underline`, `strike`, `code`, `link`, `email`. Activate them all by passing `true`. Deactivate them all by passing `false` * @param array|bool $marks */ - 'marks' => function ($marks = null) { + 'marks' => function ($marks = true) { return $marks; }, /** - * Maximum number of allowed characters - */ - 'maxlength' => function (int $maxlength = null) { - return $maxlength; - }, - - /** - * Minimum number of required characters - */ - 'minlength' => function (int $minlength = null) { - return $minlength; - }, - /** - * Sets the allowed nodes. Available nodes: `paragraph`, `heading`, `bulletList`, `orderedList`, `quote`. Activate/deactivate them all by passing `true`/`false`. Default nodes are `paragraph`, `heading`, `bulletList`, `orderedList`. + * Sets the allowed nodes. Available nodes: `paragraph`, `heading`, `bulletList`, `orderedList`. Activate/deactivate them all by passing `true`/`false`. Default nodes are `paragraph`, `heading`, `bulletList`, `orderedList`. * @param array|bool|null $nodes */ 'nodes' => function ($nodes = null) { return $nodes; - }, - /** - * Toolbar options, incl. `marks` (to narrow down which marks should have toolbar buttons), `nodes` (to narrow down which nodes should have toolbar dropdown entries) and `inline` to set the position of the toolbar (false = sticking on top of the field) - */ - 'toolbar' => function ($toolbar = null) { - return $toolbar; } ], 'computed' => [ @@ -66,28 +33,4 @@ return [ return Sane::sanitize($value, 'html'); } ], - 'validations' => [ - 'minlength' => function ($value) { - if ( - $this->minlength && - V::minLength(strip_tags($value), $this->minlength) === false - ) { - throw new InvalidArgumentException([ - 'key' => 'validation.minlength', - 'data' => ['min' => $this->minlength] - ]); - } - }, - 'maxlength' => function ($value) { - if ( - $this->maxlength && - V::maxLength(strip_tags($value), $this->maxlength) === false - ) { - throw new InvalidArgumentException([ - 'key' => 'validation.maxlength', - 'data' => ['max' => $this->maxlength] - ]); - } - }, - ] ]; diff --git a/kirby/config/helpers.php b/kirby/config/helpers.php index 2dc83d8..f8d0476 100644 --- a/kirby/config/helpers.php +++ b/kirby/config/helpers.php @@ -1,21 +1,13 @@ collection($name, $options); + return App::instance()->collection($name); } } @@ -68,7 +61,7 @@ if (Helpers::hasOverride('csrf') === false) { // @codeCoverageIgnore * @param string|null $check Pass a token here to compare it to the one in the session * @return string|bool Either the token or a boolean check result */ - function csrf(string|null $check = null): string|bool + function csrf(?string $check = null) { // check explicitly if there have been no arguments at all; // checking for null introduces a security issue because null could come @@ -86,12 +79,11 @@ if (Helpers::hasOverride('css') === false) { // @codeCoverageIgnore * Creates one or multiple CSS link tags * * @param string|array $url Relative or absolute URLs, an array of URLs or `@auto` for automatic template css loading - * @param string|array|null $options Pass an array of attributes for the link tag or a media attribute string + * @param string|array $options Pass an array of attributes for the link tag or a media attribute string + * @return string|null */ - function css( - string|array $url, - string|array|null $options = null - ): string|null { + function css($url, $options = null): ?string + { return Html::css($url, $options); } } @@ -101,6 +93,7 @@ if (Helpers::hasOverride('deprecated') === false) { // @codeCoverageIgnore * Triggers a deprecation warning if debug mode is active * @since 3.3.0 * + * @param string $message * @return bool Whether the warning was triggered */ function deprecated(string $message): bool @@ -109,12 +102,16 @@ if (Helpers::hasOverride('deprecated') === false) { // @codeCoverageIgnore } } -if (Helpers::hasOverride('dump') === false && function_exists('dump') === false) { // @codeCoverageIgnore +if (Helpers::hasOverride('dump') === false) { // @codeCoverageIgnore /** * Simple object and variable dumper * to help with debugging. + * + * @param mixed $variable + * @param bool $echo + * @return string */ - function dump(mixed $variable, bool $echo = true): string + function dump($variable, bool $echo = true): string { return Helpers::dump($variable, $echo); } @@ -124,35 +121,16 @@ if (Helpers::hasOverride('e') === false) { // @codeCoverageIgnore /** * Smart version of echo with an if condition as first argument * + * @param mixed $condition * @param mixed $value The string to be echoed if the condition is true * @param mixed $alternative An alternative string which should be echoed when the condition is false */ - function e(mixed $condition, mixed $value, mixed $alternative = null): void + function e($condition, $value, $alternative = null) { echo $condition ? $value : $alternative; } } -if (Helpers::hasOverride('endslot') === false) { // @codeCoverageIgnore - /** - * Ends the last started template slot - */ - function endslot(): void - { - Slot::end(); - } -} - -if (Helpers::hasOverride('endsnippet') === false) { // @codeCoverageIgnore - /** - * Renders the currently active snippet with slots - */ - function endsnippet(): void - { - Snippet::end(); - } -} - if (Helpers::hasOverride('esc') === false) { // @codeCoverageIgnore /** * Escape context specific output @@ -173,8 +151,9 @@ if (Helpers::hasOverride('get') === false) { // @codeCoverageIgnore * * @param mixed $key The key to look for. Pass false or null to return the entire request array. * @param mixed $default Optional default value, which should be returned if no element has been found + * @return mixed */ - function get(mixed $key = null, mixed $default = null): mixed + function get($key = null, $default = null) { return App::instance()->request()->get($key, $default); } @@ -183,8 +162,12 @@ if (Helpers::hasOverride('get') === false) { // @codeCoverageIgnore if (Helpers::hasOverride('gist') === false) { // @codeCoverageIgnore /** * Embeds a Github Gist + * + * @param string $url + * @param string|null $file + * @return string */ - function gist(string $url, string|null $file = null): string + function gist(string $url, ?string $file = null): string { return App::instance()->kirbytag([ 'gist' => $url, @@ -197,8 +180,12 @@ if (Helpers::hasOverride('go') === false) { // @codeCoverageIgnore /** * Redirects to the given Urls * Urls can be relative or absolute. + * + * @param string $url + * @param int $code + * @return void */ - function go(string $url = '/', int $code = 302): never + function go(string $url = '/', int $code = 302) { Response::go($url, $code); } @@ -209,8 +196,10 @@ if (Helpers::hasOverride('h') === false) { // @codeCoverageIgnore * Shortcut for html() * * @param string|null $string unencoded text + * @param bool $keepTags + * @return string */ - function h(string|null $string, bool $keepTags = false): string + function h(?string $string, bool $keepTags = false): string { return Html::encode($string, $keepTags); } @@ -221,8 +210,10 @@ if (Helpers::hasOverride('html') === false) { // @codeCoverageIgnore * Creates safe html by encoding special characters * * @param string|null $string unencoded text + * @param bool $keepTags + * @return string */ - function html(string|null $string, bool $keepTags = false): string + function html(?string $string, bool $keepTags = false): string { return Html::encode($string, $keepTags); } @@ -235,8 +226,11 @@ if (Helpers::hasOverride('image') === false) { // @codeCoverageIgnore * * Example: * + * + * @param string|null $path + * @return \Kirby\Cms\File|null */ - function image(string|null $path = null): File|null + function image(?string $path = null) { return App::instance()->image($path); } @@ -245,12 +239,14 @@ if (Helpers::hasOverride('image') === false) { // @codeCoverageIgnore if (Helpers::hasOverride('invalid') === false) { // @codeCoverageIgnore /** * Runs a number of validators on a set of data and checks if the data is invalid + * + * @param array $data + * @param array $rules + * @param array $messages + * @return array */ - function invalid( - array $data = [], - array $rules = [], - array $messages = [] - ): array { + function invalid(array $data = [], array $rules = [], array $messages = []): array + { return V::invalid($data, $rules, $messages); } } @@ -258,11 +254,13 @@ if (Helpers::hasOverride('invalid') === false) { // @codeCoverageIgnore if (Helpers::hasOverride('js') === false) { // @codeCoverageIgnore /** * Creates a script tag to load a javascript file + * + * @param string|array $url + * @param string|array $options + * @return string|null */ - function js( - string|array $url, - string|array|bool|null $options = null - ): string|null { + function js($url, $options = null): ?string + { return Html::js($url, $options); } } @@ -270,8 +268,10 @@ if (Helpers::hasOverride('js') === false) { // @codeCoverageIgnore if (Helpers::hasOverride('kirby') === false) { // @codeCoverageIgnore /** * Returns the Kirby object in any situation + * + * @return \Kirby\Cms\App */ - function kirby(): App + function kirby() { return App::instance(); } @@ -280,13 +280,15 @@ if (Helpers::hasOverride('kirby') === false) { // @codeCoverageIgnore if (Helpers::hasOverride('kirbytag') === false) { // @codeCoverageIgnore /** * Makes it possible to use any defined Kirbytag as standalone function + * + * @param string|array $type + * @param string|null $value + * @param array $attr + * @param array $data + * @return string */ - function kirbytag( - string|array $type, - string|null $value = null, - array $attr = [], - array $data = [] - ): string { + function kirbytag($type, ?string $value = null, array $attr = [], array $data = []): string + { return App::instance()->kirbytag($type, $value, $attr, $data); } } @@ -295,8 +297,12 @@ if (Helpers::hasOverride('kirbytags') === false) { // @codeCoverageIgnore /** * Parses KirbyTags in the given string. Shortcut * for `$kirby->kirbytags($text, $data)` + * + * @param string|null $text + * @param array $data + * @return string */ - function kirbytags(string|null $text = null, array $data = []): string + function kirbytags(?string $text = null, array $data = []): string { return App::instance()->kirbytags($text, $data); } @@ -306,8 +312,12 @@ if (Helpers::hasOverride('kirbytext') === false) { // @codeCoverageIgnore /** * Parses KirbyTags and Markdown in the * given string. Shortcut for `$kirby->kirbytext()` + * + * @param string|null $text + * @param array $data + * @return string */ - function kirbytext(string|null $text = null, array $data = []): string + function kirbytext(?string $text = null, array $data = []): string { return App::instance()->kirbytext($text, $data); } @@ -318,8 +328,12 @@ if (Helpers::hasOverride('kirbytextinline') === false) { // @codeCoverageIgnore * Parses KirbyTags and inline Markdown in the * given string. * @since 3.1.0 + * + * @param string|null $text + * @param array $options + * @return string */ - function kirbytextinline(string|null $text = null, array $options = []): string + function kirbytextinline(?string $text = null, array $options = []): string { $options['markdown']['inline'] = true; return App::instance()->kirbytext($text, $options); @@ -329,8 +343,12 @@ if (Helpers::hasOverride('kirbytextinline') === false) { // @codeCoverageIgnore if (Helpers::hasOverride('kt') === false) { // @codeCoverageIgnore /** * Shortcut for `kirbytext()` helper + * + * @param string|null $text + * @param array $data + * @return string */ - function kt(string|null $text = null, array $data = []): string + function kt(?string $text = null, array $data = []): string { return App::instance()->kirbytext($text, $data); } @@ -340,8 +358,12 @@ if (Helpers::hasOverride('kti') === false) { // @codeCoverageIgnore /** * Shortcut for `kirbytextinline()` helper * @since 3.1.0 + * + * @param string|null $text + * @param array $options + * @return string */ - function kti(string|null $text = null, array $options = []): string + function kti(?string $text = null, array $options = []): string { $options['markdown']['inline'] = true; return App::instance()->kirbytext($text, $options); @@ -351,8 +373,12 @@ if (Helpers::hasOverride('kti') === false) { // @codeCoverageIgnore if (Helpers::hasOverride('load') === false) { // @codeCoverageIgnore /** * A super simple class autoloader + * + * @param array $classmap + * @param string|null $base + * @return void */ - function load(array $classmap, string|null $base = null): void + function load(array $classmap, ?string $base = null): void { F::loadClasses($classmap, $base); } @@ -362,8 +388,12 @@ if (Helpers::hasOverride('markdown') === false) { // @codeCoverageIgnore /** * Parses markdown in the given string. Shortcut for * `$kirby->markdown($text)` + * + * @param string|null $text + * @param array $options + * @return string */ - function markdown(string|null $text = null, array $options = []): string + function markdown(?string $text = null, array $options = []): string { return App::instance()->markdown($text, $options); } @@ -372,8 +402,12 @@ if (Helpers::hasOverride('markdown') === false) { // @codeCoverageIgnore if (Helpers::hasOverride('option') === false) { // @codeCoverageIgnore /** * Shortcut for `$kirby->option($key, $default)` + * + * @param string $key + * @param mixed $default + * @return mixed */ - function option(string $key, mixed $default = null): mixed + function option(string $key, $default = null) { return App::instance()->option($key, $default); } @@ -383,8 +417,11 @@ if (Helpers::hasOverride('page') === false) { // @codeCoverageIgnore /** * Fetches a single page by id or * the current page when no id is specified + * + * @param string|null $id + * @return \Kirby\Cms\Page|null */ - function page(string|null $id = null): Page|null + function page(?string $id = null) { if (empty($id) === true) { return App::instance()->site()->page(); @@ -397,8 +434,11 @@ if (Helpers::hasOverride('page') === false) { // @codeCoverageIgnore if (Helpers::hasOverride('pages') === false) { // @codeCoverageIgnore /** * Helper to build pages collection + * + * @param string|array ...$id + * @return \Kirby\Cms\Pages|null */ - function pages(string|array ...$id): Pages|null + function pages(...$id) { // ensure that a list of string arguments and an array // as the first argument are treated the same @@ -416,9 +456,11 @@ if (Helpers::hasOverride('param') === false) { // @codeCoverageIgnore /** * Returns a single param from the URL * - * @psalm-return ($fallback is string ? string : string|null) + * @param string $key + * @param string|null $fallback + * @return string|null */ - function param(string $key, string|null $fallback = null): string|null + function param(string $key, ?string $fallback = null): ?string { return App::instance()->request()->url()->params()->$key ?? $fallback; } @@ -427,6 +469,8 @@ if (Helpers::hasOverride('param') === false) { // @codeCoverageIgnore if (Helpers::hasOverride('params') === false) { // @codeCoverageIgnore /** * Returns all params from the current Url + * + * @return array */ function params(): array { @@ -434,28 +478,16 @@ if (Helpers::hasOverride('params') === false) { // @codeCoverageIgnore } } -if (Helpers::hasOverride('qr') === false) { // @codeCoverageIgnore - /** - * Creates a QR code object - */ - function qr(string|ModelWithContent $data): QrCode - { - if ($data instanceof ModelWithContent) { - $data = $data->url(); - } - - return new QrCode($data); - } -} - if (Helpers::hasOverride('r') === false) { // @codeCoverageIgnore /** * Smart version of return with an if condition as first argument * + * @param mixed $condition * @param mixed $value The string to be returned if the condition is true * @param mixed $alternative An alternative string which should be returned when the condition is false + * @return mixed */ - function r(mixed $condition, mixed $value, mixed $alternative = null): mixed + function r($condition, $value, $alternative = null) { return $condition ? $value : $alternative; } @@ -466,13 +498,15 @@ if (Helpers::hasOverride('router') === false) { // @codeCoverageIgnore * Creates a micro-router and executes * the routing action immediately * @since 3.6.0 + * + * @param string|null $path + * @param string $method + * @param array $routes + * @param \Closure|null $callback + * @return mixed */ - function router( - string|null $path = null, - string $method = 'GET', - array $routes = [], - Closure|null $callback = null - ): mixed { + function router(?string $path = null, string $method = 'GET', array $routes = [], ?Closure $callback = null) + { return Router::execute($path, $method, $routes, $callback); } } @@ -480,8 +514,10 @@ if (Helpers::hasOverride('router') === false) { // @codeCoverageIgnore if (Helpers::hasOverride('site') === false) { // @codeCoverageIgnore /** * Returns the current site object + * + * @return \Kirby\Cms\Site */ - function site(): Site + function site() { return App::instance()->site(); } @@ -490,29 +526,26 @@ if (Helpers::hasOverride('site') === false) { // @codeCoverageIgnore if (Helpers::hasOverride('size') === false) { // @codeCoverageIgnore /** * Determines the size/length of numbers, strings, arrays and countable objects + * + * @param mixed $value + * @return int + * @throws \Kirby\Exception\InvalidArgumentException */ - function size(mixed $value): int + function size($value): int { return Helpers::size($value); } } -if (Helpers::hasOverride('slot') === false) { // @codeCoverageIgnore - /** - * Starts a new template slot - */ - function slot(string $name = 'default'): void - { - Slot::begin($name); - } -} - if (Helpers::hasOverride('smartypants') === false) { // @codeCoverageIgnore /** * Enhances the given string with * smartypants. Shortcut for `$kirby->smartypants($text)` + * + * @param string|null $text + * @return string */ - function smartypants(string|null $text = null): string + function smartypants(?string $text = null): string { return App::instance()->smartypants($text); } @@ -521,14 +554,15 @@ if (Helpers::hasOverride('smartypants') === false) { // @codeCoverageIgnore if (Helpers::hasOverride('snippet') === false) { // @codeCoverageIgnore /** * Embeds a snippet from the snippet folder + * + * @param string|array $name + * @param array|object $data + * @param bool $return + * @return string|null */ - function snippet( - $name, - $data = [], - bool $return = false, - bool $slots = false - ): Snippet|string|null { - return App::instance()->snippet($name, $data, $return, $slots); + function snippet($name, $data = [], bool $return = false): ?string + { + return App::instance()->snippet($name, $data, $return); } } @@ -536,8 +570,11 @@ if (Helpers::hasOverride('svg') === false) { // @codeCoverageIgnore /** * Includes an SVG file by absolute or * relative file path. + * + * @param string|\Kirby\Cms\File $file + * @return string|false */ - function svg(string|File $file): string|false + function svg($file) { return Html::svg($file); } @@ -546,12 +583,14 @@ if (Helpers::hasOverride('svg') === false) { // @codeCoverageIgnore if (Helpers::hasOverride('t') === false) { // @codeCoverageIgnore /** * Returns translate string for key from translation file + * + * @param string|array $key + * @param string|null $fallback + * @param string|null $locale + * @return array|string|null */ - function t( - string|array $key, - string|null $fallback = null, - string|null $locale = null - ): string|array|Closure|null { + function t($key, string $fallback = null, string $locale = null) + { return I18n::translate($key, $fallback, $locale); } } @@ -560,14 +599,18 @@ if (Helpers::hasOverride('tc') === false) { // @codeCoverageIgnore /** * Translates a count * + * @param string $key + * @param int $count + * @param string|null $locale * @param bool $formatNumber If set to `false`, the count is not formatted + * @return mixed */ function tc( string $key, int $count, - string|null $locale = null, + string $locale = null, bool $formatNumber = true - ): mixed { + ) { return I18n::translateCount($key, $count, $locale, $formatNumber); } } @@ -577,12 +620,12 @@ if (Helpers::hasOverride('timestamp') === false) { // @codeCoverageIgnore * Rounds the minutes of the given date * by the defined step * + * @param string|null $date * @param int|array|null $step array of `unit` and `size` to round to nearest + * @return int|null */ - function timestamp( - string|null $date = null, - int|array|null $step = null - ): int|null { + function timestamp(?string $date = null, $step = null): ?int + { return Date::roundedTimestamp($date, $step); } } @@ -591,25 +634,50 @@ if (Helpers::hasOverride('tt') === false) { // @codeCoverageIgnore /** * Translate by key and then replace * placeholders in the text + * + * @param string $key + * @param string|array|null $fallback + * @param array|null $replace + * @param string|null $locale + * @return string */ - function tt( - string $key, - string|array|null $fallback = null, - array|null $replace = null, - string|null $locale = null - ): string { + function tt(string $key, $fallback = null, ?array $replace = null, ?string $locale = null): string + { return I18n::template($key, $fallback, $replace, $locale); } } +if (Helpers::hasOverride('twitter') === false) { // @codeCoverageIgnore + /** + * Builds a Twitter link + * + * @param string $username + * @param string|null $text + * @param string|null $title + * @param string|null $class + * @return string + */ + function twitter(string $username, ?string $text = null, ?string $title = null, ?string $class = null): string + { + return App::instance()->kirbytag([ + 'twitter' => $username, + 'text' => $text, + 'title' => $title, + 'class' => $class + ]); + } +} + if (Helpers::hasOverride('u') === false) { // @codeCoverageIgnore /** * Shortcut for url() + * + * @param string|null $path + * @param array|string|null $options + * @return string */ - function u( - string|null $path = null, - array|string|null $options = null - ): string { + function u(?string $path = null, $options = null): string + { return Url::to($path, $options); } } @@ -617,11 +685,13 @@ if (Helpers::hasOverride('u') === false) { // @codeCoverageIgnore if (Helpers::hasOverride('url') === false) { // @codeCoverageIgnore /** * Builds an absolute URL for a given path + * + * @param string|null $path + * @param array|string|null $options + * @return string */ - function url( - string|null $path = null, - array|string|null $options = null - ): string { + function url(?string $path = null, $options = null): string + { return Url::to($path, $options); } } @@ -629,6 +699,8 @@ if (Helpers::hasOverride('url') === false) { // @codeCoverageIgnore if (Helpers::hasOverride('uuid') === false) { // @codeCoverageIgnore /** * Creates a compliant v4 UUID + * + * @return string */ function uuid(): string { @@ -641,12 +713,14 @@ if (Helpers::hasOverride('video') === false) { // @codeCoverageIgnore * Creates a video embed via iframe for Youtube or Vimeo * videos. The embed Urls are automatically detected from * the given Url. + * + * @param string $url + * @param array $options + * @param array $attr + * @return string|null */ - function video( - string $url, - array $options = [], - array $attr = [] - ): string|null { + function video(string $url, array $options = [], array $attr = []): ?string + { return Html::video($url, $options, $attr); } } @@ -654,12 +728,14 @@ if (Helpers::hasOverride('video') === false) { // @codeCoverageIgnore if (Helpers::hasOverride('vimeo') === false) { // @codeCoverageIgnore /** * Embeds a Vimeo video by URL in an iframe + * + * @param string $url + * @param array $options + * @param array $attr + * @return string|null */ - function vimeo( - string $url, - array $options = [], - array $attr = [] - ): string|null { + function vimeo(string $url, array $options = [], array $attr = []): ?string + { return Html::vimeo($url, $options, $attr); } } @@ -669,8 +745,11 @@ if (Helpers::hasOverride('widont') === false) { // @codeCoverageIgnore * The widont function makes sure that there are no * typographical widows at the end of a paragraph – * that's a single word in the last line + * + * @param string|null $string + * @return string */ - function widont(string|null $string = null): string + function widont(string $string = null): string { return Str::widont($string); } @@ -679,12 +758,14 @@ if (Helpers::hasOverride('widont') === false) { // @codeCoverageIgnore if (Helpers::hasOverride('youtube') === false) { // @codeCoverageIgnore /** * Embeds a Youtube video by URL in an iframe + * + * @param string $url + * @param array $options + * @param array $attr + * @return string|null */ - function youtube( - string $url, - array $options = [], - array $attr = [] - ): string|null { + function youtube(string $url, array $options = [], array $attr = []): ?string + { return Html::youtube($url, $options, $attr); } } diff --git a/kirby/config/methods.php b/kirby/config/methods.php index 870c243..00209c0 100644 --- a/kirby/config/methods.php +++ b/kirby/config/methods.php @@ -2,29 +2,18 @@ use Kirby\Cms\App; use Kirby\Cms\Blocks; -use Kirby\Cms\File; +use Kirby\Cms\Field; use Kirby\Cms\Files; use Kirby\Cms\Html; use Kirby\Cms\Layouts; -use Kirby\Cms\Page; -use Kirby\Cms\Pages; use Kirby\Cms\Structure; use Kirby\Cms\Url; -use Kirby\Cms\User; -use Kirby\Cms\Users; -use Kirby\Content\Content; -use Kirby\Content\Field; use Kirby\Data\Data; use Kirby\Exception\Exception; use Kirby\Exception\InvalidArgumentException; -use Kirby\Exception\NotFoundException; -use Kirby\Image\QrCode; -use Kirby\Toolkit\A; -use Kirby\Toolkit\Dom; use Kirby\Toolkit\Str; use Kirby\Toolkit\V; use Kirby\Toolkit\Xml; -use Kirby\Uuid\Uuid; /** * Field method setup @@ -36,6 +25,9 @@ return function (App $app) { /** * Converts the field value into a proper boolean and inverts it + * + * @param \Kirby\Cms\Field $field + * @return bool */ 'isFalse' => function (Field $field): bool { return $field->toBool() === false; @@ -43,6 +35,9 @@ return function (App $app) { /** * Converts the field value into a proper boolean + * + * @param \Kirby\Cms\Field $field + * @return bool */ 'isTrue' => function (Field $field): bool { return $field->toBool() === true; @@ -51,33 +46,33 @@ return function (App $app) { /** * Validates the field content with the given validator and parameters * + * @param string $validator * @param mixed ...$arguments A list of optional validator arguments + * @return bool */ - 'isValid' => function ( - Field $field, - string $validator, - ...$arguments - ): bool { + 'isValid' => function (Field $field, string $validator, ...$arguments): bool { return V::$validator($field->value, ...$arguments); }, // converters /** * Converts a yaml or json field to a Blocks object + * + * @param \Kirby\Cms\Field $field + * @return \Kirby\Cms\Blocks */ - 'toBlocks' => function (Field $field): Blocks { + 'toBlocks' => function (Field $field) { try { - $blocks = Blocks::parse($field->value()); - $blocks = Blocks::factory($blocks, [ + $blocks = Blocks::factory(Blocks::parse($field->value()), [ 'parent' => $field->parent(), - 'field' => $field, ]); - return $blocks->filter('isHidden', false); - } catch (Throwable) { - $message = 'Invalid blocks data for "' . $field->key() . '" field'; - if ($parent = $field->parent()) { - $message .= ' on parent "' . $parent->title() . '"'; + return $blocks->filter('isHidden', false); + } catch (Throwable $e) { + if ($field->parent() === null) { + $message = 'Invalid blocks data for "' . $field->key() . '" field'; + } else { + $message = 'Invalid blocks data for "' . $field->key() . '" field on parent "' . $field->parent()->title() . '"'; } throw new InvalidArgumentException($message); @@ -87,9 +82,11 @@ return function (App $app) { /** * Converts the field value into a proper boolean * + * @param \Kirby\Cms\Field $field * @param bool $default Default value if the field is empty + * @return bool */ - 'toBool' => function (Field $field, bool $default = false): bool { + 'toBool' => function (Field $field, $default = false): bool { $value = $field->isEmpty() ? $default : $field->value; return filter_var($value, FILTER_VALIDATE_BOOLEAN); }, @@ -97,26 +94,29 @@ return function (App $app) { /** * Parses the field value with the given method * + * @param \Kirby\Cms\Field $field * @param string $method [',', 'yaml', 'json'] + * @return array */ - 'toData' => function (Field $field, string $method = ','): array { - return match ($method) { - 'yaml', 'json' => Data::decode($field->value, $method), - default => $field->split($method) - }; + 'toData' => function (Field $field, string $method = ',') { + switch ($method) { + case 'yaml': + case 'json': + return Data::decode($field->value, $method); + default: + return $field->split($method); + } }, /** * Converts the field value to a timestamp or a formatted date * + * @param \Kirby\Cms\Field $field * @param string|\IntlDateFormatter|null $format PHP date formatting string - * @param string|null $fallback Fallback string for `strtotime` + * @param string|null $fallback Fallback string for `strtotime` (since 3.2) + * @return string|int */ - 'toDate' => function ( - Field $field, - string|IntlDateFormatter|null $format = null, - string $fallback = null - ) use ($app): string|int|null { + 'toDate' => function (Field $field, $format = null, string $fallback = null) use ($app) { if (empty($field->value) === true && $fallback === null) { return null; } @@ -127,28 +127,33 @@ return function (App $app) { $time = strtotime($fallback); } - return Str::date($time, $format); + $handler = $app->option('date.handler', 'date'); + return Str::date($time, $format, $handler); }, /** * Returns a file object from a filename in the field + * + * @param \Kirby\Cms\Field $field + * @return \Kirby\Cms\File|null */ - 'toFile' => function (Field $field): File|null { + 'toFile' => function (Field $field) { return $field->toFiles()->first(); }, /** * Returns a file collection from a yaml list of filenames in the field + * + * @param \Kirby\Cms\Field $field + * @param string $separator + * @return \Kirby\Cms\Files */ - 'toFiles' => function ( - Field $field, - string $separator = 'yaml' - ): Files { + 'toFiles' => function (Field $field, string $separator = 'yaml') { $parent = $field->parent(); $files = new Files([]); foreach ($field->toData($separator) as $id) { - if (is_string($id) === true && $file = $parent->kirby()->file($id, $parent)) { + if ($file = $parent->kirby()->file($id, $parent)) { $files->add($file); } } @@ -159,9 +164,11 @@ return function (App $app) { /** * Converts the field value into a proper float * + * @param \Kirby\Cms\Field $field * @param float $default Default value if the field is empty + * @return float */ - 'toFloat' => function (Field $field, float $default = 0): float { + 'toFloat' => function (Field $field, float $default = 0) { $value = $field->isEmpty() ? $default : $field->value; return (float)$value; }, @@ -169,34 +176,37 @@ return function (App $app) { /** * Converts the field value into a proper integer * + * @param \Kirby\Cms\Field $field * @param int $default Default value if the field is empty + * @return int */ - 'toInt' => function (Field $field, int $default = 0): int { + 'toInt' => function (Field $field, int $default = 0) { $value = $field->isEmpty() ? $default : $field->value; return (int)$value; }, /** - * Parse layouts and turn them into Layout objects + * Parse layouts and turn them into + * Layout objects + * + * @param \Kirby\Cms\Field $field + * @return \Kirby\Cms\Layouts */ - 'toLayouts' => function (Field $field): Layouts { + 'toLayouts' => function (Field $field) { return Layouts::factory(Layouts::parse($field->value()), [ - 'parent' => $field->parent(), - 'field' => $field, + 'parent' => $field->parent() ]); }, /** * Wraps a link tag around the field value. The field value is used as the link text * + * @param \Kirby\Cms\Field $field * @param mixed $attr1 Can be an optional Url. If no Url is set, the Url of the Page, File or Site will be used. Can also be an array of link attributes * @param mixed $attr2 If `$attr1` is used to set the Url, you can use `$attr2` to pass an array of additional attributes. + * @return string */ - 'toLink' => function ( - Field $field, - string|array|null $attr1 = null, - array|null $attr2 = null - ): string { + 'toLink' => function (Field $field, $attr1 = null, $attr2 = null) { if (is_string($attr1) === true) { $href = $attr1; $attr = $attr2; @@ -212,58 +222,41 @@ return function (App $app) { return Html::a($href, $field->value, $attr ?? []); }, - /** - * Parse yaml data and convert it to a - * content object - */ - 'toObject' => function (Field $field): Content { - return new Content($field->yaml(), $field->parent(), true); - }, - /** * Returns a page object from a page id in the field + * + * @param \Kirby\Cms\Field $field + * @return \Kirby\Cms\Page|null */ - 'toPage' => function (Field $field): Page|null { + 'toPage' => function (Field $field) { return $field->toPages()->first(); }, /** * Returns a pages collection from a yaml list of page ids in the field * + * @param \Kirby\Cms\Field $field * @param string $separator Can be any other separator to split the field value by + * @return \Kirby\Cms\Pages */ - 'toPages' => function ( - Field $field, - string $separator = 'yaml' - ) use ($app): Pages { - return $app->site()->find( - false, - false, - ...$field->toData($separator) - ); - }, - - /** - * Turns the field value into an QR code object - */ - 'toQrCode' => function (Field $field): QrCode|null { - return $field->isNotEmpty() ? new QrCode($field->value) : null; + 'toPages' => function (Field $field, string $separator = 'yaml') use ($app) { + return $app->site()->find(false, false, ...$field->toData($separator)); }, /** * Converts a yaml field to a Structure object + * + * @param \Kirby\Cms\Field $field + * @return \Kirby\Cms\Structure */ - 'toStructure' => function (Field $field): Structure { + 'toStructure' => function (Field $field) { try { - return Structure::factory( - Data::decode($field->value, 'yaml'), - ['parent' => $field->parent(), 'field' => $field] - ); - } catch (Exception) { - $message = 'Invalid structure data for "' . $field->key() . '" field'; - - if ($parent = $field->parent()) { - $message .= ' on parent "' . $parent->id() . '"'; + return new Structure(Data::decode($field->value, 'yaml'), $field->parent()); + } catch (Exception $e) { + if ($field->parent() === null) { + $message = 'Invalid structure data for "' . $field->key() . '" field'; + } else { + $message = 'Invalid structure data for "' . $field->key() . '" field on parent "' . $field->parent()->title() . '"'; } throw new InvalidArgumentException($message); @@ -272,42 +265,43 @@ return function (App $app) { /** * Converts the field value to a Unix timestamp + * + * @param \Kirby\Cms\Field $field + * @return int */ - 'toTimestamp' => function (Field $field): int|false { - return strtotime($field->value ?? ''); + 'toTimestamp' => function (Field $field): int { + return strtotime($field->value); }, /** * Turns the field value into an absolute Url + * + * @param \Kirby\Cms\Field $field + * @return string */ - 'toUrl' => function (Field $field): string|null { - try { - return $field->isNotEmpty() ? Url::to($field->value) : null; - } catch (NotFoundException) { - return null; - } + 'toUrl' => function (Field $field): string { + return Url::to($field->value); }, /** * Converts a user email address to a user object + * + * @param \Kirby\Cms\Field $field + * @return \Kirby\Cms\User|null */ - 'toUser' => function (Field $field): User|null { + 'toUser' => function (Field $field) { return $field->toUsers()->first(); }, /** - * Returns a users collection from a yaml list - * of user email addresses in the field + * Returns a users collection from a yaml list of user email addresses in the field + * + * @param \Kirby\Cms\Field $field + * @param string $separator + * @return \Kirby\Cms\Users */ - 'toUsers' => function ( - Field $field, - string $separator = 'yaml' - ) use ($app): Users { - return $app->users()->find( - false, - false, - ...$field->toData($separator) - ); + 'toUsers' => function (Field $field, string $separator = 'yaml') use ($app) { + return $app->users()->find(false, false, ...$field->toData($separator)); }, // inspectors @@ -315,15 +309,15 @@ return function (App $app) { /** * Returns the length of the field content */ - 'length' => function (Field $field): int { + 'length' => function (Field $field) { return Str::length($field->value); }, /** * Returns the number of words in the text */ - 'words' => function (Field $field): int { - return str_word_count(strip_tags($field->value ?? '')); + 'words' => function (Field $field) { + return str_word_count(strip_tags($field->value)); }, // manipulators @@ -331,8 +325,11 @@ return function (App $app) { /** * Applies the callback function to the field * @since 3.4.0 + * + * @param \Kirby\Cms\Field $field + * @param Closure $callback */ - 'callback' => function (Field $field, Closure $callback): mixed { + 'callback' => function (Field $field, Closure $callback) { return $callback($field); }, @@ -340,36 +337,36 @@ return function (App $app) { * Escapes the field value to be safely used in HTML * templates without the risk of XSS attacks * + * @param \Kirby\Cms\Field $field * @param string $context Location of output (`html`, `attr`, `js`, `css`, `url` or `xml`) */ - 'escape' => function (Field $field, string $context = 'html'): Field { - $field->value = Str::esc($field->value ?? '', $context); + 'escape' => function (Field $field, string $context = 'html') { + $field->value = Str::esc($field->value, $context); return $field; }, /** * Creates an excerpt of the field value without html * or any other formatting. + * + * @param \Kirby\Cms\Field $field + * @param int $cahrs + * @param bool $strip + * @param string $rep + * @return \Kirby\Cms\Field */ - 'excerpt' => function ( - Field $field, - int $chars = 0, - bool $strip = true, - string $rep = ' …' - ): Field { - $field->value = Str::excerpt( - $field->kirbytext()->value(), - $chars, - $strip, - $rep - ); + 'excerpt' => function (Field $field, int $chars = 0, bool $strip = true, string $rep = ' …') { + $field->value = Str::excerpt($field->kirbytext()->value(), $chars, $strip, $rep); return $field; }, /** * Converts the field content to valid HTML + * + * @param \Kirby\Cms\Field $field + * @return \Kirby\Cms\Field */ - 'html' => function (Field $field): Field { + 'html' => function (Field $field) { $field->value = Html::encode($field->value); return $field; }, @@ -379,23 +376,27 @@ return function (App $app) { * it can be safely placed inside of other inline elements * without the risk of breaking the HTML structure. * @since 3.3.0 + * + * @param \Kirby\Cms\Field $field + * @return \Kirby\Cms\Field */ - 'inline' => function (Field $field): Field { + 'inline' => function (Field $field) { // List of valid inline elements taken from: https://developer.mozilla.org/de/docs/Web/HTML/Inline_elemente // Obsolete elements, script tags, image maps and form elements have // been excluded for safety reasons and as they are most likely not // needed in most cases. - $field->value = strip_tags($field->value ?? '', Html::$inlineList); + $field->value = strip_tags($field->value, Html::$inlineList); return $field; }, /** * Converts the field content from Markdown/Kirbytext to valid HTML + * + * @param \Kirby\Cms\Field $field + * @param array $options + * @return \Kirby\Cms\Field */ - 'kirbytext' => function ( - Field $field, - array $options = [] - ) use ($app): Field { + 'kirbytext' => function (Field $field, array $options = []) use ($app) { $field->value = $app->kirbytext($field->value, A::merge($options, [ 'parent' => $field->parent(), 'field' => $field @@ -408,11 +409,12 @@ return function (App $app) { * Converts the field content from inline Markdown/Kirbytext * to valid HTML * @since 3.1.0 + * + * @param \Kirby\Cms\Field $field + * @param array $options + * @return \Kirby\Cms\Field */ - 'kirbytextinline' => function ( - Field $field, - array $options = [] - ) use ($app): Field { + 'kirbytextinline' => function (Field $field, array $options = []) use ($app) { $field->value = $app->kirbytext($field->value, A::merge($options, [ 'parent' => $field->parent(), 'field' => $field, @@ -426,8 +428,11 @@ return function (App $app) { /** * Parses all KirbyTags without also parsing Markdown + * + * @param \Kirby\Cms\Field $field + * @return \Kirby\Cms\Field */ - 'kirbytags' => function (Field $field) use ($app): Field { + 'kirbytags' => function (Field $field) use ($app) { $field->value = $app->kirbytags($field->value, [ 'parent' => $field->parent(), 'field' => $field @@ -438,19 +443,23 @@ return function (App $app) { /** * Converts the field content to lowercase + * + * @param \Kirby\Cms\Field $field + * @return \Kirby\Cms\Field */ - 'lower' => function (Field $field): Field { + 'lower' => function (Field $field) { $field->value = Str::lower($field->value); return $field; }, /** * Converts markdown to valid HTML + * + * @param \Kirby\Cms\Field $field + * @param array $options + * @return \Kirby\Cms\Field */ - 'markdown' => function ( - Field $field, - array $options = [] - ) use ($app): Field { + 'markdown' => function (Field $field, array $options = []) use ($app) { $field->value = $app->markdown($field->value, $options); return $field; }, @@ -458,54 +467,23 @@ return function (App $app) { /** * Converts all line breaks in the field content to `
` tags. * @since 3.3.0 - */ - 'nl2br' => function (Field $field): Field { - $field->value = nl2br($field->value ?? '', false); - return $field; - }, - - /** - * Parses the field value as DOM and replaces - * any permalinks in href/src attributes with - * the regular url * - * This method is still experimental! You can use - * it to solve potential problems with permalinks - * already, but it might change in the future. + * @param \Kirby\Cms\Field $field + * @return \Kirby\Cms\Field */ - 'permalinksToUrls' => function (Field $field): Field { - if ($field->isNotEmpty() === true) { - $dom = new Dom($field->value); - $attributes = ['href', 'src']; - $elements = $dom->query('//*[' . implode(' | ', A::map($attributes, fn ($attribute) => '@' . $attribute)) . ']'); - - foreach ($elements as $element) { - foreach ($attributes as $attribute) { - if ($element->hasAttribute($attribute) && $uuid = $element->getAttribute($attribute)) { - try { - if ($url = Uuid::for($uuid)?->model()?->url()) { - $element->setAttribute($attribute, $url); - } - } catch (InvalidArgumentException) { - // ignore anything else than permalinks - } - } - } - } - - $field->value = $dom->toString(); - } - + 'nl2br' => function (Field $field) { + $field->value = nl2br($field->value, false); return $field; }, /** * Uses the field value as Kirby query + * + * @param \Kirby\Cms\Field $field + * @param string|null $expect + * @return mixed */ - 'query' => function ( - Field $field, - string $expect = null - ) use ($app): mixed { + 'query' => function (Field $field, string $expect = null) use ($app) { if ($parent = $field->parent()) { return $parent->query($field->value, $expect); } @@ -520,13 +498,12 @@ return function (App $app) { /** * It parses any queries found in the field value. * - * @param string|null $fallback Fallback for tokens in the template that cannot be replaced (`null` to keep the original token) + * @param \Kirby\Cms\Field $field + * @param array $data + * @param string $fallback Fallback for tokens in the template that cannot be replaced + * @return \Kirby\Cms\Field */ - 'replace' => function ( - Field $field, - array $data = [], - string|null $fallback = '' - ) use ($app): Field { + 'replace' => function (Field $field, array $data = [], string $fallback = '') use ($app) { if ($parent = $field->parent()) { // never pass `null` as the $template to avoid the fallback to the model ID $field->value = $parent->toString($field->value ?? '', $data, $fallback); @@ -545,45 +522,55 @@ return function (App $app) { * Cuts the string after the given length and * adds "…" if it is longer * + * @param \Kirby\Cms\Field $field * @param int $length The number of characters in the string * @param string $appendix An optional replacement for the missing rest + * @return \Kirby\Cms\Field */ - 'short' => function ( - Field $field, - int $length, - string $appendix = '…' - ): Field { + 'short' => function (Field $field, int $length, string $appendix = '…') { $field->value = Str::short($field->value, $length, $appendix); return $field; }, /** * Converts the field content to a slug + * + * @param \Kirby\Cms\Field $field + * @return \Kirby\Cms\Field */ - 'slug' => function (Field $field): Field { + 'slug' => function (Field $field) { $field->value = Str::slug($field->value); return $field; }, /** * Applies SmartyPants to the field + * + * @param \Kirby\Cms\Field $field + * @return \Kirby\Cms\Field */ - 'smartypants' => function (Field $field) use ($app): Field { + 'smartypants' => function (Field $field) use ($app) { $field->value = $app->smartypants($field->value); return $field; }, /** * Splits the field content into an array + * + * @param \Kirby\Cms\Field $field + * @return array */ - 'split' => function (Field $field, $separator = ','): array { + 'split' => function (Field $field, $separator = ',') { return Str::split((string)$field->value, $separator); }, /** * Converts the field content to uppercase + * + * @param \Kirby\Cms\Field $field + * @return \Kirby\Cms\Field */ - 'upper' => function (Field $field): Field { + 'upper' => function (Field $field) { $field->value = Str::upper($field->value); return $field; }, @@ -591,16 +578,22 @@ return function (App $app) { /** * Avoids typographical widows in strings by replacing * the last space with ` ` + * + * @param \Kirby\Cms\Field $field + * @return \Kirby\Cms\Field */ - 'widont' => function (Field $field): Field { + 'widont' => function (Field $field) { $field->value = Str::widont($field->value); return $field; }, /** * Converts the field content to valid XML + * + * @param \Kirby\Cms\Field $field + * @return \Kirby\Cms\Field */ - 'xml' => function (Field $field): Field { + 'xml' => function (Field $field) { $field->value = Xml::encode($field->value); return $field; }, @@ -609,6 +602,9 @@ return function (App $app) { /** * Parses yaml in the field content and returns an array + * + * @param \Kirby\Cms\Field $field + * @return array */ 'yaml' => function (Field $field): array { return $field->toData('yaml'); diff --git a/kirby/config/presets/files.php b/kirby/config/presets/files.php index aefc535..c5cea1d 100644 --- a/kirby/config/presets/files.php +++ b/kirby/config/presets/files.php @@ -5,7 +5,7 @@ use Kirby\Toolkit\I18n; return function (array $props) { $props['sections'] = [ 'files' => [ - 'label' => $props['label'] ?? $props['headline'] ?? I18n::translate('files'), + 'headline' => $props['headline'] ?? I18n::translate('files'), 'type' => 'files', 'layout' => $props['layout'] ?? 'cards', 'template' => $props['template'] ?? null, @@ -17,7 +17,6 @@ return function (array $props) { // remove global options unset( $props['headline'], - $props['label'], $props['layout'], $props['template'], $props['image'] diff --git a/kirby/config/presets/page.php b/kirby/config/presets/page.php index a2102ef..fa0e6e6 100644 --- a/kirby/config/presets/page.php +++ b/kirby/config/presets/page.php @@ -10,7 +10,7 @@ return function ($props) { if (is_string($props) === true) { $props = [ - 'label' => $props + 'headline' => $props ]; } @@ -27,24 +27,24 @@ return function ($props) { if ($pages !== false) { $sidebar['pages'] = $section([ - 'label' => I18n::translate('pages'), - 'type' => 'pages', - 'status' => 'all', - 'layout' => 'list', + 'headline' => I18n::translate('pages'), + 'type' => 'pages', + 'status' => 'all', + 'layout' => 'list', ], $pages); } if ($files !== false) { $sidebar['files'] = $section([ - 'label' => I18n::translate('files'), - 'type' => 'files', - 'layout' => 'list' + 'headline' => I18n::translate('files'), + 'type' => 'files', + 'layout' => 'list' ], $files); } } if (empty($sidebar) === true) { - $props['fields'] ??= []; + $props['fields'] = $props['fields'] ?? []; unset( $props['files'], diff --git a/kirby/config/presets/pages.php b/kirby/config/presets/pages.php index a2c7714..8a3e51f 100644 --- a/kirby/config/presets/pages.php +++ b/kirby/config/presets/pages.php @@ -6,12 +6,12 @@ return function (array $props) { // load the general templates setting for all sections $templates = $props['templates'] ?? null; - $section = function ($label, $status, $props) use ($templates) { + $section = function ($headline, $status, $props) use ($templates) { $defaults = [ - 'label' => $label, - 'type' => 'pages', - 'layout' => 'list', - 'status' => $status + 'headline' => $headline, + 'type' => 'pages', + 'layout' => 'list', + 'status' => $status ]; if ($props === true) { @@ -20,13 +20,13 @@ return function (array $props) { if (is_string($props) === true) { $props = [ - 'label' => $props + 'headline' => $props ]; } // inject the global templates definition if (empty($templates) === false) { - $props['templates'] ??= $templates; + $props['templates'] = $props['templates'] ?? $templates; } return array_replace_recursive($defaults, $props); diff --git a/kirby/config/routes.php b/kirby/config/routes.php index cd7924d..3168dd3 100644 --- a/kirby/config/routes.php +++ b/kirby/config/routes.php @@ -1,15 +1,13 @@ option('api.slug', 'api'); $panel = $kirby->option('panel.slug', 'panel'); $index = $kirby->url('index'); @@ -33,7 +31,7 @@ return function (App $kirby) { 'pattern' => $api . '/(:all)', 'method' => 'ALL', 'env' => 'api', - 'action' => function (string $path = null) use ($kirby) { + 'action' => function ($path = null) use ($kirby) { if ($kirby->option('api') === false) { return null; } @@ -61,63 +59,37 @@ return function (App $kirby) { } ], [ - // TODO: change to '/plugins/(:any)/(:any)/(:any)/(:all)' once - // the hash is made mandatory - 'pattern' => $media . '/plugins/(:any)/(:any)/(?:(:any)/)?(:all)', + 'pattern' => $media . '/plugins/(:any)/(:any)/(:all).(css|map|gif|js|mjs|jpg|png|svg|webp|avif|woff2|woff|json)', 'env' => 'media', - 'action' => function ( - string $provider, - string $pluginName, - string $hash, - string $path - ) { - return PluginAssets::resolve( - $provider . '/' . $pluginName, - $hash, - $path - ); + 'action' => function (string $provider, string $pluginName, string $filename, string $extension) { + return PluginAssets::resolve($provider . '/' . $pluginName, $filename . '.' . $extension); } ], [ 'pattern' => $media . '/pages/(:all)/(:any)/(:any)', 'env' => 'media', - 'action' => function ( - string $path, - string $hash, - string $filename - ) use ($kirby) { + 'action' => function ($path, $hash, $filename) use ($kirby) { return Media::link($kirby->page($path), $hash, $filename); } ], [ 'pattern' => $media . '/site/(:any)/(:any)', 'env' => 'media', - 'action' => function ( - string $hash, - string $filename - ) use ($kirby) { + 'action' => function ($hash, $filename) use ($kirby) { return Media::link($kirby->site(), $hash, $filename); } ], [ 'pattern' => $media . '/users/(:any)/(:any)/(:any)', 'env' => 'media', - 'action' => function ( - string $id, - string $hash, - string $filename - ) use ($kirby) { + 'action' => function ($id, $hash, $filename) use ($kirby) { return Media::link($kirby->user($id), $hash, $filename); } ], [ 'pattern' => $media . '/assets/(:all)/(:any)/(:any)', 'env' => 'media', - 'action' => function ( - string $path, - string $hash, - string $filename - ) { + 'action' => function ($path, $hash, $filename) { return Media::thumb($path, $hash, $filename); } ], @@ -125,30 +97,10 @@ return function (App $kirby) { 'pattern' => $panel . '/(:all?)', 'method' => 'ALL', 'env' => 'panel', - 'action' => function (string $path = null) { + 'action' => function ($path = null) { return Panel::router($path); } ], - // permalinks for page/file UUIDs - [ - 'pattern' => '@/(page|file)/(:all)', - 'method' => 'ALL', - 'env' => 'site', - 'action' => function (string $type, string $id) use ($kirby) { - // try to resolve to model, but only from UUID cache; - // this ensures that only existing UUIDs can be queried - // and attackers can't force Kirby to go through the whole - // site index with a non-existing UUID - if ($model = Uuid::for($type . '://' . $id)?->model(true)) { - return $kirby - ->response() - ->redirect($model->url()); - } - - // render the error page - return false; - } - ], ]; // Multi-language setup diff --git a/kirby/config/sections/fields.php b/kirby/config/sections/fields.php index 7eb79ba..38565e5 100644 --- a/kirby/config/sections/fields.php +++ b/kirby/config/sections/fields.php @@ -1,7 +1,5 @@ function () { $fields = $this->form->fields()->toArray(); - if ( - $this->model instanceof Page || - $this->model instanceof Site - ) { + if (is_a($this->model, 'Kirby\Cms\Page') === true || is_a($this->model, 'Kirby\Cms\Site') === true) { // the title should never be updated directly via // fields section to avoid conflicts with the rename dialog unset($fields['title']); diff --git a/kirby/config/sections/files.php b/kirby/config/sections/files.php index bb8532f..eeb5347 100644 --- a/kirby/config/sections/files.php +++ b/kirby/config/sections/files.php @@ -1,7 +1,6 @@ [ - /** - * Filters pages by a query. Sorting will be disabled - */ - 'query' => function (string|null $query = null) { - return $query; - }, /** * Filters all files by template and also sets the template, which will be used for all uploads */ @@ -47,7 +40,7 @@ return [ 'template' => $this->template ]); - return $file->blueprint()->acceptAttribute(); + return $file->blueprint()->acceptMime(); } return null; @@ -55,27 +48,15 @@ return [ 'parent' => function () { return $this->parentModel(); }, - 'models' => function () { - if ($this->query !== null) { - $files = $this->parent->query($this->query, Files::class) ?? new Files([]); - } else { - $files = $this->parent->files(); - } + 'files' => function () { + $files = $this->parent->files()->template($this->template); - // filter files by template - $files = $files->template($this->template); - - // filter out all protected and hidden files - $files = $files->filter('isListable', true); + // filter out all protected files + $files = $files->filter('isReadable', true); // search if ($this->search === true && empty($this->searchterm()) === false) { $files = $files->search($this->searchterm()); - - // disable flip and sortBy while searching - // to show most relevant results - $this->flip = false; - $this->sortBy = null; } // sort @@ -99,9 +80,6 @@ return [ return $files; }, - 'files' => function () { - return $this->models; - }, 'data' => function () { $data = []; @@ -109,7 +87,7 @@ return [ // a different parent model $dragTextAbsolute = $this->model->is($this->parent) === false; - foreach ($this->models as $file) { + foreach ($this->files as $file) { $panel = $file->panel(); $item = [ @@ -140,7 +118,7 @@ return [ return $data; }, 'total' => function () { - return $this->models->pagination()->total(); + return $this->files->pagination()->total(); }, 'errors' => function () { $errors = []; @@ -179,9 +157,10 @@ return [ } // count all uploaded files - $max = $this->max ? $this->max - $this->total : null; + $total = count($this->data); + $max = $this->max ? $this->max - $total : null; - if ($this->max && $this->total === $this->max - 1) { + if ($this->max && $total === $this->max - 1) { $multiple = false; } else { $multiple = true; @@ -194,43 +173,21 @@ return [ 'multiple' => $multiple, 'max' => $max, 'api' => $this->parent->apiUrl(true) . '/files', - 'attributes' => [ - // TODO: an edge issue that needs to be solved: - // if multiple users load the same section - // at the same time and upload a file, - // uploaded files have the same sort number - 'sort' => $this->sortable === true ? $this->total + 1 : null, + 'attributes' => array_filter([ + 'sort' => $this->sortable === true ? $total + 1 : null, 'template' => $template - ] + ]) ]; } ], - // @codeCoverageIgnoreStart - 'api' => function () { - return [ - [ - 'pattern' => 'sort', - 'method' => 'PATCH', - 'action' => function () { - $this->section()->model()->files()->changeSort( - $this->requestBody('files'), - $this->requestBody('index') - ); - - return true; - } - ] - ]; - }, - // @codeCoverageIgnoreEnd 'toArray' => function () { return [ 'data' => $this->data, 'errors' => $this->errors, 'options' => [ 'accept' => $this->accept, - 'apiUrl' => $this->parent->apiUrl(true) . '/sections/' . $this->name, - 'columns' => $this->columnsWithTypes(), + 'apiUrl' => $this->parent->apiUrl(true), + 'columns' => $this->columns, 'empty' => $this->empty, 'headline' => $this->headline, 'help' => $this->help, diff --git a/kirby/config/sections/info.php b/kirby/config/sections/info.php index 7999aac..e348bd4 100644 --- a/kirby/config/sections/info.php +++ b/kirby/config/sections/info.php @@ -7,9 +7,6 @@ return [ 'headline', ], 'props' => [ - 'icon' => function (string $icon = null) { - return $icon; - }, 'text' => function ($text = null) { return I18n::translate($text, $text); }, @@ -28,10 +25,9 @@ return [ ], 'toArray' => function () { return [ - 'icon' => $this->icon, - 'label' => $this->headline, - 'text' => $this->text, - 'theme' => $this->theme + 'headline' => $this->headline, + 'text' => $this->text, + 'theme' => $this->theme ]; } ]; diff --git a/kirby/config/sections/mixins/headline.php b/kirby/config/sections/mixins/headline.php index ebc2bb7..df323c6 100644 --- a/kirby/config/sections/mixins/headline.php +++ b/kirby/config/sections/mixins/headline.php @@ -1,14 +1,20 @@ [ /** * The headline for the section. This can be a simple string or a template with additional info from the parent page. - * @deprecated 3.8.0 Use `label` instead + * @todo remove in 3.9.0 */ 'headline' => function ($headline = null) { + // TODO: add deprecation notive in 3.8.0 + // if ($headline !== null) { + // Helpers::deprecated('`headline` prop for sections has been deprecated and will be removed in Kirby 3.9.0. Use `label` instead.'); + // } + return I18n::translate($headline, $headline); }, /** @@ -22,14 +28,14 @@ return [ ], 'computed' => [ 'headline' => function () { - if ($this->label) { - return $this->model()->toString($this->label); - } - if ($this->headline) { return $this->model()->toString($this->headline); } + if ($this->label) { + return $this->model()->toString($this->label); + } + return ucfirst($this->name); } ] diff --git a/kirby/config/sections/mixins/layout.php b/kirby/config/sections/mixins/layout.php index 150498f..d362a7c 100644 --- a/kirby/config/sections/mixins/layout.php +++ b/kirby/config/sections/mixins/layout.php @@ -1,7 +1,5 @@ function (string $size = 'auto') { return $size; @@ -30,7 +28,7 @@ return [ ], 'computed' => [ 'columns' => function () { - $columns = []; + $columns = []; if ($this->layout !== 'table') { return []; @@ -78,12 +76,9 @@ return [ // keep the original column name as id $column['id'] = $columnName; - // add the custom column to the array - // allowing to extend/overwrite existing columns - $columns[$columnName] = [ - ...$columns[$columnName] ?? [], - ...$column - ]; + // add the custom column to the array with a key that won't + // override the system columns + $columns[$columnName . 'Cell'] = $column; } if ($this->type === 'pages') { @@ -99,27 +94,7 @@ return [ }, ], 'methods' => [ - 'columnsWithTypes' => function () { - $columns = $this->columns; - - // add the type to the columns for the table layout - if ($this->layout === 'table') { - $blueprint = $this->models->first()?->blueprint(); - - if ($blueprint === null) { - return $columns; - } - - foreach ($columns as $columnName => $column) { - if ($id = $column['id'] ?? null) { - $columns[$columnName]['type'] ??= $blueprint->field($id)['type'] ?? null; - } - } - } - - return $columns; - }, - 'columnsValues' => function (array $item, ModelWithContent $model) { + 'columnsValues' => function (array $item, $model) { $item['title'] = [ // override toSafeString() coming from `$item` // because the table cells don't use v-html @@ -133,20 +108,19 @@ return [ $item['info'] = $model->toString($this->info); } - // Use form to get the proper values for the columns - $form = Form::for($model)->values(); - foreach ($this->columns as $columnName => $column) { - $item[$columnName] = match (empty($column['value'])) { - // if column value defined, resolve the query - false => $model->toString($column['value']), - // otherwise use the form value, - // but don't overwrite columns - default => - $item[$columnName] ?? - $form[$column['id'] ?? $columnName] ?? - null, - }; + // don't overwrite essential columns + if (isset($item[$columnName]) === true) { + continue; + } + + if (empty($column['value']) === false) { + $value = $model->toString($column['value']); + } else { + $value = $model->content()->get($column['id'] ?? $columnName)->value(); + } + + $item[$columnName] = $value; } return $item; diff --git a/kirby/config/sections/mixins/parent.php b/kirby/config/sections/mixins/parent.php index 1096930..2df8425 100644 --- a/kirby/config/sections/mixins/parent.php +++ b/kirby/config/sections/mixins/parent.php @@ -1,9 +1,5 @@ name() . '" has to be a page, site or user object'); } diff --git a/kirby/config/sections/mixins/search.php b/kirby/config/sections/mixins/search.php index 0791152..a50a375 100644 --- a/kirby/config/sections/mixins/search.php +++ b/kirby/config/sections/mixins/search.php @@ -12,7 +12,7 @@ return [ } ], 'methods' => [ - 'searchterm' => function (): string|null { + 'searchterm' => function (): ?string { return App::instance()->request()->get('searchterm'); } ] diff --git a/kirby/config/sections/mixins/sort.php b/kirby/config/sections/mixins/sort.php index 5b994ec..4387bae 100644 --- a/kirby/config/sections/mixins/sort.php +++ b/kirby/config/sections/mixins/sort.php @@ -39,10 +39,6 @@ return [ return false; } - if ($this->query !== null) { - return false; - } - if ($this->sortBy !== null) { return false; } diff --git a/kirby/config/sections/pages.php b/kirby/config/sections/pages.php index 7f142ae..35f666e 100644 --- a/kirby/config/sections/pages.php +++ b/kirby/config/sections/pages.php @@ -1,9 +1,6 @@ function ($create = null) { return $create; }, - /** - * Filters pages by a query. Sorting will be disabled - */ - 'query' => function (string|null $query = null) { - return $query; - }, /** * Filters pages by their status. Available status settings: `draft`, `unlisted`, `listed`, `published`, `all`. */ @@ -50,23 +41,11 @@ return [ return $status; }, - /** - * Filters the list by single template. - */ - 'template' => function (string|array $template = null) { - return $template; - }, /** * Filters the list by templates and sets template options when adding new pages to the section. */ 'templates' => function ($templates = null) { return A::wrap($templates ?? $this->template); - }, - /** - * Excludes the selected templates. - */ - 'templatesIgnore' => function ($templates = null) { - return A::wrap($templates); } ], 'computed' => [ @@ -74,25 +53,30 @@ return [ $parent = $this->parentModel(); if ( - $parent instanceof Site === false && - $parent instanceof Page === false + is_a($parent, 'Kirby\Cms\Site') === false && + is_a($parent, 'Kirby\Cms\Page') === false ) { throw new InvalidArgumentException('The parent is invalid. You must choose the site or a page as parent.'); } return $parent; }, - 'models' => function () { - if ($this->query !== null) { - $pages = $this->parent->query($this->query, Pages::class) ?? new Pages([]); - } else { - $pages = match ($this->status) { - 'draft' => $this->parent->drafts(), - 'listed' => $this->parent->children()->listed(), - 'published' => $this->parent->children(), - 'unlisted' => $this->parent->children()->unlisted(), - default => $this->parent->childrenAndDrafts() - }; + 'pages' => function () { + switch ($this->status) { + case 'draft': + $pages = $this->parent->drafts(); + break; + case 'listed': + $pages = $this->parent->children()->listed(); + break; + case 'published': + $pages = $this->parent->children(); + break; + case 'unlisted': + $pages = $this->parent->children()->unlisted(); + break; + default: + $pages = $this->parent->childrenAndDrafts(); } // filters pages that are protected and not in the templates list @@ -101,26 +85,13 @@ return [ // also it has been tested that there is no performance difference // even in 0.1 seconds on 100k virtual pages $pages = $pages->filter(function ($page) { - // remove all protected and hidden pages - if ($page->isListable() === false) { + // remove all protected pages + if ($page->isReadable() === false) { return false; } - $intendedTemplate = $page->intendedTemplate()->name(); - // filter by all set templates - if ( - $this->templates && - in_array($intendedTemplate, $this->templates) === false - ) { - return false; - } - - // exclude by all ignored templates - if ( - $this->templatesIgnore && - in_array($intendedTemplate, $this->templatesIgnore) === true - ) { + if ($this->templates && in_array($page->intendedTemplate()->name(), $this->templates) === false) { return false; } @@ -130,11 +101,6 @@ return [ // search if ($this->search === true && empty($this->searchterm()) === false) { $pages = $pages->search($this->searchterm()); - - // disable flip and sortBy while searching - // to show most relevant results - $this->flip = false; - $this->sortBy = null; } // sort @@ -156,16 +122,13 @@ return [ return $pages; }, - 'pages' => function () { - return $this->models; - }, 'total' => function () { - return $this->models->pagination()->total(); + return $this->pages->pagination()->total(); }, 'data' => function () { $data = []; - foreach ($this->models as $page) { + foreach ($this->pages as $page) { $panel = $page->panel(); $permissions = $page->permissions(); @@ -232,39 +195,11 @@ return [ return false; } - if ($this->isFull() === true) { + if (in_array($this->status, ['draft', 'all']) === false) { return false; } - // form here on, we need to check with which status - // the pages are created and if the section can show - // these newly created pages - - // if the section shows pages no matter what status they have, - // we can always show the add button - if ($this->status === 'all') { - return true; - } - - // collect all statuses of the blueprints - // that are allowed to be created - $statuses = []; - - foreach ($this->blueprintNames() as $blueprint) { - try { - $props = Blueprint::load('pages/' . $blueprint); - $statuses[] = $props['create']['status'] ?? 'draft'; - } catch (Throwable) { - $statuses[] = 'draft'; // @codeCoverageIgnore - } - } - - $statuses = array_unique($statuses); - - // if there are multiple statuses or if the section is showing - // a different status than new pages would be created with, - // we cannot show the add button - if (count($statuses) > 1 || $this->status !== $statuses[0]) { + if ($this->isFull() === true) { return false; } @@ -277,41 +212,32 @@ return [ 'methods' => [ 'blueprints' => function () { $blueprints = []; + $templates = empty($this->create) === false ? A::wrap($this->create) : $this->templates; + + if (empty($templates) === true) { + $templates = $this->kirby()->blueprints(); + } // convert every template to a usable option array // for the template select box - foreach ($this->blueprintNames() as $blueprint) { + foreach ($templates as $template) { try { - $props = Blueprint::load('pages/' . $blueprint); + $props = Blueprint::load('pages/' . $template); $blueprints[] = [ 'name' => basename($props['name']), 'title' => $props['title'], ]; - } catch (Throwable) { + } catch (Throwable $e) { $blueprints[] = [ - 'name' => basename($blueprint), - 'title' => ucfirst($blueprint), + 'name' => basename($template), + 'title' => ucfirst($template), ]; } } return $blueprints; - }, - 'blueprintNames' => function () { - $blueprints = empty($this->create) === false ? A::wrap($this->create) : $this->templates; - - if (empty($blueprints) === true) { - $blueprints = $this->kirby()->blueprints(); - } - - // excludes ignored templates - if ($templatesIgnore = $this->templatesIgnore) { - $blueprints = array_diff($blueprints, $templatesIgnore); - } - - return $blueprints; - }, + } ], 'toArray' => function () { return [ @@ -319,7 +245,7 @@ return [ 'errors' => $this->errors, 'options' => [ 'add' => $this->add, - 'columns' => $this->columnsWithTypes(), + 'columns' => $this->columns, 'empty' => $this->empty, 'headline' => $this->headline, 'help' => $this->help, diff --git a/kirby/config/sections/stats.php b/kirby/config/sections/stats.php index 86efe96..e04755b 100644 --- a/kirby/config/sections/stats.php +++ b/kirby/config/sections/stats.php @@ -8,7 +8,7 @@ return [ ], 'props' => [ /** - * Array or query string for reports. Each report needs a `label` and `value` and can have additional `info`, `link`, `icon` and `theme` settings. + * Array or query string for reports. Each report needs a `label` and `value` and can have additional `info`, `link` and `theme` settings. */ 'reports' => function ($reports = null) { if ($reports === null) { @@ -34,9 +34,9 @@ return [ ], 'computed' => [ 'reports' => function () { - $reports = []; - $model = $this->model(); - $toString = fn ($value) => $value === null ? null : $model->toString($value); + $reports = []; + $model = $this->model(); + $value = fn ($value) => $value === null ? null : $model->toString($value); foreach ($this->reports as $report) { if (is_string($report) === true) { @@ -47,18 +47,12 @@ return [ continue; } - $info = $report['info'] ?? null; - $label = $report['label'] ?? null; - $link = $report['link'] ?? null; - $value = $report['value'] ?? null; - $reports[] = [ - 'icon' => $toString($report['icon'] ?? null), - 'info' => $toString(I18n::translate($info, $info)), - 'label' => $toString(I18n::translate($label, $label)), - 'link' => $toString(I18n::translate($link, $link)), - 'theme' => $toString($report['theme'] ?? null), - 'value' => $toString(I18n::translate($value, $value)) + 'label' => I18n::translate($report['label'], $report['label']), + 'value' => $value($report['value'] ?? null), + 'info' => $value($report['info'] ?? null), + 'link' => $value($report['link'] ?? null), + 'theme' => $value($report['theme'] ?? null) ]; } diff --git a/kirby/config/setup.php b/kirby/config/setup.php index 09b73bb..853b54b 100644 --- a/kirby/config/setup.php +++ b/kirby/config/setup.php @@ -1,5 +1,10 @@ [ 'attr' => [], - 'html' => function (KirbyTag $tag): string { - if (strtolower($tag->date) === 'year') { - return date('Y'); - } - - return date($tag->date); + 'html' => function ($tag) { + return strtolower($tag->date) === 'year' ? date('Y') : date($tag->date); } ], @@ -38,7 +30,7 @@ return [ 'text', 'title' ], - 'html' => function (KirbyTag $tag): string { + 'html' => function ($tag) { return Html::email($tag->value, $tag->text, [ 'class' => $tag->class, 'rel' => $tag->rel, @@ -60,9 +52,9 @@ return [ 'text', 'title' ], - 'html' => function (KirbyTag $tag): string { + 'html' => function ($tag) { if (!$file = $tag->file($tag->value)) { - return $tag->text ?? $tag->value; + return $tag->text; } // use filename if the text is empty and make sure to @@ -88,7 +80,7 @@ return [ 'attr' => [ 'file' ], - 'html' => function (KirbyTag $tag): string { + 'html' => function ($tag) { return Html::gist($tag->value, $tag->file); } ], @@ -106,29 +98,16 @@ return [ 'link', 'linkclass', 'rel', - 'srcset', 'target', 'title', 'width' ], - 'html' => function (KirbyTag $tag): string { + 'html' => function ($tag) { if ($tag->file = $tag->file($tag->value)) { - $tag->src = $tag->file->url(); - $tag->alt ??= $tag->file->alt()->or('')->value(); - $tag->title ??= $tag->file->title()->value(); - $tag->caption ??= $tag->file->caption()->value(); - - if ($srcset = $tag->srcset) { - $srcset = Str::split($srcset); - $srcset = match (count($srcset) > 1) { - // comma-separated list of sizes - true => A::map($srcset, fn ($size) => (int)trim($size)), - // srcset config name - default => $srcset[0] - }; - - $tag->srcset = $tag->file->srcset($srcset); - } + $tag->src = $tag->file->url(); + $tag->alt = $tag->alt ?? $tag->file->alt()->or(' ')->value(); + $tag->title = $tag->title ?? $tag->file->title()->value(); + $tag->caption = $tag->caption ?? $tag->file->caption()->value(); } else { $tag->src = Url::to($tag->value); } @@ -138,8 +117,11 @@ return [ return $img; } - $link = $tag->file($tag->link)?->url(); - $link ??= $tag->link === 'self' ? $tag->src : $tag->link; + if ($link = $tag->file($tag->link)) { + $link = $link->url(); + } else { + $link = $tag->link === 'self' ? $tag->src : $tag->link; + } return Html::a($link, [$img], [ 'rel' => $tag->rel, @@ -149,12 +131,11 @@ return [ }; $image = Html::img($tag->src, [ - 'srcset' => $tag->srcset, 'width' => $tag->width, 'height' => $tag->height, 'class' => $tag->imgclass, 'title' => $tag->title, - 'alt' => $tag->alt ?? '' + 'alt' => $tag->alt ?? ' ' ]); if ($tag->kirby()->option('kirbytext.image.figure', true) === false) { @@ -168,7 +149,7 @@ return [ $tag->caption = [$caption]; } - return Html::figure([$link($image)], $tag->caption, [ + return Html::figure([ $link($image) ], $tag->caption, [ 'class' => $tag->class ]); } @@ -187,33 +168,11 @@ return [ 'title', 'text', ], - 'html' => function (KirbyTag $tag): string { + 'html' => function ($tag) { if (empty($tag->lang) === false) { $tag->value = Url::to($tag->value, $tag->lang); } - // if value is a UUID, resolve to page/file model - // and use the URL as value - if ( - Uuid::is($tag->value, 'page') === true || - Uuid::is($tag->value, 'file') === true - ) { - $tag->value = Uuid::for($tag->value)->model()?->url(); - } - - // if url is empty, throw exception or link to the error page - if ($tag->value === null) { - if ($tag->kirby()->option('debug', false) === true) { - if (empty($tag->text) === false) { - throw new NotFoundException('The linked page cannot be found for the link text "' . $tag->text . '"'); - } else { - throw new NotFoundException('The linked page cannot be found'); - } - } else { - $tag->value = Url::to($tag->kirby()->site()->errorPageId()); - } - } - return Html::a($tag->value, $tag->text, [ 'rel' => $tag->rel, 'class' => $tag->class, @@ -234,7 +193,7 @@ return [ 'text', 'title' ], - 'html' => function (KirbyTag $tag): string { + 'html' => function ($tag) { return Html::tel($tag->value, $tag->text, [ 'class' => $tag->class, 'rel' => $tag->rel, @@ -243,6 +202,37 @@ return [ } ], + /** + * Twitter + */ + 'twitter' => [ + 'attr' => [ + 'class', + 'rel', + 'target', + 'text', + 'title' + ], + 'html' => function ($tag) { + // get and sanitize the username + $username = str_replace('@', '', $tag->value); + + // build the profile url + $url = 'https://twitter.com/' . $username; + + // sanitize the link text + $text = $tag->text ?? '@' . $username; + + // build the final link + return Html::a($url, $text, [ + 'class' => $tag->class, + 'rel' => $tag->rel, + 'target' => $tag->target, + 'title' => $tag->title, + ]); + } + ], + /** * Video */ @@ -252,7 +242,6 @@ return [ 'caption', 'controls', 'class', - 'disablepictureinpicture', 'height', 'loop', 'muted', @@ -262,7 +251,7 @@ return [ 'style', 'width', ], - 'html' => function (KirbyTag $tag): string { + 'html' => function ($tag) { // checks and gets if poster is local file if ( empty($tag->poster) === false && @@ -295,15 +284,12 @@ return [ // don't use attributes that iframe doesn't support if ($isProviderVideo === false) { - // convert tag attributes to supported formats (bool, string) - // to output correct html attributes - // - // for ex: - // `autoplay` will not work if `false` is a string - // instead of a boolean + // converts tag attributes to supported formats (listed below) to output correct html + // booleans: autoplay, controls, loop, muted + // strings : poster, preload + // for ex : `autoplay` will not work if `false` is a `string` instead of a `boolean` $attrs['autoplay'] = $autoplay = Str::toType($tag->autoplay, 'bool'); $attrs['controls'] = Str::toType($tag->controls ?? true, 'bool'); - $attrs['disablepictureinpicture'] = Str::toType($tag->disablepictureinpicture ?? false, 'bool'); $attrs['loop'] = Str::toType($tag->loop, 'bool'); $attrs['muted'] = Str::toType($tag->muted ?? $autoplay, 'bool'); $attrs['playsinline'] = Str::toType($tag->playsinline ?? $autoplay, 'bool'); diff --git a/kirby/dependencies/parsedown-extra/ParsedownExtra.php b/kirby/dependencies/parsedown-extra/ParsedownExtra.php index 2f9c62d..7c47422 100644 --- a/kirby/dependencies/parsedown-extra/ParsedownExtra.php +++ b/kirby/dependencies/parsedown-extra/ParsedownExtra.php @@ -465,7 +465,7 @@ class ParsedownExtra extends Parsedown ), ); - uasort($this->DefinitionData['Footnote'], [$this,'sortFootnotes']); + uasort($this->DefinitionData['Footnote'], 'self::sortFootnotes'); foreach ($this->DefinitionData['Footnote'] as $definitionId => $DefinitionData) { if (! isset($DefinitionData['number'])) { @@ -570,18 +570,8 @@ class ParsedownExtra extends Parsedown $DOMDocument = new DOMDocument(); - // Migrating away from `mb_convert_encoding($elementMarkup, - //'HTML-ENTITIES', 'UTF-8');` has caused multibyte characters like - // emojis not to be converted into entities, which is needed so that - // the `DOM` extension can properly parse the markup. - // The following line works like this: It treats the input string - // as UTF-8 and converts every Unicode character with 8 or more bits - // (= character code starting at 128 or 0x80 up to the Unicode limit - // of 0x10ffff) to an entity; the third and fourth arguments for the - // map are not needed for our use case and are set to the default values - // (no offset and a full mask) - // [http://stackoverflow.com/q/11309194/200145] - $elementMarkup = mb_encode_numericentity($elementMarkup, [0x80, 0x10ffff, 0, 0xffffff], 'UTF-8'); + # http://stackoverflow.com/q/11309194/200145 + $elementMarkup = mb_convert_encoding($elementMarkup, 'HTML-ENTITIES', 'UTF-8'); # Ensure that saveHTML() is not remove new line characters. New lines will be split by this character. $DOMDocument->formatOutput = true; diff --git a/kirby/i18n/rules/ro.json b/kirby/i18n/rules/rm.json similarity index 100% rename from kirby/i18n/rules/ro.json rename to kirby/i18n/rules/rm.json diff --git a/kirby/i18n/translations/bg.json b/kirby/i18n/translations/bg.json index 32a8d04..1b7685a 100644 --- a/kirby/i18n/translations/bg.json +++ b/kirby/i18n/translations/bg.json @@ -1,730 +1,574 @@ { - "account.changeName": "Change your name", - "account.delete": "Delete your account", - "account.delete.confirm": "Do you really want to delete your account? You will be logged out immediately. Your account cannot be recovered.", - - "activate": "Activate", - "add": "\u0414\u043e\u0431\u0430\u0432\u0438", - "alpha": "Alpha", - "author": "Author", - "avatar": "Профилна снимка", - "back": "Назад", - "cancel": "\u041e\u0442\u043a\u0430\u0436\u0438", - "change": "\u041f\u0440\u043e\u043c\u0435\u043d\u0438", - "close": "\u0417\u0430\u0442\u0432\u043e\u0440\u0438", - "changes": "Changes", - "confirm": "Ок", - "collapse": "Collapse", - "collapse.all": "Collapse All", - "color": "Color", - "coordinates": "Coordinates", - "copy": "Копирай", - "copy.all": "Copy all", - "copy.success": "{count} copied!", - "create": "Създай", - "custom": "Custom", - - "date": "Дата", - "date.select": "Select a date", - - "day": "Day", - "days.fri": "\u041f\u0442", - "days.mon": "\u041f\u043d", - "days.sat": "\u0421\u0431", - "days.sun": "\u041d\u0434", - "days.thu": "\u0427\u0442", - "days.tue": "\u0412\u0442", - "days.wed": "\u0421\u0440", - - "debugging": "Debugging", - - "delete": "\u0418\u0437\u0442\u0440\u0438\u0439", - "delete.all": "Delete all", - - "dialog.fields.empty": "This dialog has no fields", - "dialog.files.empty": "No files to select", - "dialog.pages.empty": "No pages to select", - "dialog.text.empty": "This dialog does not define any text", - "dialog.users.empty": "No users to select", - - "dimensions": "Размери", - "disable": "Disable", - "disabled": "Disabled", - "discard": "\u041e\u0442\u043c\u0435\u043d\u0438", - - "drawer.fields.empty": "This drawer has no fields", - - "domain": "Domain", - "download": "Download", - "duplicate": "Duplicate", - - "edit": "\u0420\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u0430\u0439", - - "email": "Email", - "email.placeholder": "mail@example.com", - - "enter": "Enter", - "entries": "Entries", - "entry": "Entry", - - "environment": "Environment", - - "error": "Error", - "error.access.code": "Invalid code", - "error.access.login": "Invalid login", - "error.access.panel": "Нямате права за достъп до панела", - "error.access.view": "You are not allowed to access this part of the panel", - - "error.avatar.create.fail": "Профилната снимка не може да се качи", - "error.avatar.delete.fail": "Профилната снимка не може да бъде изтрита", - "error.avatar.dimensions.invalid": "Моля запазете ширината и височината на профилната снимка под 3000 пиксела", - "error.avatar.mime.forbidden": "Профилната снимка трябва да бъде в JPEG или PNG формат", - - "error.blueprint.notFound": "Образецът \"{name}\" не може да бъде зареден", - - "error.blocks.max.plural": "You must not add more than {max} blocks", - "error.blocks.max.singular": "You must not add more than one block", - "error.blocks.min.plural": "You must add at least {min} blocks", - "error.blocks.min.singular": "You must add at least one block", - "error.blocks.validation": "There's an error on the \"{field}\" field in block {index} using the \"{fieldset}\" block type", - - "error.cache.type.invalid": "Invalid cache type \"{type}\"", - - "error.email.preset.notFound": "Email шаблонът \"{name}\" не може да бъде открит", - - "error.field.converter.invalid": "Невалиден конвертор \"{converter}\"", - "error.field.type.missing": "Field \"{ name }\": The field type \"{ type }\" does not exist", - - "error.file.changeName.empty": "The name must not be empty", - "error.file.changeName.permission": "Не можете да смените името на \"{filename}\"", - "error.file.changeTemplate.invalid": "The template for the file \"{id}\" cannot be changed to \"{template}\" (valid: \"{blueprints}\")", - "error.file.changeTemplate.permission": "You are not allowed to change the template for the file \"{id}\"", - - "error.file.duplicate": "Файл с име \"{filename}\" вече съществува", - "error.file.extension.forbidden": "Файловото разширение \"{extension}\" не е позволено", - "error.file.extension.invalid": "Invalid extension: {extension}", - "error.file.extension.missing": "Липсва файлово разширение за файла \"{filename}\"", - "error.file.maxheight": "The height of the image must not exceed {height} pixels", - "error.file.maxsize": "The file is too large", - "error.file.maxwidth": "The width of the image must not exceed {width} pixels", - "error.file.mime.differs": "Каченият файл трябва да бъде от същия mime тип \"{mime}\"", - "error.file.mime.forbidden": "The media type \"{mime}\" is not allowed", - "error.file.mime.invalid": "Invalid mime type: {mime}", - "error.file.mime.missing": "The media type for \"{filename}\" cannot be detected", - "error.file.minheight": "The height of the image must be at least {height} pixels", - "error.file.minsize": "The file is too small", - "error.file.minwidth": "The width of the image must be at least {width} pixels", - "error.file.name.unique": "The filename must be unique", - "error.file.name.missing": "Името на файла е задължително", - "error.file.notFound": "Файлът \"{filename}\" не може да бъде намерен", - "error.file.orientation": "The orientation of the image must be \"{orientation}\"", - "error.file.type.forbidden": "Не е позволен ъплоуда на файлове от тип {type}", - "error.file.type.invalid": "Invalid file type: {type}", - "error.file.undefined": "\u0424\u0430\u0439\u043b\u044a\u0442 \u043d\u0435 \u043c\u043e\u0436\u0435 \u0434\u0430 \u0431\u044a\u0434\u0435 \u043d\u0430\u043c\u0435\u0440\u0435\u043d", - - "error.form.incomplete": "Моля коригирайте всички грешки във формата...", - "error.form.notSaved": "Формата не може да бъде запазена", - - "error.language.code": "Please enter a valid code for the language", - "error.language.duplicate": "The language already exists", - "error.language.name": "Please enter a valid name for the language", - "error.language.notFound": "The language could not be found", - - "error.layout.validation.block": "There's an error on the \"{field}\" field in block {blockIndex} using the \"{fieldset}\" block type in layout {layoutIndex}", - "error.layout.validation.settings": "There's an error in layout {index} settings", - - "error.license.domain": "The domain for the license is missing", - "error.license.email": "Моля въведете валиден email адрес", - "error.license.format": "Please enter a valid license code", - "error.license.verification": "The license could not be verified", - - "error.login.totp.confirm.invalid": "Invalid code", - "error.login.totp.confirm.missing": "Please enter the current code", - - "error.object.validation": "There’s an error in the \"{label}\" field:\n{message}", - - "error.offline": "The Panel is currently offline", - - "error.page.changeSlug.permission": "Не можете да смените URL на \"{slug}\"", - "error.page.changeSlug.reserved": "The path of top-level pages must not start with \"{path}\"", - "error.page.changeStatus.incomplete": "Страницата съдържа грешки и не може да бъде публикувана", - "error.page.changeStatus.permission": "Статусът на страницата не може да бъде променен", - "error.page.changeStatus.toDraft.invalid": "Страницата \"{slug}\" не може да бъде променена в чернова", - "error.page.changeTemplate.invalid": "Темплейтът за страница \"{slug}\" не може да бъде променен", - "error.page.changeTemplate.permission": "Нямате права за да промените шаблона за \"{slug}\"", - "error.page.changeTitle.empty": "Заглавието е задължително", - "error.page.changeTitle.permission": "Не можете да промените заглавието на \"{slug}\"", - "error.page.create.permission": "Не можете да създадете \"{slug}\"", - "error.page.delete": "Страницата \"{slug}\" не може да бъде изтрита", - "error.page.delete.confirm": "Моля въведете името на страницата, за да потвърдите", - "error.page.delete.hasChildren": "Страницата има подстраници и не може да бъде изтрита", - "error.page.delete.permission": "Не можете да изтриете \"{slug}\"", - "error.page.draft.duplicate": "Вече съществува чернова с URL-добавка \"{slug}\"", - "error.page.duplicate": "Страница с URL-добавка \"{slug}\" вече съществува", - "error.page.duplicate.permission": "You are not allowed to duplicate \"{slug}\"", - "error.page.move.ancestor": "The page cannot be moved into itself", - "error.page.move.directory": "The page directory cannot be moved", - "error.page.move.duplicate": "A sub page with the URL appendix \"{slug}\" already exists", - "error.page.move.notFound": "The moved page could not be found", - "error.page.move.permission": "You are not allowed to move \"{slug}\"", - "error.page.move.template": "The \"{template}\" template is not accepted as a subpage of \"{parent}\"", - "error.page.notFound": "Страницата \"{slug}\" не може да бъде намерена", - "error.page.num.invalid": "Моля въведете валидно число за сортиране. Числата не трябва да са негативни.", - "error.page.slug.invalid": "Please enter a valid URL appendix", - "error.page.slug.maxlength": "Slug length must be less than \"{length}\" characters", - "error.page.sort.permission": "Страницата \"{slug}\" не може да бъде сортирана", - "error.page.status.invalid": "Моля изберете валиден статус на страницата", - "error.page.undefined": "\u0421\u0442\u0440\u0430\u043d\u0438\u0446\u0430\u0442\u0430 \u043d\u0435 \u043c\u043e\u0436\u0435 \u0434\u0430 \u0431\u044a\u0434\u0435 \u043d\u0430\u043c\u0435\u0440\u0435\u043d\u0430", - "error.page.update.permission": "Не можете да обновите \"{slug}\"", - - "error.section.files.max.plural": "Не можете да добавяте повече от {max} файлa в секция \"{section}\"", - "error.section.files.max.singular": "Не можете да добавяте повече от един файл в секция \"{section}\"", - "error.section.files.min.plural": "The \"{section}\" section requires at least {min} files", - "error.section.files.min.singular": "The \"{section}\" section requires at least one file", - - "error.section.pages.max.plural": "Не можете да добавяте повече от {max} страници в секция \"{section}\"", - "error.section.pages.max.singular": "Не можете да добавяте повече от една страница в секция \"{section}\"", - "error.section.pages.min.plural": "The \"{section}\" section requires at least {min} pages", - "error.section.pages.min.singular": "The \"{section}\" section requires at least one page", - - "error.section.notLoaded": "Секция \"{name}\" не може да бъде заредена", - "error.section.type.invalid": "Типът \"{type}\" на секция не е валиден", - - "error.site.changeTitle.empty": "Заглавието е задължително", - "error.site.changeTitle.permission": "Не може да променяте заглавието на сайта", - "error.site.update.permission": "Нямате права за да обновите сайта", - - "error.structure.validation": "There's an error on the \"{field}\" field in row {index}", - - "error.template.default.notFound": "Стандартният шаблон не съществува", - - "error.unexpected": "An unexpected error occurred! Enable debug mode for more info: https://getkirby.com/docs/reference/system/options/debug", - - "error.user.changeEmail.permission": "Нямате права да промените имейла на този потребител \"{name}\"", - "error.user.changeLanguage.permission": "Нямате права да промените езика за този потребител \"{name}\"", - "error.user.changeName.permission": "Нямате права да промените името на този потребител \"{name}\"", - "error.user.changePassword.permission": "Нямате права да промените паролата за този потребител \"{name}\"", - "error.user.changeRole.lastAdmin": "Ролята на последния администратор не може да бъде променена", - "error.user.changeRole.permission": "Нямате права да промените ролята на този потребител \"{name}\"", - "error.user.changeRole.toAdmin": "You are not allowed to promote someone to the admin role", - "error.user.create.permission": "Нямате права да създадете този потребител", - "error.user.delete": "\u041f\u043e\u0442\u0440\u0435\u0431\u0438\u0442\u0435\u043b\u044f\u0442 \u043d\u0435 \u043c\u043e\u0436\u0435 \u0434\u0430 \u0431\u044a\u0434\u0435 \u0438\u0437\u0442\u0440\u0438\u0442", - "error.user.delete.lastAdmin": "\u041d\u0435 \u043c\u043e\u0436\u0435\u0442\u0435 \u0434\u0430 \u0438\u0437\u0442\u0440\u0438\u0435\u0442\u0435 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u044f \u0430\u0434\u043c\u0438\u043d\u0438\u0441\u0442\u0440\u0430\u0442\u043e\u0440", - "error.user.delete.lastUser": "Последният потребител не може да бъде изтрит", - "error.user.delete.permission": "\u041d\u0435 \u0435 \u043f\u043e\u0437\u0432\u043e\u043b\u0435\u043d\u043e \u0434\u0430 \u0438\u0437\u0442\u0440\u0438\u0432\u0430\u0442\u0435 \u0442\u043e\u0437\u0438 \u043f\u043e\u0442\u0440\u0435\u0431\u0438\u0442\u0435\u043b", - "error.user.duplicate": "Потребител с имейл \"{email}\" вече съществува", - "error.user.email.invalid": "Моля въведете валиден email адрес", - "error.user.language.invalid": "Моля въведете валиден език", - "error.user.notFound": "\u041f\u043e\u0442\u0440\u0435\u0431\u0438\u0442\u0435\u043b\u044f\u0442 \u043d\u0435 \u043c\u043e\u0436\u0435 \u0434\u0430 \u0431\u044a\u0434\u0435 \u043d\u0430\u043c\u0435\u0440\u0435\u043d.", - "error.user.password.excessive": "Please enter a valid password. Passwords must not be longer than 1000 characters.", - "error.user.password.invalid": "Моля въведете валидна парола. Тя трабва да съдържа поне 8 символа.", - "error.user.password.notSame": "\u041c\u043e\u043b\u044f, \u043f\u043e\u0442\u0432\u044a\u0440\u0434\u0435\u0442\u0435 \u043f\u0430\u0440\u043e\u043b\u0430\u0442\u0430", - "error.user.password.undefined": "Потребителят няма парола", - "error.user.password.wrong": "Wrong password", - "error.user.role.invalid": "Моля въведете валидна роля", - "error.user.undefined": "Потребителят не може да бъде намерен.", - "error.user.update.permission": "Нямате права да обновите този потребител \"{name}\"", - - "error.validation.accepted": "Моля потвърдете", - "error.validation.alpha": "Моля въвдете символи измежду a-z", - "error.validation.alphanum": "Моля въвдете символи измежду a-z или цифри 0-9", - "error.validation.anchor": "Please enter a correct link anchor", - "error.validation.between": "Моля въведете стойност между \"{min}\" и \"{max}\"", - "error.validation.boolean": "Моля потвърдете или откажете", - "error.validation.color": "Please enter a valid color in the {format} format", - "error.validation.contains": "Моля въведете стойност, която съдържа \"{needle}\"", - "error.validation.date": "Моля въведете валидна дата", - "error.validation.date.after": "Please enter a date after {date}", - "error.validation.date.before": "Please enter a date before {date}", - "error.validation.date.between": "Please enter a date between {min} and {max}", - "error.validation.denied": "Моля откажете", - "error.validation.different": "Стойността не трябва да е \"{other}\"", - "error.validation.email": "Моля въведете валиден email адрес", - "error.validation.endswith": "Стойността трябва да завършва с \"{end\"}", - "error.validation.filename": "Моля въведете валидно име на файла", - "error.validation.in": "Моля въведете едно от следните: ({in})", - "error.validation.integer": "Моля въведете валидно цяло число", - "error.validation.ip": "Моля въведете валиден IP адрес", - "error.validation.less": "Моля въведете стойност по-ниска от {max}", - "error.validation.linkType": "The link type is not allowed", - "error.validation.match": "Стойността не съвпада с очаквания модел", - "error.validation.max": "Please enter a value equal to or lower than {max}", - "error.validation.maxlength": "Моля въведете по-къса стойност. (макс. {max} символа)", - "error.validation.maxwords": "Моля въведете не повече от {max} дума(и)", - "error.validation.min": "Please enter a value equal to or greater than {min}", - "error.validation.minlength": "Моля въведете по-дълга стойност. (мин. {min} символа)", - "error.validation.minwords": "Моля въведете поне {min} дума(и).", - "error.validation.more": "Моля въведете стойност по-висока от {min}", - "error.validation.notcontains": "Моля въведете стойност, която не съдържа \"{needle}\"", - "error.validation.notin": "Моля не въвеждайте нито едно от следните: ({notIn})", - "error.validation.option": "Моля изберете валидна опция", - "error.validation.num": "Моля въведете валидно число", - "error.validation.required": "Моля въведете нещо", - "error.validation.same": "Моля въведете \"{other}\"", - "error.validation.size": "Размерът на стойността трябва да бъде \"{size}\"", - "error.validation.startswith": "Стойността трябва да започва с \"{start}\"", - "error.validation.tel": "Please enter an unformatted phone number", - "error.validation.time": "Моля въведете валидно време", - "error.validation.time.after": "Please enter a time after {time}", - "error.validation.time.before": "Please enter a time before {time}", - "error.validation.time.between": "Please enter a time between {min} and {max}", - "error.validation.uuid": "Please enter a valid UUID", - "error.validation.url": "Моля въведете валиден URL", - - "expand": "Expand", - "expand.all": "Expand All", - - "field.invalid": "The field is invalid", - "field.required": "The field is required", - "field.blocks.changeType": "Change type", - "field.blocks.code.name": "Код", - "field.blocks.code.language": "Език", - "field.blocks.code.placeholder": "Your code …", - "field.blocks.delete.confirm": "Do you really want to delete this block?", - "field.blocks.delete.confirm.all": "Do you really want to delete all blocks?", - "field.blocks.delete.confirm.selected": "Do you really want to delete the selected blocks?", - "field.blocks.empty": "No blocks yet", - "field.blocks.fieldsets.empty": "No fieldsets yet", - "field.blocks.fieldsets.label": "Please select a block type …", - "field.blocks.fieldsets.paste": "Press {{ shortcut }} to import layouts/blocks from your clipboard Only those allowed in the current field will get inserted.", - "field.blocks.gallery.name": "Gallery", - "field.blocks.gallery.images.empty": "No images yet", - "field.blocks.gallery.images.label": "Images", - "field.blocks.heading.level": "Level", - "field.blocks.heading.name": "Heading", - "field.blocks.heading.text": "Text", - "field.blocks.heading.placeholder": "Heading …", - "field.blocks.image.alt": "Alternative text", - "field.blocks.image.caption": "Caption", - "field.blocks.image.crop": "Crop", - "field.blocks.image.link": "Връзка", - "field.blocks.image.location": "Location", - "field.blocks.image.location.internal": "This website", - "field.blocks.image.location.external": "External source", - "field.blocks.image.name": "Изображение", - "field.blocks.image.placeholder": "Select an image", - "field.blocks.image.ratio": "Ratio", - "field.blocks.image.url": "Image URL", - "field.blocks.line.name": "Line", - "field.blocks.list.name": "List", - "field.blocks.markdown.name": "Markdown", - "field.blocks.markdown.label": "Text", - "field.blocks.markdown.placeholder": "Markdown …", - "field.blocks.quote.name": "Quote", - "field.blocks.quote.text.label": "Text", - "field.blocks.quote.text.placeholder": "Quote …", - "field.blocks.quote.citation.label": "Citation", - "field.blocks.quote.citation.placeholder": "by …", - "field.blocks.text.name": "Text", - "field.blocks.text.placeholder": "Text …", - "field.blocks.video.autoplay": "Autoplay", - "field.blocks.video.caption": "Caption", - "field.blocks.video.controls": "Controls", - "field.blocks.video.location": "Location", - "field.blocks.video.loop": "Loop", - "field.blocks.video.muted": "Muted", - "field.blocks.video.name": "Video", - "field.blocks.video.placeholder": "Enter a video URL", - "field.blocks.video.poster": "Poster", - "field.blocks.video.preload": "Preload", - "field.blocks.video.url.label": "Video-URL", - "field.blocks.video.url.placeholder": "https://youtube.com/?v=", - - "field.files.empty": "Все още не са избрани файлове", - - "field.layout.change": "Change layout", - "field.layout.delete": "Delete layout", - "field.layout.delete.confirm": "Do you really want to delete this layout?", - "field.layout.delete.confirm.all": "Do you really want to delete all layouts?", - "field.layout.empty": "No rows yet", - "field.layout.select": "Select a layout", - - "field.object.empty": "No information yet", - - "field.pages.empty": "Все още не са избрани страници", - - "field.structure.delete.confirm": "Сигурни ли сте, че искате да изтриете това вписване?", - "field.structure.delete.confirm.all": "Do you really want to delete all entries?", - "field.structure.empty": "Все още няма статии", - - "field.users.empty": "Все още не са избрани потребители", - - "fields.empty": "No fields yet", - - "file": "Файл", - "file.blueprint": "This file has no blueprint yet. You can define the setup in /site/blueprints/files/{blueprint}.yml", - "file.changeTemplate": "Промени шаблон", - "file.changeTemplate.notice": "Changing the file's template will remove content for fields that don't match in type. If the new template defines certain rules, e.g. image dimensions, those will also be applied irreversibly. Use with caution.", - "file.delete.confirm": "Сигурни ли сте, че искате да изтриете
{filename}?", - "file.focus.placeholder": "Set focal point", - "file.focus.reset": "Remove focal point", - "file.focus.title": "Focus", - "file.sort": "Change position", - - "files": "Файлове", - "files.empty": "Няма файлове", - - "filter": "Filter", - - "hide": "Hide", - "hour": "Hour", - "hue": "Hue", - "import": "Import", - "info": "Info", - "insert": "\u0412\u043c\u044a\u043a\u043d\u0438", - "insert.after": "Insert after", - "insert.before": "Insert before", - "install": "Инсталирай", - - "installation": "Инсталация", - "installation.completed": "The panel has been installed", - "installation.disabled": "The panel installer is disabled on public servers by default. Please run the installer on a local machine or enable it with the panel.install option.", - "installation.issues.accounts": "Папката /site/accounts не съществува или не позволява запис", - "installation.issues.content": "Папката /content и всички файлове в нея трябва да позволяват запис", - "installation.issues.curl": "Изисква се CURL разширението", - "installation.issues.headline": "Панелът не може да бъде инсталиран", - "installation.issues.mbstring": "Изисква се разширението MB String", - "installation.issues.media": "Папката /media не съществува или няма права за запис", - "installation.issues.php": "Бъдете сигурни, че използвате PHP 8+", - "installation.issues.sessions": "The /site/sessions folder does not exist or is not writable", - - "language": "\u0415\u0437\u0438\u043a", - "language.code": "Код", - "language.convert": "Направи по подразбиране", - "language.convert.confirm": "

Сигурни ли сте, че искате да зададете {name} за език по подразбиране? Действието не може да бъде отменено.

В случай, че в {name} има непреведено съдържание, то части от сайта ви могат да останат празни.

", - "language.create": "Добавете нов език", - "language.default": "Език по подразбиране", - "language.delete.confirm": "Сигурни ли сте, че искате да изтриете език {name}, включително всички негови преводи? Действието не може да бъде отменено!", - "language.deleted": "Езикът беше изтрит", - "language.direction": "Посока на четене", - "language.direction.ltr": "Отляво надясно", - "language.direction.rtl": "Отдясно наляво", - "language.locale": "PHP locale string", - "language.locale.warning": "You are using a custom locale set up. Please modify it in the language file in /site/languages", - "language.name": "Име", - "language.secondary": "Secondary language", - "language.settings": "Language settings", - "language.updated": "Езикът беше обновен", - "language.variables": "Language variables", - "language.variables.empty": "No translations yet", - - "language.variable.delete.confirm": "Do you really want to delete the variable for {key}?", - "language.variable.key": "Key", - "language.variable.notFound": "The variable could not be found", - "language.variable.value": "Value", - - "languages": "Езици", - "languages.default": "Език по подразбиране", - "languages.empty": "Все още няма добавени езици", - "languages.secondary": "Второстепенни езици", - "languages.secondary.empty": "Все още няма второстепенни езици", - - "license": "\u041b\u0438\u0446\u0435\u043d\u0437 \u0437\u0430 Kirby", - "license.activate": "Activate it now", - "license.activate.label": "Please activate your license", - "license.activate.domain": "Your license will be activated for {host}.", - "license.activate.local": "You are about to activate your Kirby license for your local domain {host}. If this site will be deployed to a public domain, please activate it there instead. If {host} is the domain you want to use your license for, please continue.", - "license.activated": "Activated", - "license.buy": "Купи лиценз", - "license.code": "Код", - "license.code.help": "You received your license code after the purchase via email. Please copy and paste it here.", - "license.code.label": "Please enter your license code", - "license.status.active.info": "Includes new major versions until {date}", - "license.status.active.label": "Valid license", - "license.status.demo.info": "This is a demo installation", - "license.status.demo.label": "Demo", - "license.status.inactive.info": "Renew license to update to new major versions", - "license.status.inactive.label": "No new major versions", - "license.status.legacy.bubble": "Ready to renew your license?", - "license.status.legacy.info": "Your license does not cover this version", - "license.status.legacy.label": "Please renew your license", - "license.status.missing.bubble": "Ready to launch your site?", - "license.status.missing.info": "No valid license", - "license.status.missing.label": "Please activate your license", - "license.manage": "Manage your licenses", - "license.purchased": "Purchased", - "license.success": "Thank you for supporting Kirby", - "license.unregistered.label": "Unregistered", - - "link": "\u0412\u0440\u044a\u0437\u043a\u0430", - "link.text": "Текстова връзка", - - "loading": "Зареждане", - - "lock.unsaved": "Unsaved changes", - "lock.unsaved.empty": "There are no more unsaved changes", - "lock.isLocked": "Unsaved changes by {email}", - "lock.unlock": "Unlock", - "lock.unlock.submit": "Unlock and overwrite unsaved changes by {email}", - "lock.isUnlocked": "Was unlocked by another user", - - "login": "Подписване", - "login.code.label.login": "Login code", - "login.code.label.password-reset": "Password reset code", - "login.code.placeholder.email": "000 000", - "login.code.placeholder.totp": "000000", - "login.code.text.email": "If your email address is registered, the requested code was sent via email.", - "login.code.text.totp": "Please enter the one‑time code from your authenticator app.", - "login.email.login.body": "Hi {user.nameOrEmail},\n\nYou recently requested a login code for the Panel of {site}.\nThe following login code will be valid for {timeout} minutes:\n\n{code}\n\nIf you did not request a login code, please ignore this email or contact your administrator if you have questions.\nFor security, please DO NOT forward this email.", - "login.email.login.subject": "Your login code", - "login.email.password-reset.body": "Hi {user.nameOrEmail},\n\nYou recently requested a password reset code for the Panel of {site}.\nThe following password reset code will be valid for {timeout} minutes:\n\n{code}\n\nIf you did not request a password reset code, please ignore this email or contact your administrator if you have questions.\nFor security, please DO NOT forward this email.", - "login.email.password-reset.subject": "Your password reset code", - "login.remember": "Keep me logged in", - "login.reset": "Reset password", - "login.toggleText.code.email": "Login via email", - "login.toggleText.code.email-password": "Login with password", - "login.toggleText.password-reset.email": "Forgot your password?", - "login.toggleText.password-reset.email-password": "← Back to login", - "login.totp.enable.option": "Set up one‑time codes", - "login.totp.enable.intro": "Authenticator apps can generate one‑time codes that are used as a second factor when signing into your account.", - "login.totp.enable.qr.label": "1. Scan this QR code", - "login.totp.enable.qr.help": "Unable to scan? Add the setup key {secret} manually to your authenticator app.", - "login.totp.enable.confirm.headline": "2. Confirm with generated code", - "login.totp.enable.confirm.text": "Your app generates a new one‑time code every 30 seconds. Enter the current code to complete the setup:", - "login.totp.enable.confirm.label": "Current code", - "login.totp.enable.confirm.help": "After this setup, we will ask you for a one‑time code every time you log in.", - "login.totp.enable.success": "One‑time codes enabled", - "login.totp.disable.option": "Disable one‑time codes", - "login.totp.disable.label": "Enter your password to disable one‑time codes", - "login.totp.disable.help": "In the future, a different second factor like a login code sent via email will be requested when you log in. You can always set up one‑time codes again later.", - "login.totp.disable.admin": "

This will disable one‑time codes for {user}.

In the future, a different second factor like a login code sent via email will be requested when they log in. {user} can set up one‑time codes again after their next login.

", - "login.totp.disable.success": "One‑time codes disabled", - - "logout": "Изход", - - "merge": "Merge", - "menu": "Меню", - "meridiem": "AM/PM", - "mime": "Media Type", - "minutes": "Minutes", - - "month": "Month", - "months.april": "\u0410\u043f\u0440\u0438\u043b", - "months.august": "\u0410\u0432\u0433\u0443\u0441\u0442", - "months.december": "\u0414\u0435\u043a\u0435\u043c\u0432\u0440\u0438", - "months.february": "Февруари", - "months.january": "\u042f\u043d\u0443\u0430\u0440\u0438", - "months.july": "\u042e\u043b\u0438", - "months.june": "\u042e\u043d\u0438", - "months.march": "\u041c\u0430\u0440\u0442", - "months.may": "\u041c\u0430\u0439", - "months.november": "\u041d\u043e\u0435\u043c\u0432\u0440\u0438", - "months.october": "\u041e\u043a\u0442\u043e\u043c\u0432\u0440\u0438", - "months.september": "\u0421\u0435\u043f\u0442\u0435\u043c\u0432\u0440\u0438", - - "more": "Още", - "move": "Move", - "name": "Име", - "next": "Next", - "night": "Night", - "no": "no", - "off": "off", - "on": "on", - "open": "Отвори", - "open.newWindow": "Open in new window", - "option": "Option", - "options": "Options", - "options.none": "No options", - "options.all": "Show all {count} options", - - "orientation": "Ориентация", - "orientation.landscape": "Пейзаж", - "orientation.portrait": "Портрет", - "orientation.square": "Квадрат", - - "page": "Страница", - "page.blueprint": "This page has no blueprint yet. You can define the setup in /site/blueprints/pages/{blueprint}.yml", - "page.changeSlug": "\u041f\u0440\u043e\u043c\u0435\u043d\u0438 URL", - "page.changeSlug.fromTitle": "\u0421\u044a\u0437\u0434\u0430\u0439\u0442\u0435 \u043e\u0442 \u0437\u0430\u0433\u043b\u0430\u0432\u0438\u0435\u0442\u043e", - "page.changeStatus": "Промени статус", - "page.changeStatus.position": "Моля изберете позиция", - "page.changeStatus.select": "Изберете нов статус", - "page.changeTemplate": "Промени шаблон", - "page.changeTemplate.notice": "Changing the page's template will remove content for fields that don't match in type. Use with caution.", - "page.create": "Create as {status}", - "page.delete.confirm": "Сигурни ли сте, че искате да изтриете {title}?", - "page.delete.confirm.subpages": "Тази страница има подстраници.
Всички подстраници също ще бъдат изтрити.", - "page.delete.confirm.title": "Въведи заглавие на страница за да потвърдиш", - "page.duplicate.appendix": "Копирай", - "page.duplicate.files": "Copy files", - "page.duplicate.pages": "Copy pages", - "page.move": "Move page", - "page.sort": "Change position", - "page.status": "Status", - "page.status.draft": "Чернова", - "page.status.draft.description": "The page is in draft mode and only visible for logged in editors or via secret link", - "page.status.listed": "Публично", - "page.status.listed.description": "Страницата е публична за всички", - "page.status.unlisted": "Скрит", - "page.status.unlisted.description": "Страницата е достъпна само чрез URL", - - "pages": "Страници", - "pages.empty": "Все още няма страници", - "pages.status.draft": "Drafts", - "pages.status.listed": "Published", - "pages.status.unlisted": "Скрит", - - "pagination.page": "Страница", - - "password": "\u041f\u0430\u0440\u043e\u043b\u0430", - "paste": "Paste", - "paste.after": "Paste after", - "paste.success": "{count} pasted!", - "pixel": "Пиксел", - "plugin": "Plugin", - "plugins": "Plugins", - "prev": "Previous", - "preview": "Preview", - "remove": "Премахни", - "rename": "Преименувай", - "renew": "Renew", - "replace": "\u0417\u0430\u043c\u0435\u0441\u0442\u0438", - "replace.with": "Replace with", - "retry": "\u041e\u043f\u0438\u0442\u0430\u0439 \u043f\u0430\u043a", - "revert": "\u041e\u0442\u043c\u0435\u043d\u0438", - "revert.confirm": "Do you really want to delete all unsaved changes?", - - "role": "\u0420\u043e\u043b\u044f", - "role.admin.description": "The admin has all rights", - "role.admin.title": "Admin", - "role.all": "Всички", - "role.empty": "Не съществуват потребители с тази роля", - "role.description.placeholder": "Липсва описание", - "role.nobody.description": "This is a fallback role without any permissions", - "role.nobody.title": "Nobody", - - "save": "\u0417\u0430\u043f\u0438\u0448\u0438", - "search": "Търси", - "search.min": "Enter {min} characters to search", - "search.all": "Show all {count} results", - "search.results.none": "No results", - - "section.invalid": "The section is invalid", - "section.required": "The section is required", - - "security": "Security", - "select": "Избери", - "server": "Server", - "settings": "Настройки", - "show": "Show", - "site.blueprint": "The site has no blueprint yet. You can define the setup in /site/blueprints/site.yml", - "size": "Размер", - "slug": "URL-\u0434\u043e\u0431\u0430\u0432\u043a\u0430", - "sort": "Сортирай", - "sort.drag": "Drag to sort …", - "split": "Split", - - "stats.empty": "No reports", - "status": "Status", - - "system.info.copy": "Copy info", - "system.info.copied": "System info copied", - "system.issues.content": "The content folder seems to be exposed", - "system.issues.eol.kirby": "Your installed Kirby version has reached end-of-life and will not receive further security updates", - "system.issues.eol.plugin": "Your installed version of the { plugin } plugin is has reached end-of-life and will not receive further security updates", - "system.issues.eol.php": "Your installed PHP release { release } has reached end-of-life and will not receive further security updates", - "system.issues.debug": "Debugging must be turned off in production", - "system.issues.git": "The .git folder seems to be exposed", - "system.issues.https": "We recommend HTTPS for all your sites", - "system.issues.kirby": "The kirby folder seems to be exposed", - "system.issues.site": "The site folder seems to be exposed", - "system.issues.vulnerability.kirby": "Your installation might be affected by the following vulnerability ({ severity } severity): { description }", - "system.issues.vulnerability.plugin": "Your installation might be affected by the following vulnerability in the { plugin } plugin ({ severity } severity): { description }", - "system.updateStatus": "Update status", - "system.updateStatus.error": "Could not check for updates", - "system.updateStatus.not-vulnerable": "No known vulnerabilities", - "system.updateStatus.security-update": "Free security update { version } available", - "system.updateStatus.security-upgrade": "Upgrade { version } with security fixes available", - "system.updateStatus.unreleased": "Unreleased version", - "system.updateStatus.up-to-date": "Up to date", - "system.updateStatus.update": "Free update { version } available", - "system.updateStatus.upgrade": "Upgrade { version } available", - - "tel": "Phone", - "tel.placeholder": "+49123456789", - "template": "Образец", - "title": "Заглавие", - "today": "Днес", - - "toolbar.button.clear": "Clear formatting", - "toolbar.button.code": "Код", - "toolbar.button.bold": "\u041f\u043e\u043b\u0443\u0447\u0435\u0440 \u0448\u0440\u0438\u0444\u0442", - "toolbar.button.email": "Email", - "toolbar.button.headings": "Заглавия", - "toolbar.button.heading.1": "Заглавие 1", - "toolbar.button.heading.2": "Заглавие 2", - "toolbar.button.heading.3": "Заглавие 3", - "toolbar.button.heading.4": "Heading 4", - "toolbar.button.heading.5": "Heading 5", - "toolbar.button.heading.6": "Heading 6", - "toolbar.button.italic": "\u041d\u0430\u043a\u043b\u043e\u043d\u0435\u043d \u0448\u0440\u0438\u0444\u0442", - "toolbar.button.file": "Файл", - "toolbar.button.file.select": "Select a file", - "toolbar.button.file.upload": "Upload a file", - "toolbar.button.link": "\u0412\u0440\u044a\u0437\u043a\u0430", - "toolbar.button.paragraph": "Paragraph", - "toolbar.button.strike": "Strike-through", - "toolbar.button.sub": "Subscript", - "toolbar.button.sup": "Superscript", - "toolbar.button.ol": "Подреден списък", - "toolbar.button.underline": "Underline", - "toolbar.button.ul": "Списък", - - "translation.author": "Kirby екип", - "translation.direction": "ltr", - "translation.name": "Български", - "translation.locale": "bg_BG", - - "type": "Type", - - "upload": "Прикачи", - "upload.error.cantMove": "The uploaded file could not be moved", - "upload.error.cantWrite": "Failed to write file to disk", - "upload.error.default": "The file could not be uploaded", - "upload.error.extension": "File upload stopped by extension", - "upload.error.formSize": "The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the form", - "upload.error.iniPostSize": "The uploaded file exceeds the post_max_size directive in php.ini", - "upload.error.iniSize": "The uploaded file exceeds the upload_max_filesize directive in php.ini", - "upload.error.noFile": "No file was uploaded", - "upload.error.noFiles": "No files were uploaded", - "upload.error.partial": "The uploaded file was only partially uploaded", - "upload.error.tmpDir": "Missing a temporary folder", - "upload.errors": "Грешка", - "upload.progress": "Uploading…", - - "url": "Url", - "url.placeholder": "https://example.com", - - "user": "Потребител", - "user.blueprint": "You can define additional sections and form fields for this user role in /site/blueprints/users/{blueprint}.yml", - "user.changeEmail": "Промени email", - "user.changeLanguage": "Промени език", - "user.changeName": "Преименувай този потребител", - "user.changePassword": "Промени парола", - "user.changePassword.new": "Нова парола", - "user.changePassword.new.confirm": "Потвърдете новата парола...", - "user.changeRole": "Променете роля", - "user.changeRole.select": "Изберете нова роля", - "user.create": "Добавете нов потребител", - "user.delete": "Изтрийте потребителя", - "user.delete.confirm": "Сигурни ли сте, че искате да изтриете
{email}?", - - "users": "Потребители", - - "version": "\u0412\u0435\u0440\u0441\u0438\u044f \u043d\u0430 Kirby", - "version.current": "Current version", - "version.latest": "Latest version", - "versionInformation": "Version information", - - "view.account": "\u0412\u0430\u0448\u0438\u044f \u0430\u043a\u0430\u0443\u043d\u0442", - "view.installation": "\u0418\u043d\u0441\u0442\u0430\u043b\u0430\u0446\u0438\u044f", - "view.languages": "Езици", - "view.resetPassword": "Reset password", - "view.site": "Сайт", - "view.system": "System", - "view.users": "\u041f\u043e\u0442\u0440\u0435\u0431\u0438\u0442\u0435\u043b\u0438", - - "welcome": "Добре дошли", - "year": "Year", - "yes": "yes" + "account.changeName": "Change your name", + "account.delete": "Delete your account", + "account.delete.confirm": "Do you really want to delete your account? You will be logged out immediately. Your account cannot be recovered.", + + "add": "\u0414\u043e\u0431\u0430\u0432\u0438", + "author": "Author", + "avatar": "Профилна снимка", + "back": "Назад", + "cancel": "\u041e\u0442\u043a\u0430\u0436\u0438", + "change": "\u041f\u0440\u043e\u043c\u0435\u043d\u0438", + "close": "\u0417\u0430\u0442\u0432\u043e\u0440\u0438", + "confirm": "Ок", + "collapse": "Collapse", + "collapse.all": "Collapse All", + "copy": "Копирай", + "copy.all": "Copy all", + "create": "Създай", + + "date": "Дата", + "date.select": "Select a date", + + "day": "Day", + "days.fri": "\u041f\u0442", + "days.mon": "\u041f\u043d", + "days.sat": "\u0421\u0431", + "days.sun": "\u041d\u0434", + "days.thu": "\u0427\u0442", + "days.tue": "\u0412\u0442", + "days.wed": "\u0421\u0440", + + "debugging": "Debugging", + + "delete": "\u0418\u0437\u0442\u0440\u0438\u0439", + "delete.all": "Delete all", + + "dialog.files.empty": "No files to select", + "dialog.pages.empty": "No pages to select", + "dialog.users.empty": "No users to select", + + "dimensions": "Размери", + "disabled": "Disabled", + "discard": "\u041e\u0442\u043c\u0435\u043d\u0438", + "download": "Download", + "duplicate": "Duplicate", + + "edit": "\u0420\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u0430\u0439", + + "email": "Email", + "email.placeholder": "mail@example.com", + + "entries": "Entries", + "entry": "Entry", + + "environment": "Environment", + + "error.access.code": "Invalid code", + "error.access.login": "Invalid login", + "error.access.panel": "Нямате права за достъп до панела", + "error.access.view": "You are not allowed to access this part of the panel", + + "error.avatar.create.fail": "Профилната снимка не може да се качи", + "error.avatar.delete.fail": "Профилната снимка не може да бъде изтрита", + "error.avatar.dimensions.invalid": "Моля запазете ширината и височината на профилната снимка под 3000 пиксела", + "error.avatar.mime.forbidden": "Профилната снимка трябва да бъде в JPEG или PNG формат", + + "error.blueprint.notFound": "Образецът \"{name}\" не може да бъде зареден", + + "error.blocks.max.plural": "You must not add more than {max} blocks", + "error.blocks.max.singular": "You must not add more than one block", + "error.blocks.min.plural": "You must add at least {min} blocks", + "error.blocks.min.singular": "You must add at least one block", + "error.blocks.validation": "There's an error in block {index}", + + "error.email.preset.notFound": "Email шаблонът \"{name}\" не може да бъде открит", + + "error.field.converter.invalid": "Невалиден конвертор \"{converter}\"", + + "error.file.changeName.empty": "The name must not be empty", + "error.file.changeName.permission": "Не можете да смените името на \"{filename}\"", + "error.file.duplicate": "Файл с име \"{filename}\" вече съществува", + "error.file.extension.forbidden": "Файловото разширение \"{extension}\" не е позволено", + "error.file.extension.invalid": "Invalid extension: {extension}", + "error.file.extension.missing": "Липсва файлово разширение за файла \"{filename}\"", + "error.file.maxheight": "The height of the image must not exceed {height} pixels", + "error.file.maxsize": "The file is too large", + "error.file.maxwidth": "The width of the image must not exceed {width} pixels", + "error.file.mime.differs": "Каченият файл трябва да бъде от същия mime тип \"{mime}\"", + "error.file.mime.forbidden": "The media type \"{mime}\" is not allowed", + "error.file.mime.invalid": "Invalid mime type: {mime}", + "error.file.mime.missing": "The media type for \"{filename}\" cannot be detected", + "error.file.minheight": "The height of the image must be at least {height} pixels", + "error.file.minsize": "The file is too small", + "error.file.minwidth": "The width of the image must be at least {width} pixels", + "error.file.name.missing": "Името на файла е задължително", + "error.file.notFound": "Файлът \"{filename}\" не може да бъде намерен", + "error.file.orientation": "The orientation of the image must be \"{orientation}\"", + "error.file.type.forbidden": "Не е позволен ъплоуда на файлове от тип {type}", + "error.file.type.invalid": "Invalid file type: {type}", + "error.file.undefined": "\u0424\u0430\u0439\u043b\u044a\u0442 \u043d\u0435 \u043c\u043e\u0436\u0435 \u0434\u0430 \u0431\u044a\u0434\u0435 \u043d\u0430\u043c\u0435\u0440\u0435\u043d", + + "error.form.incomplete": "Моля коригирайте всички грешки във формата...", + "error.form.notSaved": "Формата не може да бъде запазена", + + "error.language.code": "Please enter a valid code for the language", + "error.language.duplicate": "The language already exists", + "error.language.name": "Please enter a valid name for the language", + "error.language.notFound": "The language could not be found", + + "error.layout.validation.block": "There's an error in block {blockIndex} in layout {layoutIndex}", + "error.layout.validation.settings": "There's an error in layout {index} settings", + + "error.license.format": "Please enter a valid license key", + "error.license.email": "Моля въведете валиден email адрес", + "error.license.verification": "The license could not be verified", + + "error.offline": "The Panel is currently offline", + + "error.page.changeSlug.permission": "Не можете да смените URL на \"{slug}\"", + "error.page.changeStatus.incomplete": "Страницата съдържа грешки и не може да бъде публикувана", + "error.page.changeStatus.permission": "Статусът на страницата не може да бъде променен", + "error.page.changeStatus.toDraft.invalid": "Страницата \"{slug}\" не може да бъде променена в чернова", + "error.page.changeTemplate.invalid": "Темплейтът за страница \"{slug}\" не може да бъде променен", + "error.page.changeTemplate.permission": "Нямате права за да промените шаблона за \"{slug}\"", + "error.page.changeTitle.empty": "Заглавието е задължително", + "error.page.changeTitle.permission": "Не можете да промените заглавието на \"{slug}\"", + "error.page.create.permission": "Не можете да създадете \"{slug}\"", + "error.page.delete": "Страницата \"{slug}\" не може да бъде изтрита", + "error.page.delete.confirm": "Моля въведете името на страницата, за да потвърдите", + "error.page.delete.hasChildren": "Страницата има подстраници и не може да бъде изтрита", + "error.page.delete.permission": "Не можете да изтриете \"{slug}\"", + "error.page.draft.duplicate": "Вече съществува чернова с URL-добавка \"{slug}\"", + "error.page.duplicate": "Страница с URL-добавка \"{slug}\" вече съществува", + "error.page.duplicate.permission": "You are not allowed to duplicate \"{slug}\"", + "error.page.notFound": "Страницата \"{slug}\" не може да бъде намерена", + "error.page.num.invalid": "Моля въведете валидно число за сортиране. Числата не трябва да са негативни.", + "error.page.slug.invalid": "Please enter a valid URL appendix", + "error.page.slug.maxlength": "Slug length must be less than \"{length}\" characters", + "error.page.sort.permission": "Страницата \"{slug}\" не може да бъде сортирана", + "error.page.status.invalid": "Моля изберете валиден статус на страницата", + "error.page.undefined": "\u0421\u0442\u0440\u0430\u043d\u0438\u0446\u0430\u0442\u0430 \u043d\u0435 \u043c\u043e\u0436\u0435 \u0434\u0430 \u0431\u044a\u0434\u0435 \u043d\u0430\u043c\u0435\u0440\u0435\u043d\u0430", + "error.page.update.permission": "Не можете да обновите \"{slug}\"", + + "error.section.files.max.plural": "Не можете да добавяте повече от {max} файлa в секция \"{section}\"", + "error.section.files.max.singular": "Не можете да добавяте повече от един файл в секция \"{section}\"", + "error.section.files.min.plural": "The \"{section}\" section requires at least {min} files", + "error.section.files.min.singular": "The \"{section}\" section requires at least one file", + + "error.section.pages.max.plural": "Не можете да добавяте повече от {max} страници в секция \"{section}\"", + "error.section.pages.max.singular": "Не можете да добавяте повече от една страница в секция \"{section}\"", + "error.section.pages.min.plural": "The \"{section}\" section requires at least {min} pages", + "error.section.pages.min.singular": "The \"{section}\" section requires at least one page", + + "error.section.notLoaded": "Секция \"{name}\" не може да бъде заредена", + "error.section.type.invalid": "Типът \"{type}\" на секция не е валиден", + + "error.site.changeTitle.empty": "Заглавието е задължително", + "error.site.changeTitle.permission": "Не може да променяте заглавието на сайта", + "error.site.update.permission": "Нямате права за да обновите сайта", + + "error.template.default.notFound": "Стандартният шаблон не съществува", + + "error.unexpected": "An unexpected error occurred! Enable debug mode for more info: https://getkirby.com/docs/reference/system/options/debug", + + "error.user.changeEmail.permission": "Нямате права да промените имейла на този потребител \"{name}\"", + "error.user.changeLanguage.permission": "Нямате права да промените езика за този потребител \"{name}\"", + "error.user.changeName.permission": "Нямате права да промените името на този потребител \"{name}\"", + "error.user.changePassword.permission": "Нямате права да промените паролата за този потребител \"{name}\"", + "error.user.changeRole.lastAdmin": "Ролята на последния администратор не може да бъде променена", + "error.user.changeRole.permission": "Нямате права да промените ролята на този потребител \"{name}\"", + "error.user.changeRole.toAdmin": "You are not allowed to promote someone to the admin role", + "error.user.create.permission": "Нямате права да създадете този потребител", + "error.user.delete": "\u041f\u043e\u0442\u0440\u0435\u0431\u0438\u0442\u0435\u043b\u044f\u0442 \u043d\u0435 \u043c\u043e\u0436\u0435 \u0434\u0430 \u0431\u044a\u0434\u0435 \u0438\u0437\u0442\u0440\u0438\u0442", + "error.user.delete.lastAdmin": "\u041d\u0435 \u043c\u043e\u0436\u0435\u0442\u0435 \u0434\u0430 \u0438\u0437\u0442\u0440\u0438\u0435\u0442\u0435 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u044f \u0430\u0434\u043c\u0438\u043d\u0438\u0441\u0442\u0440\u0430\u0442\u043e\u0440", + "error.user.delete.lastUser": "Последният потребител не може да бъде изтрит", + "error.user.delete.permission": "\u041d\u0435 \u0435 \u043f\u043e\u0437\u0432\u043e\u043b\u0435\u043d\u043e \u0434\u0430 \u0438\u0437\u0442\u0440\u0438\u0432\u0430\u0442\u0435 \u0442\u043e\u0437\u0438 \u043f\u043e\u0442\u0440\u0435\u0431\u0438\u0442\u0435\u043b", + "error.user.duplicate": "Потребител с имейл \"{email}\" вече съществува", + "error.user.email.invalid": "Моля въведете валиден email адрес", + "error.user.language.invalid": "Моля въведете валиден език", + "error.user.notFound": "\u041f\u043e\u0442\u0440\u0435\u0431\u0438\u0442\u0435\u043b\u044f\u0442 \u043d\u0435 \u043c\u043e\u0436\u0435 \u0434\u0430 \u0431\u044a\u0434\u0435 \u043d\u0430\u043c\u0435\u0440\u0435\u043d.", + "error.user.password.excessive": "Please enter a valid password. Passwords must not be longer than 1000 characters.", + "error.user.password.invalid": "Моля въведете валидна парола. Тя трабва да съдържа поне 8 символа.", + "error.user.password.notSame": "\u041c\u043e\u043b\u044f, \u043f\u043e\u0442\u0432\u044a\u0440\u0434\u0435\u0442\u0435 \u043f\u0430\u0440\u043e\u043b\u0430\u0442\u0430", + "error.user.password.undefined": "Потребителят няма парола", + "error.user.password.wrong": "Wrong password", + "error.user.role.invalid": "Моля въведете валидна роля", + "error.user.undefined": "Потребителят не може да бъде намерен.", + "error.user.update.permission": "Нямате права да обновите този потребител \"{name}\"", + + "error.validation.accepted": "Моля потвърдете", + "error.validation.alpha": "Моля въвдете символи измежду a-z", + "error.validation.alphanum": "Моля въвдете символи измежду a-z или цифри 0-9", + "error.validation.between": "Моля въведете стойност между \"{min}\" и \"{max}\"", + "error.validation.boolean": "Моля потвърдете или откажете", + "error.validation.contains": "Моля въведете стойност, която съдържа \"{needle}\"", + "error.validation.date": "Моля въведете валидна дата", + "error.validation.date.after": "Please enter a date after {date}", + "error.validation.date.before": "Please enter a date before {date}", + "error.validation.date.between": "Please enter a date between {min} and {max}", + "error.validation.denied": "Моля откажете", + "error.validation.different": "Стойността не трябва да е \"{other}\"", + "error.validation.email": "Моля въведете валиден email адрес", + "error.validation.endswith": "Стойността трябва да завършва с \"{end\"}", + "error.validation.filename": "Моля въведете валидно име на файла", + "error.validation.in": "Моля въведете едно от следните: ({in})", + "error.validation.integer": "Моля въведете валидно цяло число", + "error.validation.ip": "Моля въведете валиден IP адрес", + "error.validation.less": "Моля въведете стойност по-ниска от {max}", + "error.validation.match": "Стойността не съвпада с очаквания модел", + "error.validation.max": "Please enter a value equal to or lower than {max}", + "error.validation.maxlength": "Моля въведете по-къса стойност. (макс. {max} символа)", + "error.validation.maxwords": "Моля въведете не повече от {max} дума(и)", + "error.validation.min": "Please enter a value equal to or greater than {min}", + "error.validation.minlength": "Моля въведете по-дълга стойност. (мин. {min} символа)", + "error.validation.minwords": "Моля въведете поне {min} дума(и).", + "error.validation.more": "Моля въведете стойност по-висока от {min}", + "error.validation.notcontains": "Моля въведете стойност, която не съдържа \"{needle}\"", + "error.validation.notin": "Моля не въвеждайте нито едно от следните: ({notIn})", + "error.validation.option": "Моля изберете валидна опция", + "error.validation.num": "Моля въведете валидно число", + "error.validation.required": "Моля въведете нещо", + "error.validation.same": "Моля въведете \"{other}\"", + "error.validation.size": "Размерът на стойността трябва да бъде \"{size}\"", + "error.validation.startswith": "Стойността трябва да започва с \"{start}\"", + "error.validation.time": "Моля въведете валидно време", + "error.validation.time.after": "Please enter a time after {time}", + "error.validation.time.before": "Please enter a time before {time}", + "error.validation.time.between": "Please enter a time between {min} and {max}", + "error.validation.url": "Моля въведете валиден URL", + + "expand": "Expand", + "expand.all": "Expand All", + + "field.required": "The field is required", + "field.blocks.changeType": "Change type", + "field.blocks.code.name": "Код", + "field.blocks.code.language": "Език", + "field.blocks.code.placeholder": "Your code …", + "field.blocks.delete.confirm": "Do you really want to delete this block?", + "field.blocks.delete.confirm.all": "Do you really want to delete all blocks?", + "field.blocks.delete.confirm.selected": "Do you really want to delete the selected blocks?", + "field.blocks.empty": "No blocks yet", + "field.blocks.fieldsets.label": "Please select a block type …", + "field.blocks.fieldsets.paste": "Press {{ shortcut }} to paste/import blocks from your clipboard", + "field.blocks.gallery.name": "Gallery", + "field.blocks.gallery.images.empty": "No images yet", + "field.blocks.gallery.images.label": "Images", + "field.blocks.heading.level": "Level", + "field.blocks.heading.name": "Heading", + "field.blocks.heading.text": "Text", + "field.blocks.heading.placeholder": "Heading …", + "field.blocks.image.alt": "Alternative text", + "field.blocks.image.caption": "Caption", + "field.blocks.image.crop": "Crop", + "field.blocks.image.link": "Връзка", + "field.blocks.image.location": "Location", + "field.blocks.image.name": "Изображение", + "field.blocks.image.placeholder": "Select an image", + "field.blocks.image.ratio": "Ratio", + "field.blocks.image.url": "Image URL", + "field.blocks.line.name": "Line", + "field.blocks.list.name": "List", + "field.blocks.markdown.name": "Markdown", + "field.blocks.markdown.label": "Text", + "field.blocks.markdown.placeholder": "Markdown …", + "field.blocks.quote.name": "Quote", + "field.blocks.quote.text.label": "Text", + "field.blocks.quote.text.placeholder": "Quote …", + "field.blocks.quote.citation.label": "Citation", + "field.blocks.quote.citation.placeholder": "by …", + "field.blocks.text.name": "Text", + "field.blocks.text.placeholder": "Text …", + "field.blocks.video.caption": "Caption", + "field.blocks.video.name": "Video", + "field.blocks.video.placeholder": "Enter a video URL", + "field.blocks.video.url.label": "Video-URL", + "field.blocks.video.url.placeholder": "https://youtube.com/?v=", + + "field.files.empty": "Все още не са избрани файлове", + + "field.layout.delete": "Delete layout", + "field.layout.delete.confirm": "Do you really want to delete this layout?", + "field.layout.empty": "No rows yet", + "field.layout.select": "Select a layout", + + "field.pages.empty": "Все още не са избрани страници", + "field.structure.delete.confirm": "Сигурни ли сте, че искате да изтриете това вписване?", + "field.structure.empty": "Все още няма статии", + "field.users.empty": "Все още не са избрани потребители", + + "file.blueprint": "This file has no blueprint yet. You can define the setup in /site/blueprints/files/{blueprint}.yml", + "file.delete.confirm": "Сигурни ли сте, че искате да изтриете
{filename}?", + "file.sort": "Change position", + + "files": "Файлове", + "files.empty": "Няма файлове", + + "hide": "Hide", + "hour": "Hour", + "import": "Import", + "info": "Info", + "insert": "\u0412\u043c\u044a\u043a\u043d\u0438", + "insert.after": "Insert after", + "insert.before": "Insert before", + "install": "Инсталирай", + + "installation": "Инсталация", + "installation.completed": "The panel has been installed", + "installation.disabled": "The panel installer is disabled on public servers by default. Please run the installer on a local machine or enable it with the panel.install option.", + "installation.issues.accounts": "Папката /site/accounts не съществува или не позволява запис", + "installation.issues.content": "Папката /content и всички файлове в нея трябва да позволяват запис", + "installation.issues.curl": "Изисква се CURL разширението", + "installation.issues.headline": "Панелът не може да бъде инсталиран", + "installation.issues.mbstring": "Изисква се разширението MB String", + "installation.issues.media": "Папката /media не съществува или няма права за запис", + "installation.issues.php": "Бъдете сигурни, че използвате PHP 7+", + "installation.issues.server": "Kirby изисква Apache, Nginx или Caddy", + "installation.issues.sessions": "The /site/sessions folder does not exist or is not writable", + + "language": "\u0415\u0437\u0438\u043a", + "language.code": "Код", + "language.convert": "Направи по подразбиране", + "language.convert.confirm": "

Сигурни ли сте, че искате да зададете {name} за език по подразбиране? Действието не може да бъде отменено.

В случай, че в {name} има непреведено съдържание, то части от сайта ви могат да останат празни.

", + "language.create": "Добавете нов език", + "language.delete.confirm": "Сигурни ли сте, че искате да изтриете език {name}, включително всички негови преводи? Действието не може да бъде отменено!", + "language.deleted": "Езикът беше изтрит", + "language.direction": "Посока на четене", + "language.direction.ltr": "Отляво надясно", + "language.direction.rtl": "Отдясно наляво", + "language.locale": "PHP locale string", + "language.locale.warning": "You are using a custom locale set up. Please modify it in the language file in /site/languages", + "language.name": "Име", + "language.updated": "Езикът беше обновен", + + "languages": "Езици", + "languages.default": "Език по подразбиране", + "languages.empty": "Все още няма добавени езици", + "languages.secondary": "Второстепенни езици", + "languages.secondary.empty": "Все още няма второстепенни езици", + + "license": "\u041b\u0438\u0446\u0435\u043d\u0437 \u0437\u0430 Kirby", + "license.buy": "Купи лиценз", + "license.register": "Регистрирай", + "license.manage": "Manage your licenses", + "license.register.help": "You received your license code after the purchase via email. Please copy and paste it to register.", + "license.register.label": "Please enter your license code", + "license.register.success": "Thank you for supporting Kirby", + "license.unregistered": "Това е нерегистрирана демо версия на Kirby", + "license.unregistered.label": "Unregistered", + + "link": "\u0412\u0440\u044a\u0437\u043a\u0430", + "link.text": "Текстова връзка", + + "loading": "Зареждане", + + "lock.unsaved": "Unsaved changes", + "lock.unsaved.empty": "There are no more unsaved changes", + "lock.isLocked": "Unsaved changes by {email}", + "lock.file.isLocked": "The file is currently being edited by {email} and cannot be changed.", + "lock.page.isLocked": "The page is currently being edited by {email} and cannot be changed.", + "lock.unlock": "Unlock", + "lock.isUnlocked": "Your unsaved changes have been overwritten by another user. You can download your changes to merge them manually.", + + "login": "Подписване", + "login.code.label.login": "Login code", + "login.code.label.password-reset": "Password reset code", + "login.code.placeholder.email": "000 000", + "login.code.text.email": "If your email address is registered, the requested code was sent via email.", + "login.email.login.body": "Hi {user.nameOrEmail},\n\nYou recently requested a login code for the Panel of {site}.\nThe following login code will be valid for {timeout} minutes:\n\n{code}\n\nIf you did not request a login code, please ignore this email or contact your administrator if you have questions.\nFor security, please DO NOT forward this email.", + "login.email.login.subject": "Your login code", + "login.email.password-reset.body": "Hi {user.nameOrEmail},\n\nYou recently requested a password reset code for the Panel of {site}.\nThe following password reset code will be valid for {timeout} minutes:\n\n{code}\n\nIf you did not request a password reset code, please ignore this email or contact your administrator if you have questions.\nFor security, please DO NOT forward this email.", + "login.email.password-reset.subject": "Your password reset code", + "login.remember": "Keep me logged in", + "login.reset": "Reset password", + "login.toggleText.code.email": "Login via email", + "login.toggleText.code.email-password": "Login with password", + "login.toggleText.password-reset.email": "Forgot your password?", + "login.toggleText.password-reset.email-password": "← Back to login", + + "logout": "Изход", + + "menu": "Меню", + "meridiem": "AM/PM", + "mime": "Media Type", + "minutes": "Minutes", + + "month": "Month", + "months.april": "\u0410\u043f\u0440\u0438\u043b", + "months.august": "\u0410\u0432\u0433\u0443\u0441\u0442", + "months.december": "\u0414\u0435\u043a\u0435\u043c\u0432\u0440\u0438", + "months.february": "Февруари", + "months.january": "\u042f\u043d\u0443\u0430\u0440\u0438", + "months.july": "\u042e\u043b\u0438", + "months.june": "\u042e\u043d\u0438", + "months.march": "\u041c\u0430\u0440\u0442", + "months.may": "\u041c\u0430\u0439", + "months.november": "\u041d\u043e\u0435\u043c\u0432\u0440\u0438", + "months.october": "\u041e\u043a\u0442\u043e\u043c\u0432\u0440\u0438", + "months.september": "\u0421\u0435\u043f\u0442\u0435\u043c\u0432\u0440\u0438", + + "more": "Още", + "name": "Име", + "next": "Next", + "no": "no", + "off": "off", + "on": "on", + "open": "Отвори", + "open.newWindow": "Open in new window", + "options": "Options", + "options.none": "No options", + + "orientation": "Ориентация", + "orientation.landscape": "Пейзаж", + "orientation.portrait": "Портрет", + "orientation.square": "Квадрат", + + "page.blueprint": "This page has no blueprint yet. You can define the setup in /site/blueprints/pages/{blueprint}.yml", + "page.changeSlug": "\u041f\u0440\u043e\u043c\u0435\u043d\u0438 URL", + "page.changeSlug.fromTitle": "\u0421\u044a\u0437\u0434\u0430\u0439\u0442\u0435 \u043e\u0442 \u0437\u0430\u0433\u043b\u0430\u0432\u0438\u0435\u0442\u043e", + "page.changeStatus": "Промени статус", + "page.changeStatus.position": "Моля изберете позиция", + "page.changeStatus.select": "Изберете нов статус", + "page.changeTemplate": "Промени шаблон", + "page.delete.confirm": "Сигурни ли сте, че искате да изтриете {title}?", + "page.delete.confirm.subpages": "Тази страница има подстраници.
Всички подстраници също ще бъдат изтрити.", + "page.delete.confirm.title": "Въведи заглавие на страница за да потвърдиш", + "page.draft.create": "Създай чернова", + "page.duplicate.appendix": "Копирай", + "page.duplicate.files": "Copy files", + "page.duplicate.pages": "Copy pages", + "page.sort": "Change position", + "page.status": "Status", + "page.status.draft": "Чернова", + "page.status.draft.description": "The page is in draft mode and only visible for logged in editors or via secret link", + "page.status.listed": "Публично", + "page.status.listed.description": "Страницата е публична за всички", + "page.status.unlisted": "Скрит", + "page.status.unlisted.description": "Страницата е достъпна само чрез URL", + + "pages": "Страници", + "pages.empty": "Все още няма страници", + "pages.status.draft": "Drafts", + "pages.status.listed": "Published", + "pages.status.unlisted": "Скрит", + + "pagination.page": "Страница", + + "password": "\u041f\u0430\u0440\u043e\u043b\u0430", + "paste": "Paste", + "paste.after": "Paste after", + "pixel": "Пиксел", + "plugins": "Plugins", + "prev": "Previous", + "preview": "Preview", + "remove": "Премахни", + "rename": "Преименувай", + "replace": "\u0417\u0430\u043c\u0435\u0441\u0442\u0438", + "retry": "\u041e\u043f\u0438\u0442\u0430\u0439 \u043f\u0430\u043a", + "revert": "\u041e\u0442\u043c\u0435\u043d\u0438", + "revert.confirm": "Do you really want to delete all unsaved changes?", + + "role": "\u0420\u043e\u043b\u044f", + "role.admin.description": "The admin has all rights", + "role.admin.title": "Admin", + "role.all": "Всички", + "role.empty": "Не съществуват потребители с тази роля", + "role.description.placeholder": "Липсва описание", + "role.nobody.description": "This is a fallback role without any permissions", + "role.nobody.title": "Nobody", + + "save": "\u0417\u0430\u043f\u0438\u0448\u0438", + "search": "Търси", + "search.min": "Enter {min} characters to search", + "search.all": "Show all", + "search.results.none": "No results", + + "section.required": "The section is required", + + "security": "Security", + "select": "Избери", + "server": "Server", + "settings": "Настройки", + "show": "Show", + "site.blueprint": "The site has no blueprint yet. You can define the setup in /site/blueprints/site.yml", + "size": "Размер", + "slug": "URL-\u0434\u043e\u0431\u0430\u0432\u043a\u0430", + "sort": "Сортирай", + + "stats.empty": "No reports", + "system.issues.content": "The content folder seems to be exposed", + "system.issues.debug": "Debugging must be turned off in production", + "system.issues.git": "The .git folder seems to be exposed", + "system.issues.https": "We recommend HTTPS for all your sites", + "system.issues.kirby": "The kirby folder seems to be exposed", + "system.issues.site": "The site folder seems to be exposed", + + "title": "Заглавие", + "template": "Образец", + "today": "Днес", + + "toolbar.button.code": "Код", + "toolbar.button.bold": "\u041f\u043e\u043b\u0443\u0447\u0435\u0440 \u0448\u0440\u0438\u0444\u0442", + "toolbar.button.email": "Email", + "toolbar.button.headings": "Заглавия", + "toolbar.button.heading.1": "Заглавие 1", + "toolbar.button.heading.2": "Заглавие 2", + "toolbar.button.heading.3": "Заглавие 3", + "toolbar.button.heading.4": "Heading 4", + "toolbar.button.heading.5": "Heading 5", + "toolbar.button.heading.6": "Heading 6", + "toolbar.button.italic": "\u041d\u0430\u043a\u043b\u043e\u043d\u0435\u043d \u0448\u0440\u0438\u0444\u0442", + "toolbar.button.file": "Файл", + "toolbar.button.file.select": "Select a file", + "toolbar.button.file.upload": "Upload a file", + "toolbar.button.link": "\u0412\u0440\u044a\u0437\u043a\u0430", + "toolbar.button.paragraph": "Paragraph", + "toolbar.button.strike": "Strike-through", + "toolbar.button.ol": "Подреден списък", + "toolbar.button.underline": "Underline", + "toolbar.button.ul": "Списък", + + "translation.author": "Kirby екип", + "translation.direction": "ltr", + "translation.name": "Български", + "translation.locale": "bg_BG", + + "upload": "Прикачи", + "upload.error.cantMove": "The uploaded file could not be moved", + "upload.error.cantWrite": "Failed to write file to disk", + "upload.error.default": "The file could not be uploaded", + "upload.error.extension": "File upload stopped by extension", + "upload.error.formSize": "The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the form", + "upload.error.iniPostSize": "The uploaded file exceeds the post_max_size directive in php.ini", + "upload.error.iniSize": "The uploaded file exceeds the upload_max_filesize directive in php.ini", + "upload.error.noFile": "No file was uploaded", + "upload.error.noFiles": "No files were uploaded", + "upload.error.partial": "The uploaded file was only partially uploaded", + "upload.error.tmpDir": "Missing a temporary folder", + "upload.errors": "Грешка", + "upload.progress": "Uploading…", + + "url": "Url", + "url.placeholder": "https://example.com", + + "user": "Потребител", + "user.blueprint": "You can define additional sections and form fields for this user role in /site/blueprints/users/{blueprint}.yml", + "user.changeEmail": "Промени email", + "user.changeLanguage": "Промени език", + "user.changeName": "Преименувай този потребител", + "user.changePassword": "Промени парола", + "user.changePassword.new": "Нова парола", + "user.changePassword.new.confirm": "Потвърдете новата парола...", + "user.changeRole": "Променете роля", + "user.changeRole.select": "Изберете нова роля", + "user.create": "Добавете нов потребител", + "user.delete": "Изтрийте потребителя", + "user.delete.confirm": "Сигурни ли сте, че искате да изтриете
{email}?", + + "users": "Потребители", + + "version": "\u0412\u0435\u0440\u0441\u0438\u044f \u043d\u0430 Kirby", + + "view.account": "\u0412\u0430\u0448\u0438\u044f \u0430\u043a\u0430\u0443\u043d\u0442", + "view.installation": "\u0418\u043d\u0441\u0442\u0430\u043b\u0430\u0446\u0438\u044f", + "view.languages": "Езици", + "view.resetPassword": "Reset password", + "view.site": "Сайт", + "view.system": "System", + "view.users": "\u041f\u043e\u0442\u0440\u0435\u0431\u0438\u0442\u0435\u043b\u0438", + + "welcome": "Добре дошли", + "year": "Year", + "yes": "yes" } diff --git a/kirby/i18n/translations/ca.json b/kirby/i18n/translations/ca.json index 7048d1b..f021bd7 100644 --- a/kirby/i18n/translations/ca.json +++ b/kirby/i18n/translations/ca.json @@ -1,730 +1,574 @@ { - "account.changeName": "Change your name", - "account.delete": "Delete your account", - "account.delete.confirm": "Do you really want to delete your account? You will be logged out immediately. Your account cannot be recovered.", - - "activate": "Activate", - "add": "Afegir", - "alpha": "Alpha", - "author": "Author", - "avatar": "Imatge del perfil", - "back": "Tornar", - "cancel": "Cancel\u00b7lar", - "change": "Canviar", - "close": "Tancar", - "changes": "Changes", - "confirm": "Ok", - "collapse": "Col·lapsar", - "collapse.all": "Col·lapsar tot", - "color": "Color", - "coordinates": "Coordinates", - "copy": "Copiar", - "copy.all": "Copy all", - "copy.success": "{count} copied!", - "create": "Crear", - "custom": "Custom", - - "date": "Data", - "date.select": "Selecciona una data", - - "day": "Dia", - "days.fri": "dv.", - "days.mon": "dl.", - "days.sat": "ds.", - "days.sun": "dg.", - "days.thu": "dj.", - "days.tue": "dt.", - "days.wed": "dc.", - - "debugging": "Debugging", - - "delete": "Eliminar", - "delete.all": "Eliminar tot", - - "dialog.fields.empty": "This dialog has no fields", - "dialog.files.empty": "No hi ha cap fitxer per seleccionar", - "dialog.pages.empty": "No hi ha cap pàgina per seleccionar", - "dialog.text.empty": "This dialog does not define any text", - "dialog.users.empty": "No hi ha cap usuari per seleccionar", - - "dimensions": "Dimensions", - "disable": "Disable", - "disabled": "Desactivat", - "discard": "Descartar", - - "drawer.fields.empty": "This drawer has no fields", - - "domain": "Domain", - "download": "Descarregar", - "duplicate": "Duplicar", - - "edit": "Editar", - - "email": "Email", - "email.placeholder": "mail@exemple.com", - - "enter": "Enter", - "entries": "Entries", - "entry": "Entry", - - "environment": "Environment", - - "error": "Error", - "error.access.code": "Codi invàlid", - "error.access.login": "Inici de sessió no vàlid", - "error.access.panel": "No tens permís per accedir al panell", - "error.access.view": "No tens accés a aquesta part del tauler", - - "error.avatar.create.fail": "No s'ha pogut carregar la imatge del perfil", - "error.avatar.delete.fail": "La imatge del perfil no s'ha pogut eliminar", - "error.avatar.dimensions.invalid": "Mantingueu l'amplada i l'alçada de la imatge de perfil de menys de 3000 píxels", - "error.avatar.mime.forbidden": "La imatge del perfil ha de ser fitxers JPEG o PNG", - - "error.blueprint.notFound": "No s'ha potgut carregar el blueprint \"{name}\"", - - "error.blocks.max.plural": "You must not add more than {max} blocks", - "error.blocks.max.singular": "You must not add more than one block", - "error.blocks.min.plural": "You must add at least {min} blocks", - "error.blocks.min.singular": "You must add at least one block", - "error.blocks.validation": "There's an error on the \"{field}\" field in block {index} using the \"{fieldset}\" block type", - - "error.cache.type.invalid": "Invalid cache type \"{type}\"", - - "error.email.preset.notFound": "No es pot trobar la configuració de correu electrònic \"{name}\"", - - "error.field.converter.invalid": "Convertidor no vàlid \"{converter}\"", - "error.field.type.missing": "Field \"{ name }\": The field type \"{ type }\" does not exist", - - "error.file.changeName.empty": "El nom no pot estar buit", - "error.file.changeName.permission": "No tens permís per canviar el nom de \"{filename}\"", - "error.file.changeTemplate.invalid": "The template for the file \"{id}\" cannot be changed to \"{template}\" (valid: \"{blueprints}\")", - "error.file.changeTemplate.permission": "You are not allowed to change the template for the file \"{id}\"", - - "error.file.duplicate": "Ja existeix un fitxer amb el nom \"{filename}\"", - "error.file.extension.forbidden": "L'extensió de l'arxiu \"{extension}\" no està permesa", - "error.file.extension.invalid": "Invalid extension: {extension}", - "error.file.extension.missing": "Falta l'extensió de l'arxiu \"{filename}\"", - "error.file.maxheight": "L'alçada de la imatge no ha de ser superior a {height} píxels", - "error.file.maxsize": "El fitxer és massa gran", - "error.file.maxwidth": "L'amplada de la imatge no ha de ser superior a {width} píxels", - "error.file.mime.differs": "L'arxiu carregat ha ha de ser del mateix tipus de mime \"{mime}\"", - "error.file.mime.forbidden": "El tipus de mitjà \"{mime}\" no està permès", - "error.file.mime.invalid": "Mime type no vàlid: {mime}", - "error.file.mime.missing": "El tipus de suport per a \"{filename}\" no es pot detectar", - "error.file.minheight": "L'alçada de la imatge ha de ser com a mínim de {height} píxels", - "error.file.minsize": "El fitxer és massa petit", - "error.file.minwidth": "L'amplada de la imatge ha de ser com a mínim de {width} píxels", - "error.file.name.unique": "The filename must be unique", - "error.file.name.missing": "El nom del fitxer no pot estar buit", - "error.file.notFound": "L'arxiu \"{filename}\" no s'ha trobat", - "error.file.orientation": "L’orientació de la imatge ha de ser \"{orientation}\"", - "error.file.type.forbidden": "No tens permís per penjar fitxers {type}", - "error.file.type.invalid": "Invalid file type: {type}", - "error.file.undefined": "L'arxiu no s'ha trobat", - - "error.form.incomplete": "Si us plau, corregeix els errors del formulari ...", - "error.form.notSaved": "No s'ha pogut desar el formulari", - - "error.language.code": "Introdueix un codi vàlid per a l’idioma", - "error.language.duplicate": "L'idioma ja existeix", - "error.language.name": "Introdueix un nom vàlid per a l'idioma", - "error.language.notFound": "The language could not be found", - - "error.layout.validation.block": "There's an error on the \"{field}\" field in block {blockIndex} using the \"{fieldset}\" block type in layout {layoutIndex}", - "error.layout.validation.settings": "There's an error in layout {index} settings", - - "error.license.domain": "The domain for the license is missing", - "error.license.email": "Si us plau, introdueix una adreça de correu electrònic vàlida", - "error.license.format": "Please enter a valid license code", - "error.license.verification": "No s’ha pogut verificar la llicència", - - "error.login.totp.confirm.invalid": "Codi invàlid", - "error.login.totp.confirm.missing": "Please enter the current code", - - "error.object.validation": "There’s an error in the \"{label}\" field:\n{message}", - - "error.offline": "The Panel is currently offline", - - "error.page.changeSlug.permission": "No teniu permís per canviar l'apèndix d'URL per a \"{slug}\"", - "error.page.changeSlug.reserved": "The path of top-level pages must not start with \"{path}\"", - "error.page.changeStatus.incomplete": "La pàgina té errors i no es pot publicar", - "error.page.changeStatus.permission": "No es pot canviar l'estat d'aquesta pàgina", - "error.page.changeStatus.toDraft.invalid": "La pàgina \"{slug}\" no es pot convertir en un esborrany", - "error.page.changeTemplate.invalid": "La plantilla per a la pàgina \"{slug}\" no es pot canviar", - "error.page.changeTemplate.permission": "No tens permís per canviar la plantilla per \"{slug}\"", - "error.page.changeTitle.empty": "El títol no pot estar buit", - "error.page.changeTitle.permission": "No tens permís per canviar el títol de \"{slug}\"", - "error.page.create.permission": "No tens permís per crear \"{slug}\"", - "error.page.delete": "La pàgina \"{slug}\" no es pot esborrar", - "error.page.delete.confirm": "Si us plau, introdueix el títol de la pàgina per confirmar", - "error.page.delete.hasChildren": "La pàgina té subpàgines i no es pot esborrar", - "error.page.delete.permission": "No tens permís per esborrar \"{slug}\"", - "error.page.draft.duplicate": "Ja existeix un esborrany de pàgina amb l'apèndix d'URL \"{slug}\"", - "error.page.duplicate": "Ja existeix una pàgina amb l'apèndix d'URL \"{slug}\"", - "error.page.duplicate.permission": "No tens permís per duplicar \"{slug}\"", - "error.page.move.ancestor": "The page cannot be moved into itself", - "error.page.move.directory": "The page directory cannot be moved", - "error.page.move.duplicate": "A sub page with the URL appendix \"{slug}\" already exists", - "error.page.move.notFound": "The moved page could not be found", - "error.page.move.permission": "You are not allowed to move \"{slug}\"", - "error.page.move.template": "The \"{template}\" template is not accepted as a subpage of \"{parent}\"", - "error.page.notFound": "La pàgina \"{slug}\" no s'ha trobat", - "error.page.num.invalid": "Si us plau, introdueix un número d 'ordenació vàlid. Els números no poden ser negatius.", - "error.page.slug.invalid": "Please enter a valid URL appendix", - "error.page.slug.maxlength": "La longitud del nom ha de tenir menys de caràcters \"{length}\"", - "error.page.sort.permission": "La pàgina \"{slug}\" no es pot ordenar", - "error.page.status.invalid": "Si us plau, estableix un estat de pàgina vàlid", - "error.page.undefined": "La p\u00e0gina no s'ha trobat", - "error.page.update.permission": "No tens permís per actualitzar \"{slug}\"", - - "error.section.files.max.plural": "No has d'afegir més de {max} fitxers a la secció \"{section}\"", - "error.section.files.max.singular": "No podeu afegir més d'un fitxer a la secció \"{section}\"", - "error.section.files.min.plural": "La secció \"{section}\" requereix almenys {min} fitxer", - "error.section.files.min.singular": "La secció \"{section}\" requereix almenys un fitxer", - - "error.section.pages.max.plural": "No heu d'afegir més de {max} pàgines a la secció \"{section}\"", - "error.section.pages.max.singular": "No podeu afegir més d'una pàgina a la secció \"{section}\"", - "error.section.pages.min.plural": "La secció \"{section}\" requereix almenys {min} pàgines", - "error.section.pages.min.singular": "La secció \"{section}\" requereix almenys una pàgina", - - "error.section.notLoaded": "No s'ha pogut carregar la secció \"{name}\"", - "error.section.type.invalid": "La secció tipus \"{type}\" no és vàlida", - - "error.site.changeTitle.empty": "El títol no pot estar buit", - "error.site.changeTitle.permission": "No tens permís per canviar el títol del lloc web", - "error.site.update.permission": "No tens permís per actualitzar el lloc web", - - "error.structure.validation": "There's an error on the \"{field}\" field in row {index}", - - "error.template.default.notFound": "La plantilla predeterminada no existeix", - - "error.unexpected": "An unexpected error occurred! Enable debug mode for more info: https://getkirby.com/docs/reference/system/options/debug", - - "error.user.changeEmail.permission": "No tens permís per canviar el correu electrònic per a l'usuari \"{name}\"", - "error.user.changeLanguage.permission": "No tens permís per canviar l'idioma de l'usuari \"{name}\"", - "error.user.changeName.permission": "No tens permís per canviar el nom de l'usuari \"{name}\"", - "error.user.changePassword.permission": "No tens permís per canviar la contrasenya de l'usuari \"{name}\"", - "error.user.changeRole.lastAdmin": "El rol del darrer administrador no es pot canviar", - "error.user.changeRole.permission": "No tens permís per canviar el rol de l'usuari \"{name}\"", - "error.user.changeRole.toAdmin": "No tens permís per promocionar algú al rol d’administrador", - "error.user.create.permission": "No tens permís per crear aquest usuari", - "error.user.delete": "L'usuari \"{name}\" no es pot eliminar", - "error.user.delete.lastAdmin": "No es pot eliminar l'\u00faltim administrador", - "error.user.delete.lastUser": "El darrer usuari no es pot eliminar", - "error.user.delete.permission": "No pots eliminar l'usuari \"{name}\"", - "error.user.duplicate": "Ja existeix un usuari amb l'adreça electrònica \"{email}\"", - "error.user.email.invalid": "Si us plau, introdueix una adreça de correu electrònic vàlida", - "error.user.language.invalid": "Introduïu un idioma vàlid", - "error.user.notFound": "L'usuari \"{name}\" no s'ha trobat", - "error.user.password.excessive": "Please enter a valid password. Passwords must not be longer than 1000 characters.", - "error.user.password.invalid": "Introduïu una contrasenya vàlida. Les contrasenyes han de tenir com a mínim 8 caràcters.", - "error.user.password.notSame": "Les contrasenyes no coincideixen", - "error.user.password.undefined": "L'usuari no té una contrasenya", - "error.user.password.wrong": "Wrong password", - "error.user.role.invalid": "Si us plau, introdueix un rol vàlid", - "error.user.undefined": "L'usuari no s'ha trobat", - "error.user.update.permission": "No tens permís per actualitzar l'usuari \"{name}\"", - - "error.validation.accepted": "Si us plau confirma", - "error.validation.alpha": "Si us plau, introdueix únicament caràcters entre a-z", - "error.validation.alphanum": "Si us plau, introdueix únicament caràcters entre a-z o números de 0-9", - "error.validation.anchor": "Please enter a correct link anchor", - "error.validation.between": "Introdueix un valor entre \"{min}\" i \"{max}\"", - "error.validation.boolean": "Si us plau confirma o denega", - "error.validation.color": "Please enter a valid color in the {format} format", - "error.validation.contains": "Si us plau, introduïu un valor que contingui \"{needle}\"", - "error.validation.date": "Si us plau, introdueix una data vàlida", - "error.validation.date.after": "Introdueix una data posterior {date}", - "error.validation.date.before": "Introdueix una data anterior {date}", - "error.validation.date.between": "Introdueix una data entre {min} i {max}", - "error.validation.denied": "Si us plau, denegui", - "error.validation.different": "El valor no ha de ser \"{other}\"", - "error.validation.email": "Si us plau, introdueix una adreça de correu electrònic vàlida", - "error.validation.endswith": "El valor ha de finalitzar amb \"{end}\"", - "error.validation.filename": "Si us plau, introdueix un nom de fitxer vàlid", - "error.validation.in": "Si us plau, introduïu una de les opcions següents: ({in})", - "error.validation.integer": "Si us plau, introduïu un nombre enter vàlid", - "error.validation.ip": "Si us plau, introduïu una adreça IP vàlida", - "error.validation.less": "Si us plau, introduïu un valor inferior a {max}", - "error.validation.linkType": "The link type is not allowed", - "error.validation.match": "El valor no coincideix amb el patró esperat", - "error.validation.max": "Si us plau, introduïu un valor igual o inferior a {max}", - "error.validation.maxlength": "Si us plau, introduïu un valor més curt. (màxim {max} caràcters)", - "error.validation.maxwords": "Si us plau, introduïu no més de {max} paraula(es)", - "error.validation.min": "Si us plau, introduïu un valor igual o superior a {min}", - "error.validation.minlength": "Si us plau, introduïu un valor més llarg. (min. {min} caràcters)", - "error.validation.minwords": "Si us plau, introduïu almenys {min} paraula(es)", - "error.validation.more": "Si us plau, introduïu un valor més gran que {min}", - "error.validation.notcontains": "Introduïu un valor que no contingui \"{needle}\"", - "error.validation.notin": "Si us plau, no introduïu cap d'aquests elements: ({notIn})", - "error.validation.option": "Si us plau, seleccioneu una opció vàlida", - "error.validation.num": "Si us plau, introduïu un número vàlid", - "error.validation.required": "Si us plau, introduïu alguna cosa", - "error.validation.same": "Si us plau, introduïu \"{other}\"", - "error.validation.size": "La mida del valor ha de ser \"{size}\"", - "error.validation.startswith": "El valor ha de començar amb \"{start}\"", - "error.validation.tel": "Please enter an unformatted phone number", - "error.validation.time": "Si us plau, introduïu una hora vàlida", - "error.validation.time.after": "Please enter a time after {time}", - "error.validation.time.before": "Please enter a time before {time}", - "error.validation.time.between": "Please enter a time between {min} and {max}", - "error.validation.uuid": "Please enter a valid UUID", - "error.validation.url": "Si us plau, introduïu una URL vàlida", - - "expand": "Expandir", - "expand.all": "Expandir tot", - - "field.invalid": "The field is invalid", - "field.required": "El camp és obligatori", - "field.blocks.changeType": "Change type", - "field.blocks.code.name": "Codi", - "field.blocks.code.language": "Idioma", - "field.blocks.code.placeholder": "Your code …", - "field.blocks.delete.confirm": "Do you really want to delete this block?", - "field.blocks.delete.confirm.all": "Do you really want to delete all blocks?", - "field.blocks.delete.confirm.selected": "Do you really want to delete the selected blocks?", - "field.blocks.empty": "No blocks yet", - "field.blocks.fieldsets.empty": "No fieldsets yet", - "field.blocks.fieldsets.label": "Please select a block type …", - "field.blocks.fieldsets.paste": "Press {{ shortcut }} to import layouts/blocks from your clipboard Only those allowed in the current field will get inserted.", - "field.blocks.gallery.name": "Gallery", - "field.blocks.gallery.images.empty": "No images yet", - "field.blocks.gallery.images.label": "Images", - "field.blocks.heading.level": "Level", - "field.blocks.heading.name": "Heading", - "field.blocks.heading.text": "Text", - "field.blocks.heading.placeholder": "Heading …", - "field.blocks.image.alt": "Alternative text", - "field.blocks.image.caption": "Caption", - "field.blocks.image.crop": "Crop", - "field.blocks.image.link": "Enllaç", - "field.blocks.image.location": "Location", - "field.blocks.image.location.internal": "This website", - "field.blocks.image.location.external": "External source", - "field.blocks.image.name": "Imatge", - "field.blocks.image.placeholder": "Select an image", - "field.blocks.image.ratio": "Ratio", - "field.blocks.image.url": "Image URL", - "field.blocks.line.name": "Line", - "field.blocks.list.name": "List", - "field.blocks.markdown.name": "Markdown", - "field.blocks.markdown.label": "Text", - "field.blocks.markdown.placeholder": "Markdown …", - "field.blocks.quote.name": "Quote", - "field.blocks.quote.text.label": "Text", - "field.blocks.quote.text.placeholder": "Quote …", - "field.blocks.quote.citation.label": "Citation", - "field.blocks.quote.citation.placeholder": "by …", - "field.blocks.text.name": "Text", - "field.blocks.text.placeholder": "Text …", - "field.blocks.video.autoplay": "Autoplay", - "field.blocks.video.caption": "Caption", - "field.blocks.video.controls": "Controls", - "field.blocks.video.location": "Location", - "field.blocks.video.loop": "Loop", - "field.blocks.video.muted": "Muted", - "field.blocks.video.name": "Video", - "field.blocks.video.placeholder": "Enter a video URL", - "field.blocks.video.poster": "Poster", - "field.blocks.video.preload": "Preload", - "field.blocks.video.url.label": "Video-URL", - "field.blocks.video.url.placeholder": "https://youtube.com/?v=", - - "field.files.empty": "Encara no hi ha cap fitxer seleccionat", - - "field.layout.change": "Change layout", - "field.layout.delete": "Delete layout", - "field.layout.delete.confirm": "Do you really want to delete this layout?", - "field.layout.delete.confirm.all": "Do you really want to delete all layouts?", - "field.layout.empty": "No rows yet", - "field.layout.select": "Select a layout", - - "field.object.empty": "No information yet", - - "field.pages.empty": "Encara no s'ha seleccionat cap pàgina", - - "field.structure.delete.confirm": "Segur que voleu eliminar aquesta fila?", - "field.structure.delete.confirm.all": "Do you really want to delete all entries?", - "field.structure.empty": "Encara no hi ha entrades.", - - "field.users.empty": "Encara no s'ha seleccionat cap usuari", - - "fields.empty": "No fields yet", - - "file": "Arxiu", - "file.blueprint": "This file has no blueprint yet. You can define the setup in /site/blueprints/files/{blueprint}.yml", - "file.changeTemplate": "Canviar la plantilla", - "file.changeTemplate.notice": "Changing the file's template will remove content for fields that don't match in type. If the new template defines certain rules, e.g. image dimensions, those will also be applied irreversibly. Use with caution.", - "file.delete.confirm": "Esteu segurs d'eliminar
{filename}?", - "file.focus.placeholder": "Set focal point", - "file.focus.reset": "Remove focal point", - "file.focus.title": "Focus", - "file.sort": "Change position", - - "files": "Arxius", - "files.empty": "Encara no hi ha fitxers", - - "filter": "Filter", - - "hide": "Hide", - "hour": "Hora", - "hue": "Hue", - "import": "Import", - "info": "Info", - "insert": "Insertar", - "insert.after": "Insert after", - "insert.before": "Insert before", - "install": "Instal·lar", - - "installation": "Instal·lació", - "installation.completed": "S'ha instal·lat el panell", - "installation.disabled": "L'instal·lador del panell està desactivat per defecte als servidors públics. Si us plau, executeu l'instal·lador en una màquina local o habiliteu-lo amb l'opció panel.install", - "installation.issues.accounts": "La carpeta /site/accounts no existeix o no es pot escriure", - "installation.issues.content": "La carpeta /content no existeix o no es pot escriure", - "installation.issues.curl": "Es requereix l'extensió CURL", - "installation.issues.headline": "El panell no es pot instal·lar", - "installation.issues.mbstring": "Es requereix l'extensió de MB String", - "installation.issues.media": "La carpeta /media no existeix o no es pot escriure", - "installation.issues.php": "Assegureu-vos d'utilitzar PHP 8+", - "installation.issues.sessions": "La carpeta /site/sessions no existeix o no es pot escriure", - - "language": "Idioma", - "language.code": "Codi", - "language.convert": "Fer per defecte", - "language.convert.confirm": "

Segur que voleu convertir {name} a l'idioma predeterminat? Això no es pot desfer.

Si {name} té contingut no traduït, ja no podreu tornar enrere i algunes parts del vostre lloc poden quedar buides.

", - "language.create": "Afegir un nou idioma", - "language.default": "Idioma per defecte", - "language.delete.confirm": "Segur que voleu eliminar l'idioma {name} incloent totes les traduccions? Això no es pot desfer!", - "language.deleted": "S'ha suprimit l'idioma", - "language.direction": "Direcció de lectura", - "language.direction.ltr": "Esquerra a dreta", - "language.direction.rtl": "De dreta a esquerra", - "language.locale": "Cadena local de PHP", - "language.locale.warning": "S'està fent servir una configuració regional personalitzada. Modifica el fitxer d'idioma a /site/languages", - "language.name": "Nom", - "language.secondary": "Secondary language", - "language.settings": "Language settings", - "language.updated": "S'ha actualitzat l'idioma", - "language.variables": "Language variables", - "language.variables.empty": "No translations yet", - - "language.variable.delete.confirm": "Do you really want to delete the variable for {key}?", - "language.variable.key": "Key", - "language.variable.notFound": "The variable could not be found", - "language.variable.value": "Value", - - "languages": "Idiomes", - "languages.default": "Idioma per defecte", - "languages.empty": "Encara no hi ha cap idioma", - "languages.secondary": "Idiomes secundaris", - "languages.secondary.empty": "Encara no hi ha idiomes secundaris", - - "license": "Llic\u00e8ncia Kirby", - "license.activate": "Activate it now", - "license.activate.label": "Please activate your license", - "license.activate.domain": "Your license will be activated for {host}.", - "license.activate.local": "You are about to activate your Kirby license for your local domain {host}. If this site will be deployed to a public domain, please activate it there instead. If {host} is the domain you want to use your license for, please continue.", - "license.activated": "Activated", - "license.buy": "Comprar una llicència", - "license.code": "Codi", - "license.code.help": "You received your license code after the purchase via email. Please copy and paste it here.", - "license.code.label": "Si us plau, introdueixi el seu codi de llicència", - "license.status.active.info": "Includes new major versions until {date}", - "license.status.active.label": "Valid license", - "license.status.demo.info": "This is a demo installation", - "license.status.demo.label": "Demo", - "license.status.inactive.info": "Renew license to update to new major versions", - "license.status.inactive.label": "No new major versions", - "license.status.legacy.bubble": "Ready to renew your license?", - "license.status.legacy.info": "Your license does not cover this version", - "license.status.legacy.label": "Please renew your license", - "license.status.missing.bubble": "Ready to launch your site?", - "license.status.missing.info": "No valid license", - "license.status.missing.label": "Please activate your license", - "license.manage": "Manage your licenses", - "license.purchased": "Purchased", - "license.success": "Gràcies per donar suport a Kirby", - "license.unregistered.label": "Unregistered", - - "link": "Enlla\u00e7", - "link.text": "Enllaç de text", - - "loading": "Carregant", - - "lock.unsaved": "Canvis no guardats", - "lock.unsaved.empty": "Ja no hi ha canvis no guardats", - "lock.isLocked": "Unsaved changes by {email}", - "lock.unlock": "Desbloquejar", - "lock.unlock.submit": "Unlock and overwrite unsaved changes by {email}", - "lock.isUnlocked": "Was unlocked by another user", - - "login": "Entrar", - "login.code.label.login": "Login code", - "login.code.label.password-reset": "Password reset code", - "login.code.placeholder.email": "000 000", - "login.code.placeholder.totp": "000000", - "login.code.text.email": "If your email address is registered, the requested code was sent via email.", - "login.code.text.totp": "Please enter the one‑time code from your authenticator app.", - "login.email.login.body": "Hi {user.nameOrEmail},\n\nYou recently requested a login code for the Panel of {site}.\nThe following login code will be valid for {timeout} minutes:\n\n{code}\n\nIf you did not request a login code, please ignore this email or contact your administrator if you have questions.\nFor security, please DO NOT forward this email.", - "login.email.login.subject": "Your login code", - "login.email.password-reset.body": "Hi {user.nameOrEmail},\n\nYou recently requested a password reset code for the Panel of {site}.\nThe following password reset code will be valid for {timeout} minutes:\n\n{code}\n\nIf you did not request a password reset code, please ignore this email or contact your administrator if you have questions.\nFor security, please DO NOT forward this email.", - "login.email.password-reset.subject": "Your password reset code", - "login.remember": "Manten-me connectat", - "login.reset": "Reset password", - "login.toggleText.code.email": "Login via email", - "login.toggleText.code.email-password": "Login with password", - "login.toggleText.password-reset.email": "Forgot your password?", - "login.toggleText.password-reset.email-password": "← Back to login", - "login.totp.enable.option": "Set up one‑time codes", - "login.totp.enable.intro": "Authenticator apps can generate one‑time codes that are used as a second factor when signing into your account.", - "login.totp.enable.qr.label": "1. Scan this QR code", - "login.totp.enable.qr.help": "Unable to scan? Add the setup key {secret} manually to your authenticator app.", - "login.totp.enable.confirm.headline": "2. Confirm with generated code", - "login.totp.enable.confirm.text": "Your app generates a new one‑time code every 30 seconds. Enter the current code to complete the setup:", - "login.totp.enable.confirm.label": "Current code", - "login.totp.enable.confirm.help": "After this setup, we will ask you for a one‑time code every time you log in.", - "login.totp.enable.success": "One‑time codes enabled", - "login.totp.disable.option": "Disable one‑time codes", - "login.totp.disable.label": "Enter your password to disable one‑time codes", - "login.totp.disable.help": "In the future, a different second factor like a login code sent via email will be requested when you log in. You can always set up one‑time codes again later.", - "login.totp.disable.admin": "

This will disable one‑time codes for {user}.

In the future, a different second factor like a login code sent via email will be requested when they log in. {user} can set up one‑time codes again after their next login.

", - "login.totp.disable.success": "One‑time codes disabled", - - "logout": "Tancar sessió", - - "merge": "Merge", - "menu": "Menú", - "meridiem": "AM/PM", - "mime": "Tipus de mitjà", - "minutes": "Minuts", - - "month": "Mes", - "months.april": "Abril", - "months.august": "Agost", - "months.december": "Desembre", - "months.february": "Febrer", - "months.january": "Gener", - "months.july": "Juliol", - "months.june": "Juny", - "months.march": "Mar\u00e7", - "months.may": "Maig", - "months.november": "Novembre", - "months.october": "Octubre", - "months.september": "Setembre", - - "more": "Més", - "move": "Move", - "name": "Nom", - "next": "Següent", - "night": "Night", - "no": "no", - "off": "apagat", - "on": "encès", - "open": "Obrir", - "open.newWindow": "Open in new window", - "option": "Option", - "options": "Opcions", - "options.none": "Sense opcions", - "options.all": "Show all {count} options", - - "orientation": "Orientació", - "orientation.landscape": "Horitzontal", - "orientation.portrait": "Vertical", - "orientation.square": "Quadrat", - - "page": "Page", - "page.blueprint": "This page has no blueprint yet. You can define the setup in /site/blueprints/pages/{blueprint}.yml", - "page.changeSlug": "Canviar URL", - "page.changeSlug.fromTitle": "Crear a partir del t\u00edtol", - "page.changeStatus": "Canviar l'estat", - "page.changeStatus.position": "Si us plau, seleccioneu una posició", - "page.changeStatus.select": "Seleccioneu un nou estat", - "page.changeTemplate": "Canviar la plantilla", - "page.changeTemplate.notice": "Changing the page's template will remove content for fields that don't match in type. Use with caution.", - "page.create": "Create as {status}", - "page.delete.confirm": "Segur que voleu eliminar {title}?", - "page.delete.confirm.subpages": "Aquesta pàgina té subpàgines.
Totes les subpàgines també s'eliminaran.", - "page.delete.confirm.title": "Introduïu el títol de la pàgina per confirmar", - "page.duplicate.appendix": "Copiar", - "page.duplicate.files": "Copiar fitxers", - "page.duplicate.pages": "Copiar pàgines", - "page.move": "Move page", - "page.sort": "Change position", - "page.status": "Estat", - "page.status.draft": "Esborrany", - "page.status.draft.description": "La pàgina està en mode d'esborrany i només és visible per als editors registrats o a través d'un enllaç secret", - "page.status.listed": "Públic", - "page.status.listed.description": "La pàgina és pública per a tothom", - "page.status.unlisted": "Sense classificar", - "page.status.unlisted.description": "La pàgina només es pot accedir a través de l'URL", - - "pages": "Pàgines", - "pages.empty": "Encara no hi ha pàgines", - "pages.status.draft": "Esborranys", - "pages.status.listed": "Publicat", - "pages.status.unlisted": "Sense classificar", - - "pagination.page": "Pàgina", - - "password": "Contrasenya", - "paste": "Paste", - "paste.after": "Paste after", - "paste.success": "{count} pasted!", - "pixel": "Pixel", - "plugin": "Plugin", - "plugins": "Plugins", - "prev": "Anterior", - "preview": "Preview", - "remove": "Eliminar", - "rename": "Canviar el nom", - "renew": "Renew", - "replace": "Reempla\u00e7ar", - "replace.with": "Replace with", - "retry": "Reintentar", - "revert": "Revertir", - "revert.confirm": "Segur que voleu eliminar tots els canvis pendents desar?", - - "role": "Rol", - "role.admin.description": "L’administrador té tots els permisos", - "role.admin.title": "Administrador", - "role.all": "Tots", - "role.empty": "No hi ha usuaris amb aquest rol", - "role.description.placeholder": "Sense descripció", - "role.nobody.description": "Aquest és un rol per defecte sense permisos", - "role.nobody.title": "Ningú", - - "save": "Desar", - "search": "Cercar", - "search.min": "Introduïu {min} caràcters per cercar", - "search.all": "Show all {count} results", - "search.results.none": "Sense resultats", - - "section.invalid": "The section is invalid", - "section.required": "La secció és obligatòria", - - "security": "Security", - "select": "Seleccionar", - "server": "Server", - "settings": "Configuració", - "show": "Show", - "site.blueprint": "The site has no blueprint yet. You can define the setup in /site/blueprints/site.yml", - "size": "Tamany", - "slug": "URL-ap\u00e8ndix", - "sort": "Ordenar", - "sort.drag": "Drag to sort …", - "split": "Split", - - "stats.empty": "No reports", - "status": "Estat", - - "system.info.copy": "Copy info", - "system.info.copied": "System info copied", - "system.issues.content": "The content folder seems to be exposed", - "system.issues.eol.kirby": "Your installed Kirby version has reached end-of-life and will not receive further security updates", - "system.issues.eol.plugin": "Your installed version of the { plugin } plugin is has reached end-of-life and will not receive further security updates", - "system.issues.eol.php": "Your installed PHP release { release } has reached end-of-life and will not receive further security updates", - "system.issues.debug": "Debugging must be turned off in production", - "system.issues.git": "The .git folder seems to be exposed", - "system.issues.https": "We recommend HTTPS for all your sites", - "system.issues.kirby": "The kirby folder seems to be exposed", - "system.issues.site": "The site folder seems to be exposed", - "system.issues.vulnerability.kirby": "Your installation might be affected by the following vulnerability ({ severity } severity): { description }", - "system.issues.vulnerability.plugin": "Your installation might be affected by the following vulnerability in the { plugin } plugin ({ severity } severity): { description }", - "system.updateStatus": "Update status", - "system.updateStatus.error": "Could not check for updates", - "system.updateStatus.not-vulnerable": "No known vulnerabilities", - "system.updateStatus.security-update": "Free security update { version } available", - "system.updateStatus.security-upgrade": "Upgrade { version } with security fixes available", - "system.updateStatus.unreleased": "Unreleased version", - "system.updateStatus.up-to-date": "Up to date", - "system.updateStatus.update": "Free update { version } available", - "system.updateStatus.upgrade": "Upgrade { version } available", - - "tel": "Phone", - "tel.placeholder": "+49123456789", - "template": "Plantilla", - "title": "Títol", - "today": "Avui", - - "toolbar.button.clear": "Clear formatting", - "toolbar.button.code": "Codi", - "toolbar.button.bold": "Negreta", - "toolbar.button.email": "Email", - "toolbar.button.headings": "Encapçalaments", - "toolbar.button.heading.1": "Encapçalament 1", - "toolbar.button.heading.2": "Encapçalament 2", - "toolbar.button.heading.3": "Encapçalament 3", - "toolbar.button.heading.4": "Heading 4", - "toolbar.button.heading.5": "Heading 5", - "toolbar.button.heading.6": "Heading 6", - "toolbar.button.italic": "Cursiva", - "toolbar.button.file": "Arxiu", - "toolbar.button.file.select": "Selecciona un fitxer", - "toolbar.button.file.upload": "Carrega un fitxer", - "toolbar.button.link": "Enlla\u00e7", - "toolbar.button.paragraph": "Paragraph", - "toolbar.button.strike": "Strike-through", - "toolbar.button.sub": "Subscript", - "toolbar.button.sup": "Superscript", - "toolbar.button.ol": "Llista ordenada", - "toolbar.button.underline": "Underline", - "toolbar.button.ul": "Llista de vinyetes", - - "translation.author": "Equip Kirby", - "translation.direction": "ltr", - "translation.name": "Catalan", - "translation.locale": "ca_ES", - - "type": "Type", - - "upload": "Carregar", - "upload.error.cantMove": "El fitxer carregat no s'ha pogut moure", - "upload.error.cantWrite": "No s'ha pogut escriure el fitxer al disc", - "upload.error.default": "No s'ha pogut carregar el fitxer", - "upload.error.extension": "La càrrega del fitxer s'ha aturat per l'extensió", - "upload.error.formSize": "El fitxer carregat supera la directiva MAX_FILE_SIZE especificada en el formulari", - "upload.error.iniPostSize": "El fitxer carregat supera la directiva post_max_size especifiada al php.ini", - "upload.error.iniSize": "El fitxer carregat supera la directiva upload_max_filesize especifiada al php.ini", - "upload.error.noFile": "No s'ha carregat cap fitxer", - "upload.error.noFiles": "No s'ha penjat cap fitxer", - "upload.error.partial": "El fitxer carregat només s'ha carregat parcialment", - "upload.error.tmpDir": "Falta una carpeta temporal", - "upload.errors": "Error", - "upload.progress": "Carregant...", - - "url": "Url", - "url.placeholder": "https://example.com", - - "user": "Usuari", - "user.blueprint": "You can define additional sections and form fields for this user role in /site/blueprints/users/{blueprint}.yml", - "user.changeEmail": "Canviar e-mail", - "user.changeLanguage": "Canviar idioma", - "user.changeName": "Canviar el nom d'aquest usuari", - "user.changePassword": "Canviar contrasenya", - "user.changePassword.new": "Nova contrasenya", - "user.changePassword.new.confirm": "Confirma la nova contrasenya ...", - "user.changeRole": "Canviar el rol", - "user.changeRole.select": "Seleccionar un nou rol", - "user.create": "Afegir un nou usuari", - "user.delete": "Eliminar aquest usuari", - "user.delete.confirm": "Segur que voleu eliminar
{email}?", - - "users": "Usuaris", - - "version": "Versi\u00f3 de Kirby", - "version.current": "Current version", - "version.latest": "Latest version", - "versionInformation": "Version information", - - "view.account": "La teva compta", - "view.installation": "Instal·lació", - "view.languages": "Idiomes", - "view.resetPassword": "Reset password", - "view.site": "Lloc web", - "view.system": "System", - "view.users": "Usuaris", - - "welcome": "Benvinguda", - "year": "Any", - "yes": "yes" + "account.changeName": "Change your name", + "account.delete": "Delete your account", + "account.delete.confirm": "Do you really want to delete your account? You will be logged out immediately. Your account cannot be recovered.", + + "add": "Afegir", + "author": "Author", + "avatar": "Imatge del perfil", + "back": "Tornar", + "cancel": "Cancel\u00b7lar", + "change": "Canviar", + "close": "Tancar", + "confirm": "Ok", + "collapse": "Col·lapsar", + "collapse.all": "Col·lapsar tot", + "copy": "Copiar", + "copy.all": "Copy all", + "create": "Crear", + + "date": "Data", + "date.select": "Selecciona una data", + + "day": "Dia", + "days.fri": "dv.", + "days.mon": "dl.", + "days.sat": "ds.", + "days.sun": "dg.", + "days.thu": "dj.", + "days.tue": "dt.", + "days.wed": "dc.", + + "debugging": "Debugging", + + "delete": "Eliminar", + "delete.all": "Eliminar tot", + + "dialog.files.empty": "No hi ha cap fitxer per seleccionar", + "dialog.pages.empty": "No hi ha cap pàgina per seleccionar", + "dialog.users.empty": "No hi ha cap usuari per seleccionar", + + "dimensions": "Dimensions", + "disabled": "Desactivat", + "discard": "Descartar", + "download": "Descarregar", + "duplicate": "Duplicar", + + "edit": "Editar", + + "email": "Email", + "email.placeholder": "mail@exemple.com", + + "entries": "Entries", + "entry": "Entry", + + "environment": "Environment", + + "error.access.code": "Codi invàlid", + "error.access.login": "Inici de sessió no vàlid", + "error.access.panel": "No tens permís per accedir al panell", + "error.access.view": "No tens accés a aquesta part del tauler", + + "error.avatar.create.fail": "No s'ha pogut carregar la imatge del perfil", + "error.avatar.delete.fail": "La imatge del perfil no s'ha pogut eliminar", + "error.avatar.dimensions.invalid": "Mantingueu l'amplada i l'alçada de la imatge de perfil de menys de 3000 píxels", + "error.avatar.mime.forbidden": "La imatge del perfil ha de ser fitxers JPEG o PNG", + + "error.blueprint.notFound": "No s'ha potgut carregar el blueprint \"{name}\"", + + "error.blocks.max.plural": "You must not add more than {max} blocks", + "error.blocks.max.singular": "You must not add more than one block", + "error.blocks.min.plural": "You must add at least {min} blocks", + "error.blocks.min.singular": "You must add at least one block", + "error.blocks.validation": "There's an error in block {index}", + + "error.email.preset.notFound": "No es pot trobar la configuració de correu electrònic \"{name}\"", + + "error.field.converter.invalid": "Convertidor no vàlid \"{converter}\"", + + "error.file.changeName.empty": "El nom no pot estar buit", + "error.file.changeName.permission": "No tens permís per canviar el nom de \"{filename}\"", + "error.file.duplicate": "Ja existeix un fitxer amb el nom \"{filename}\"", + "error.file.extension.forbidden": "L'extensió de l'arxiu \"{extension}\" no està permesa", + "error.file.extension.invalid": "Invalid extension: {extension}", + "error.file.extension.missing": "Falta l'extensió de l'arxiu \"{filename}\"", + "error.file.maxheight": "L'alçada de la imatge no ha de ser superior a {height} píxels", + "error.file.maxsize": "El fitxer és massa gran", + "error.file.maxwidth": "L'amplada de la imatge no ha de ser superior a {width} píxels", + "error.file.mime.differs": "L'arxiu carregat ha ha de ser del mateix tipus de mime \"{mime}\"", + "error.file.mime.forbidden": "El tipus de mitjà \"{mime}\" no està permès", + "error.file.mime.invalid": "Mime type no vàlid: {mime}", + "error.file.mime.missing": "El tipus de suport per a \"{filename}\" no es pot detectar", + "error.file.minheight": "L'alçada de la imatge ha de ser com a mínim de {height} píxels", + "error.file.minsize": "El fitxer és massa petit", + "error.file.minwidth": "L'amplada de la imatge ha de ser com a mínim de {width} píxels", + "error.file.name.missing": "El nom del fitxer no pot estar buit", + "error.file.notFound": "L'arxiu \"{filename}\" no s'ha trobat", + "error.file.orientation": "L’orientació de la imatge ha de ser \"{orientation}\"", + "error.file.type.forbidden": "No tens permís per penjar fitxers {type}", + "error.file.type.invalid": "Invalid file type: {type}", + "error.file.undefined": "L'arxiu no s'ha trobat", + + "error.form.incomplete": "Si us plau, corregeix els errors del formulari ...", + "error.form.notSaved": "No s'ha pogut desar el formulari", + + "error.language.code": "Introdueix un codi vàlid per a l’idioma", + "error.language.duplicate": "L'idioma ja existeix", + "error.language.name": "Introdueix un nom vàlid per a l'idioma", + "error.language.notFound": "The language could not be found", + + "error.layout.validation.block": "There's an error in block {blockIndex} in layout {layoutIndex}", + "error.layout.validation.settings": "There's an error in layout {index} settings", + + "error.license.format": "Introduïu una clau de llicència vàlida", + "error.license.email": "Si us plau, introdueix una adreça de correu electrònic vàlida", + "error.license.verification": "No s’ha pogut verificar la llicència", + + "error.offline": "The Panel is currently offline", + + "error.page.changeSlug.permission": "No teniu permís per canviar l'apèndix d'URL per a \"{slug}\"", + "error.page.changeStatus.incomplete": "La pàgina té errors i no es pot publicar", + "error.page.changeStatus.permission": "No es pot canviar l'estat d'aquesta pàgina", + "error.page.changeStatus.toDraft.invalid": "La pàgina \"{slug}\" no es pot convertir en un esborrany", + "error.page.changeTemplate.invalid": "La plantilla per a la pàgina \"{slug}\" no es pot canviar", + "error.page.changeTemplate.permission": "No tens permís per canviar la plantilla per \"{slug}\"", + "error.page.changeTitle.empty": "El títol no pot estar buit", + "error.page.changeTitle.permission": "No tens permís per canviar el títol de \"{slug}\"", + "error.page.create.permission": "No tens permís per crear \"{slug}\"", + "error.page.delete": "La pàgina \"{slug}\" no es pot esborrar", + "error.page.delete.confirm": "Si us plau, introdueix el títol de la pàgina per confirmar", + "error.page.delete.hasChildren": "La pàgina té subpàgines i no es pot esborrar", + "error.page.delete.permission": "No tens permís per esborrar \"{slug}\"", + "error.page.draft.duplicate": "Ja existeix un esborrany de pàgina amb l'apèndix d'URL \"{slug}\"", + "error.page.duplicate": "Ja existeix una pàgina amb l'apèndix d'URL \"{slug}\"", + "error.page.duplicate.permission": "No tens permís per duplicar \"{slug}\"", + "error.page.notFound": "La pàgina \"{slug}\" no s'ha trobat", + "error.page.num.invalid": "Si us plau, introdueix un número d 'ordenació vàlid. Els números no poden ser negatius.", + "error.page.slug.invalid": "Please enter a valid URL appendix", + "error.page.slug.maxlength": "La longitud del nom ha de tenir menys de caràcters \"{length}\"", + "error.page.sort.permission": "La pàgina \"{slug}\" no es pot ordenar", + "error.page.status.invalid": "Si us plau, estableix un estat de pàgina vàlid", + "error.page.undefined": "La p\u00e0gina no s'ha trobat", + "error.page.update.permission": "No tens permís per actualitzar \"{slug}\"", + + "error.section.files.max.plural": "No has d'afegir més de {max} fitxers a la secció \"{section}\"", + "error.section.files.max.singular": "No podeu afegir més d'un fitxer a la secció \"{section}\"", + "error.section.files.min.plural": "La secció \"{section}\" requereix almenys {min} fitxer", + "error.section.files.min.singular": "La secció \"{section}\" requereix almenys un fitxer", + + "error.section.pages.max.plural": "No heu d'afegir més de {max} pàgines a la secció \"{section}\"", + "error.section.pages.max.singular": "No podeu afegir més d'una pàgina a la secció \"{section}\"", + "error.section.pages.min.plural": "La secció \"{section}\" requereix almenys {min} pàgines", + "error.section.pages.min.singular": "La secció \"{section}\" requereix almenys una pàgina", + + "error.section.notLoaded": "No s'ha pogut carregar la secció \"{name}\"", + "error.section.type.invalid": "La secció tipus \"{type}\" no és vàlida", + + "error.site.changeTitle.empty": "El títol no pot estar buit", + "error.site.changeTitle.permission": "No tens permís per canviar el títol del lloc web", + "error.site.update.permission": "No tens permís per actualitzar el lloc web", + + "error.template.default.notFound": "La plantilla predeterminada no existeix", + + "error.unexpected": "An unexpected error occurred! Enable debug mode for more info: https://getkirby.com/docs/reference/system/options/debug", + + "error.user.changeEmail.permission": "No tens permís per canviar el correu electrònic per a l'usuari \"{name}\"", + "error.user.changeLanguage.permission": "No tens permís per canviar l'idioma de l'usuari \"{name}\"", + "error.user.changeName.permission": "No tens permís per canviar el nom de l'usuari \"{name}\"", + "error.user.changePassword.permission": "No tens permís per canviar la contrasenya de l'usuari \"{name}\"", + "error.user.changeRole.lastAdmin": "El rol del darrer administrador no es pot canviar", + "error.user.changeRole.permission": "No tens permís per canviar el rol de l'usuari \"{name}\"", + "error.user.changeRole.toAdmin": "No tens permís per promocionar algú al rol d’administrador", + "error.user.create.permission": "No tens permís per crear aquest usuari", + "error.user.delete": "L'usuari \"{name}\" no es pot eliminar", + "error.user.delete.lastAdmin": "No es pot eliminar l'\u00faltim administrador", + "error.user.delete.lastUser": "El darrer usuari no es pot eliminar", + "error.user.delete.permission": "No pots eliminar l'usuari \"{name}\"", + "error.user.duplicate": "Ja existeix un usuari amb l'adreça electrònica \"{email}\"", + "error.user.email.invalid": "Si us plau, introdueix una adreça de correu electrònic vàlida", + "error.user.language.invalid": "Introduïu un idioma vàlid", + "error.user.notFound": "L'usuari \"{name}\" no s'ha trobat", + "error.user.password.excessive": "Please enter a valid password. Passwords must not be longer than 1000 characters.", + "error.user.password.invalid": "Introduïu una contrasenya vàlida. Les contrasenyes han de tenir com a mínim 8 caràcters.", + "error.user.password.notSame": "Les contrasenyes no coincideixen", + "error.user.password.undefined": "L'usuari no té una contrasenya", + "error.user.password.wrong": "Wrong password", + "error.user.role.invalid": "Si us plau, introdueix un rol vàlid", + "error.user.undefined": "L'usuari no s'ha trobat", + "error.user.update.permission": "No tens permís per actualitzar l'usuari \"{name}\"", + + "error.validation.accepted": "Si us plau confirma", + "error.validation.alpha": "Si us plau, introdueix únicament caràcters entre a-z", + "error.validation.alphanum": "Si us plau, introdueix únicament caràcters entre a-z o números de 0-9", + "error.validation.between": "Introdueix un valor entre \"{min}\" i \"{max}\"", + "error.validation.boolean": "Si us plau confirma o denega", + "error.validation.contains": "Si us plau, introduïu un valor que contingui \"{needle}\"", + "error.validation.date": "Si us plau, introdueix una data vàlida", + "error.validation.date.after": "Introdueix una data posterior {date}", + "error.validation.date.before": "Introdueix una data anterior {date}", + "error.validation.date.between": "Introdueix una data entre {min} i {max}", + "error.validation.denied": "Si us plau, denegui", + "error.validation.different": "El valor no ha de ser \"{other}\"", + "error.validation.email": "Si us plau, introdueix una adreça de correu electrònic vàlida", + "error.validation.endswith": "El valor ha de finalitzar amb \"{end}\"", + "error.validation.filename": "Si us plau, introdueix un nom de fitxer vàlid", + "error.validation.in": "Si us plau, introduïu una de les opcions següents: ({in})", + "error.validation.integer": "Si us plau, introduïu un nombre enter vàlid", + "error.validation.ip": "Si us plau, introduïu una adreça IP vàlida", + "error.validation.less": "Si us plau, introduïu un valor inferior a {max}", + "error.validation.match": "El valor no coincideix amb el patró esperat", + "error.validation.max": "Si us plau, introduïu un valor igual o inferior a {max}", + "error.validation.maxlength": "Si us plau, introduïu un valor més curt. (màxim {max} caràcters)", + "error.validation.maxwords": "Si us plau, introduïu no més de {max} paraula(es)", + "error.validation.min": "Si us plau, introduïu un valor igual o superior a {min}", + "error.validation.minlength": "Si us plau, introduïu un valor més llarg. (min. {min} caràcters)", + "error.validation.minwords": "Si us plau, introduïu almenys {min} paraula(es)", + "error.validation.more": "Si us plau, introduïu un valor més gran que {min}", + "error.validation.notcontains": "Introduïu un valor que no contingui \"{needle}\"", + "error.validation.notin": "Si us plau, no introduïu cap d'aquests elements: ({notIn})", + "error.validation.option": "Si us plau, seleccioneu una opció vàlida", + "error.validation.num": "Si us plau, introduïu un número vàlid", + "error.validation.required": "Si us plau, introduïu alguna cosa", + "error.validation.same": "Si us plau, introduïu \"{other}\"", + "error.validation.size": "La mida del valor ha de ser \"{size}\"", + "error.validation.startswith": "El valor ha de començar amb \"{start}\"", + "error.validation.time": "Si us plau, introduïu una hora vàlida", + "error.validation.time.after": "Please enter a time after {time}", + "error.validation.time.before": "Please enter a time before {time}", + "error.validation.time.between": "Please enter a time between {min} and {max}", + "error.validation.url": "Si us plau, introduïu una URL vàlida", + + "expand": "Expandir", + "expand.all": "Expandir tot", + + "field.required": "El camp és obligatori", + "field.blocks.changeType": "Change type", + "field.blocks.code.name": "Codi", + "field.blocks.code.language": "Idioma", + "field.blocks.code.placeholder": "Your code …", + "field.blocks.delete.confirm": "Do you really want to delete this block?", + "field.blocks.delete.confirm.all": "Do you really want to delete all blocks?", + "field.blocks.delete.confirm.selected": "Do you really want to delete the selected blocks?", + "field.blocks.empty": "No blocks yet", + "field.blocks.fieldsets.label": "Please select a block type …", + "field.blocks.fieldsets.paste": "Press {{ shortcut }} to paste/import blocks from your clipboard", + "field.blocks.gallery.name": "Gallery", + "field.blocks.gallery.images.empty": "No images yet", + "field.blocks.gallery.images.label": "Images", + "field.blocks.heading.level": "Level", + "field.blocks.heading.name": "Heading", + "field.blocks.heading.text": "Text", + "field.blocks.heading.placeholder": "Heading …", + "field.blocks.image.alt": "Alternative text", + "field.blocks.image.caption": "Caption", + "field.blocks.image.crop": "Crop", + "field.blocks.image.link": "Enllaç", + "field.blocks.image.location": "Location", + "field.blocks.image.name": "Imatge", + "field.blocks.image.placeholder": "Select an image", + "field.blocks.image.ratio": "Ratio", + "field.blocks.image.url": "Image URL", + "field.blocks.line.name": "Line", + "field.blocks.list.name": "List", + "field.blocks.markdown.name": "Markdown", + "field.blocks.markdown.label": "Text", + "field.blocks.markdown.placeholder": "Markdown …", + "field.blocks.quote.name": "Quote", + "field.blocks.quote.text.label": "Text", + "field.blocks.quote.text.placeholder": "Quote …", + "field.blocks.quote.citation.label": "Citation", + "field.blocks.quote.citation.placeholder": "by …", + "field.blocks.text.name": "Text", + "field.blocks.text.placeholder": "Text …", + "field.blocks.video.caption": "Caption", + "field.blocks.video.name": "Video", + "field.blocks.video.placeholder": "Enter a video URL", + "field.blocks.video.url.label": "Video-URL", + "field.blocks.video.url.placeholder": "https://youtube.com/?v=", + + "field.files.empty": "Encara no hi ha cap fitxer seleccionat", + + "field.layout.delete": "Delete layout", + "field.layout.delete.confirm": "Do you really want to delete this layout?", + "field.layout.empty": "No rows yet", + "field.layout.select": "Select a layout", + + "field.pages.empty": "Encara no s'ha seleccionat cap pàgina", + "field.structure.delete.confirm": "Segur que voleu eliminar aquesta fila?", + "field.structure.empty": "Encara no hi ha entrades.", + "field.users.empty": "Encara no s'ha seleccionat cap usuari", + + "file.blueprint": "This file has no blueprint yet. You can define the setup in /site/blueprints/files/{blueprint}.yml", + "file.delete.confirm": "Esteu segurs d'eliminar
{filename}?", + "file.sort": "Change position", + + "files": "Arxius", + "files.empty": "Encara no hi ha fitxers", + + "hide": "Hide", + "hour": "Hora", + "import": "Import", + "info": "Info", + "insert": "Insertar", + "insert.after": "Insert after", + "insert.before": "Insert before", + "install": "Instal·lar", + + "installation": "Instal·lació", + "installation.completed": "S'ha instal·lat el panell", + "installation.disabled": "L'instal·lador del panell està desactivat per defecte als servidors públics. Si us plau, executeu l'instal·lador en una màquina local o habiliteu-lo amb l'opció panel.install", + "installation.issues.accounts": "La carpeta /site/accounts no existeix o no es pot escriure", + "installation.issues.content": "La carpeta /content no existeix o no es pot escriure", + "installation.issues.curl": "Es requereix l'extensió CURL", + "installation.issues.headline": "El panell no es pot instal·lar", + "installation.issues.mbstring": "Es requereix l'extensió de MB String", + "installation.issues.media": "La carpeta /media no existeix o no es pot escriure", + "installation.issues.php": "Assegureu-vos d'utilitzar PHP 7+", + "installation.issues.server": "Kirby requereix Apache, Nginx o Caddy", + "installation.issues.sessions": "La carpeta /site/sessions no existeix o no es pot escriure", + + "language": "Idioma", + "language.code": "Codi", + "language.convert": "Fer per defecte", + "language.convert.confirm": "

Segur que voleu convertir {name} a l'idioma predeterminat? Això no es pot desfer.

Si {name} té contingut no traduït, ja no podreu tornar enrere i algunes parts del vostre lloc poden quedar buides.

", + "language.create": "Afegir un nou idioma", + "language.delete.confirm": "Segur que voleu eliminar l'idioma {name} incloent totes les traduccions? Això no es pot desfer!", + "language.deleted": "S'ha suprimit l'idioma", + "language.direction": "Direcció de lectura", + "language.direction.ltr": "Esquerra a dreta", + "language.direction.rtl": "De dreta a esquerra", + "language.locale": "Cadena local de PHP", + "language.locale.warning": "S'està fent servir una configuració regional personalitzada. Modifica el fitxer d'idioma a /site/languages", + "language.name": "Nom", + "language.updated": "S'ha actualitzat l'idioma", + + "languages": "Idiomes", + "languages.default": "Idioma per defecte", + "languages.empty": "Encara no hi ha cap idioma", + "languages.secondary": "Idiomes secundaris", + "languages.secondary.empty": "Encara no hi ha idiomes secundaris", + + "license": "Llic\u00e8ncia Kirby", + "license.buy": "Comprar una llicència", + "license.register": "Registrar", + "license.manage": "Manage your licenses", + "license.register.help": "Heu rebut el codi de la vostra llicència després de la compra, per correu electrònic. Copieu-lo i enganxeu-lo per registrar-vos.", + "license.register.label": "Si us plau, introdueixi el seu codi de llicència", + "license.register.success": "Gràcies per donar suport a Kirby", + "license.unregistered": "Aquesta és una demo no registrada de Kirby", + "license.unregistered.label": "Unregistered", + + "link": "Enlla\u00e7", + "link.text": "Enllaç de text", + + "loading": "Carregant", + + "lock.unsaved": "Canvis no guardats", + "lock.unsaved.empty": "Ja no hi ha canvis no guardats", + "lock.isLocked": "Canvis no guardats per {email}", + "lock.file.isLocked": "El fitxer està sent editat actualment per {email} i no pot ser modificat.", + "lock.page.isLocked": "La pàgina està sent editat actualment per {email} i no pot ser modificat.", + "lock.unlock": "Desbloquejar", + "lock.isUnlocked": "Els teus canvis sense guardar han estat sobreescrits per a un altra usuario. Pots descarregar els teus canvis per combinar-los manualment.", + + "login": "Entrar", + "login.code.label.login": "Login code", + "login.code.label.password-reset": "Password reset code", + "login.code.placeholder.email": "000 000", + "login.code.text.email": "If your email address is registered, the requested code was sent via email.", + "login.email.login.body": "Hi {user.nameOrEmail},\n\nYou recently requested a login code for the Panel of {site}.\nThe following login code will be valid for {timeout} minutes:\n\n{code}\n\nIf you did not request a login code, please ignore this email or contact your administrator if you have questions.\nFor security, please DO NOT forward this email.", + "login.email.login.subject": "Your login code", + "login.email.password-reset.body": "Hi {user.nameOrEmail},\n\nYou recently requested a password reset code for the Panel of {site}.\nThe following password reset code will be valid for {timeout} minutes:\n\n{code}\n\nIf you did not request a password reset code, please ignore this email or contact your administrator if you have questions.\nFor security, please DO NOT forward this email.", + "login.email.password-reset.subject": "Your password reset code", + "login.remember": "Manten-me connectat", + "login.reset": "Reset password", + "login.toggleText.code.email": "Login via email", + "login.toggleText.code.email-password": "Login with password", + "login.toggleText.password-reset.email": "Forgot your password?", + "login.toggleText.password-reset.email-password": "← Back to login", + + "logout": "Tancar sessi\u00f3", + + "menu": "Menú", + "meridiem": "AM/PM", + "mime": "Tipus de mitjà", + "minutes": "Minuts", + + "month": "Mes", + "months.april": "Abril", + "months.august": "Agost", + "months.december": "Desembre", + "months.february": "Febrer", + "months.january": "Gener", + "months.july": "Juliol", + "months.june": "Juny", + "months.march": "Mar\u00e7", + "months.may": "Maig", + "months.november": "Novembre", + "months.october": "Octubre", + "months.september": "Setembre", + + "more": "Més", + "name": "Nom", + "next": "Següent", + "no": "no", + "off": "apagat", + "on": "encès", + "open": "Obrir", + "open.newWindow": "Open in new window", + "options": "Opcions", + "options.none": "Sense opcions", + + "orientation": "Orientació", + "orientation.landscape": "Horitzontal", + "orientation.portrait": "Vertical", + "orientation.square": "Quadrat", + + "page.blueprint": "This page has no blueprint yet. You can define the setup in /site/blueprints/pages/{blueprint}.yml", + "page.changeSlug": "Canviar URL", + "page.changeSlug.fromTitle": "Crear a partir del t\u00edtol", + "page.changeStatus": "Canviar l'estat", + "page.changeStatus.position": "Si us plau, seleccioneu una posició", + "page.changeStatus.select": "Seleccioneu un nou estat", + "page.changeTemplate": "Canviar la plantilla", + "page.delete.confirm": "Segur que voleu eliminar {title}?", + "page.delete.confirm.subpages": "Aquesta pàgina té subpàgines.
Totes les subpàgines també s'eliminaran.", + "page.delete.confirm.title": "Introduïu el títol de la pàgina per confirmar", + "page.draft.create": "Crear un esborrany", + "page.duplicate.appendix": "Copiar", + "page.duplicate.files": "Copiar fitxers", + "page.duplicate.pages": "Copiar pàgines", + "page.sort": "Change position", + "page.status": "Estat", + "page.status.draft": "Esborrany", + "page.status.draft.description": "La pàgina està en mode d'esborrany i només és visible per als editors registrats o a través d'un enllaç secret", + "page.status.listed": "Públic", + "page.status.listed.description": "La pàgina és pública per a tothom", + "page.status.unlisted": "Sense classificar", + "page.status.unlisted.description": "La pàgina només es pot accedir a través de l'URL", + + "pages": "Pàgines", + "pages.empty": "Encara no hi ha pàgines", + "pages.status.draft": "Esborranys", + "pages.status.listed": "Publicat", + "pages.status.unlisted": "Sense classificar", + + "pagination.page": "Pàgina", + + "password": "Contrasenya", + "paste": "Paste", + "paste.after": "Paste after", + "pixel": "Pixel", + "plugins": "Plugins", + "prev": "Anterior", + "preview": "Preview", + "remove": "Eliminar", + "rename": "Canviar el nom", + "replace": "Reempla\u00e7ar", + "retry": "Reintentar", + "revert": "Revertir", + "revert.confirm": "Segur que voleu eliminar tots els canvis pendents desar?", + + "role": "Rol", + "role.admin.description": "L’administrador té tots els permisos", + "role.admin.title": "Administrador", + "role.all": "Tots", + "role.empty": "No hi ha usuaris amb aquest rol", + "role.description.placeholder": "Sense descripció", + "role.nobody.description": "Aquest és un rol per defecte sense permisos", + "role.nobody.title": "Ningú", + + "save": "Desar", + "search": "Cercar", + "search.min": "Introduïu {min} caràcters per cercar", + "search.all": "Mostrar tots", + "search.results.none": "Sense resultats", + + "section.required": "La secció és obligatòria", + + "security": "Security", + "select": "Seleccionar", + "server": "Server", + "settings": "Configuració", + "show": "Show", + "site.blueprint": "The site has no blueprint yet. You can define the setup in /site/blueprints/site.yml", + "size": "Tamany", + "slug": "URL-ap\u00e8ndix", + "sort": "Ordenar", + + "stats.empty": "No reports", + "system.issues.content": "The content folder seems to be exposed", + "system.issues.debug": "Debugging must be turned off in production", + "system.issues.git": "The .git folder seems to be exposed", + "system.issues.https": "We recommend HTTPS for all your sites", + "system.issues.kirby": "The kirby folder seems to be exposed", + "system.issues.site": "The site folder seems to be exposed", + + "title": "Títol", + "template": "Plantilla", + "today": "Avui", + + "toolbar.button.code": "Codi", + "toolbar.button.bold": "Negreta", + "toolbar.button.email": "Email", + "toolbar.button.headings": "Encapçalaments", + "toolbar.button.heading.1": "Encapçalament 1", + "toolbar.button.heading.2": "Encapçalament 2", + "toolbar.button.heading.3": "Encapçalament 3", + "toolbar.button.heading.4": "Heading 4", + "toolbar.button.heading.5": "Heading 5", + "toolbar.button.heading.6": "Heading 6", + "toolbar.button.italic": "Cursiva", + "toolbar.button.file": "Arxiu", + "toolbar.button.file.select": "Selecciona un fitxer", + "toolbar.button.file.upload": "Carrega un fitxer", + "toolbar.button.link": "Enlla\u00e7", + "toolbar.button.paragraph": "Paragraph", + "toolbar.button.strike": "Strike-through", + "toolbar.button.ol": "Llista ordenada", + "toolbar.button.underline": "Underline", + "toolbar.button.ul": "Llista de vinyetes", + + "translation.author": "Equip Kirby", + "translation.direction": "ltr", + "translation.name": "Catalan", + "translation.locale": "ca_ES", + + "upload": "Carregar", + "upload.error.cantMove": "El fitxer carregat no s'ha pogut moure", + "upload.error.cantWrite": "No s'ha pogut escriure el fitxer al disc", + "upload.error.default": "No s'ha pogut carregar el fitxer", + "upload.error.extension": "La càrrega del fitxer s'ha aturat per l'extensió", + "upload.error.formSize": "El fitxer carregat supera la directiva MAX_FILE_SIZE especificada en el formulari", + "upload.error.iniPostSize": "El fitxer carregat supera la directiva post_max_size especifiada al php.ini", + "upload.error.iniSize": "El fitxer carregat supera la directiva upload_max_filesize especifiada al php.ini", + "upload.error.noFile": "No s'ha carregat cap fitxer", + "upload.error.noFiles": "No s'ha penjat cap fitxer", + "upload.error.partial": "El fitxer carregat només s'ha carregat parcialment", + "upload.error.tmpDir": "Falta una carpeta temporal", + "upload.errors": "Error", + "upload.progress": "Carregant...", + + "url": "Url", + "url.placeholder": "https://example.com", + + "user": "Usuari", + "user.blueprint": "You can define additional sections and form fields for this user role in /site/blueprints/users/{blueprint}.yml", + "user.changeEmail": "Canviar e-mail", + "user.changeLanguage": "Canviar idioma", + "user.changeName": "Canviar el nom d'aquest usuari", + "user.changePassword": "Canviar contrasenya", + "user.changePassword.new": "Nova contrasenya", + "user.changePassword.new.confirm": "Confirma la nova contrasenya ...", + "user.changeRole": "Canviar el rol", + "user.changeRole.select": "Seleccionar un nou rol", + "user.create": "Afegir un nou usuari", + "user.delete": "Eliminar aquest usuari", + "user.delete.confirm": "Segur que voleu eliminar
{email}?", + + "users": "Usuaris", + + "version": "Versi\u00f3 de Kirby", + + "view.account": "La teva compta", + "view.installation": "Instal·lació", + "view.languages": "Idiomes", + "view.resetPassword": "Reset password", + "view.site": "Lloc web", + "view.system": "System", + "view.users": "Usuaris", + + "welcome": "Benvinguda", + "year": "Any", + "yes": "yes" } diff --git a/kirby/i18n/translations/cs.json b/kirby/i18n/translations/cs.json index 4576dee..bcf15d1 100644 --- a/kirby/i18n/translations/cs.json +++ b/kirby/i18n/translations/cs.json @@ -1,730 +1,574 @@ { - "account.changeName": "Přejmenovat uživatele", - "account.delete": "Smazat účet", - "account.delete.confirm": "Opravdu chcete smazat svůj účet? Budete okamžitě odhlášeni. Účet nemůže být zpětně obnoven.", - - "activate": "Aktivovat", - "add": "P\u0159idat", - "alpha": "Alfa", - "author": "Autor", - "avatar": "Profilov\u00fd obr\u00e1zek", - "back": "Zpět", - "cancel": "Zru\u0161it", - "change": "Zm\u011bnit", - "close": "Zavřít", - "changes": "Změny", - "confirm": "Ok", - "collapse": "Sbalit", - "collapse.all": "Sbalit vše", - "color": "Barva", - "coordinates": "Souřadnice", - "copy": "Kopírovat", - "copy.all": "Kopírovat vše", - "copy.success": "{count} zkopírováno!", - "create": "Vytvořit", - "custom": "Vlastní", - - "date": "Datum", - "date.select": "Vyberte datum", - - "day": "Den", - "days.fri": "p\u00e1", - "days.mon": "po", - "days.sat": "so", - "days.sun": "ne", - "days.thu": "\u010dt", - "days.tue": "\u00fat", - "days.wed": "st", - - "debugging": "Ladění", - - "delete": "Smazat", - "delete.all": "Smazat vše", - - "dialog.fields.empty": "Tento dialog neobsahuje žádná pole", - "dialog.files.empty": "Žádné soubory k výběru", - "dialog.pages.empty": "Žádné stránky k výběru", - "dialog.text.empty": "Tento dialog nemá definovaný žádný text", - "dialog.users.empty": "Žádní uživatelé k výběru", - - "dimensions": "Rozměry", - "disable": "Deaktivovat", - "disabled": "Zakázáno", - "discard": "Zahodit", - - "drawer.fields.empty": "Tento vysouvací panel nemá žádná pole", - - "domain": "Doména", - "download": "Stáhnout", - "duplicate": "Duplikovat", - - "edit": "Upravit", - - "email": "Email", - "email.placeholder": "mail@example.com", - - "enter": "Zapsat", - "entries": "Záznamy", - "entry": "Záznam", - - "environment": "Prostředí", - - "error": "Chyba", - "error.access.code": "Neplatný kód", - "error.access.login": "Neplatné přihlášení", - "error.access.panel": "Nemáte oprávnění k přihlášení do panelu", - "error.access.view": "Nemáte oprávnění ke vstupu do této části panelu.", - - "error.avatar.create.fail": "Nebylo možné nahrát profilový obrázek", - "error.avatar.delete.fail": "Nebylo mo\u017en\u00e9 smazat profilov\u00fd obr\u00e1zek", - "error.avatar.dimensions.invalid": "Šířka a výška obrázku musí být pod 3000 pixelů", - "error.avatar.mime.forbidden": "Profilový obrázek musí být ve formátu JPEG nebo PNG", - - "error.blueprint.notFound": "Nelze načíst blueprint \"{name}\" ", - - "error.blocks.max.plural": "Nelze přidat více něž {max} bloků", - "error.blocks.max.singular": "Nelze přidat více než jeden blok", - "error.blocks.min.plural": "Musíte přidat alespoň {min} bloků", - "error.blocks.min.singular": "Musíte přidat alespoň jeden blok", - "error.blocks.validation": "V poli \"{field}\" v bloku {index} je při použití \"{fieldset}\" typu chyba", - - "error.cache.type.invalid": "Neplatný typ cache \"{type}\"", - - "error.email.preset.notFound": "Nelze nalézt emailové přednastavení \"{name}\"", - - "error.field.converter.invalid": "Neplatný konvertor \"{converter}\"", - "error.field.type.missing": "Pole \"{ name }\": Typ pole \"{ type }\" neexistuje", - - "error.file.changeName.empty": "Toto jméno nesmí být prázdné", - "error.file.changeName.permission": "Nemáte povoleno změnit jméno souboru \"{filename}\"", - "error.file.changeTemplate.invalid": "Šablonu souboru \"{id}\" nelze změnit na \"{template}\" (platné: \"{blueprints}\")", - "error.file.changeTemplate.permission": "Nemáte dovoleno změnit šablonu souboru \"{id}\"", - - "error.file.duplicate": "Soubor s názvem \"{filename}\" již existuje", - "error.file.extension.forbidden": "Přípona souboru \"{extension}\" není povolena", - "error.file.extension.invalid": "Neplatná přípona souboru: {extension}", - "error.file.extension.missing": "Nem\u016f\u017eete nahr\u00e1t soubor bez p\u0159\u00edpony", - "error.file.maxheight": "Výška obrázku nesmí přesáhnout {height} pixelů", - "error.file.maxsize": "Soubor je příliš velký", - "error.file.maxwidth": "Šířka obrázku nesmí přesáhnout {width} pixelů", - "error.file.mime.differs": "Nahraný soubor musí být stejného typu \"{mime}\"", - "error.file.mime.forbidden": "Soubor typu \"{mime}\" není povolený", - "error.file.mime.invalid": "Neplatný MIME typ: {mime}", - "error.file.mime.missing": "Nelze rozeznat mime typ souboru \"{filename}\"", - "error.file.minheight": "Výška obrázku musí být alespoň {height} pixelů", - "error.file.minsize": "Soubor je příliš malý", - "error.file.minwidth": "Šířka obrázku musí být alespoň {width} pixelů", - "error.file.name.unique": "Název souboru musí být unikátní", - "error.file.name.missing": "Název souboru nesmí být prázdný", - "error.file.notFound": "Soubor se nepoda\u0159ilo nal\u00e9zt", - "error.file.orientation": "Orientace obrázku másí být \"{orientation}\"", - "error.file.type.forbidden": "Nemáte povoleno nahrávat soubory typu {type} ", - "error.file.type.invalid": "Neplatný typ souboru: {type}", - "error.file.undefined": "Soubor se nepoda\u0159ilo nal\u00e9zt", - - "error.form.incomplete": "Prosím opravte všechny chyby ve formuláři", - "error.form.notSaved": "Formulář nemohl být uložen", - - "error.language.code": "Zadejte prosím platný kód jazyka", - "error.language.duplicate": "Jazyk již existuje", - "error.language.name": "Zadejte prosím platné jméno jazyka", - "error.language.notFound": "Jazyk nebyl nalezen", - - "error.layout.validation.block": "V rozvržení {layoutIndex} je v poli \"{field}\" v bloku {blockIndex} při použití \"{fieldset}\" typu chyba", - "error.layout.validation.settings": "Chyba v nastavení rozvržení {index}", - - "error.license.domain": "Licenčnímu klíči chybí doména", - "error.license.email": "Zadejte prosím platnou emailovou adresu", - "error.license.format": "Zadejte prosím platné licenční číslo", - "error.license.verification": "Licenci nelze ověřit", - - "error.login.totp.confirm.invalid": "Neplatný kód", - "error.login.totp.confirm.missing": "Zadejte prosím licenční kód", - - "error.object.validation": "V poli \"{label}\" je chyba:\n{message}", - - "error.offline": "Panel je v současnosti off-line", - - "error.page.changeSlug.permission": "Nem\u016f\u017eete zm\u011bnit URL t\u00e9to str\u00e1nky", - "error.page.changeSlug.reserved": "Cesta k stránkám na nevyšší úrovni nesmí začínat jako \"{path}\"", - "error.page.changeStatus.incomplete": "Stránka obsahuje chyby a nemohla být zveřejněna", - "error.page.changeStatus.permission": "Status této stránky nelze změnit", - "error.page.changeStatus.toDraft.invalid": "Stránka \"{slug}\" nemůže být převedena na koncept", - "error.page.changeTemplate.invalid": "Šablonu stránky \"{slug}\" nelze změnit", - "error.page.changeTemplate.permission": "Nemáte dovoleno změnit šablonu stránky \"{slug}\"", - "error.page.changeTitle.empty": "Titulek nesmí být prázdný", - "error.page.changeTitle.permission": "Nemáte dovoleno změnit titulek stránky \"{slug}\"", - "error.page.create.permission": "Nemáte dovoleno vytvořit \"{slug}\"", - "error.page.delete": "Stránku \"{slug}\" nelze vymazat", - "error.page.delete.confirm": "Pro potvrzení prosím zadejte titulek stránky", - "error.page.delete.hasChildren": "Stránka má podstránky, nemůže být vymazána", - "error.page.delete.permission": "Nemáte dovoleno odstranit \"{slug}\"", - "error.page.draft.duplicate": "Koncept stránky, který obsahuje v adrese URL \"{slug}\" již existuje ", - "error.page.duplicate": "Stránka, která v adrese URL obsahuje \"{slug}\" již existuje", - "error.page.duplicate.permission": "Nemáte dovoleno duplikovat \"{slug}\"", - "error.page.move.ancestor": "Stránka nemůže být přesunuta sama do sebe", - "error.page.move.directory": "Adresář stránky nelze přesunout", - "error.page.move.duplicate": "Podstránka s URL \"{slug}\" již existuje", - "error.page.move.notFound": "Přesunutá stránka nebyla nalezena", - "error.page.move.permission": "Nemáte dovoleno přesunout stránku \"{slug}\"", - "error.page.move.template": "Šablonu \"{template}\" nelze použít pro podstránku \"{parent}\"", - "error.page.notFound": "Str\u00e1nku se nepoda\u0159ilo nal\u00e9zt.", - "error.page.num.invalid": "Zadejte prosím platné pořadové číslo. Čísla nesmí být záporná.", - "error.page.slug.invalid": "Podtržení", - "error.page.slug.maxlength": "URL musí mít méně než \"{length}\" znaků", - "error.page.sort.permission": "Stránce \"{slug}\" nelze změnit pořadí", - "error.page.status.invalid": "Nastavte prosím platný status stránky", - "error.page.undefined": "Str\u00e1nku se nepoda\u0159ilo nal\u00e9zt.", - "error.page.update.permission": "Nemáte dovoleno upravit \"{slug}\"", - - "error.section.files.max.plural": "Sekce \"{section}\" nesmí obsahovat více jak {max} souborů", - "error.section.files.max.singular": "Sekce \"{section}\" může obsahovat nejvýše jeden soubor", - "error.section.files.min.plural": "Sekce \"{section}\" vyžaduje nejméně {min} souborů", - "error.section.files.min.singular": "Sekce \"{section}\" vyžaduje alespoň jeden soubor", - - "error.section.pages.max.plural": "Sekce \"{section}\" nesmí obsahovat více jak {max} stránek", - "error.section.pages.max.singular": "Sekce \"{section}\" může obsahovat nejvýše jednu stránku", - "error.section.pages.min.plural": "Sekce \"{section}\" vyžaduje alespoň {min} stránek", - "error.section.pages.min.singular": "Sekce \"{section}\" vyžaduje alespoň jednu stránku", - - "error.section.notLoaded": "Nelze načíst sekci \"{name}\"", - "error.section.type.invalid": "Typ sekce \"{type}\" není platný", - - "error.site.changeTitle.empty": "Titulek nesmí být prázdný", - "error.site.changeTitle.permission": "Nemáte dovoleno změnit titulek stránky", - "error.site.update.permission": "Nemáte dovoleno upravit stránku", - - "error.structure.validation": "Chyba v poli \"{field}\" na řádku {index}", - - "error.template.default.notFound": "Výchozí šablona neexistuje", - - "error.unexpected": "Vyskytla se neočekávaná chyba! Pro více informací povolte debug mód, viz: https://getkirby.com/docs/reference/system/options/debug", - - "error.user.changeEmail.permission": "Nemáte dovoleno měnit email uživatele \"{name}\"", - "error.user.changeLanguage.permission": "Nemáte dovoleno změnit jazyk uživatele \"{name}\"", - "error.user.changeName.permission": "Nemáte dovoleno změnit jméno uživatele \"{name}\"", - "error.user.changePassword.permission": "Nemáte dovoleno změnit heslo uživatele \"{name}\"", - "error.user.changeRole.lastAdmin": "Role posledního administrátora nemůže být změněna", - "error.user.changeRole.permission": "Nemáte dovoleno změnit roli uživatele \"{name}\"", - "error.user.changeRole.toAdmin": "Nemáte dovoleno povýšit uživatele do role administrátora.", - "error.user.create.permission": "Nemáte dovoleno vytvořit tohoto uživatele", - "error.user.delete": "U\u017eivatel nemohl b\u00fdt smaz\u00e1n", - "error.user.delete.lastAdmin": "Nem\u016f\u017eete smazat posledn\u00edho administr\u00e1tora", - "error.user.delete.lastUser": "Poslední uživatel nemůže být smazán", - "error.user.delete.permission": "Nem\u00e1te dovoleno smazat tohoto u\u017eivatele", - "error.user.duplicate": "Uživatel s emailovou adresou \"{email}\" již existuje", - "error.user.email.invalid": "Zadejte prosím platnou emailovou adresu", - "error.user.language.invalid": "Zadejte prosím platný jazyk", - "error.user.notFound": "U\u017eivatele se nepoda\u0159ilo nal\u00e9zt", - "error.user.password.excessive": "Zadejte prosím platné heslo. Heslo nesmí být delší než 1000 znaků.", - "error.user.password.invalid": "Zadejte prosím platné heslo. Heslo musí být dlouhé alespoň 8 znaků.", - "error.user.password.notSame": "Pros\u00edm potvr\u010fte heslo", - "error.user.password.undefined": "Uživatel nemá nastavené heslo.", - "error.user.password.wrong": "Špatné heslo", - "error.user.role.invalid": "Zadejte prosím platnou roli", - "error.user.undefined": "Uživatele se nepodařilo nalézt", - "error.user.update.permission": "Nemáte dovoleno upravit uživatele \"{name}\"", - - "error.validation.accepted": "Potvrďte prosím", - "error.validation.alpha": "Zadávejte prosím pouze znaky v rozmezí a-z", - "error.validation.alphanum": "Zadávejte prosím pouze znaky v rozmezí a-z nebo čísla v rozmezí 0-9", - "error.validation.anchor": "Zadejte správný název kotvy", - "error.validation.between": "Zadejte prosím hodnotu mez \"{min}\" a \"{max}\"", - "error.validation.boolean": "Potvrďte prosím, nebo odmítněte", - "error.validation.color": "Zadejte platnou barvu ve formátu {format}", - "error.validation.contains": "Zadejte prosím hodnotu, která obsahuje \"{needle}\"", - "error.validation.date": "Zadejte prosím platné datum", - "error.validation.date.after": "Zadejte prosím datum po {date}", - "error.validation.date.before": "Zadejte prosím datum před {date}", - "error.validation.date.between": "Zadejte prosím datum mezi {min} a {max}", - "error.validation.denied": "Prosím, odmítněte", - "error.validation.different": "Hodnota nesmí být \"{other}\"", - "error.validation.email": "Zadejte prosím platnou emailovou adresu", - "error.validation.endswith": "Hodnota nesmí končit \"{end}\"", - "error.validation.filename": "Zadejte prosím platný název souboru", - "error.validation.in": "Zadejte prosím některou z následujíích hodnot: ({in})", - "error.validation.integer": "Zadejte prosím platné celé číslo", - "error.validation.ip": "Zadejte prosím platnou IP adresu", - "error.validation.less": "Zadejte prosím hodnotu menší než {max}", - "error.validation.linkType": "Typ odkazu není povolen", - "error.validation.match": "Hodnota neodpovídá očekávanému vzoru", - "error.validation.max": "Zadejte prosím hodnotu rovnou, nebo menší než {max}", - "error.validation.maxlength": "Zadaná hodnota je příliš dlouhá. (Povoleno nejvýše {max} znaků)", - "error.validation.maxwords": "Nezadávejte prosím více jak {max} slov", - "error.validation.min": "Zadejte prosím hodnotu rovnou, nebo větší než {min}", - "error.validation.minlength": "Zadaná hodnota je příliš krátká. (Požadováno nejméně {min} znaků)", - "error.validation.minwords": "Zadejte prosím alespoň {min} slov", - "error.validation.more": "Zadejte prosím hodnotu větší než {min}", - "error.validation.notcontains": "Zadejte prosím hodnotu, která neobsahuje \"{needle}\"", - "error.validation.notin": "Nezadávejte prosím žádnou z následujíích hodnot: ({notIn})", - "error.validation.option": "Vyberte prosím platnou možnost", - "error.validation.num": "Zadejte prosím platné číslo", - "error.validation.required": "Zadejte prosím jakoukoli hodnotu", - "error.validation.same": "Zadejte prosím \"{other}\"", - "error.validation.size": "Velikost hodnoty musí být \"{size}\"", - "error.validation.startswith": "Hodnota musí začínat \"{start}\"", - "error.validation.tel": "Zadejte neformátované telefonní číslo ", - "error.validation.time": "Zadejte prosím platný čas", - "error.validation.time.after": "Zadejte prosím čas po {time}", - "error.validation.time.before": "Zadejte prosím čas před {time}", - "error.validation.time.between": "Zadejte prosím čas v rozmezí od {min} do {max}", - "error.validation.uuid": "Zadejte platné UUID", - "error.validation.url": "Zadejte prosím platnou adresu URL", - - "expand": "Rozbalit", - "expand.all": "Rozbalit vše", - - "field.invalid": "Pole není platné", - "field.required": "Pole musí být vyplněno.", - "field.blocks.changeType": "Změnit typ", - "field.blocks.code.name": "Kód", - "field.blocks.code.language": "Jazyk", - "field.blocks.code.placeholder": "Váš kód …", - "field.blocks.delete.confirm": "Opravdu chcete smazat tento blok?", - "field.blocks.delete.confirm.all": "Opravdu chcete smazat všechny bloky?", - "field.blocks.delete.confirm.selected": "Opravdu chcete smazat vybrané bloky?", - "field.blocks.empty": "Zatím žádné bloky", - "field.blocks.fieldsets.empty": "Zatím žádné fieldsets", - "field.blocks.fieldsets.label": "Vyberte prosím typ bloku …", - "field.blocks.fieldsets.paste": "Stiskněte{{ shortcut }} pro vložení rozvržení/bloků ze schránky Vloženy budou jen ty, které jsou v aktuálním poli povolené.", - "field.blocks.gallery.name": "Galerie", - "field.blocks.gallery.images.empty": "Zatím žádné obrázky", - "field.blocks.gallery.images.label": "Obrázky", - "field.blocks.heading.level": "Úroveň", - "field.blocks.heading.name": "Nadpis", - "field.blocks.heading.text": "Text", - "field.blocks.heading.placeholder": "Nadpis …", - "field.blocks.image.alt": "Alternativní text", - "field.blocks.image.caption": "Titulek", - "field.blocks.image.crop": "Oříznout", - "field.blocks.image.link": "Odkaz", - "field.blocks.image.location": "Umístění", - "field.blocks.image.location.internal": "Tato webová stránka", - "field.blocks.image.location.external": "Externí zdroj", - "field.blocks.image.name": "Obrázek", - "field.blocks.image.placeholder": "Vyberte obrázek", - "field.blocks.image.ratio": "Poměr stran", - "field.blocks.image.url": "URL obrázku", - "field.blocks.line.name": "Čára", - "field.blocks.list.name": "Seznam", - "field.blocks.markdown.name": "Markdown", - "field.blocks.markdown.label": "Text", - "field.blocks.markdown.placeholder": "Markdown …", - "field.blocks.quote.name": "Citát", - "field.blocks.quote.text.label": "Text", - "field.blocks.quote.text.placeholder": "Citát …", - "field.blocks.quote.citation.label": "Citace", - "field.blocks.quote.citation.placeholder": "od …", - "field.blocks.text.name": "Text", - "field.blocks.text.placeholder": "Text …", - "field.blocks.video.autoplay": "Autoplay", - "field.blocks.video.caption": "Titulek", - "field.blocks.video.controls": "Ovládání", - "field.blocks.video.location": "Umístění", - "field.blocks.video.loop": "Smyčka", - "field.blocks.video.muted": "Ztlumené", - "field.blocks.video.name": "Video", - "field.blocks.video.placeholder": "Zadejte URL adresu videa", - "field.blocks.video.poster": "Náhledový obrázek", - "field.blocks.video.preload": "Předběžně načíst", - "field.blocks.video.url.label": "URL adresa videa", - "field.blocks.video.url.placeholder": "https://youtube.com/?v=", - - "field.files.empty": "Nebyly zatím vybrány žádné soubory", - - "field.layout.change": "Změnit rozvržení", - "field.layout.delete": "Smazat rozvržení", - "field.layout.delete.confirm": "Opravdu chcete smazat toto rozvržení?", - "field.layout.delete.confirm.all": "Opravdu chcete smazat všechna rozvržení?", - "field.layout.empty": "Zatím žádné řádky", - "field.layout.select": "Vyberte rozvržení", - - "field.object.empty": "Zatím žádná informace", - - "field.pages.empty": "Nebyly zatím vybrány žádné stránky", - - "field.structure.delete.confirm": "Opravdu chcete smazat tento z\u00e1znam?", - "field.structure.delete.confirm.all": "Opravdu chcete smazat všechny záznamy?", - "field.structure.empty": "Zat\u00edm nejsou \u017e\u00e1dn\u00e9 z\u00e1znamy.", - - "field.users.empty": "Nebyli zatím vybráni žádní uživatelé", - - "fields.empty": "Zatím žádné pole", - - "file": "Soubor", - "file.blueprint": "Tento typ souboru nemá blueprint. Blueprint můžete definovat v /site/blueprints/files/{blueprint}.yml", - "file.changeTemplate": "Změnit šablonu", - "file.changeTemplate.notice": "Změna šablony souboru změní obsah pro pole, která mají odlišný typ. Pokud má nová šablona nastavena určitá pravidla, např. rozměry obrázku, tato pravidla budou také aplikována. Používejte obezřetně.", - "file.delete.confirm": "Opravdu chcete smazat tento soubor?", - "file.focus.placeholder": "Nastavit ohnisko", - "file.focus.reset": "Odstranit ohnisko", - "file.focus.title": "Zaměřit na", - "file.sort": "Změnit pozici", - - "files": "Soubory", - "files.empty": "Zatím žádné soubory", - - "filter": "Filtr", - - "hide": "Skrýt", - "hour": "Hodina", - "hue": "Odstín", - "import": "Import", - "info": "Informace", - "insert": "Vlo\u017eit", - "insert.after": "Vložit za", - "insert.before": "Vložit před", - "install": "Instalovat", - - "installation": "Instalace", - "installation.completed": "Panel byl nainstalován", - "installation.disabled": "Instalátor panelu je ve výchozím nastavení na veřejných serverech zakázán. Spusťte prosím instalátor na lokálním počítači nebo jej povolte prostřednictvím panel.install.", - "installation.issues.accounts": "\/site\/accounts nen\u00ed zapisovateln\u00e9", - "installation.issues.content": "Slo\u017eka content a v\u0161echny soubory a slo\u017eky v n\u00ed mus\u00ed b\u00fdt zapisovateln\u00e9.", - "installation.issues.curl": "Je vyžadováno rozšířeníCURL", - "installation.issues.headline": "Panel nelze nainstalovat", - "installation.issues.mbstring": "Je vyžadováno rozšířeníMB String", - "installation.issues.media": "Složka/media neexistuje, nebo nemá povolený zápis", - "installation.issues.php": "Ujistěte se, že používátePHP 8+", - "installation.issues.sessions": "Složka/site/sessions neexistuje, nebo nemá povolený zápis", - - "language": "Jazyk", - "language.code": "Kód", - "language.convert": "Nastavte výchozí možnost", - "language.convert.confirm": "

Opravdu chcete převést{name} na výchozí jazyk? Tuto volbu nelze vzít zpátky.

Pokud {name} obsahuje nepřeložený text, nebude již k dispozici záložní varianta a části stránky mohou zůstat prázdné.

", - "language.create": "Přidat nový jazyk", - "language.default": "Výchozí jazyk", - "language.delete.confirm": "Opravdu chcete smazat jazyk {name} včetně všech překladů? Tuto volbu nelze vzít zpátky!", - "language.deleted": "Jazyk byl smazán", - "language.direction": "Směr čtení", - "language.direction.ltr": "Zleva doprava", - "language.direction.rtl": "Zprava doleva", - "language.locale": "Řetězec lokalizace PHP", - "language.locale.warning": "Používáte vlastní jazykové nastavení. Upravte prosím soubor s nastavením v /site/languages", - "language.name": "Jméno", - "language.secondary": "Sekundární jazyk", - "language.settings": "Nastavení jazyka", - "language.updated": "Jazyk byl aktualizován", - "language.variables": "Jazykové proměnné", - "language.variables.empty": "Zatím žádné překlady", - - "language.variable.delete.confirm": "Doopravdy chcete smazat proměnou {key}?", - "language.variable.key": "Klíč", - "language.variable.notFound": "Proměnná nebyla nalezena", - "language.variable.value": "Hodnota", - - "languages": "Jazyky", - "languages.default": "Výchozí jazyk", - "languages.empty": "Zatím neexistují žádné jazyky", - "languages.secondary": "Další jazyky", - "languages.secondary.empty": "Neexistují zatím žádné další jazyky", - - "license": "Kirby licence", - "license.activate": "Aktivovat nyní", - "license.activate.label": "Prosím aktivute svoji licenci", - "license.activate.domain": "Vaše licence bude zaregistrována na {host}.", - "license.activate.local": "Chystáte se registrovat licenci na Vaší lokální doméně {host}. Pokud bude tato stránka nasazena na veřejnou doménu, registrujte prosím licenci až tam. Pokud je {host} opravdu doménou, na které si přejete licenci registrovat, pokračujte prosím dále.", - "license.activated": "Aktivováno", - "license.buy": "Zakoupit licenci", - "license.code": "Kód", - "license.code.help": "Licenční kód jste po zakoupení obdrželi na email. Vložte prosím kód a zaregistrujte Vaší kopii.", - "license.code.label": "Zadejte prosím licenční kód", - "license.status.active.info": "Platí pro nové verze až do {date}", - "license.status.active.label": "Platná licence", - "license.status.demo.info": "Tato instalace je pouze demoverze", - "license.status.demo.label": "Demoverze", - "license.status.inactive.info": "Pro update na novou hlavní verzi musíte obnovit licenci", - "license.status.inactive.label": "Žádné nové hlavní verze", - "license.status.legacy.bubble": "Vše připraveno na obnovení licence?", - "license.status.legacy.info": "Vaše licence se nevztahuje na tuto verzi", - "license.status.legacy.label": "Prosím obnovte svoji licenci", - "license.status.missing.bubble": "Vše připraveno na spuštění vaši stránky?", - "license.status.missing.info": "Žádlná platná licence", - "license.status.missing.label": "Prosím aktivute svoji licenci", - "license.manage": "Spravovat licence", - "license.purchased": "Zakoupeno", - "license.success": "Děkujeme Vám za podporu Kirby", - "license.unregistered.label": "Neregistrovaný", - - "link": "Odkaz", - "link.text": "Text odkazu", - - "loading": "Načítám", - - "lock.unsaved": "Neuložené změny", - "lock.unsaved.empty": "Nezbývají již žádné neuložené změny.", - "lock.isLocked": "Neuložené změny od {email}", - "lock.unlock": "Odemknout", - "lock.unlock.submit": "Odemknout a přepsat neuložené změny od {email}", - "lock.isUnlocked": "Bylo odemknuto jiným uživatelem", - - "login": "Přihlásit se", - "login.code.label.login": "Kód pro přihlášení", - "login.code.label.password-reset": "Kód pro resetování hesla", - "login.code.placeholder.email": "000 000", - "login.code.placeholder.totp": "000000", - "login.code.text.email": "Vaše e-mailová adresa byla zaregistrována, kód byl odeslán do Vaší e-mailové schránky.", - "login.code.text.totp": "Prosím vložte jednorázový kód z vaší autentifikační aplikace.", - "login.email.login.body": "Ahoj {user.nameOrEmail},\n\nV nedávné době jsi zažádal(a) o kód pro přihlášení do Kirby Panelu na stránce {site}.\nNásledující kód pro přihlášení je platný {timeout} minut:\n\n{code}\n\nPokud jsi o kód pro přihlášení nežádal(a), tuto zprávu prosím ignoruj a v případě dotazů prosím kontaktuj svého administrátora.\nZ bezpečnostních důvodů prosím tuto zprávu nepřeposílej nikomu dalšímu.", - "login.email.login.subject": "Váš kód pro přihlášení", - "login.email.password-reset.body": "Ahoj {user.nameOrEmail},\n\nV nedávné době jsi zažádal(a) o kód pro resetování hesla do Kirby Panelu na stránce {site}.\nNásledující kód pro resetování hesla je platný {timeout} minut:\n\n{code}\n\nPokud jsi o kód pro resetování hesla nežádal(a), tuto zprávu prosím ignoruj a v případě dotazů prosím kontaktuj svého administrátora.\nZ bezpečnostních důvodů prosím tuto zprávu nepřeposílej nikomu dalšímu.", - "login.email.password-reset.subject": "Váš kód pro resetování hesla", - "login.remember": "Zůstat přihlášen", - "login.reset": "Resetovat heslo", - "login.toggleText.code.email": "Přihlásit se pomocí e-mailu", - "login.toggleText.code.email-password": "Přihlásit se pomocí hesla", - "login.toggleText.password-reset.email": "Zapomenuté heslo?", - "login.toggleText.password-reset.email-password": "← Zpět na přihlášení", - "login.totp.enable.option": "Nastavit jednorázové kódy", - "login.totp.enable.intro": "Autentifikační aplikace umí generovat jednorázové kódy, které jsou použitý jako druhý faktor při přihlášení do vašeho účtu.", - "login.totp.enable.qr.label": "1. Naskenujte tento QR kód", - "login.totp.enable.qr.help": "Nepodařilo se scanovat? Přidejte klíč pro nastavení  {secret} ručně do své autentifikační aplikace.", - "login.totp.enable.confirm.headline": "2. Potvrďte vygenerovaným kódem", - "login.totp.enable.confirm.text": "Vaše aplikace generuje každých 30 sekund nový jednorázový kód. Zadejte aktuální kód a dokončete nastavení:", - "login.totp.enable.confirm.label": "Současný kód", - "login.totp.enable.confirm.help": "Po tomto nastavení vás při každém přihlášení požádáme o jednorázový kód.", - "login.totp.enable.success": "Jednorázové kódy zapnuty", - "login.totp.disable.option": "Vypnutí jednorázových kódu", - "login.totp.disable.label": "Pro vypnutí jednorázových kódů zadejte svoje heslo", - "login.totp.disable.help": "V budoucnu bude při přihlašování vyžadován jiný druhý faktor, například přihlašovací kód zaslaný e-mailem. Jednorázové kódy můžete vždy později nastavit znovu.", - "login.totp.disable.admin": "

Tím se jednorázové kódy pro{user} zakážou.

V budoucnu bude při přihlášení vyžadován jiný druhý faktor, například přihlašovací kód zaslaný e-mailem. Jednorázové kódy si může {user} nastavit znovu po svém dalším přihlášení.", - "login.totp.disable.success": "Jednorázové kódy vypnuty", - - "logout": "Odhlásit se", - - "merge": "Spojit", - "menu": "Menu", - "meridiem": "AM/PM", - "mime": "Typ média", - "minutes": "Minuty", - - "month": "Měsíc", - "months.april": "Duben", - "months.august": "Srpen", - "months.december": "Prosinec", - "months.february": "Únor", - "months.january": "Leden", - "months.july": "\u010cervenec", - "months.june": "\u010cerven", - "months.march": "B\u0159ezen", - "months.may": "Kv\u011bten", - "months.november": "Listopad", - "months.october": "\u0158\u00edjen", - "months.september": "Z\u00e1\u0159\u00ed", - - "more": "Více", - "move": "Přesunout", - "name": "Jméno", - "next": "Další", - "night": "Noc", - "no": "ne", - "off": "vypnuto", - "on": "zapnuto", - "open": "Otevřít", - "open.newWindow": "Otevřít v novém okně", - "option": "Možnost", - "options": "Možnosti", - "options.none": "Žádné možnosti", - "options.all": "Zobrazit všech {count} možností", - - "orientation": "Orientace", - "orientation.landscape": "Na šířku", - "orientation.portrait": "Na výšku", - "orientation.square": "Čtverec", - - "page": "Stránka", - "page.blueprint": "Tento typ stránky nemá blueprint. Blueprint můžete definovat v /site/blueprints/pages/{blueprint}.yml", - "page.changeSlug": "Zm\u011bnit URL", - "page.changeSlug.fromTitle": "Vytvo\u0159it z n\u00e1zvu", - "page.changeStatus": "Změnit status", - "page.changeStatus.position": "Vyberte prosím pozici", - "page.changeStatus.select": "Vybrat nový status", - "page.changeTemplate": "Změnit šablonu", - "page.changeTemplate.notice": "Změna šablony stránky odstraní obsah pro pole, jejichž typy se neshodují. Používejte obezřetně.", - "page.create": "Vytvořit jako {status}", - "page.delete.confirm": "Opravdu chcete smazat tuto str\u00e1nku?", - "page.delete.confirm.subpages": "Tato stránka má podstránky.
Všechny podstránky budou vymazány.", - "page.delete.confirm.title": "Pro potvrzení zadejte titulek stránky", - "page.duplicate.appendix": "Kopírovat", - "page.duplicate.files": "Kopírovat soubory", - "page.duplicate.pages": "Kopírovat stránky", - "page.move": "Přesunout stránku", - "page.sort": "Změnit pozici", - "page.status": "Stav", - "page.status.draft": "Koncept", - "page.status.draft.description": "Stránka je ve stavu konceptu a je viditelná pouze pro přihlášené editory, nebo přes tajný odkaz", - "page.status.listed": "Veřejná", - "page.status.listed.description": "Stránka je zveřejněná pro všechny", - "page.status.unlisted": "Neveřejná", - "page.status.unlisted.description": "Tato stránka je dostupná pouze přes URL.", - - "pages": "Stránky", - "pages.empty": "Zatím žádné stránky", - "pages.status.draft": "Koncepty", - "pages.status.listed": "Zveřejněno", - "pages.status.unlisted": "Neveřejná", - - "pagination.page": "Stránka", - - "password": "Heslo", - "paste": "Vložit", - "paste.after": "Vložit za", - "paste.success": "{count} vloženo!", - "pixel": "Pixel", - "plugin": "Doplňek", - "plugins": "Doplňky", - "prev": "Předchozí", - "preview": "Náhled", - "remove": "Odstranit", - "rename": "Přejmenovat", - "renew": "Obnovit", - "replace": "Nahradit", - "replace.with": "Nahradit pomocí", - "retry": "Zkusit znovu", - "revert": "Zahodit", - "revert.confirm": "Opravdu chcete smazat všechny provedené změny?", - - "role": "Role", - "role.admin.description": "Administrátor má všechna práva", - "role.admin.title": "Administrátor", - "role.all": "Vše", - "role.empty": "Neexistují uživatelé s touto rolí", - "role.description.placeholder": "Žádný popis", - "role.nobody.description": "Toto je výchozí role bez jakýchkoli oprávnění", - "role.nobody.title": "Nikdo", - - "save": "Ulo\u017eit", - "search": "Hledat", - "search.min": "Pro vyhledání zadejte alespoň {min} znaky", - "search.all": "Zobrazit všech {count} výsledků", - "search.results.none": "Žádné výsledky", - - "section.invalid": "Sekce je neplatná", - "section.required": "Sekce musí být vyplněna", - - "security": "Zabezpečení", - "select": "Vybrat", - "server": "Server", - "settings": "Nastavení", - "show": "Zobrazit", - "site.blueprint": "Hlavní panel nemá blueprint. Blueprint můžete definovat v /site/blueprints/site.yml", - "size": "Velikost", - "slug": "P\u0159\u00edpona URL", - "sort": "Řadit", - "sort.drag": "Táhnout pro změnu řazení ...", - "split": "Rozdělit", - - "stats.empty": "Žádná hlášení", - "status": "Stav", - - "system.info.copy": "Copy info", - "system.info.copied": "System info copied", - "system.issues.content": "Složka content je zřejmě přístupná zvenčí", - "system.issues.eol.kirby": "Instalovaná verze Kirby dosáhla konce životnosti a nebude již dále dostávat bezpečnostní aktualizace", - "system.issues.eol.plugin": "Instalovaná verze doplňku { plugin } dosáhla konce životnosti a nebude již dále dostávat bezpečnostní aktualizace", - "system.issues.eol.php": "Instalovaná verze PHP { release } dosálhla konce životnosti a nebude již dále dostávat bezpečností aktualizace", - "system.issues.debug": "Debug mode musí být v produkci vypnutý", - "system.issues.git": "Složka .git je zřejmě přístupná zvenčí", - "system.issues.https": "Pro všechny stránky doporučujeme používat protokol HTTPS", - "system.issues.kirby": "Složka kirby je zřejmě přístupná zvenčí", - "system.issues.site": "Složka site je zřejmě přístupná zvenčí", - "system.issues.vulnerability.kirby": "Vaše instalace může být ovlivněna následující zranitelností (stupeň vážnosti - { severity }): { description }", - "system.issues.vulnerability.plugin": "Vaše instalace může být ovlivněna následující zranitelností v doplňku { plugin } (stupeň vážnosti - { severity }): { description }", - "system.updateStatus": "Status aktualizací", - "system.updateStatus.error": "Nepodařilo se zkontrolovat aktualizace", - "system.updateStatus.not-vulnerable": "Žádné známé zranitelnosti", - "system.updateStatus.security-update": "Je dostupná bezplatná bezpečnostní aktualizace { version }", - "system.updateStatus.security-upgrade": "Je dostupný upgrade { version } s bezpečnostními opravami", - "system.updateStatus.unreleased": "Nevydaná verze", - "system.updateStatus.up-to-date": "Aktuální", - "system.updateStatus.update": "Je dostupná bezplatná nová verze { version }", - "system.updateStatus.upgrade": "Je dostupný upgrade na verzi { version }", - - "tel": "Telefon", - "tel.placeholder": "+49123456789", - "template": "\u0160ablona", - "title": "Název", - "today": "Dnes", - - "toolbar.button.clear": "Odstranit formátování", - "toolbar.button.code": "Kód", - "toolbar.button.bold": "Tu\u010dn\u00fd text", - "toolbar.button.email": "Email", - "toolbar.button.headings": "Nadpisy", - "toolbar.button.heading.1": "Nadpis 1", - "toolbar.button.heading.2": "Nadpis 2", - "toolbar.button.heading.3": "Nadpis 3", - "toolbar.button.heading.4": "Nadpis 4", - "toolbar.button.heading.5": "Nadpis 5", - "toolbar.button.heading.6": "Nadpis 6", - "toolbar.button.italic": "Kurz\u00edva", - "toolbar.button.file": "Soubor", - "toolbar.button.file.select": "Vyberte soubor", - "toolbar.button.file.upload": "Nahrajte soubor", - "toolbar.button.link": "Odkaz", - "toolbar.button.paragraph": "Odstavec", - "toolbar.button.strike": "Přeškrtnutí", - "toolbar.button.sub": "Dolní index", - "toolbar.button.sup": "Horní index", - "toolbar.button.ol": "Číslovaný seznam", - "toolbar.button.underline": "Podtržení", - "toolbar.button.ul": "Odrážkový seznam", - - "translation.author": "Kirby tým", - "translation.direction": "ltr", - "translation.name": "\u010cesky", - "translation.locale": "cs_CZ", - - "type": "Typ", - - "upload": "Nahrát", - "upload.error.cantMove": "Nahraný soubor nemohl být přesunut", - "upload.error.cantWrite": "Zápis souboru na disk se nezdařil", - "upload.error.default": "Soubor se nepodařilo nahrát", - "upload.error.extension": "Nahrávání souboru přerušeno rozšířením.", - "upload.error.formSize": "Velikost nahrávaného souboru převyšuje omezení stanovené direktivou MAX_FILE_SIZE", - "upload.error.iniPostSize": "Velikost nahrávaného souboru převyšuje omezení stanovené direktivou post_max_size, která je nastavena v php.ini", - "upload.error.iniSize": "Velikost nahrávaného souboru převyšuje omezení stanovené direktivou upload_max_filesize, která je nastavena v php.ini ", - "upload.error.noFile": "Nebyl nahrán žádný soubor", - "upload.error.noFiles": "Nebyly nahrány žádné soubory", - "upload.error.partial": "Soubor byl nahrán pouze z části", - "upload.error.tmpDir": "Chybí dočasná složka", - "upload.errors": "Chyba", - "upload.progress": "Nahrávání...", - - "url": "Url", - "url.placeholder": "https://example.com", - - "user": "Uživatel", - "user.blueprint": "Pro tuto uživatelskou roli můžete definovat další sekce a pole v /site/blueprints/users/{blueprint}.yml", - "user.changeEmail": "Změnit email", - "user.changeLanguage": "Změnit jazyk", - "user.changeName": "Přejmenovat tohoto uživatele", - "user.changePassword": "Změnit heslo", - "user.changePassword.new": "Nové heslo", - "user.changePassword.new.confirm": "Potvrdit nové heslo...", - "user.changeRole": "Změnit roli", - "user.changeRole.select": "Vybrat novou roli", - "user.create": "Přidat nového uživatele", - "user.delete": "Smazat tohoto uživatele", - "user.delete.confirm": "Opravdu chcete smazat tohoto u\u017eivatele?", - - "users": "Uživatelé", - - "version": "Verze Kirby", - "version.current": "Současná verze", - "version.latest": "Poslední verze", - "versionInformation": "Informace o verzi", - - "view.account": "V\u00e1\u0161 \u00fa\u010det", - "view.installation": "Instalace", - "view.languages": "Jazyky", - "view.resetPassword": "Resetovat heslo", - "view.site": "Stránka", - "view.system": "Systém", - "view.users": "U\u017eivatel\u00e9", - - "welcome": "Vítejte", - "year": "Rok", - "yes": "ano" + "account.changeName": "Přejmenovat", + "account.delete": "Smazat účet", + "account.delete.confirm": "Opravdu chcete smazat svůj účet? Budete okamžitě odhlášeni. Účet nemůže být zpětně obnoven.", + + "add": "P\u0159idat", + "author": "Autor", + "avatar": "Profilov\u00fd obr\u00e1zek", + "back": "Zpět", + "cancel": "Zru\u0161it", + "change": "Zm\u011bnit", + "close": "Zavřít", + "confirm": "Ok", + "collapse": "Sbalit", + "collapse.all": "Sbalit vše", + "copy": "Kopírovat", + "copy.all": "Kopírovat vše", + "create": "Vytvořit", + + "date": "Datum", + "date.select": "Vyberte datum", + + "day": "Den", + "days.fri": "p\u00e1", + "days.mon": "po", + "days.sat": "so", + "days.sun": "ne", + "days.thu": "\u010dt", + "days.tue": "\u00fat", + "days.wed": "st", + + "debugging": "Ladění", + + "delete": "Smazat", + "delete.all": "Smazat vše", + + "dialog.files.empty": "Žádné soubory k výběru", + "dialog.pages.empty": "Žádné stránky k výběru", + "dialog.users.empty": "Žádní uživatelé k výběru", + + "dimensions": "Rozměry", + "disabled": "Zakázáno", + "discard": "Zahodit", + "download": "Stáhnout", + "duplicate": "Duplikovat", + + "edit": "Upravit", + + "email": "Email", + "email.placeholder": "mail@example.com", + + "entries": "Entries", + "entry": "Entry", + + "environment": "Prostředí", + + "error.access.code": "Neplatný kód", + "error.access.login": "Neplatné přihlášení", + "error.access.panel": "Nemáte oprávnění k přihlášení do panelu", + "error.access.view": "Nemáte oprávnění ke vstupu do této části panelu.", + + "error.avatar.create.fail": "Nebylo možné nahrát profilový obrázek", + "error.avatar.delete.fail": "Nebylo mo\u017en\u00e9 smazat profilov\u00fd obr\u00e1zek", + "error.avatar.dimensions.invalid": "Šířka a výška obrázku musí být pod 3000 pixelů", + "error.avatar.mime.forbidden": "Profilový obrázek musí být ve formátu JPEG nebo PNG", + + "error.blueprint.notFound": "Nelze načíst blueprint \"{name}\" ", + + "error.blocks.max.plural": "Nelze přidat více něž {max} bloků", + "error.blocks.max.singular": "Nelze přidat více než jeden blok", + "error.blocks.min.plural": "Musíte přidat alespoň {min} bloků", + "error.blocks.min.singular": "Musíte přidat alespoň jeden blok", + "error.blocks.validation": "Chyba v bloku {index}", + + "error.email.preset.notFound": "Nelze nalézt emailové přednastavení \"{name}\"", + + "error.field.converter.invalid": "Neplatný konvertor \"{converter}\"", + + "error.file.changeName.empty": "Toto jméno nesmí být prázdné", + "error.file.changeName.permission": "Nemáte povoleno změnit jméno souboru \"{filename}\"", + "error.file.duplicate": "Soubor s názvem \"{filename}\" již existuje", + "error.file.extension.forbidden": "Přípona souboru \"{extension}\" není povolena", + "error.file.extension.invalid": "Neplatná přípona souboru: {extension}", + "error.file.extension.missing": "Nem\u016f\u017eete nahr\u00e1t soubor bez p\u0159\u00edpony", + "error.file.maxheight": "Výška obrázku nesmí přesáhnout {height} pixelů", + "error.file.maxsize": "Soubor je příliš velký", + "error.file.maxwidth": "Šířka obrázku nesmí přesáhnout {width} pixelů", + "error.file.mime.differs": "Nahraný soubor musí být stejného typu \"{mime}\"", + "error.file.mime.forbidden": "Soubor typu \"{mime}\" není povolený", + "error.file.mime.invalid": "Neplatný MIME typ: {mime}", + "error.file.mime.missing": "Nelze rozeznat mime typ souboru \"{filename}\"", + "error.file.minheight": "Výška obrázku musí být alespoň {height} pixelů", + "error.file.minsize": "Soubor je příliš malý", + "error.file.minwidth": "Šířka obrázku musí být alespoň {width} pixelů", + "error.file.name.missing": "Název souboru nesmí být prázdný", + "error.file.notFound": "Soubor se nepoda\u0159ilo nal\u00e9zt", + "error.file.orientation": "Orientace obrázku másí být \"{orientation}\"", + "error.file.type.forbidden": "Nemáte povoleno nahrávat soubory typu {type} ", + "error.file.type.invalid": "Neplatný typ souboru: {type}", + "error.file.undefined": "Soubor se nepoda\u0159ilo nal\u00e9zt", + + "error.form.incomplete": "Prosím opravte všechny chyby ve formuláři", + "error.form.notSaved": "Formulář nemohl být uložen", + + "error.language.code": "Zadejte prosím platný kód jazyka", + "error.language.duplicate": "Jazyk již existuje", + "error.language.name": "Zadejte prosím platné jméno jazyka", + "error.language.notFound": "Jazyk nebyl nalezen", + + "error.layout.validation.block": "Chyba v bloku {blockIndex} v rozvržení {layoutIndex}", + "error.layout.validation.settings": "Chyba v nastavení rozvržení {index}", + + "error.license.format": "Zadejte prosím platné licenční číslo", + "error.license.email": "Zadejte prosím platnou emailovou adresu", + "error.license.verification": "Licenci nelze ověřit", + + "error.offline": "Panel je v současnosti off-line", + + "error.page.changeSlug.permission": "Nem\u016f\u017eete zm\u011bnit URL t\u00e9to str\u00e1nky", + "error.page.changeStatus.incomplete": "Stránka obsahuje chyby a nemohla být zveřejněna", + "error.page.changeStatus.permission": "Status této stránky nelze změnit", + "error.page.changeStatus.toDraft.invalid": "Stránka \"{slug}\" nemůže být převedena na koncept", + "error.page.changeTemplate.invalid": "Šablonu stránky \"{slug}\" nelze změnit", + "error.page.changeTemplate.permission": "Nemáte dovoleno změnit šablonu stránky \"{slug}\"", + "error.page.changeTitle.empty": "Titulek nesmí být prázdný", + "error.page.changeTitle.permission": "Nemáte dovoleno změnit titulek stránky \"{slug}\"", + "error.page.create.permission": "Nemáte dovoleno vytvořit \"{slug}\"", + "error.page.delete": "Stránku \"{slug}\" nelze vymazat", + "error.page.delete.confirm": "Pro potvrzení prosím zadejte titulek stránky", + "error.page.delete.hasChildren": "Stránka má podstránky, nemůže být vymazána", + "error.page.delete.permission": "Nemáte dovoleno odstranit \"{slug}\"", + "error.page.draft.duplicate": "Koncept stránky, který obsahuje v adrese URL \"{slug}\" již existuje ", + "error.page.duplicate": "Stránka, která v adrese URL obsahuje \"{slug}\" již existuje", + "error.page.duplicate.permission": "Nemáte dovoleno duplikovat \"{slug}\"", + "error.page.notFound": "Str\u00e1nku se nepoda\u0159ilo nal\u00e9zt.", + "error.page.num.invalid": "Zadejte prosím platné pořadové číslo. Čísla nesmí být záporná.", + "error.page.slug.invalid": "Podtržení", + "error.page.slug.maxlength": "URL musí mít méně než \"{length}\" znaků", + "error.page.sort.permission": "Stránce \"{slug}\" nelze změnit pořadí", + "error.page.status.invalid": "Nastavte prosím platný status stránky", + "error.page.undefined": "Str\u00e1nku se nepoda\u0159ilo nal\u00e9zt.", + "error.page.update.permission": "Nemáte dovoleno upravit \"{slug}\"", + + "error.section.files.max.plural": "Sekce \"{section}\" nesmí obsahovat více jak {max} souborů", + "error.section.files.max.singular": "Sekce \"{section}\" může obsahovat nejvýše jeden soubor", + "error.section.files.min.plural": "Sekce \"{section}\" vyžaduje nejméně {min} souborů", + "error.section.files.min.singular": "Sekce \"{section}\" vyžaduje alespoň jeden soubor", + + "error.section.pages.max.plural": "Sekce \"{section}\" nesmí obsahovat více jak {max} stránek", + "error.section.pages.max.singular": "Sekce \"{section}\" může obsahovat nejvýše jednu stránku", + "error.section.pages.min.plural": "Sekce \"{section}\" vyžaduje alespoň {min} stránek", + "error.section.pages.min.singular": "Sekce \"{section}\" vyžaduje alespoň jednu stránku", + + "error.section.notLoaded": "Nelze načíst sekci \"{name}\"", + "error.section.type.invalid": "Typ sekce \"{type}\" není platný", + + "error.site.changeTitle.empty": "Titulek nesmí být prázdný", + "error.site.changeTitle.permission": "Nemáte dovoleno změnit titulek stránky", + "error.site.update.permission": "Nemáte dovoleno upravit stránku", + + "error.template.default.notFound": "Výchozí šablona neexistuje", + + "error.unexpected": "Vyskytla se neočekávaná chyba! Pro více informací povolte debug mód, viz: https://getkirby.com/docs/reference/system/options/debug", + + "error.user.changeEmail.permission": "Nemáte dovoleno měnit email uživatele \"{name}\"", + "error.user.changeLanguage.permission": "Nemáte dovoleno změnit jazyk uživatele \"{name}\"", + "error.user.changeName.permission": "Nemáte dovoleno změnit jméno uživatele \"{name}\"", + "error.user.changePassword.permission": "Nemáte dovoleno změnit heslo uživatele \"{name}\"", + "error.user.changeRole.lastAdmin": "Role posledního administrátora nemůže být změněna", + "error.user.changeRole.permission": "Nemáte dovoleno změnit roli uživatele \"{name}\"", + "error.user.changeRole.toAdmin": "Nemáte dovoleno povýšit uživatele do role administrátora.", + "error.user.create.permission": "Nemáte dovoleno vytvořit tohoto uživatele", + "error.user.delete": "U\u017eivatel nemohl b\u00fdt smaz\u00e1n", + "error.user.delete.lastAdmin": "Nem\u016f\u017eete smazat posledn\u00edho administr\u00e1tora", + "error.user.delete.lastUser": "Poslední uživatel nemůže být smazán", + "error.user.delete.permission": "Nem\u00e1te dovoleno smazat tohoto u\u017eivatele", + "error.user.duplicate": "Uživatel s emailovou adresou \"{email}\" již existuje", + "error.user.email.invalid": "Zadejte prosím platnou emailovou adresu", + "error.user.language.invalid": "Zadejte prosím platný jazyk", + "error.user.notFound": "U\u017eivatele se nepoda\u0159ilo nal\u00e9zt", + "error.user.password.excessive": "Please enter a valid password. Passwords must not be longer than 1000 characters.", + "error.user.password.invalid": "Zadejte prosím platné heslo. Heslo musí být dlouhé alespoň 8 znaků.", + "error.user.password.notSame": "Pros\u00edm potvr\u010fte heslo", + "error.user.password.undefined": "Uživatel nemá nastavené heslo.", + "error.user.password.wrong": "Špatné heslo", + "error.user.role.invalid": "Zadejte prosím platnou roli", + "error.user.undefined": "Uživatele se nepodařilo nalézt", + "error.user.update.permission": "Nemáte dovoleno upravit uživatele \"{name}\"", + + "error.validation.accepted": "Potvrďte prosím", + "error.validation.alpha": "Zadávejte prosím pouze znaky v rozmezí a-z", + "error.validation.alphanum": "Zadávejte prosím pouze znaky v rozmezí a-z nebo čísla v rozmezí 0-9", + "error.validation.between": "Zadejte prosím hodnotu mez \"{min}\" a \"{max}\"", + "error.validation.boolean": "Potvrďte prosím, nebo odmítněte", + "error.validation.contains": "Zadejte prosím hodnotu, která obsahuje \"{needle}\"", + "error.validation.date": "Zadejte prosím platné datum", + "error.validation.date.after": "Zadejte prosím datum po {date}", + "error.validation.date.before": "Zadejte prosím datum před {date}", + "error.validation.date.between": "Zadejte prosím datum mezi {min} a {max}", + "error.validation.denied": "Prosím, odmítněte", + "error.validation.different": "Hodnota nesmí být \"{other}\"", + "error.validation.email": "Zadejte prosím platnou emailovou adresu", + "error.validation.endswith": "Hodnota nesmí končit \"{end}\"", + "error.validation.filename": "Zadejte prosím platný název souboru", + "error.validation.in": "Zadejte prosím některou z následujíích hodnot: ({in})", + "error.validation.integer": "Zadejte prosím platné celé číslo", + "error.validation.ip": "Zadejte prosím platnou IP adresu", + "error.validation.less": "Zadejte prosím hodnotu menší než {max}", + "error.validation.match": "Hodnota neodpovídá očekávanému vzoru", + "error.validation.max": "Zadejte prosím hodnotu rovnou, nebo menší než {max}", + "error.validation.maxlength": "Zadaná hodnota je příliš dlouhá. (Povoleno nejvýše {max} znaků)", + "error.validation.maxwords": "Nezadávejte prosím více jak {max} slov", + "error.validation.min": "Zadejte prosím hodnotu rovnou, nebo větší než {min}", + "error.validation.minlength": "Zadaná hodnota je příliš krátká. (Požadováno nejméně {min} znaků)", + "error.validation.minwords": "Zadejte prosím alespoň {min} slov", + "error.validation.more": "Zadejte prosím hodnotu větší než {min}", + "error.validation.notcontains": "Zadejte prosím hodnotu, která neobsahuje \"{needle}\"", + "error.validation.notin": "Nezadávejte prosím žádnou z následujíích hodnot: ({notIn})", + "error.validation.option": "Vyberte prosím platnou možnost", + "error.validation.num": "Zadejte prosím platné číslo", + "error.validation.required": "Zadejte prosím jakoukoli hodnotu", + "error.validation.same": "Zadejte prosím \"{other}\"", + "error.validation.size": "Velikost hodnoty musí být \"{size}\"", + "error.validation.startswith": "Hodnota musí začínat \"{start}\"", + "error.validation.time": "Zadejte prosím platný čas", + "error.validation.time.after": "Zadejte prosím čas po {time}", + "error.validation.time.before": "Zadejte prosím čas před {time}", + "error.validation.time.between": "Zadejte prosím čas v rozmezí od {min} do {max}", + "error.validation.url": "Zadejte prosím platnou adresu URL", + + "expand": "Rozbalit", + "expand.all": "Rozbalit vše", + + "field.required": "Pole musí být vyplněno.", + "field.blocks.changeType": "Změnit typ", + "field.blocks.code.name": "Kód", + "field.blocks.code.language": "Jazyk", + "field.blocks.code.placeholder": "Váš kód …", + "field.blocks.delete.confirm": "Opravdu chcete smazat tento blok?", + "field.blocks.delete.confirm.all": "Opravdu chcete smazat všechny bloky?", + "field.blocks.delete.confirm.selected": "Opravdu chcete smazat vybrané bloky?", + "field.blocks.empty": "Zatím žádné bloky", + "field.blocks.fieldsets.label": "Vyberte prosím typ bloku …", + "field.blocks.fieldsets.paste": "Stiskněte{{ shortcut }} pro vložení/import bloků z Vaší schránky", + "field.blocks.gallery.name": "Galerie", + "field.blocks.gallery.images.empty": "Zatím žádné obrázky", + "field.blocks.gallery.images.label": "Obrázky", + "field.blocks.heading.level": "Úroveň", + "field.blocks.heading.name": "Nadpis", + "field.blocks.heading.text": "Text", + "field.blocks.heading.placeholder": "Nadpis …", + "field.blocks.image.alt": "Alternativní text", + "field.blocks.image.caption": "Titulek", + "field.blocks.image.crop": "Oříznout", + "field.blocks.image.link": "Odkaz", + "field.blocks.image.location": "Umístění", + "field.blocks.image.name": "Obrázek", + "field.blocks.image.placeholder": "Vyberte obrázek", + "field.blocks.image.ratio": "Poměr stran", + "field.blocks.image.url": "URL obrázku", + "field.blocks.line.name": "Čára", + "field.blocks.list.name": "Seznam", + "field.blocks.markdown.name": "Markdown", + "field.blocks.markdown.label": "Text", + "field.blocks.markdown.placeholder": "Markdown …", + "field.blocks.quote.name": "Citát", + "field.blocks.quote.text.label": "Text", + "field.blocks.quote.text.placeholder": "Citát …", + "field.blocks.quote.citation.label": "Citace", + "field.blocks.quote.citation.placeholder": "od …", + "field.blocks.text.name": "Text", + "field.blocks.text.placeholder": "Text …", + "field.blocks.video.caption": "Titulek", + "field.blocks.video.name": "Video", + "field.blocks.video.placeholder": "Zadejte URL adresu videa", + "field.blocks.video.url.label": "URL adresa videa", + "field.blocks.video.url.placeholder": "https://youtube.com/?v=", + + "field.files.empty": "Nebyly zatím vybrány žádné soubory", + + "field.layout.delete": "Smazat rozložení", + "field.layout.delete.confirm": "Opravdu chcete smazat toto rozložení?", + "field.layout.empty": "Zatím žádné řádky", + "field.layout.select": "Vyberte rozložení", + + "field.pages.empty": "Nebyly zatím vybrány žádné stránky", + "field.structure.delete.confirm": "Opravdu chcete smazat tento z\u00e1znam?", + "field.structure.empty": "Zat\u00edm nejsou \u017e\u00e1dn\u00e9 z\u00e1znamy.", + "field.users.empty": "Nebyli zatím vybráni žádní uživatelé", + + "file.blueprint": "Tento typ souboru nemá blueprint. Blueprint můžete definovat v /site/blueprints/files/{blueprint}.yml", + "file.delete.confirm": "Opravdu chcete smazat tento soubor?", + "file.sort": "Změnit pozici", + + "files": "Soubory", + "files.empty": "Zatím žádné soubory", + + "hide": "Skrýt", + "hour": "Hodina", + "import": "Import", + "info": "Info", + "insert": "Vlo\u017eit", + "insert.after": "Vložit za", + "insert.before": "Vložit před", + "install": "Instalovat", + + "installation": "Instalace", + "installation.completed": "Panel byl nainstalován", + "installation.disabled": "Instalátor panelu je ve výchozím nastavení na veřejných serverech zakázán. Spusťte prosím instalátor na lokálním počítači nebo jej povolte prostřednictvím panel.install.", + "installation.issues.accounts": "\/site\/accounts nen\u00ed zapisovateln\u00e9", + "installation.issues.content": "Slo\u017eka content a v\u0161echny soubory a slo\u017eky v n\u00ed mus\u00ed b\u00fdt zapisovateln\u00e9.", + "installation.issues.curl": "Je vyžadováno rozšířeníCURL", + "installation.issues.headline": "Panel nelze nainstalovat", + "installation.issues.mbstring": "Je vyžadováno rozšířeníMB String", + "installation.issues.media": "Složka/media neexistuje, nebo nemá povolený zápis", + "installation.issues.php": "Ujistěte se, že používátePHP 7+", + "installation.issues.server": "Kirby vyžadujeApache, Nginx neboCaddy", + "installation.issues.sessions": "Složka/site/sessions neexistuje, nebo nemá povolený zápis", + + "language": "Jazyk", + "language.code": "Kód", + "language.convert": "Nastavte výchozí možnost", + "language.convert.confirm": "

Opravdu chcete převést{name} na výchozí jazyk? Tuto volbu nelze vzít zpátky.

Pokud {name} obsahuje nepřeložený text, nebude již k dispozici záložní varianta a části stránky mohou zůstat prázdné.

", + "language.create": "Přidat nový jazyk", + "language.delete.confirm": "Opravdu chcete smazat jazyk {name} včetně všech překladů? Tuto volbu nelze vzít zpátky!", + "language.deleted": "Jazyk byl smazán", + "language.direction": "Směr čtení", + "language.direction.ltr": "Zleva doprava", + "language.direction.rtl": "Zprava doleva", + "language.locale": "Řetězec lokalizace PHP", + "language.locale.warning": "Používáte vlastní jazykové nastavení. Upravte prosím soubor s nastavením v /site/languages", + "language.name": "Jméno", + "language.updated": "Jazyk byl aktualizován", + + "languages": "Jazyky", + "languages.default": "Výchozí jazyk", + "languages.empty": "Zatím neexistují žádné jazyky", + "languages.secondary": "Další jazyky", + "languages.secondary.empty": "Neexistují zatím žádné další jazyky", + + "license": "Kirby licence", + "license.buy": "Zakoupit licenci", + "license.register": "Registrovat", + "license.manage": "Manage your licenses", + "license.register.help": "Licenční kód jste po zakoupení obdrželi na email. Vložte prosím kód a zaregistrujte Vaší kopii.", + "license.register.label": "Zadejte prosím licenční kód", + "license.register.success": "Děkujeme Vám za podporu Kirby", + "license.unregistered": "Toto je neregistrovaná kopie Kirby", + "license.unregistered.label": "Unregistered", + + "link": "Odkaz", + "link.text": "Text odkazu", + + "loading": "Načítám", + + "lock.unsaved": "Neuložené změny", + "lock.unsaved.empty": "Nezbývají již žádné neuložené změny.", + "lock.isLocked": "Neuložené změny provedené {email}", + "lock.file.isLocked": "Soubor nelze změnit, právě jej upravuje {email}.", + "lock.page.isLocked": "Stránku nelze změnit, právě jí upravuje {email} .", + "lock.unlock": "Odemknout", + "lock.isUnlocked": "Vaše neuložené změny byly přepsány jiným uživatelem. Můžeze si své úpravy stáhnout a zapracovat je ručně.", + + "login": "P\u0159ihl\u00e1sit se", + "login.code.label.login": "Kód pro přihlášení", + "login.code.label.password-reset": "Kód pro resetování hesla", + "login.code.placeholder.email": "000 000", + "login.code.text.email": "Vaše e-mailová adresa byla zaregistrována, kód byl odeslán do Vaší e-mailové schránky.", + "login.email.login.body": "Ahoj {user.nameOrEmail},\n\nV nedávné době jsi zažádal(a) o kód pro přihlášení do Kirby Panelu na stránce {site}.\nNásledující kód pro přihlášení je platný {timeout} minut:\n\n{code}\n\nPokud jsi o kód pro přihlášení nežádal(a), tuto zprávu prosím ignoruj a v případě dotazů prosím kontaktuj svého administrátora.\nZ bezpečnostních důvodů prosím tuto zprávu nepřeposílej nikomu dalšímu.", + "login.email.login.subject": "Váš kód pro přihlášení", + "login.email.password-reset.body": "Ahoj {user.nameOrEmail},\n\nV nedávné době jsi zažádal(a) o kód pro resetování hesla do Kirby Panelu na stránce {site}.\nNásledující kód pro resetování hesla je platný {timeout} minut:\n\n{code}\n\nPokud jsi o kód pro resetování hesla nežádal(a), tuto zprávu prosím ignoruj a v případě dotazů prosím kontaktuj svého administrátora.\nZ bezpečnostních důvodů prosím tuto zprávu nepřeposílej nikomu dalšímu.", + "login.email.password-reset.subject": "Váš kód pro resetování hesla", + "login.remember": "Zůstat přihlášen", + "login.reset": "Resetovat heslo", + "login.toggleText.code.email": "Přihlásit se pomocí e-mailu", + "login.toggleText.code.email-password": "Přihlásit se pomocí hesla", + "login.toggleText.password-reset.email": "Zapomenuté heslo?", + "login.toggleText.password-reset.email-password": "← Zpět na přihlášení", + + "logout": "Odhl\u00e1sit se", + + "menu": "Menu", + "meridiem": "AM/PM", + "mime": "Typ média", + "minutes": "Minuty", + + "month": "Měsíc", + "months.april": "Duben", + "months.august": "Srpen", + "months.december": "Prosinec", + "months.february": "Únor", + "months.january": "Leden", + "months.july": "\u010cervenec", + "months.june": "\u010cerven", + "months.march": "B\u0159ezen", + "months.may": "Kv\u011bten", + "months.november": "Listopad", + "months.october": "\u0158\u00edjen", + "months.september": "Z\u00e1\u0159\u00ed", + + "more": "Více", + "name": "Jméno", + "next": "Další", + "no": "ne", + "off": "vypnuto", + "on": "zapnuto", + "open": "Otevřít", + "open.newWindow": "Otevřít v novém okně", + "options": "Možnosti", + "options.none": "Žádné možnosti", + + "orientation": "Orientace", + "orientation.landscape": "Na šířku", + "orientation.portrait": "Na výšku", + "orientation.square": "Čtverec", + + "page.blueprint": "Tento typ stránky nemá blueprint. Blueprint můžete definovat v /site/blueprints/pages/{blueprint}.yml", + "page.changeSlug": "Zm\u011bnit URL", + "page.changeSlug.fromTitle": "Vytvo\u0159it z n\u00e1zvu", + "page.changeStatus": "Změnit status", + "page.changeStatus.position": "Vyberte prosím pozici", + "page.changeStatus.select": "Vybrat nový status", + "page.changeTemplate": "Změnit šablonu", + "page.delete.confirm": "Opravdu chcete smazat tuto str\u00e1nku?", + "page.delete.confirm.subpages": "Tato stránka má podstránky.
Všechny podstránky budou vymazány.", + "page.delete.confirm.title": "Pro potvrzení zadejte titulek stránky", + "page.draft.create": "Vytvořit koncept", + "page.duplicate.appendix": "Kopírovat", + "page.duplicate.files": "Kopírovat soubory", + "page.duplicate.pages": "Kopírovat stránky", + "page.sort": "Změnit pozici", + "page.status": "Stav", + "page.status.draft": "Koncept", + "page.status.draft.description": "Stránka je ve stavu konceptu a je viditelná pouze pro přihlášené editory, nebo přes tajný odkaz", + "page.status.listed": "Veřejná", + "page.status.listed.description": "Stránka je zveřejněná pro všechny", + "page.status.unlisted": "Neveřejná", + "page.status.unlisted.description": "Tato stránka je dostupná pouze přes URL.", + + "pages": "Stránky", + "pages.empty": "Zatím žádné stránky", + "pages.status.draft": "Koncepty", + "pages.status.listed": "Zveřejněno", + "pages.status.unlisted": "Neveřejná", + + "pagination.page": "Stránka", + + "password": "Heslo", + "paste": "Vložit", + "paste.after": "Vložit za", + "pixel": "Pixel", + "plugins": "Doplňky", + "prev": "Předchozí", + "preview": "Náhled", + "remove": "Odstranit", + "rename": "Přejmenovat", + "replace": "Nahradit", + "retry": "Zkusit znovu", + "revert": "Zahodit", + "revert.confirm": "Opravdu chcete smazat všechny provedené změny?", + + "role": "Role", + "role.admin.description": "Administrátor má všechna práva", + "role.admin.title": "Administrátor", + "role.all": "Vše", + "role.empty": "Neexistují uživatelé s touto rolí", + "role.description.placeholder": "Žádný popis", + "role.nobody.description": "Toto je výchozí role bez jakýchkoli oprávnění", + "role.nobody.title": "Nikdo", + + "save": "Ulo\u017eit", + "search": "Hledat", + "search.min": "Pro vyhledání zadejte alespoň {min} znaky", + "search.all": "Zobrazit vše", + "search.results.none": "Žádné výsledky", + + "section.required": "Sekce musí být vyplněna", + + "security": "Security", + "select": "Vybrat", + "server": "Server", + "settings": "Nastavení", + "show": "Zobrazit", + "site.blueprint": "Hlavní panel nemá blueprint. Blueprint můžete definovat v /site/blueprints/site.yml", + "size": "Velikost", + "slug": "P\u0159\u00edpona URL", + "sort": "Řadit", + + "stats.empty": "No reports", + "system.issues.content": "The content folder seems to be exposed", + "system.issues.debug": "Debugging must be turned off in production", + "system.issues.git": "The .git folder seems to be exposed", + "system.issues.https": "We recommend HTTPS for all your sites", + "system.issues.kirby": "The kirby folder seems to be exposed", + "system.issues.site": "The site folder seems to be exposed", + + "title": "Název", + "template": "\u0160ablona", + "today": "Dnes", + + "toolbar.button.code": "Kód", + "toolbar.button.bold": "Tu\u010dn\u00fd text", + "toolbar.button.email": "Email", + "toolbar.button.headings": "Nadpisy", + "toolbar.button.heading.1": "Nadpis 1", + "toolbar.button.heading.2": "Nadpis 2", + "toolbar.button.heading.3": "Nadpis 3", + "toolbar.button.heading.4": "Nadpis 4", + "toolbar.button.heading.5": "Nadpis 5", + "toolbar.button.heading.6": "Nadpis 6", + "toolbar.button.italic": "Kurz\u00edva", + "toolbar.button.file": "Soubor", + "toolbar.button.file.select": "Vyberte soubor", + "toolbar.button.file.upload": "Nahrajte soubor", + "toolbar.button.link": "Odkaz", + "toolbar.button.paragraph": "Odstavec", + "toolbar.button.strike": "Přeškrtnutí", + "toolbar.button.ol": "Číslovaný seznam", + "toolbar.button.underline": "Podtržení", + "toolbar.button.ul": "Odrážkový seznam", + + "translation.author": "Kirby tým", + "translation.direction": "ltr", + "translation.name": "\u010cesky", + "translation.locale": "cs_CZ", + + "upload": "Nahrát", + "upload.error.cantMove": "Nahraný soubor nemohl být přesunut", + "upload.error.cantWrite": "Zápis souboru na disk se nezdařil", + "upload.error.default": "Soubor se nepodařilo nahrát", + "upload.error.extension": "Nahrávání souboru přerušeno rozšířením.", + "upload.error.formSize": "Velikost nahrávaného souboru převyšuje omezení stanovené direktivou MAX_FILE_SIZE", + "upload.error.iniPostSize": "Velikost nahrávaného souboru převyšuje omezení stanovené direktivou post_max_size, která je nastavena v php.ini", + "upload.error.iniSize": "Velikost nahrávaného souboru převyšuje omezení stanovené direktivou upload_max_filesize, která je nastavena v php.ini ", + "upload.error.noFile": "Nebyl nahrán žádný soubor", + "upload.error.noFiles": "Nebyly nahrány žádné soubory", + "upload.error.partial": "Soubor byl nahrán pouze z části", + "upload.error.tmpDir": "Chybí dočasná složka", + "upload.errors": "Chyba", + "upload.progress": "Nahrávání...", + + "url": "Url", + "url.placeholder": "https://example.com", + + "user": "Uživatel", + "user.blueprint": "Pro tuto uživatelskou roli můžete definovat další sekce a pole v /site/blueprints/users/{blueprint}.yml", + "user.changeEmail": "Změnit email", + "user.changeLanguage": "Změnit jazyk", + "user.changeName": "Přejmenovat tohoto uživatele", + "user.changePassword": "Změnit heslo", + "user.changePassword.new": "Nové heslo", + "user.changePassword.new.confirm": "Potvrdit nové heslo...", + "user.changeRole": "Změnit roli", + "user.changeRole.select": "Vybrat novou roli", + "user.create": "Přidat nového uživatele", + "user.delete": "Smazat tohoto uživatele", + "user.delete.confirm": "Opravdu chcete smazat tohoto u\u017eivatele?", + + "users": "Uživatelé", + + "version": "Verze Kirby", + + "view.account": "V\u00e1\u0161 \u00fa\u010det", + "view.installation": "Instalace", + "view.languages": "Jazyky", + "view.resetPassword": "Resetovat heslo", + "view.site": "Stránka", + "view.system": "Systém", + "view.users": "U\u017eivatel\u00e9", + + "welcome": "Vítejte", + "year": "Rok", + "yes": "ano" } diff --git a/kirby/i18n/translations/da.json b/kirby/i18n/translations/da.json index dfd45e8..f1873de 100644 --- a/kirby/i18n/translations/da.json +++ b/kirby/i18n/translations/da.json @@ -1,730 +1,574 @@ { - "account.changeName": "Ændre dit navn", - "account.delete": "Slet din konto", - "account.delete.confirm": "Ønsker du virkelig at slette din konto? Du vil blive logget ud med det samme. Din konto kan ikke gendannes.", - - "activate": "Activate", - "add": "Ny", - "alpha": "Alpha", - "author": "Forfatter", - "avatar": "Profilbillede", - "back": "Tilbage", - "cancel": "Annuller", - "change": "\u00c6ndre", - "close": "Luk", - "changes": "Changes", - "confirm": "Gem", - "collapse": "Fold sammen", - "collapse.all": "Fold alle sammen", - "color": "Color", - "coordinates": "Coordinates", - "copy": "Kopier", - "copy.all": "Kopier alle", - "copy.success": "{count} copied!", - "create": "Opret", - "custom": "Custom", - - "date": "Dato", - "date.select": "Vælg en dato", - - "day": "Dag", - "days.fri": "Fre", - "days.mon": "Man", - "days.sat": "L\u00f8r", - "days.sun": "S\u00f8n", - "days.thu": "Tor", - "days.tue": "Tir", - "days.wed": "Ons", - - "debugging": "Fejlfinding", - - "delete": "Slet", - "delete.all": "Slet alle", - - "dialog.fields.empty": "This dialog has no fields", - "dialog.files.empty": "Ingen filer kan vælges", - "dialog.pages.empty": "Ingen sider kan vælges", - "dialog.text.empty": "This dialog does not define any text", - "dialog.users.empty": "Ingen brugere kan vælges", - - "dimensions": "Dimensioner", - "disable": "Disable", - "disabled": "Deaktiveret", - "discard": "Kass\u00e9r", - - "drawer.fields.empty": "This drawer has no fields", - - "domain": "Domain", - "download": "Download", - "duplicate": "Dupliker", - - "edit": "Rediger", - - "email": "Email", - "email.placeholder": "mail@eksempel.dk", - - "enter": "Enter", - "entries": "Entries", - "entry": "Entry", - - "environment": "Miljø", - - "error": "Fejl", - "error.access.code": "Ugyldig kode", - "error.access.login": "Ugyldigt log ind", - "error.access.panel": "Du har ikke adgang til panelet", - "error.access.view": "Du har ikke adgang til denne del af panelet", - - "error.avatar.create.fail": "Profilbilledet kunne blev ikke uploadet ", - "error.avatar.delete.fail": "Profilbilledet kunne ikke slettes", - "error.avatar.dimensions.invalid": "Hold venligst bredte og højde på billedet under 3000 pixels", - "error.avatar.mime.forbidden": "Uacceptabel fil-type", - - "error.blueprint.notFound": "Blueprint \"{name}\" kunne ikke indlæses", - - "error.blocks.max.plural": "Du må ikke tilføje flere end {max} blokke", - "error.blocks.max.singular": "Du må ikke tilføje mere end een blok", - "error.blocks.min.plural": "Du skal tilføje minimum {min} blokke", - "error.blocks.min.singular": "Du skal tilføje minimum een blok", - "error.blocks.validation": "There's an error on the \"{field}\" field in block {index} using the \"{fieldset}\" block type", - - "error.cache.type.invalid": "Invalid cache type \"{type}\"", - - "error.email.preset.notFound": "Email preset \"{name}\" findes ikke", - - "error.field.converter.invalid": "Ugyldig converter \"{converter}\"", - "error.field.type.missing": "Field \"{ name }\": The field type \"{ type }\" does not exist", - - "error.file.changeName.empty": "Navn kan ikke efterlades tomt", - "error.file.changeName.permission": "Du har ikke tilladelse til at ændre navnet på filen \"{filename}\"", - "error.file.changeTemplate.invalid": "The template for the file \"{id}\" cannot be changed to \"{template}\" (valid: \"{blueprints}\")", - "error.file.changeTemplate.permission": "You are not allowed to change the template for the file \"{id}\"", - - "error.file.duplicate": "En fil med navnet \"{filename}\" eksisterer allerede", - "error.file.extension.forbidden": "Uacceptabel fil-endelse", - "error.file.extension.invalid": "Ugyldig endelse: {extension}", - "error.file.extension.missing": "Du kan ikke uploade filer uden fil-endelse", - "error.file.maxheight": "Højden på billedet af billedet må ikke være større end {height} pixels", - "error.file.maxsize": "Filen er for stor", - "error.file.maxwidth": "Bredden af billedet må ikke være større end {width} pixels", - "error.file.mime.differs": "Den uploadede fil skal være af samme mime type \"{mime}\"", - "error.file.mime.forbidden": "Media typen \"{mime}\" er ikke tilladt", - "error.file.mime.invalid": "Ugyldig mime type: {mime}", - "error.file.mime.missing": "Media typen for \"{filename}\" kan ikke bestemmes", - "error.file.minheight": "Højden af billedet skal mindst være {height} pixels", - "error.file.minsize": "Filen er for lille", - "error.file.minwidth": "Bredden af billedet skal mindst være {width} pixels", - "error.file.name.unique": "The filename must be unique", - "error.file.name.missing": "Filnavn må ikke være tomt", - "error.file.notFound": "Filen kunne ikke findes", - "error.file.orientation": "Formatet på billedet skal være \"{orientation}\"", - "error.file.type.forbidden": "Du har ikke tilladelse til at uploade {type} filer", - "error.file.type.invalid": "Ugyldig filtype: {type}", - "error.file.undefined": "Filen kunne ikke findes", - - "error.form.incomplete": "Ret venligst alle fejl i formularen...", - "error.form.notSaved": "Formularen kunne ikke gemmes", - - "error.language.code": "Indtast venligst en gyldig kode for sproget", - "error.language.duplicate": "Sproget eksisterer allerede", - "error.language.name": "Indtast venligst et gyldigt navn for sproget", - "error.language.notFound": "Sproget fandtes ikke", - - "error.layout.validation.block": "There's an error on the \"{field}\" field in block {blockIndex} using the \"{fieldset}\" block type in layout {layoutIndex}", - "error.layout.validation.settings": "Der er fejl i layout {index} indstillinger", - - "error.license.domain": "The domain for the license is missing", - "error.license.email": "Indtast venligst en gyldig email adresse", - "error.license.format": "Please enter a valid license code", - "error.license.verification": "Licensen kunne ikke verificeres", - - "error.login.totp.confirm.invalid": "Ugyldig kode", - "error.login.totp.confirm.missing": "Please enter the current code", - - "error.object.validation": "There’s an error in the \"{label}\" field:\n{message}", - - "error.offline": "Panelet er i øjeblikket offline", - - "error.page.changeSlug.permission": "Du kan ikke ændre URL-endelse for \"{slug}\"", - "error.page.changeSlug.reserved": "The path of top-level pages must not start with \"{path}\"", - "error.page.changeStatus.incomplete": "Siden indeholder fejl og kan derfor ikke udgives", - "error.page.changeStatus.permission": "Status for denne side kan ikke ændres", - "error.page.changeStatus.toDraft.invalid": "Siden \"{slug}\" kan ikke konverteres om til en kladde", - "error.page.changeTemplate.invalid": "Skabelonen for siden \"{slug}\" kan ikke ændres", - "error.page.changeTemplate.permission": "Du har ikke tilladelse til at ændre skabelonen for \"{slug}\"", - "error.page.changeTitle.empty": "Titlen kan ikke være tom", - "error.page.changeTitle.permission": "Du har ikke tilladelse til at ændre titlen for \"{slug}\"", - "error.page.create.permission": "Du har ikke tilladelse til at oprette \"{slug}\"", - "error.page.delete": "Siden \"{slug}\" kan ikke slettes", - "error.page.delete.confirm": "Indtast venligst sidens titel for at bekræfte", - "error.page.delete.hasChildren": "Siden har unsersider og kan derfor ikke slettes", - "error.page.delete.permission": "Du har ikke tilladelse til at slette \"{slug}\"", - "error.page.draft.duplicate": "En sidekladde med URL-endelsen \"{slug}\" eksisterer allerede", - "error.page.duplicate": "En side med URL-endelsen \"{slug}\" eksisterer allerede", - "error.page.duplicate.permission": "Du har ikke mulighed for at duplikere \"{slug}\"", - "error.page.move.ancestor": "The page cannot be moved into itself", - "error.page.move.directory": "The page directory cannot be moved", - "error.page.move.duplicate": "A sub page with the URL appendix \"{slug}\" already exists", - "error.page.move.notFound": "The moved page could not be found", - "error.page.move.permission": "You are not allowed to move \"{slug}\"", - "error.page.move.template": "The \"{template}\" template is not accepted as a subpage of \"{parent}\"", - "error.page.notFound": "Siden kunne ikke findes", - "error.page.num.invalid": "Indtast venligst et gyldigt sorteringsnummer. Nummeret kan ikke være negativt.", - "error.page.slug.invalid": "Indtast venligst et gyldigt URL appendix", - "error.page.slug.maxlength": "Navnet skal være kortere end \"{length}\" tegn", - "error.page.sort.permission": "Siden \"{slug}\" kan ikke sorteres", - "error.page.status.invalid": "Sæt venligst en gyldig status for siden", - "error.page.undefined": "Siden kunne ikke findes", - "error.page.update.permission": "Du har ikke tilladelse til at opdatere \"{slug}\"", - - "error.section.files.max.plural": "Du kan ikk tilføje mere end {max} filer til \"{section}\" sektionen", - "error.section.files.max.singular": "Du kan ikke tilføje mere end een fil til \"{section}\" sektionen", - "error.section.files.min.plural": "Sektionen \"{section}\" kræver mindst {min} filer", - "error.section.files.min.singular": "Sektionen \"{section}\" kræver mindst een fil", - - "error.section.pages.max.plural": "Du kan ikke tilføje flere end {max} sider til \"{section}\" sektionen", - "error.section.pages.max.singular": "Du kan ikke tilføje mere end een side til \"{section}\" sektionen", - "error.section.pages.min.plural": "Sektionen \"{section}\" kræver mindst {min} sider", - "error.section.pages.min.singular": "Sektionen \"{section}\" kræver mindst een side", - - "error.section.notLoaded": "Sektionen \"{section}\" kunne ikke indlæses", - "error.section.type.invalid": "Sektionstypen \"{type}\" er ikke gyldig", - - "error.site.changeTitle.empty": "Titlen kan ikke være tom", - "error.site.changeTitle.permission": "Du har ikke tilladelse til at ændre titlen på sitet", - "error.site.update.permission": "Du har ikke tilladelse til at opdatere sitet", - - "error.structure.validation": "There's an error on the \"{field}\" field in row {index}", - - "error.template.default.notFound": "Standardskabelonen eksisterer ikke", - - "error.unexpected": "En uventet fejl opstod! Aktiver debug mode for mere info: https://getkirby.com/docs/reference/system/options/debug", - - "error.user.changeEmail.permission": "Du har ikke tilladelse til at ændre emailen for brugeren \"{name}\"", - "error.user.changeLanguage.permission": "Du har ikke tilladelse til at ændre sproget for brugeren \"{name}\"", - "error.user.changeName.permission": "Du har ikke tilladelse til at ændre navn på brugeren \"{name}\"", - "error.user.changePassword.permission": "Du har ikke tilladelse til at ændre adgangskoden for brugeren \"{name}\"", - "error.user.changeRole.lastAdmin": "Rollen for den sidste admin kan ikke ændres", - "error.user.changeRole.permission": "Du har ikke tilladelse til at ændre rollen for brugeren \"{name}\"", - "error.user.changeRole.toAdmin": "Du har ikke tilladelse til at tildele nogen admin rollen", - "error.user.create.permission": "Du har ikke tilladelse til at oprette denne bruger", - "error.user.delete": "Brugeren kunne ikke slettes", - "error.user.delete.lastAdmin": "Du kan ikke slette den sidste admin", - "error.user.delete.lastUser": "Den sidste bruger kan ikke slettes", - "error.user.delete.permission": "Du har ikke tilladelse til at slette denne bruger", - "error.user.duplicate": "En bruger med email adresse \"{email}\" eksisterer allerede", - "error.user.email.invalid": "Indtast venligst en gyldig email adresse", - "error.user.language.invalid": "Indtast venligst et gyldigt sprog", - "error.user.notFound": "Brugeren kunne ikke findes", - "error.user.password.excessive": "Please enter a valid password. Passwords must not be longer than 1000 characters.", - "error.user.password.invalid": "Indtast venligst en gyldig adgangskode. Adgangskoder skal minimum være 8 tegn lange.", - "error.user.password.notSame": "Bekr\u00e6ft venligst adgangskoden", - "error.user.password.undefined": "Brugeren har ikke en adgangskode", - "error.user.password.wrong": "Forkert adgangskode", - "error.user.role.invalid": "Indtast venligst en gyldig rolle", - "error.user.undefined": "Brugeren kunne ikke findes", - "error.user.update.permission": "Du har ikke tilladelse til at opdatere brugeren \"{name}\"", - - "error.validation.accepted": "Bekræft venligst", - "error.validation.alpha": "Indtast venligst kun bogstaver imellem a-z", - "error.validation.alphanum": "Indtast venligst kun bogstaver og tal imellem a-z eller 0-9", - "error.validation.anchor": "Please enter a correct link anchor", - "error.validation.between": "Indtast venligst en værdi imellem \"{min}\" og \"{max}\"", - "error.validation.boolean": "Venligst bekræft eller afvis", - "error.validation.color": "Please enter a valid color in the {format} format", - "error.validation.contains": "Indtast venligst en værdi der indeholder \"{needle}\"", - "error.validation.date": "Indtast venligst en gyldig dato", - "error.validation.date.after": "Indtast venligst en dato efter {date}", - "error.validation.date.before": "Indtast venligst en dato før {date}", - "error.validation.date.between": "Indtast venligst en dato imellem {min} og {max}", - "error.validation.denied": "Venligst afvis", - "error.validation.different": "Værdien må ikke være \"{other}\"", - "error.validation.email": "Indtast venligst en gyldig email adresse", - "error.validation.endswith": "Værdi skal ende med \"{end}\"", - "error.validation.filename": "Indtast venligst et gyldigt filnavn", - "error.validation.in": "Indtast venligst en af følgende: ({in})", - "error.validation.integer": "Indtast et gyldigt tal", - "error.validation.ip": "Indtast en gyldig IP adresse", - "error.validation.less": "Indtast venligst en værdi mindre end {max}", - "error.validation.linkType": "The link type is not allowed", - "error.validation.match": "Værdien matcher ikke det forventede mønster", - "error.validation.max": "Indtast venligst en værdi lig med eller lavere end {max}", - "error.validation.maxlength": "Indtast venligst en kortere værdi. (maks. {max} karakterer)", - "error.validation.maxwords": "Indtast ikke flere end {max} ord", - "error.validation.min": "Indtast en værdi lig med eller højere end {min}", - "error.validation.minlength": "Indtast venligst en længere værdi. (min. {min} karakterer)", - "error.validation.minwords": "Indtast venligst mindst {min} ord", - "error.validation.more": "Indtast venligst en værdi større end {min}", - "error.validation.notcontains": "Indtast venligst en værdi der ikke indeholder \"{needle}\"", - "error.validation.notin": "Indtast venligst ikke nogen af følgende: ({notIn})", - "error.validation.option": "Vælg venligst en gyldig mulighed", - "error.validation.num": "Indtast venligst et gyldigt nummer", - "error.validation.required": "Indtast venligst noget", - "error.validation.same": "Indtast venligst \"{other}\"", - "error.validation.size": "Størrelsen på værdien skal være \"{size}\"", - "error.validation.startswith": "Værdien skal starte med \"{start}\"", - "error.validation.tel": "Please enter an unformatted phone number", - "error.validation.time": "Indtast venligst et gyldigt tidspunkt", - "error.validation.time.after": "Indtast venligst et tidspunkt efter {time}", - "error.validation.time.before": "Indtast venligst et tidspunkt inden {time}", - "error.validation.time.between": "Indtast venligst et tidspunkt imellem {min} og {max}", - "error.validation.uuid": "Please enter a valid UUID", - "error.validation.url": "Indtast venligst en gyldig URL", - - "expand": "Fold ud", - "expand.all": "Fold alle ud", - - "field.invalid": "The field is invalid", - "field.required": "Feltet er påkrævet", - "field.blocks.changeType": "Skift type", - "field.blocks.code.name": "Kode", - "field.blocks.code.language": "Sprog", - "field.blocks.code.placeholder": "Din kode …", - "field.blocks.delete.confirm": "Ønsker du virkelig at slette denne blok?", - "field.blocks.delete.confirm.all": "Ønsker du virkelig at slette alle blokke?", - "field.blocks.delete.confirm.selected": "Ønsker du virkelig at slette de valgte blokke?", - "field.blocks.empty": "Ingen blokke endnu", - "field.blocks.fieldsets.empty": "No fieldsets yet", - "field.blocks.fieldsets.label": "Vælg venligst en blok type", - "field.blocks.fieldsets.paste": "Press {{ shortcut }} to import layouts/blocks from your clipboard Only those allowed in the current field will get inserted.", - "field.blocks.gallery.name": "Galleri", - "field.blocks.gallery.images.empty": "Ingen billeder endnu", - "field.blocks.gallery.images.label": "Billeder", - "field.blocks.heading.level": "Niveau", - "field.blocks.heading.name": "Overskrift", - "field.blocks.heading.text": "Tekst", - "field.blocks.heading.placeholder": "Overskrift …", - "field.blocks.image.alt": "Alternativ tekst", - "field.blocks.image.caption": "Billedtekst", - "field.blocks.image.crop": "Beskær", - "field.blocks.image.link": "Link", - "field.blocks.image.location": "Placering", - "field.blocks.image.location.internal": "This website", - "field.blocks.image.location.external": "External source", - "field.blocks.image.name": "Billede", - "field.blocks.image.placeholder": "Vælg et billede", - "field.blocks.image.ratio": "Størrelsesforhold", - "field.blocks.image.url": "Billede URL", - "field.blocks.line.name": "Linje", - "field.blocks.list.name": "Liste", - "field.blocks.markdown.name": "Markdown", - "field.blocks.markdown.label": "Tekst", - "field.blocks.markdown.placeholder": "Markdown …", - "field.blocks.quote.name": "Citat", - "field.blocks.quote.text.label": "Tekst", - "field.blocks.quote.text.placeholder": "Citat …", - "field.blocks.quote.citation.label": "Citeret af", - "field.blocks.quote.citation.placeholder": "af …", - "field.blocks.text.name": "Tekst", - "field.blocks.text.placeholder": "Tekst …", - "field.blocks.video.autoplay": "Autoplay", - "field.blocks.video.caption": "Billedtekst", - "field.blocks.video.controls": "Controls", - "field.blocks.video.location": "Placering", - "field.blocks.video.loop": "Loop", - "field.blocks.video.muted": "Muted", - "field.blocks.video.name": "Video", - "field.blocks.video.placeholder": "Indtast URL til en video", - "field.blocks.video.poster": "Poster", - "field.blocks.video.preload": "Preload", - "field.blocks.video.url.label": "Video-URL", - "field.blocks.video.url.placeholder": "https://youtube.com/?v=", - - "field.files.empty": "Ingen filer valgt endnu", - - "field.layout.change": "Change layout", - "field.layout.delete": "Slet layout", - "field.layout.delete.confirm": "Ønsker du virkelig at slette dette layout", - "field.layout.delete.confirm.all": "Do you really want to delete all layouts?", - "field.layout.empty": "Ingen rækker endnu", - "field.layout.select": "Vælg et layout", - - "field.object.empty": "No information yet", - - "field.pages.empty": "Ingen sider valgt endnu", - - "field.structure.delete.confirm": "\u00d8nsker du virkelig at slette denne indtastning?", - "field.structure.delete.confirm.all": "Do you really want to delete all entries?", - "field.structure.empty": "Ingen indtastninger endnu.", - - "field.users.empty": "Ingen brugere er valgt", - - "fields.empty": "No fields yet", - - "file": "File", - "file.blueprint": "Denne fil har intet blueprint endnu. Du kan definere opsætningen i /site/blueprints/files/{blueprint}.yml", - "file.changeTemplate": "Skift skabelon", - "file.changeTemplate.notice": "Changing the file's template will remove content for fields that don't match in type. If the new template defines certain rules, e.g. image dimensions, those will also be applied irreversibly. Use with caution.", - "file.delete.confirm": "\u00d8nsker du virkelig at slette denne fil?", - "file.focus.placeholder": "Set focal point", - "file.focus.reset": "Remove focal point", - "file.focus.title": "Focus", - "file.sort": "Skift position", - - "files": "Filer", - "files.empty": "Ingen filer endnu", - - "filter": "Filter", - - "hide": "Skjul", - "hour": "Time", - "hue": "Hue", - "import": "Importer", - "info": "Info", - "insert": "Inds\u00e6t", - "insert.after": "Indsæt efter", - "insert.before": "Indsæt før", - "install": "Installer", - - "installation": "Installation", - "installation.completed": "Panelet er blevet installeret", - "installation.disabled": "Panel installationen er deaktiveret på offentlige servere som standard. Kør venligst installationen på en lokal maskine eller aktiver det med panel.install panel.install muligheden.", - "installation.issues.accounts": "\/site\/accounts er ikke skrivbar", - "installation.issues.content": "Content mappen samt alle underliggende filer og mapper skal v\u00e6re skrivbare.", - "installation.issues.curl": "CURL extension er påkrævet", - "installation.issues.headline": "Panelet kan ikke installeres", - "installation.issues.mbstring": "MB String extension er påkrævet", - "installation.issues.media": "/media mappen eksisterer ikke eller er ikke skrivbar", - "installation.issues.php": "Sikre dig at der benyttes PHP 8+", - "installation.issues.sessions": "/site/sessions mappen eksisterer ikke eller er ikke skrivbar", - - "language": "Sprog", - "language.code": "Kode", - "language.convert": "Gør standard", - "language.convert.confirm": "

Ønsker du virkelig at konvertere {name} til standardsproget? Dette kan ikke fortrydes.

Hvis {name} har uoversat indhold, vil der ikke længere være et gyldigt tilbagefald og dele af dit website vil måske fremstå tomt.

", - "language.create": "Tilføj nyt sprog", - "language.default": "Standardsprog", - "language.delete.confirm": "Ønsker du virkelig at slette sproget {name} inklusiv alle oversættelser? Kan ikke fortrydes!", - "language.deleted": "Sproget er blevet slettet", - "language.direction": "Læseretning", - "language.direction.ltr": "Venstre mod højre", - "language.direction.rtl": "Højre mod venstre", - "language.locale": "PHP locale string", - "language.locale.warning": "Du benytter en brugerdefineret sprogopsætning. Rediger venligst dette i sprogfilen i /site/languages", - "language.name": "Navn", - "language.secondary": "Secondary language", - "language.settings": "Language settings", - "language.updated": "Sproget er blevet opdateret", - "language.variables": "Language variables", - "language.variables.empty": "No translations yet", - - "language.variable.delete.confirm": "Do you really want to delete the variable for {key}?", - "language.variable.key": "Key", - "language.variable.notFound": "The variable could not be found", - "language.variable.value": "Value", - - "languages": "Sprog", - "languages.default": "Standardsprog", - "languages.empty": "Der er ingen sprog endnu", - "languages.secondary": "Sekundære sprog", - "languages.secondary.empty": "Der er ingen sekundære sprog endnu", - - "license": "Kirby licens", - "license.activate": "Activate it now", - "license.activate.label": "Please activate your license", - "license.activate.domain": "Your license will be activated for {host}.", - "license.activate.local": "You are about to activate your Kirby license for your local domain {host}. If this site will be deployed to a public domain, please activate it there instead. If {host} is the domain you want to use your license for, please continue.", - "license.activated": "Activated", - "license.buy": "Køb en licens", - "license.code": "Kode", - "license.code.help": "You received your license code after the purchase via email. Please copy and paste it here.", - "license.code.label": "Indtast venligst din licenskode", - "license.status.active.info": "Includes new major versions until {date}", - "license.status.active.label": "Valid license", - "license.status.demo.info": "This is a demo installation", - "license.status.demo.label": "Demo", - "license.status.inactive.info": "Renew license to update to new major versions", - "license.status.inactive.label": "No new major versions", - "license.status.legacy.bubble": "Ready to renew your license?", - "license.status.legacy.info": "Your license does not cover this version", - "license.status.legacy.label": "Please renew your license", - "license.status.missing.bubble": "Ready to launch your site?", - "license.status.missing.info": "No valid license", - "license.status.missing.label": "Please activate your license", - "license.manage": "Manage your licenses", - "license.purchased": "Purchased", - "license.success": "Tak for din støtte af Kirby", - "license.unregistered.label": "Unregistered", - - "link": "Link", - "link.text": "Link tekst", - - "loading": "Indlæser", - - "lock.unsaved": "Ugemte ændringer", - "lock.unsaved.empty": "Der er ikke flere ændringer der ikke er gamt", - "lock.isLocked": "Unsaved changes by {email}", - "lock.unlock": "Lås op", - "lock.unlock.submit": "Unlock and overwrite unsaved changes by {email}", - "lock.isUnlocked": "Was unlocked by another user", - - "login": "Log ind", - "login.code.label.login": "Log ind kode", - "login.code.label.password-reset": "Sikkerhedskode", - "login.code.placeholder.email": "000 000", - "login.code.placeholder.totp": "000000", - "login.code.text.email": "Hvis din email adresse er registreret er en sikkerhedskode blevet sendt via email.", - "login.code.text.totp": "Please enter the one‑time code from your authenticator app.", - "login.email.login.body": "Hej {user.nameOrEmail},\n\nDu har for nyligt anmodet om en log ind kode til panelet af {site}.\nFølgende log ind kode vil være gyldig i {timeout} minutter:\n\n{code}\n\nHvis du ikke har anmodet om en log ind kode, kan du blot ignorere denne email eller kontakte din administrator hvis du har spørgsmål.\nAf sikkerhedsmæssige årsager, bør du IKKE videresende denne email.", - "login.email.login.subject": "Din log ind kode", - "login.email.password-reset.body": "Hej {user.nameOrEmail},\n\nDu har for nyligt anmodet om kode til nulstilling af adgangskode til panelet af {site}.\nFølgende kode til nulstilling af adgangskode vil være gyldig i {timeout} minutter:\n\n{code}\n\nHvis du ikke har anmodet om kode til nulstilling af adgangskode, kan du blot ignorere denne email eller kontakte din administrator hvis du har spørgsmål.\nAf sikkerhedsmæssige årsager, bør du IKKE videresende denne email.", - "login.email.password-reset.subject": "Din kode til nulstilling af adgangskode", - "login.remember": "Forbliv logget ind", - "login.reset": "Nulstil adgangskode", - "login.toggleText.code.email": "Log ind via email", - "login.toggleText.code.email-password": "Log ind med adgangskode", - "login.toggleText.password-reset.email": "Glemt din adgangskode?", - "login.toggleText.password-reset.email-password": "← Tilbage til log ind", - "login.totp.enable.option": "Set up one‑time codes", - "login.totp.enable.intro": "Authenticator apps can generate one‑time codes that are used as a second factor when signing into your account.", - "login.totp.enable.qr.label": "1. Scan this QR code", - "login.totp.enable.qr.help": "Unable to scan? Add the setup key {secret} manually to your authenticator app.", - "login.totp.enable.confirm.headline": "2. Confirm with generated code", - "login.totp.enable.confirm.text": "Your app generates a new one‑time code every 30 seconds. Enter the current code to complete the setup:", - "login.totp.enable.confirm.label": "Current code", - "login.totp.enable.confirm.help": "After this setup, we will ask you for a one‑time code every time you log in.", - "login.totp.enable.success": "One‑time codes enabled", - "login.totp.disable.option": "Disable one‑time codes", - "login.totp.disable.label": "Enter your password to disable one‑time codes", - "login.totp.disable.help": "In the future, a different second factor like a login code sent via email will be requested when you log in. You can always set up one‑time codes again later.", - "login.totp.disable.admin": "

This will disable one‑time codes for {user}.

In the future, a different second factor like a login code sent via email will be requested when they log in. {user} can set up one‑time codes again after their next login.

", - "login.totp.disable.success": "One‑time codes disabled", - - "logout": "Log ud", - - "merge": "Merge", - "menu": "Menu", - "meridiem": "AM/PM", - "mime": "Medie Type", - "minutes": "Minutter", - - "month": "Måned", - "months.april": "April", - "months.august": "August", - "months.december": "December", - "months.february": "Februar", - "months.january": "Januar", - "months.july": "Juli", - "months.june": "Juni", - "months.march": "Marts", - "months.may": "Maj", - "months.november": "November", - "months.october": "Oktober", - "months.september": "September", - - "more": "Mere", - "move": "Move", - "name": "Navn", - "next": "Næste", - "night": "Night", - "no": "nej", - "off": "Sluk", - "on": "Aktiveret", - "open": "Åben", - "open.newWindow": "Åben i et nyt vindue", - "option": "Option", - "options": "Indstillinger", - "options.none": "Ingen muligheder", - "options.all": "Show all {count} options", - - "orientation": "Orientering", - "orientation.landscape": "Landskab", - "orientation.portrait": "Portræt", - "orientation.square": "Kvadrat", - - "page": "Page", - "page.blueprint": "Denne side har intet blueprint endnu. Du kan definere opsætningen i /site/blueprints/pages/{blueprint}.yml", - "page.changeSlug": "\u00c6ndre URL", - "page.changeSlug.fromTitle": "Generer udfra titel", - "page.changeStatus": "Skift status", - "page.changeStatus.position": "Vælg venligst position", - "page.changeStatus.select": "Vælg en ny status", - "page.changeTemplate": "Skift skabelon", - "page.changeTemplate.notice": "Changing the page's template will remove content for fields that don't match in type. Use with caution.", - "page.create": "Create as {status}", - "page.delete.confirm": "\u00d8nsker du virkelig at slette denne side?", - "page.delete.confirm.subpages": "Denne side har undersider.
Alle undersider vil også blive slettet.", - "page.delete.confirm.title": "Indtast sidens titel for at bekræfte", - "page.duplicate.appendix": "Kopier", - "page.duplicate.files": "Kopier filer", - "page.duplicate.pages": "Kopier sider", - "page.move": "Move page", - "page.sort": "Skift position", - "page.status": "Status", - "page.status.draft": "Kladde", - "page.status.draft.description": "Siden er i kladde udgave og er kun synlig for redaktører der er logget ind eller via hemmeligt link", - "page.status.listed": "Offentlig", - "page.status.listed.description": "Siden er offentlig for enhver", - "page.status.unlisted": "Ulistede", - "page.status.unlisted.description": "Siden er kun tilgængelig via URL", - - "pages": "Sider", - "pages.empty": "Ingen sider endnu", - "pages.status.draft": "Kladder", - "pages.status.listed": "Udgivede", - "pages.status.unlisted": "Ulistede", - - "pagination.page": "Side", - - "password": "Adgangskode", - "paste": "Indsæt", - "paste.after": "Indsæt efter", - "paste.success": "{count} pasted!", - "pixel": "Pixel", - "plugin": "Plugin", - "plugins": "Plugins", - "prev": "Forrige", - "preview": "Forhåndsvisning", - "remove": "Fjern", - "rename": "Omdøb", - "renew": "Renew", - "replace": "Erstat", - "replace.with": "Replace with", - "retry": "Pr\u00f8v igen", - "revert": "Kass\u00e9r", - "revert.confirm": "Ønsker du virkelig at slette all ændringer der ikke er gemt?", - - "role": "Rolle", - "role.admin.description": "Admin har alle rettigheder", - "role.admin.title": "Admin", - "role.all": "All", - "role.empty": "Der er ingen bruger med denne rolle", - "role.description.placeholder": "Ingen beskrivelse", - "role.nobody.description": "Dette er en tilbagefaldsrolle uden rettigheder", - "role.nobody.title": "Ingen", - - "save": "Gem", - "search": "Søg", - "search.min": "Indtast {min} tegn for at søge", - "search.all": "Show all {count} results", - "search.results.none": "Ingen resultater", - - "section.invalid": "The section is invalid", - "section.required": "Sektionen er påkrævet", - - "security": "Security", - "select": "Vælg", - "server": "Server", - "settings": "Indstillinger", - "show": "Vis", - "site.blueprint": "Sitet har intet blueprint endnu. Du kan definere opsætningen i /site/blueprints/site.yml", - "size": "Størrelse", - "slug": "URL-appendiks", - "sort": "Sorter", - "sort.drag": "Drag to sort …", - "split": "Split", - - "stats.empty": "No reports", - "status": "Status", - - "system.info.copy": "Copy info", - "system.info.copied": "System info copied", - "system.issues.content": "The content folder seems to be exposed", - "system.issues.eol.kirby": "Your installed Kirby version has reached end-of-life and will not receive further security updates", - "system.issues.eol.plugin": "Your installed version of the { plugin } plugin is has reached end-of-life and will not receive further security updates", - "system.issues.eol.php": "Your installed PHP release { release } has reached end-of-life and will not receive further security updates", - "system.issues.debug": "Debugging must be turned off in production", - "system.issues.git": "The .git folder seems to be exposed", - "system.issues.https": "We recommend HTTPS for all your sites", - "system.issues.kirby": "The kirby folder seems to be exposed", - "system.issues.site": "The site folder seems to be exposed", - "system.issues.vulnerability.kirby": "Your installation might be affected by the following vulnerability ({ severity } severity): { description }", - "system.issues.vulnerability.plugin": "Your installation might be affected by the following vulnerability in the { plugin } plugin ({ severity } severity): { description }", - "system.updateStatus": "Update status", - "system.updateStatus.error": "Could not check for updates", - "system.updateStatus.not-vulnerable": "No known vulnerabilities", - "system.updateStatus.security-update": "Free security update { version } available", - "system.updateStatus.security-upgrade": "Upgrade { version } with security fixes available", - "system.updateStatus.unreleased": "Unreleased version", - "system.updateStatus.up-to-date": "Up to date", - "system.updateStatus.update": "Free update { version } available", - "system.updateStatus.upgrade": "Upgrade { version } available", - - "tel": "Phone", - "tel.placeholder": "+49123456789", - "template": "Skabelon", - "title": "Titel", - "today": "Idag", - - "toolbar.button.clear": "Clear formatting", - "toolbar.button.code": "Kode", - "toolbar.button.bold": "Fed tekst", - "toolbar.button.email": "Email", - "toolbar.button.headings": "Overskrifter", - "toolbar.button.heading.1": "Overskrift 1", - "toolbar.button.heading.2": "Overskrift 2", - "toolbar.button.heading.3": "Overskrift 3", - "toolbar.button.heading.4": "Overskrift 4", - "toolbar.button.heading.5": "Overskrift 5", - "toolbar.button.heading.6": "Overskrift 6", - "toolbar.button.italic": "Kursiv tekst", - "toolbar.button.file": "Fil", - "toolbar.button.file.select": "Vælg en fil", - "toolbar.button.file.upload": "Upload en fil", - "toolbar.button.link": "Link", - "toolbar.button.paragraph": "Afsnit", - "toolbar.button.strike": "Gennemstreg", - "toolbar.button.sub": "Subscript", - "toolbar.button.sup": "Superscript", - "toolbar.button.ol": "Ordnet liste", - "toolbar.button.underline": "Understreg", - "toolbar.button.ul": "Punktliste", - - "translation.author": "Kirby Team", - "translation.direction": "ltr", - "translation.name": "Dansk", - "translation.locale": "da_DK", - - "type": "Type", - - "upload": "Upload", - "upload.error.cantMove": "Den uploadede fil kunne ikke flyttes", - "upload.error.cantWrite": "Kunne ikke skrive fil til disk", - "upload.error.default": "Filen kunne ikke uploades", - "upload.error.extension": "Upload af filen blev stoppet af dens type", - "upload.error.formSize": "Filen overskrider MAX_FILE_SIZE direktivet der er specificeret for formularen", - "upload.error.iniPostSize": "FIlen overskrider post_max_size direktivet i php.ini", - "upload.error.iniSize": "FIlen overskrider upload_max_filesize direktivet i php.ini", - "upload.error.noFile": "Ingen fil blev uploadet", - "upload.error.noFiles": "Ingen filer blev uploadet", - "upload.error.partial": "Den uploadede fil blev kun delvist uploadet", - "upload.error.tmpDir": "Der mangler en midlertidig mappe", - "upload.errors": "Fejl", - "upload.progress": "Uploader...", - - "url": "Url", - "url.placeholder": "https://example.com", - - "user": "Bruger", - "user.blueprint": "Du kan definere yderligere sektioner og formular felter for denne brugerrolle i /site/blueprints/users/{blueprint}.yml", - "user.changeEmail": "Skift email", - "user.changeLanguage": "Skift sprog", - "user.changeName": "Omdøb denne bruger", - "user.changePassword": "Skift adgangskode", - "user.changePassword.new": "Ny adgangskode", - "user.changePassword.new.confirm": "Bekræft den nye adgangskode...", - "user.changeRole": "Skift rolle", - "user.changeRole.select": "Vælg en ny rolle", - "user.create": "Tilføj en ny bruger", - "user.delete": "Slet denne bruger", - "user.delete.confirm": "\u00d8nsker du virkelig at slette denne bruger?", - - "users": "Brugere", - - "version": "Kirby version", - "version.current": "Current version", - "version.latest": "Latest version", - "versionInformation": "Version information", - - "view.account": "Din konto", - "view.installation": "Installation", - "view.languages": "Sprog", - "view.resetPassword": "Nulstil adgangskode", - "view.site": "Website", - "view.system": "System", - "view.users": "Brugere", - - "welcome": "Velkommen", - "year": "År", - "yes": "ja" + "account.changeName": "Ændre dit navn", + "account.delete": "Slet din konto", + "account.delete.confirm": "Ønsker du virkelig at slette din konto? Du vil blive logget ud med det samme. Din konto kan ikke gendannes.", + + "add": "Ny", + "author": "Forfatter", + "avatar": "Profilbillede", + "back": "Tilbage", + "cancel": "Annuller", + "change": "\u00c6ndre", + "close": "Luk", + "confirm": "Gem", + "collapse": "Fold sammen", + "collapse.all": "Fold alle sammen", + "copy": "Kopier", + "copy.all": "Kopier alle", + "create": "Opret", + + "date": "Dato", + "date.select": "Vælg en dato", + + "day": "Dag", + "days.fri": "Fre", + "days.mon": "Man", + "days.sat": "L\u00f8r", + "days.sun": "S\u00f8n", + "days.thu": "Tor", + "days.tue": "Tir", + "days.wed": "Ons", + + "debugging": "Fejlfinding", + + "delete": "Slet", + "delete.all": "Slet alle", + + "dialog.files.empty": "Ingen filer kan vælges", + "dialog.pages.empty": "Ingen sider kan vælges", + "dialog.users.empty": "Ingen brugere kan vælges", + + "dimensions": "Dimensioner", + "disabled": "Deaktiveret", + "discard": "Kass\u00e9r", + "download": "Download", + "duplicate": "Dupliker", + + "edit": "Rediger", + + "email": "Email", + "email.placeholder": "mail@eksempel.dk", + + "entries": "Entries", + "entry": "Entry", + + "environment": "Miljø", + + "error.access.code": "Ugyldig kode", + "error.access.login": "Ugyldigt log ind", + "error.access.panel": "Du har ikke adgang til panelet", + "error.access.view": "Du har ikke adgang til denne del af panelet", + + "error.avatar.create.fail": "Profilbilledet kunne blev ikke uploadet ", + "error.avatar.delete.fail": "Profilbilledet kunne ikke slettes", + "error.avatar.dimensions.invalid": "Hold venligst bredte og højde på billedet under 3000 pixels", + "error.avatar.mime.forbidden": "Uacceptabel fil-type", + + "error.blueprint.notFound": "Blueprint \"{name}\" kunne ikke indlæses", + + "error.blocks.max.plural": "Du må ikke tilføje flere end {max} blokke", + "error.blocks.max.singular": "Du må ikke tilføje mere end een blok", + "error.blocks.min.plural": "Du skal tilføje minimum {min} blokke", + "error.blocks.min.singular": "Du skal tilføje minimum een blok", + "error.blocks.validation": "Der er fejl i blok {index}", + + "error.email.preset.notFound": "Email preset \"{name}\" findes ikke", + + "error.field.converter.invalid": "Ugyldig converter \"{converter}\"", + + "error.file.changeName.empty": "Navn kan ikke efterlades tomt", + "error.file.changeName.permission": "Du har ikke tilladelse til at ændre navnet på filen \"{filename}\"", + "error.file.duplicate": "En fil med navnet \"{filename}\" eksisterer allerede", + "error.file.extension.forbidden": "Uacceptabel fil-endelse", + "error.file.extension.invalid": "Ugyldig endelse: {extension}", + "error.file.extension.missing": "Du kan ikke uploade filer uden fil-endelse", + "error.file.maxheight": "Højden på billedet af billedet må ikke være større end {height} pixels", + "error.file.maxsize": "Filen er for stor", + "error.file.maxwidth": "Bredden af billedet må ikke være større end {width} pixels", + "error.file.mime.differs": "Den uploadede fil skal være af samme mime type \"{mime}\"", + "error.file.mime.forbidden": "Media typen \"{mime}\" er ikke tilladt", + "error.file.mime.invalid": "Ugyldig mime type: {mime}", + "error.file.mime.missing": "Media typen for \"{filename}\" kan ikke bestemmes", + "error.file.minheight": "Højden af billedet skal mindst være {height} pixels", + "error.file.minsize": "Filen er for lille", + "error.file.minwidth": "Bredden af billedet skal mindst være {width} pixels", + "error.file.name.missing": "Filnavn må ikke være tomt", + "error.file.notFound": "Filen kunne ikke findes", + "error.file.orientation": "Formatet på billedet skal være \"{orientation}\"", + "error.file.type.forbidden": "Du har ikke tilladelse til at uploade {type} filer", + "error.file.type.invalid": "Ugyldig filtype: {type}", + "error.file.undefined": "Filen kunne ikke findes", + + "error.form.incomplete": "Ret venligst alle fejl i formularen...", + "error.form.notSaved": "Formularen kunne ikke gemmes", + + "error.language.code": "Indtast venligst en gyldig kode for sproget", + "error.language.duplicate": "Sproget eksisterer allerede", + "error.language.name": "Indtast venligst et gyldigt navn for sproget", + "error.language.notFound": "Sproget fandtes ikke", + + "error.layout.validation.block": "Der er fejl i blok {blockIndex} i layout {layoutIndex}", + "error.layout.validation.settings": "Der er fejl i layout {index} indstillinger", + + "error.license.format": "Indtast venligst en gyldig licensnøgle", + "error.license.email": "Indtast venligst en gyldig email adresse", + "error.license.verification": "Licensen kunne ikke verificeres", + + "error.offline": "Panelet er i øjeblikket offline", + + "error.page.changeSlug.permission": "Du kan ikke ændre URL-endelse for \"{slug}\"", + "error.page.changeStatus.incomplete": "Siden indeholder fejl og kan derfor ikke udgives", + "error.page.changeStatus.permission": "Status for denne side kan ikke ændres", + "error.page.changeStatus.toDraft.invalid": "Siden \"{slug}\" kan ikke konverteres om til en kladde", + "error.page.changeTemplate.invalid": "Skabelonen for siden \"{slug}\" kan ikke ændres", + "error.page.changeTemplate.permission": "Du har ikke tilladelse til at ændre skabelonen for \"{slug}\"", + "error.page.changeTitle.empty": "Titlen kan ikke være tom", + "error.page.changeTitle.permission": "Du har ikke tilladelse til at ændre titlen for \"{slug}\"", + "error.page.create.permission": "Du har ikke tilladelse til at oprette \"{slug}\"", + "error.page.delete": "Siden \"{slug}\" kan ikke slettes", + "error.page.delete.confirm": "Indtast venligst sidens titel for at bekræfte", + "error.page.delete.hasChildren": "Siden har unsersider og kan derfor ikke slettes", + "error.page.delete.permission": "Du har ikke tilladelse til at slette \"{slug}\"", + "error.page.draft.duplicate": "En sidekladde med URL-endelsen \"{slug}\" eksisterer allerede", + "error.page.duplicate": "En side med URL-endelsen \"{slug}\" eksisterer allerede", + "error.page.duplicate.permission": "Du har ikke mulighed for at duplikere \"{slug}\"", + "error.page.notFound": "Siden kunne ikke findes", + "error.page.num.invalid": "Indtast venligst et gyldigt sorteringsnummer. Nummeret kan ikke være negativt.", + "error.page.slug.invalid": "Indtast venligst et gyldigt URL appendix", + "error.page.slug.maxlength": "Navnet skal være kortere end \"{length}\" tegn", + "error.page.sort.permission": "Siden \"{slug}\" kan ikke sorteres", + "error.page.status.invalid": "Sæt venligst en gyldig status for siden", + "error.page.undefined": "Siden kunne ikke findes", + "error.page.update.permission": "Du har ikke tilladelse til at opdatere \"{slug}\"", + + "error.section.files.max.plural": "Du kan ikk tilføje mere end {max} filer til \"{section}\" sektionen", + "error.section.files.max.singular": "Du kan ikke tilføje mere end een fil til \"{section}\" sektionen", + "error.section.files.min.plural": "Sektionen \"{section}\" kræver mindst {min} filer", + "error.section.files.min.singular": "Sektionen \"{section}\" kræver mindst een fil", + + "error.section.pages.max.plural": "Du kan ikke tilføje flere end {max} sider til \"{section}\" sektionen", + "error.section.pages.max.singular": "Du kan ikke tilføje mere end een side til \"{section}\" sektionen", + "error.section.pages.min.plural": "Sektionen \"{section}\" kræver mindst {min} sider", + "error.section.pages.min.singular": "Sektionen \"{section}\" kræver mindst een side", + + "error.section.notLoaded": "Sektionen \"{section}\" kunne ikke indlæses", + "error.section.type.invalid": "Sektionstypen \"{type}\" er ikke gyldig", + + "error.site.changeTitle.empty": "Titlen kan ikke være tom", + "error.site.changeTitle.permission": "Du har ikke tilladelse til at ændre titlen på sitet", + "error.site.update.permission": "Du har ikke tilladelse til at opdatere sitet", + + "error.template.default.notFound": "Standardskabelonen eksisterer ikke", + + "error.unexpected": "En uventet fejl opstod! Aktiver debug mode for mere info: https://getkirby.com/docs/reference/system/options/debug", + + "error.user.changeEmail.permission": "Du har ikke tilladelse til at ændre emailen for brugeren \"{name}\"", + "error.user.changeLanguage.permission": "Du har ikke tilladelse til at ændre sproget for brugeren \"{name}\"", + "error.user.changeName.permission": "Du har ikke tilladelse til at ændre navn på brugeren \"{name}\"", + "error.user.changePassword.permission": "Du har ikke tilladelse til at ændre adgangskoden for brugeren \"{name}\"", + "error.user.changeRole.lastAdmin": "Rollen for den sidste admin kan ikke ændres", + "error.user.changeRole.permission": "Du har ikke tilladelse til at ændre rollen for brugeren \"{name}\"", + "error.user.changeRole.toAdmin": "Du har ikke tilladelse til at tildele nogen admin rollen", + "error.user.create.permission": "Du har ikke tilladelse til at oprette denne bruger", + "error.user.delete": "Brugeren kunne ikke slettes", + "error.user.delete.lastAdmin": "Du kan ikke slette den sidste admin", + "error.user.delete.lastUser": "Den sidste bruger kan ikke slettes", + "error.user.delete.permission": "Du har ikke tilladelse til at slette denne bruger", + "error.user.duplicate": "En bruger med email adresse \"{email}\" eksisterer allerede", + "error.user.email.invalid": "Indtast venligst en gyldig email adresse", + "error.user.language.invalid": "Indtast venligst et gyldigt sprog", + "error.user.notFound": "Brugeren kunne ikke findes", + "error.user.password.excessive": "Please enter a valid password. Passwords must not be longer than 1000 characters.", + "error.user.password.invalid": "Indtast venligst en gyldig adgangskode. Adgangskoder skal minimum være 8 tegn lange.", + "error.user.password.notSame": "Bekr\u00e6ft venligst adgangskoden", + "error.user.password.undefined": "Brugeren har ikke en adgangskode", + "error.user.password.wrong": "Forkert adgangskode", + "error.user.role.invalid": "Indtast venligst en gyldig rolle", + "error.user.undefined": "Brugeren kunne ikke findes", + "error.user.update.permission": "Du har ikke tilladelse til at opdatere brugeren \"{name}\"", + + "error.validation.accepted": "Bekræft venligst", + "error.validation.alpha": "Indtast venligst kun bogstaver imellem a-z", + "error.validation.alphanum": "Indtast venligst kun bogstaver og tal imellem a-z eller 0-9", + "error.validation.between": "Indtast venligst en værdi imellem \"{min}\" og \"{max}\"", + "error.validation.boolean": "Venligst bekræft eller afvis", + "error.validation.contains": "Indtast venligst en værdi der indeholder \"{needle}\"", + "error.validation.date": "Indtast venligst en gyldig dato", + "error.validation.date.after": "Indtast venligst en dato efter {date}", + "error.validation.date.before": "Indtast venligst en dato før {date}", + "error.validation.date.between": "Indtast venligst en dato imellem {min} og {max}", + "error.validation.denied": "Venligst afvis", + "error.validation.different": "Værdien må ikke være \"{other}\"", + "error.validation.email": "Indtast venligst en gyldig email adresse", + "error.validation.endswith": "Værdi skal ende med \"{end}\"", + "error.validation.filename": "Indtast venligst et gyldigt filnavn", + "error.validation.in": "Indtast venligst en af følgende: ({in})", + "error.validation.integer": "Indtast et gyldigt tal", + "error.validation.ip": "Indtast en gyldig IP adresse", + "error.validation.less": "Indtast venligst en værdi mindre end {max}", + "error.validation.match": "Værdien matcher ikke det forventede mønster", + "error.validation.max": "Indtast venligst en værdi lig med eller lavere end {max}", + "error.validation.maxlength": "Indtast venligst en kortere værdi. (maks. {max} karakterer)", + "error.validation.maxwords": "Indtast ikke flere end {max} ord", + "error.validation.min": "Indtast en værdi lig med eller højere end {min}", + "error.validation.minlength": "Indtast venligst en længere værdi. (min. {min} karakterer)", + "error.validation.minwords": "Indtast venligst mindst {min} ord", + "error.validation.more": "Indtast venligst en værdi større end {min}", + "error.validation.notcontains": "Indtast venligst en værdi der ikke indeholder \"{needle}\"", + "error.validation.notin": "Indtast venligst ikke nogen af følgende: ({notIn})", + "error.validation.option": "Vælg venligst en gyldig mulighed", + "error.validation.num": "Indtast venligst et gyldigt nummer", + "error.validation.required": "Indtast venligst noget", + "error.validation.same": "Indtast venligst \"{other}\"", + "error.validation.size": "Størrelsen på værdien skal være \"{size}\"", + "error.validation.startswith": "Værdien skal starte med \"{start}\"", + "error.validation.time": "Indtast venligst et gyldigt tidspunkt", + "error.validation.time.after": "Indtast venligst et tidspunkt efter {time}", + "error.validation.time.before": "Indtast venligst et tidspunkt inden {time}", + "error.validation.time.between": "Indtast venligst et tidspunkt imellem {min} og {max}", + "error.validation.url": "Indtast venligst en gyldig URL", + + "expand": "Fold ud", + "expand.all": "Fold alle ud", + + "field.required": "Feltet er påkrævet", + "field.blocks.changeType": "Skift type", + "field.blocks.code.name": "Kode", + "field.blocks.code.language": "Sprog", + "field.blocks.code.placeholder": "Din kode …", + "field.blocks.delete.confirm": "Ønsker du virkelig at slette denne blok?", + "field.blocks.delete.confirm.all": "Ønsker du virkelig at slette alle blokke?", + "field.blocks.delete.confirm.selected": "Ønsker du virkelig at slette de valgte blokke?", + "field.blocks.empty": "Ingen blokke endnu", + "field.blocks.fieldsets.label": "Vælg venligst en blok type", + "field.blocks.fieldsets.paste": "Tryk {{ shortcut }} for at indsætte/importere blokke fra dit udklipsholder", + "field.blocks.gallery.name": "Galleri", + "field.blocks.gallery.images.empty": "Ingen billeder endnu", + "field.blocks.gallery.images.label": "Billeder", + "field.blocks.heading.level": "Niveau", + "field.blocks.heading.name": "Overskrift", + "field.blocks.heading.text": "Tekst", + "field.blocks.heading.placeholder": "Overskrift …", + "field.blocks.image.alt": "Alternativ tekst", + "field.blocks.image.caption": "Billedtekst", + "field.blocks.image.crop": "Beskær", + "field.blocks.image.link": "Link", + "field.blocks.image.location": "Placering", + "field.blocks.image.name": "Billede", + "field.blocks.image.placeholder": "Vælg et billede", + "field.blocks.image.ratio": "Størrelsesforhold", + "field.blocks.image.url": "Billede URL", + "field.blocks.line.name": "Linje", + "field.blocks.list.name": "Liste", + "field.blocks.markdown.name": "Markdown", + "field.blocks.markdown.label": "Tekst", + "field.blocks.markdown.placeholder": "Markdown …", + "field.blocks.quote.name": "Citat", + "field.blocks.quote.text.label": "Tekst", + "field.blocks.quote.text.placeholder": "Citat …", + "field.blocks.quote.citation.label": "Citeret af", + "field.blocks.quote.citation.placeholder": "af …", + "field.blocks.text.name": "Tekst", + "field.blocks.text.placeholder": "Tekst …", + "field.blocks.video.caption": "Billedtekst", + "field.blocks.video.name": "Video", + "field.blocks.video.placeholder": "Indtast URL til en video", + "field.blocks.video.url.label": "Video-URL", + "field.blocks.video.url.placeholder": "https://youtube.com/?v=", + + "field.files.empty": "Ingen filer valgt endnu", + + "field.layout.delete": "Slet layout", + "field.layout.delete.confirm": "Ønsker du virkelig at slette dette layout", + "field.layout.empty": "Ingen rækker endnu", + "field.layout.select": "Vælg et layout", + + "field.pages.empty": "Ingen sider valgt endnu", + "field.structure.delete.confirm": "\u00d8nsker du virkelig at slette denne indtastning?", + "field.structure.empty": "Ingen indtastninger endnu.", + "field.users.empty": "Ingen brugere er valgt", + + "file.blueprint": "Denne fil har intet blueprint endnu. Du kan definere opsætningen i /site/blueprints/files/{blueprint}.yml", + "file.delete.confirm": "\u00d8nsker du virkelig at slette denne fil?", + "file.sort": "Skift position", + + "files": "Filer", + "files.empty": "Ingen filer endnu", + + "hide": "Skjul", + "hour": "Time", + "import": "Importer", + "info": "Info", + "insert": "Inds\u00e6t", + "insert.after": "Indsæt efter", + "insert.before": "Indsæt før", + "install": "Installer", + + "installation": "Installation", + "installation.completed": "Panelet er blevet installeret", + "installation.disabled": "Panel installationen er deaktiveret på offentlige servere som standard. Kør venligst installationen på en lokal maskine eller aktiver det med panel.install panel.install muligheden.", + "installation.issues.accounts": "\/site\/accounts er ikke skrivbar", + "installation.issues.content": "Content mappen samt alle underliggende filer og mapper skal v\u00e6re skrivbare.", + "installation.issues.curl": "CURL extension er påkrævet", + "installation.issues.headline": "Panelet kan ikke installeres", + "installation.issues.mbstring": "MB String extension er påkrævet", + "installation.issues.media": "/media mappen eksisterer ikke eller er ikke skrivbar", + "installation.issues.php": "Sikre dig at der benyttes PHP 7+", + "installation.issues.server": "Kirby kræver Apache, Nginx eller Caddy", + "installation.issues.sessions": "/site/sessions mappen eksisterer ikke eller er ikke skrivbar", + + "language": "Sprog", + "language.code": "Kode", + "language.convert": "Gør standard", + "language.convert.confirm": "

Ønsker du virkelig at konvertere {name} til standardsproget? Dette kan ikke fortrydes.

Hvis {name} har uoversat indhold, vil der ikke længere være et gyldigt tilbagefald og dele af dit website vil måske fremstå tomt.

", + "language.create": "Tilføj nyt sprog", + "language.delete.confirm": "Ønsker du virkelig at slette sproget {name} inklusiv alle oversættelser? Kan ikke fortrydes!", + "language.deleted": "Sproget er blevet slettet", + "language.direction": "Læseretning", + "language.direction.ltr": "Venstre mod højre", + "language.direction.rtl": "Højre mod venstre", + "language.locale": "PHP locale string", + "language.locale.warning": "Du benytter en brugerdefineret sprogopsætning. Rediger venligst dette i sprogfilen i /site/languages", + "language.name": "Navn", + "language.updated": "Sproget er blevet opdateret", + + "languages": "Sprog", + "languages.default": "Standardsprog", + "languages.empty": "Der er ingen sprog endnu", + "languages.secondary": "Sekundære sprog", + "languages.secondary.empty": "Der er ingen sekundære sprog endnu", + + "license": "Kirby licens", + "license.buy": "Køb en licens", + "license.register": "Registrer", + "license.manage": "Manage your licenses", + "license.register.help": "Du modtog din licenskode efter købet via email. Venligst kopier og indsæt den for at registrere.", + "license.register.label": "Indtast venligst din licenskode", + "license.register.success": "Tak for din støtte af Kirby", + "license.unregistered": "Dette er en uregistreret demo af Kirby", + "license.unregistered.label": "Unregistered", + + "link": "Link", + "link.text": "Link tekst", + + "loading": "Indlæser", + + "lock.unsaved": "Ugemte ændringer", + "lock.unsaved.empty": "Der er ikke flere ændringer der ikke er gamt", + "lock.isLocked": "Ugemte ændringer af {email}", + "lock.file.isLocked": "Filen redigeres på nuværende af {email} og kan derfor ikke ændres.", + "lock.page.isLocked": "Siden redigeres på nuværende af {email} og kan derfor ikke ændres.", + "lock.unlock": "Lås op", + "lock.isUnlocked": "Dine ugemte ændringer er blevet overskrevet af en anden bruger. Du kan downloade dine ændringer for at flette dem ind manuelt.", + + "login": "Log ind", + "login.code.label.login": "Log ind kode", + "login.code.label.password-reset": "Sikkerhedskode", + "login.code.placeholder.email": "000 000", + "login.code.text.email": "Hvis din email adresse er registreret er en sikkerhedskode blevet sendt via email.", + "login.email.login.body": "Hej {user.nameOrEmail},\n\nDu har for nyligt anmodet om en log ind kode til panelet af {site}.\nFølgende log ind kode vil være gyldig i {timeout} minutter:\n\n{code}\n\nHvis du ikke har anmodet om en log ind kode, kan du blot ignorere denne email eller kontakte din administrator hvis du har spørgsmål.\nAf sikkerhedsmæssige årsager, bør du IKKE videresende denne email.", + "login.email.login.subject": "Din log ind kode", + "login.email.password-reset.body": "Hej {user.nameOrEmail},\n\nDu har for nyligt anmodet om kode til nulstilling af adgangskode til panelet af {site}.\nFølgende kode til nulstilling af adgangskode vil være gyldig i {timeout} minutter:\n\n{code}\n\nHvis du ikke har anmodet om kode til nulstilling af adgangskode, kan du blot ignorere denne email eller kontakte din administrator hvis du har spørgsmål.\nAf sikkerhedsmæssige årsager, bør du IKKE videresende denne email.", + "login.email.password-reset.subject": "Din kode til nulstilling af adgangskode", + "login.remember": "Forbliv logget ind", + "login.reset": "Nulstil adgangskode", + "login.toggleText.code.email": "Log ind via email", + "login.toggleText.code.email-password": "Log ind med adgangskode", + "login.toggleText.password-reset.email": "Glemt din adgangskode?", + "login.toggleText.password-reset.email-password": "← Tilbage til log ind", + + "logout": "Log ud", + + "menu": "Menu", + "meridiem": "AM/PM", + "mime": "Medie Type", + "minutes": "Minutter", + + "month": "Måned", + "months.april": "April", + "months.august": "August", + "months.december": "December", + "months.february": "Februar", + "months.january": "Januar", + "months.july": "Juli", + "months.june": "Juni", + "months.march": "Marts", + "months.may": "Maj", + "months.november": "November", + "months.october": "Oktober", + "months.september": "September", + + "more": "Mere", + "name": "Navn", + "next": "Næste", + "no": "nej", + "off": "Sluk", + "on": "Aktiveret", + "open": "Åben", + "open.newWindow": "Åben i et nyt vindue", + "options": "Indstillinger", + "options.none": "Ingen muligheder", + + "orientation": "Orientering", + "orientation.landscape": "Landskab", + "orientation.portrait": "Portræt", + "orientation.square": "Kvadrat", + + "page.blueprint": "Denne side har intet blueprint endnu. Du kan definere opsætningen i /site/blueprints/pages/{blueprint}.yml", + "page.changeSlug": "\u00c6ndre URL", + "page.changeSlug.fromTitle": "Generer udfra titel", + "page.changeStatus": "Skift status", + "page.changeStatus.position": "Vælg venligst position", + "page.changeStatus.select": "Vælg en ny status", + "page.changeTemplate": "Skift skabelon", + "page.delete.confirm": "\u00d8nsker du virkelig at slette denne side?", + "page.delete.confirm.subpages": "Denne side har undersider.
Alle undersider vil også blive slettet.", + "page.delete.confirm.title": "Indtast sidens titel for at bekræfte", + "page.draft.create": "Opret kladde", + "page.duplicate.appendix": "Kopier", + "page.duplicate.files": "Kopier filer", + "page.duplicate.pages": "Kopier sider", + "page.sort": "Skift position", + "page.status": "Status", + "page.status.draft": "Kladde", + "page.status.draft.description": "Siden er i kladde udgave og er kun synlig for redaktører der er logget ind eller via hemmeligt link", + "page.status.listed": "Offentlig", + "page.status.listed.description": "Siden er offentlig for enhver", + "page.status.unlisted": "Ulistede", + "page.status.unlisted.description": "Siden er kun tilgængelig via URL", + + "pages": "Sider", + "pages.empty": "Ingen sider endnu", + "pages.status.draft": "Kladder", + "pages.status.listed": "Udgivede", + "pages.status.unlisted": "Ulistede", + + "pagination.page": "Side", + + "password": "Adgangskode", + "paste": "Indsæt", + "paste.after": "Indsæt efter", + "pixel": "Pixel", + "plugins": "Plugins", + "prev": "Forrige", + "preview": "Forhåndsvisning", + "remove": "Fjern", + "rename": "Omdøb", + "replace": "Erstat", + "retry": "Pr\u00f8v igen", + "revert": "Kass\u00e9r", + "revert.confirm": "Ønsker du virkelig at slette all ændringer der ikke er gemt?", + + "role": "Rolle", + "role.admin.description": "Admin har alle rettigheder", + "role.admin.title": "Admin", + "role.all": "All", + "role.empty": "Der er ingen bruger med denne rolle", + "role.description.placeholder": "Ingen beskrivelse", + "role.nobody.description": "Dette er en tilbagefaldsrolle uden rettigheder", + "role.nobody.title": "Ingen", + + "save": "Gem", + "search": "Søg", + "search.min": "Indtast {min} tegn for at søge", + "search.all": "Vis alle", + "search.results.none": "Ingen resultater", + + "section.required": "Sektionen er påkrævet", + + "security": "Security", + "select": "Vælg", + "server": "Server", + "settings": "Indstillinger", + "show": "Vis", + "site.blueprint": "Sitet har intet blueprint endnu. Du kan definere opsætningen i /site/blueprints/site.yml", + "size": "Størrelse", + "slug": "URL-appendiks", + "sort": "Sorter", + + "stats.empty": "No reports", + "system.issues.content": "The content folder seems to be exposed", + "system.issues.debug": "Debugging must be turned off in production", + "system.issues.git": "The .git folder seems to be exposed", + "system.issues.https": "We recommend HTTPS for all your sites", + "system.issues.kirby": "The kirby folder seems to be exposed", + "system.issues.site": "The site folder seems to be exposed", + + "title": "Titel", + "template": "Skabelon", + "today": "Idag", + + "toolbar.button.code": "Kode", + "toolbar.button.bold": "Fed tekst", + "toolbar.button.email": "Email", + "toolbar.button.headings": "Overskrifter", + "toolbar.button.heading.1": "Overskrift 1", + "toolbar.button.heading.2": "Overskrift 2", + "toolbar.button.heading.3": "Overskrift 3", + "toolbar.button.heading.4": "Overskrift 4", + "toolbar.button.heading.5": "Overskrift 5", + "toolbar.button.heading.6": "Overskrift 6", + "toolbar.button.italic": "Kursiv tekst", + "toolbar.button.file": "Fil", + "toolbar.button.file.select": "Vælg en fil", + "toolbar.button.file.upload": "Upload en fil", + "toolbar.button.link": "Link", + "toolbar.button.paragraph": "Afsnit", + "toolbar.button.strike": "Gennemstreg", + "toolbar.button.ol": "Ordnet liste", + "toolbar.button.underline": "Understreg", + "toolbar.button.ul": "Punktliste", + + "translation.author": "Kirby Team", + "translation.direction": "ltr", + "translation.name": "Dansk", + "translation.locale": "da_DK", + + "upload": "Upload", + "upload.error.cantMove": "Den uploadede fil kunne ikke flyttes", + "upload.error.cantWrite": "Kunne ikke skrive fil til disk", + "upload.error.default": "Filen kunne ikke uploades", + "upload.error.extension": "Upload af filen blev stoppet af dens type", + "upload.error.formSize": "Filen overskrider MAX_FILE_SIZE direktivet der er specificeret for formularen", + "upload.error.iniPostSize": "FIlen overskrider post_max_size direktivet i php.ini", + "upload.error.iniSize": "FIlen overskrider upload_max_filesize direktivet i php.ini", + "upload.error.noFile": "Ingen fil blev uploadet", + "upload.error.noFiles": "Ingen filer blev uploadet", + "upload.error.partial": "Den uploadede fil blev kun delvist uploadet", + "upload.error.tmpDir": "Der mangler en midlertidig mappe", + "upload.errors": "Fejl", + "upload.progress": "Uploader...", + + "url": "Url", + "url.placeholder": "https://example.com", + + "user": "Bruger", + "user.blueprint": "Du kan definere yderligere sektioner og formular felter for denne brugerrolle i /site/blueprints/users/{blueprint}.yml", + "user.changeEmail": "Skift email", + "user.changeLanguage": "Skift sprog", + "user.changeName": "Omdøb denne bruger", + "user.changePassword": "Skift adgangskode", + "user.changePassword.new": "Ny adgangskode", + "user.changePassword.new.confirm": "Bekræft den nye adgangskode...", + "user.changeRole": "Skift rolle", + "user.changeRole.select": "Vælg en ny rolle", + "user.create": "Tilføj en ny bruger", + "user.delete": "Slet denne bruger", + "user.delete.confirm": "\u00d8nsker du virkelig at slette denne bruger?", + + "users": "Brugere", + + "version": "Kirby version", + + "view.account": "Din konto", + "view.installation": "Installation", + "view.languages": "Sprog", + "view.resetPassword": "Nulstil adgangskode", + "view.site": "Website", + "view.system": "System", + "view.users": "Brugere", + + "welcome": "Velkommen", + "year": "År", + "yes": "ja" } diff --git a/kirby/i18n/translations/de.json b/kirby/i18n/translations/de.json index 040645c..93b7f34 100644 --- a/kirby/i18n/translations/de.json +++ b/kirby/i18n/translations/de.json @@ -1,730 +1,574 @@ { - "account.changeName": "Deinen Namen ändern", - "account.delete": "Deinen Account löschen", - "account.delete.confirm": "Willst du deinen Account wirklich löschen? Du wirst sofort danach abgemeldet. Dein Account kann nicht wieder hergestellt werden.", - - "activate": "Aktivieren", - "add": "Hinzuf\u00fcgen", - "alpha": "Alpha", - "author": "Autor", - "avatar": "Profilbild", - "back": "Zurück", - "cancel": "Abbrechen", - "change": "\u00c4ndern", - "close": "Schlie\u00dfen", - "changes": "Änderungen", - "confirm": "OK", - "collapse": "Zusammenklappen", - "collapse.all": "Alle zusammenklappen", - "color": "Farbe", - "coordinates": "Koordinaten", - "copy": "Kopieren", - "copy.all": "Alle kopieren", - "copy.success": "{count} kopiert!", - "create": "Erstellen", - "custom": "Benutzerdefiniert", - - "date": "Datum", - "date.select": "Datum auswählen", - - "day": "Tag", - "days.fri": "Fr", - "days.mon": "Mo", - "days.sat": "Sa", - "days.sun": "So", - "days.thu": "Do", - "days.tue": "Di", - "days.wed": "Mi", - - "debugging": "Debugging", - - "delete": "L\u00f6schen", - "delete.all": "Alle löschen", - - "dialog.fields.empty": "Der Dialog hat keine Felder", - "dialog.files.empty": "Keine verfügbaren Dateien", - "dialog.pages.empty": "Keine verfügbaren Seiten", - "dialog.text.empty": "Dieser Dialog definiert keinen Text", - "dialog.users.empty": "Keine verfügbaren Accounts", - - "dimensions": "Maße", - "disable": "Deaktivieren", - "disabled": "Gesperrt", - "discard": "Verwerfen", - - "drawer.fields.empty": "Die Schublade hat keine Felder", - - "domain": "Domain", - "download": "Download", - "duplicate": "Duplizieren", - - "edit": "Bearbeiten", - - "email": "E-Mail", - "email.placeholder": "mail@beispiel.de", - - "enter": "Enter", - "entries": "Einträge", - "entry": "Eintrag", - - "environment": "Umgebung", - - "error": "Fehler", - "error.access.code": "Ungültiger Code", - "error.access.login": "Ungültige Zugangsdaten", - "error.access.panel": "Du hast keinen Zugang zum Panel", - "error.access.view": "Du hast keinen Zugriff auf diesen Teil des Panels", - - "error.avatar.create.fail": "Das Profilbild konnte nicht hochgeladen werden", - "error.avatar.delete.fail": "Das Profilbild konnte nicht gel\u00f6scht werden", - "error.avatar.dimensions.invalid": "Bitte lade ein Profilbild hoch, das nicht breiter oder höher als 3000 Pixel ist.", - "error.avatar.mime.forbidden": "Das Profilbild muss vom Format JPEG oder PNG sein", - - "error.blueprint.notFound": "Das Blueprint \"{name}\" konnte nicht geladen werden.", - - "error.blocks.max.plural": "Bitte füge nicht mehr als {max} Blöcke hinzu", - "error.blocks.max.singular": "Bitte füge nicht mehr als einen Block hinzu", - "error.blocks.min.plural": "Bitte füge mindestens {min} Blöcke hinzu", - "error.blocks.min.singular": "Bitte füge mindestens einen Block hinzu", - "error.blocks.validation": "Fehler im \"{field}\" Feld in Block {index} mit dem Block Typ \"{fieldset}\"", - - "error.cache.type.invalid": "Ungültiger Cachetyp: \"{type}\"", - - "error.email.preset.notFound": "Die E-Mailvorlage \"{name}\" wurde nicht gefunden", - - "error.field.converter.invalid": "Ungültiger Konverter: \"{converter}\"", - "error.field.type.missing": "Feld \"{ name }\": Der Feldtyp \"{ type }\" existiert nicht", - - "error.file.changeName.empty": "Bitte gib einen Namen an", - "error.file.changeName.permission": "Du darfst den Dateinamen von \"{filename}\" nicht ändern", - "error.file.changeTemplate.invalid": "Die Vorlage für die Datei \"{id}\" kann nicht zu \"{template}\" geändert werden (gültig: \"{blueprints}\")", - "error.file.changeTemplate.permission": "Du kannst die Vorlage für die Datei \"{id}\" nicht ändern", - - "error.file.duplicate": "Eine Datei mit dem Dateinamen \"{filename}\" besteht bereits", - "error.file.extension.forbidden": "Verbotene Dateiendung \"{extension}\"", - "error.file.extension.invalid": "Verbotene Dateiendung \"{extension}\"", - "error.file.extension.missing": "Du kannst keine Dateien ohne Dateiendung hochladen", - "error.file.maxheight": "Die Bildhöhe darf {height} Pixel nicht überschreiten", - "error.file.maxsize": "Die Datei ist zu groß", - "error.file.maxwidth": "Die Bildbreite darf {width} Pixel nicht überschreiten", - "error.file.mime.differs": "Die Datei muss den Medientyp \"{mime}\" haben.", - "error.file.mime.forbidden": "Der Medientyp \"{mime}\" ist nicht erlaubt", - "error.file.mime.invalid": "Ungültiger Dateityp: {mime}", - "error.file.mime.missing": "Der Medientyp für \"{filename}\" konnte nicht erkannt werden", - "error.file.minheight": "Die Bildhöhe muss mindestens {height} Pixel betragen", - "error.file.minsize": "Die Datei ist zu klein", - "error.file.minwidth": "Die Bildbreite muss mindestens {width} Pixel betragen", - "error.file.name.unique": "Der Dateiname besteht bereits", - "error.file.name.missing": "Bitte gib einen Dateinamen an", - "error.file.notFound": "Die Datei \"{filename}\" konnte nicht gefunden werden", - "error.file.orientation": "Das Bildformat ist ungültig. Erwartetes Format: \"{orientation}\"", - "error.file.type.forbidden": "Du kannst keinen {type}-Dateien hochladen", - "error.file.type.invalid": "Ungültiger Dateityp: {mime}", - "error.file.undefined": "Die Datei konnte nicht gefunden werden", - - "error.form.incomplete": "Bitte behebe alle Fehler …", - "error.form.notSaved": "Das Formular konnte nicht gespeichert werden", - - "error.language.code": "Bitte gib einen gültigen Code für die Sprache an", - "error.language.duplicate": "Die Sprache besteht bereits", - "error.language.name": "Bitte gib einen gültigen Namen für die Sprache an", - "error.language.notFound": "Die Sprache konnte nicht gefunden werden", - - "error.layout.validation.block": "Fehler im \"{field}\" Feld in Block {blockIndex} mit dem Blocktyp \"{fieldset}\" in Layout {layoutIndex}", - "error.layout.validation.settings": "Fehler in den Einstellungen von Layout {index}", - - "error.license.domain": "Die Domain für die Lizenz fehlt", - "error.license.email": "Bitte gib eine gültige E-Mailadresse an", - "error.license.format": "Bitte gib einen gültigen Lizenzschlüssel ein", - "error.license.verification": "Die Lizenz konnte nicht verifiziert werden", - - "error.login.totp.confirm.invalid": "Ungültiger Code", - "error.login.totp.confirm.missing": "Bitte gib den aktuellen Code ein", - - "error.object.validation": "Fehler im \"{label}\" Feld:\n{message}", - - "error.offline": "Das Panel ist zur Zeit offline", - - "error.page.changeSlug.permission": "Du darfst die URL der Seite \"{slug}\" nicht ändern", - "error.page.changeSlug.reserved": "Der Pfad für Top-Level Seiten darf nicht mit \"{path}\" beginnen.", - "error.page.changeStatus.incomplete": "Die Seite ist nicht vollständig und kann daher nicht veröffentlicht werden", - "error.page.changeStatus.permission": "Der Status der Seite kann nicht geändert werden", - "error.page.changeStatus.toDraft.invalid": "Die Seite \"{slug}\" kann nicht in einen Entwurf umgewandelt werden", - "error.page.changeTemplate.invalid": "Die Vorlage für die Seite \"{slug}\" kann nicht geändert werden", - "error.page.changeTemplate.permission": "Du kannst die Vorlage für die Seite \"{slug}\" nicht ändern", - "error.page.changeTitle.empty": "Bitte gib einen Titel an", - "error.page.changeTitle.permission": "Du kannst den Titel für die Seite \"{slug}\" nicht ändern", - "error.page.create.permission": "Du kannst die Seite \"{slug}\" nicht anlegen", - "error.page.delete": "Die Seite \"{slug}\" kann nicht gelöscht werden", - "error.page.delete.confirm": "Bitte gib zur Bestätigung den Seitentitel ein", - "error.page.delete.hasChildren": "Die Seite hat Unterseiten und kann nicht gelöscht werden", - "error.page.delete.permission": "Du kannst die Seite \"{slug}\" nicht löschen", - "error.page.draft.duplicate": "Ein Entwurf mit dem URL-Kürzel \"{slug}\" besteht bereits", - "error.page.duplicate": "Eine Seite mit dem URL-Kürzel \"{slug}\" besteht bereits", - "error.page.duplicate.permission": "Du kannst die Seite \"{slug}\" nicht duplizieren", - "error.page.move.ancestor": "Die Seite kann nicht in sich selbst verschoben werden", - "error.page.move.directory": "Der Ordner der Seite kann nicht verschoben werden", - "error.page.move.duplicate": "Eine Seite mit dem URL-Kürzel \"{slug}\" besteht bereits", - "error.page.move.notFound": "Die verschobene Seite kann nicht gefunden werden", - "error.page.move.permission": "Du kannst die Seite \"{slug}\" nicht verschieben", - "error.page.move.template": "Die Vorlage \"{template}\" wird nicht als Unterseite von \"{parent}\" akzeptiert", - "error.page.notFound": "Die Seite \"{slug}\" konnte nicht gefunden werden", - "error.page.num.invalid": "Bitte gib eine gültige Sortierungszahl an. Negative Zahlen sind nicht erlaubt.", - "error.page.slug.invalid": "Bitte gib ein gültiges URL-Kürzel an", - "error.page.slug.maxlength": "Die Pfadlänge darf {length} Zeichen nicht überschreiten", - "error.page.sort.permission": "Die Seite \"{slug}\" kann nicht umsortiert werden", - "error.page.status.invalid": "Bitte gib einen gültigen Seitenstatus an", - "error.page.undefined": "Die Seite konnte nicht gefunden werden", - "error.page.update.permission": "Du kannst die Seite \"{slug}\" nicht editieren", - - "error.section.files.max.plural": "Bitte füge nicht mehr als {max} Dateien zum Bereich \"{section}\" hinzu", - "error.section.files.max.singular": "Bitte füge nicht mehr als eine Datei zum Bereich \"{section}\" hinzu", - "error.section.files.min.plural": "Der Bereich \"{section}\" benötigt mindestens {min} Dateien", - "error.section.files.min.singular": "Der Bereich \"{section}\" benötigt mindestens eine Datei", - - "error.section.pages.max.plural": "Bitte füge nicht mehr als {max} Seiten zum Bereich \"{section}\" hinzu", - "error.section.pages.max.singular": "Bitte füge nicht mehr als eine Seite zum Bereich \"{section}\" hinzu", - "error.section.pages.min.plural": "Der Bereich \"{section}\" benötigt mindestens {min} Seiten", - "error.section.pages.min.singular": "Der Bereich \"{section}\" benötigt mindestens eine Seite", - - "error.section.notLoaded": "Der Bereich \"{name}\" konnte nicht geladen werden", - "error.section.type.invalid": "Der Bereichstyp \"{type}\" ist nicht gültig", - - "error.site.changeTitle.empty": "Bitte gib einen Titel an", - "error.site.changeTitle.permission": "Du kannst den Titel der Seite nicht ändern", - "error.site.update.permission": "Du darfst die Seite nicht bearbeiten", - - "error.structure.validation": "Fehler im Feld \"{field}\" in Zeile {index}", - - "error.template.default.notFound": "Die \"Default\"-Vorlage existiert nicht", - - "error.unexpected": "Ein unerwarteter Fehler ist aufgetreten. Aktiviere den Debug-Modus für weitere Informationen: https://getkirby.com/docs/reference/system/options/debug", - - "error.user.changeEmail.permission": "Du kannst die E-Mailadresse für den Account \"{name}\" nicht ändern", - "error.user.changeLanguage.permission": "Du kannst die Sprache für den Account \"{name}\" nicht ändern", - "error.user.changeName.permission": "Du kannst den Namen für den Account \"{name}\" nicht ändern", - "error.user.changePassword.permission": "Du kannst das Passwort für den Account \"{name}\" nicht ändern", - "error.user.changeRole.lastAdmin": "Die Rolle des letzten Accounts mit Administrationsrechten kann nicht geändert werden", - "error.user.changeRole.permission": "Du kannst die Rolle für den Benutzer \"{name}\" nicht ändern", - "error.user.changeRole.toAdmin": "Du darfst die Admin-Rolle nicht an andere Accounts vergeben", - "error.user.create.permission": "Du darfst diesen Account nicht anlegen", - "error.user.delete": "Der Account \"{name}\" konnte nicht gelöscht werden", - "error.user.delete.lastAdmin": "Du kannst den letzten Account mit Administrationsrechten nicht löschen", - "error.user.delete.lastUser": "Der letzte Account kann nicht gelöscht werden", - "error.user.delete.permission": "Du darfst den Account \"{name}\" nicht löschen", - "error.user.duplicate": "Ein Account mit der E-Mailadresse \"{email}\" besteht bereits", - "error.user.email.invalid": "Bitte gib eine gültige E-Mailadresse an", - "error.user.language.invalid": "Bitte gib eine gültige Sprache an", - "error.user.notFound": "Der Account \"{name}\" wurde nicht gefunden", - "error.user.password.excessive": "Bitte gib ein gültiges Passwort ein. Passwörter dürfen nicht länger als 1000 Zeichen sein.", - "error.user.password.invalid": "Bitte gib ein gültiges Passwort ein. Passwörter müssen mindestens 8 Zeichen lang sein.", - "error.user.password.notSame": "Die Passwörter stimmen nicht überein", - "error.user.password.undefined": "Der Account hat kein Passwort", - "error.user.password.wrong": "Falsches Passwort", - "error.user.role.invalid": "Bitte gib eine gültige Rolle an", - "error.user.undefined": "Der Benutzer wurde nicht gefunden", - "error.user.update.permission": "Du darfst den den Account \"{name}\" nicht bearbeiten", - - "error.validation.accepted": "Bitte bestätige", - "error.validation.alpha": "Bitte gib nur Zeichen zwischen A und Z ein", - "error.validation.alphanum": "Bitte gib nur Zeichen zwischen A und Z und Zahlen zwischen 0 und 9 ein", - "error.validation.anchor": "Bitte gib einen korrekten Anker an", - "error.validation.between": "Bitte gib einen Wert zwischen \"{min}\" und \"{max}\" ein", - "error.validation.boolean": "Bitte bestätige oder lehne ab", - "error.validation.color": "Bitte gib eine gültige Farbe im Format {format} ein", - "error.validation.contains": "Bitte gib einen Wert ein, der \"{needle}\" enthält", - "error.validation.date": "Bitte gib ein gültiges Datum ein", - "error.validation.date.after": "Bitte gib ein Datum nach dem {date} ein", - "error.validation.date.before": "Bitte gib ein Datum vor dem {date} ein", - "error.validation.date.between": "Bitte gib ein Datum zwischen dem {min} und dem {max} ein", - "error.validation.denied": "Bitte lehne die Eingabe ab", - "error.validation.different": "Der Wert darf nicht \"{other}\" sein", - "error.validation.email": "Bitte gib eine gültige E-Mailadresse an", - "error.validation.endswith": "Der Wert muss auf \"{end}\" enden", - "error.validation.filename": "Bitte gib einen gültigen Dateinamen ein", - "error.validation.in": "Bitte gib einen der folgenden Werte ein: ({in})", - "error.validation.integer": "Bitte gib eine ganze Zahl ein", - "error.validation.ip": "Bitte gib eine gültige IP Adresse ein", - "error.validation.less": "Bitte gib einen Wert kleiner als {max} ein", - "error.validation.linkType": "Der Linktyp ist nicht erlaubt", - "error.validation.match": "Der Wert entspricht nicht dem erwarteten Muster", - "error.validation.max": "Bitte gib einen Wert ein, der nicht größer als {max} ist", - "error.validation.maxlength": "Bitte gib einen kürzeren Text ein (max. {max} Zeichen)", - "error.validation.maxwords": "Bitte nutze nicht mehr als {max} Wort(e)", - "error.validation.min": "Bitte gib einen Wert ein, der nicht kleiner als {min} ist", - "error.validation.minlength": "Bitte gib einen längeren Text ein. (min. {min} Zeichen)", - "error.validation.minwords": "Bitte nutze mindestens {min} Wort(e)", - "error.validation.more": "Bitte gib einen größeren Wert als {min} ein", - "error.validation.notcontains": "Bitte gib einen Wert ein, der nicht \"{needle}\" enthält", - "error.validation.notin": "Bitte gib keinen der folgenden Werte ein: ({notIn})", - "error.validation.option": "Bitte wähle eine gültige Option aus", - "error.validation.num": "Bitte gib eine gültige Zahl an", - "error.validation.required": "Bitte gib etwas ein", - "error.validation.same": "Bitte gib \"{other}\" ein", - "error.validation.size": "Die Größe des Wertes muss \"{size}\" sein", - "error.validation.startswith": "Der Wert muss mit \"{start}\" beginnen", - "error.validation.tel": "Bitte gib eine unformatierte Telefonnummer an", - "error.validation.time": "Bitte gib eine gültige Uhrzeit ein", - "error.validation.time.after": "Bitte gib eine Zeit nach {time} ein", - "error.validation.time.before": "Bitte gib eine Zeit vor {time} ein", - "error.validation.time.between": "Bitte gib eine Zeit zwischen {min} und {max} ein", - "error.validation.uuid": "Bitte gib eine gültige UUID an", - "error.validation.url": "Bitte gib eine gültige URL ein", - - "expand": "Aufklappen", - "expand.all": "Alle aufklappen", - - "field.invalid": "Das Feld ist ungültig", - "field.required": "Das Feld ist Pflicht", - "field.blocks.changeType": "Blocktyp ändern", - "field.blocks.code.name": "Code", - "field.blocks.code.language": "Sprache", - "field.blocks.code.placeholder": "Code …", - "field.blocks.delete.confirm": "Willst du diesen Block wirklich löschen?", - "field.blocks.delete.confirm.all": "Willst du wirklich alle Blöcke löschen?", - "field.blocks.delete.confirm.selected": "Willst du wirklich die ausgewählten Blöcke löschen?", - "field.blocks.empty": "Keine Blöcke", - "field.blocks.fieldsets.empty": "Keine Block Definition", - "field.blocks.fieldsets.label": "Bitte wähle einen Blocktyp aus …", - "field.blocks.fieldsets.paste": "Drücke {{ shortcut }} um Layouts/Blocks von deinem Clipboard zu importieren. Nur die, die im aktuellen Feld erlaubt sind werden eingefügt.", - "field.blocks.gallery.name": "Galerie", - "field.blocks.gallery.images.empty": "Keine Bilder", - "field.blocks.gallery.images.label": "Bilder", - "field.blocks.heading.level": "Ebene", - "field.blocks.heading.name": "Überschrift", - "field.blocks.heading.text": "Text", - "field.blocks.heading.placeholder": "Überschrift …", - "field.blocks.image.alt": "Alternativer Text", - "field.blocks.image.caption": "Bildunterschrift", - "field.blocks.image.crop": "Beschneiden", - "field.blocks.image.link": "Link", - "field.blocks.image.location": "Ort", - "field.blocks.image.location.internal": "Diese Webseite", - "field.blocks.image.location.external": "Externe Quelle", - "field.blocks.image.name": "Bild", - "field.blocks.image.placeholder": "Bild auswählen", - "field.blocks.image.ratio": "Seitenverhältnis", - "field.blocks.image.url": "Bild URL", - "field.blocks.line.name": "Linie", - "field.blocks.list.name": "Liste", - "field.blocks.markdown.name": "Markdown", - "field.blocks.markdown.label": "Text", - "field.blocks.markdown.placeholder": "Markdown …", - "field.blocks.quote.name": "Zitat", - "field.blocks.quote.text.label": "Text", - "field.blocks.quote.text.placeholder": "Zitat …", - "field.blocks.quote.citation.label": "Quelle", - "field.blocks.quote.citation.placeholder": "Quelle …", - "field.blocks.text.name": "Text", - "field.blocks.text.placeholder": "Text …", - "field.blocks.video.autoplay": "Autoplay", - "field.blocks.video.caption": "Bildunterschrift", - "field.blocks.video.controls": "Steuerung", - "field.blocks.video.location": "Ort", - "field.blocks.video.loop": "Schleife", - "field.blocks.video.muted": "Stumm", - "field.blocks.video.name": "Video", - "field.blocks.video.placeholder": "Video-URL eingeben", - "field.blocks.video.poster": "Poster", - "field.blocks.video.preload": "Vorladen", - "field.blocks.video.url.label": "Video-URL", - "field.blocks.video.url.placeholder": "https://youtube.com/?v=", - - "field.files.empty": "Keine Dateien ausgewählt", - - "field.layout.change": "Layout ändern", - "field.layout.delete": "Layout löschen", - "field.layout.delete.confirm": "Willst du dieses Layout wirklich löschen?", - "field.layout.delete.confirm.all": "Willst du wirklich alle Layouts löschen?", - "field.layout.empty": "Keine Layouts", - "field.layout.select": "Layout auswählen", - - "field.object.empty": "Noch keine Information", - - "field.pages.empty": "Keine Seiten ausgewählt", - - "field.structure.delete.confirm": "Willst du diesen Eintrag wirklich l\u00f6schen?", - "field.structure.delete.confirm.all": "Möchtest du wirklich alle Einträge löschen?", - "field.structure.empty": "Es bestehen keine Eintr\u00e4ge.", - - "field.users.empty": "Keine Accounts ausgewählt", - - "fields.empty": "Keine Felder", - - "file": "Datei", - "file.blueprint": "Du kannst zusätzliche Felder und Bereiche für diese Datei in /site/blueprints/files/{blueprint}.yml anlegen", - "file.changeTemplate": "Vorlage ändern", - "file.changeTemplate.notice": "Das Ändern der Dateivorlage wird alle Inhalte von Feldern entfernen, deren Feldtypen nicht übereinstimmen. Wenn die neue Vorlage bestimmte Regeln definiert, z.B. Bildabmessungen, werden diese unwiderruflich angewandt. Benutze diese Funktion mit Vorsicht.", - "file.delete.confirm": "Willst du die Datei {filename}
wirklich löschen?", - "file.focus.placeholder": "Fokuspunkt setzen", - "file.focus.reset": "Fokuspunkt entfernen", - "file.focus.title": "Fokus", - "file.sort": "Position ändern", - - "files": "Dateien", - "files.empty": "Keine Dateien", - - "filter": "Filter", - - "hide": "Verbergen", - "hour": "Stunde", - "hue": "Farbton", - "import": "Importieren", - "info": "Info", - "insert": "Einf\u00fcgen", - "insert.after": "Danach einfügen", - "insert.before": "Davor einfügen", - "install": "Installieren", - - "installation": "Installation", - "installation.completed": "Das Panel wurde installiert", - "installation.disabled": "Die Panel-Installation ist auf öffentlichen Servern automatisch deaktiviert. Bitte installiere das Panel auf einem lokalen Server oder aktiviere die Installation gezielt mit der panel.install Option. ", - "installation.issues.accounts": "/site/accounts ist nicht beschreibbar", - "installation.issues.content": "/content existiert nicht oder ist nicht beschreibbar", - "installation.issues.curl": "Die CURL Erweiterung wird benötigt", - "installation.issues.headline": "Das Panel kann nicht installiert werden", - "installation.issues.mbstring": "Die MB String Erweiterung wird benötigt", - "installation.issues.media": "Der /media Ordner ist nicht beschreibbar", - "installation.issues.php": "Bitte verwende PHP 8+", - "installation.issues.sessions": "/site/sessions ist nicht beschreibbar", - - "language": "Sprache", - "language.code": "Code", - "language.convert": "Als Standard auswählen", - "language.convert.confirm": "

Willst du {name} wirklich in die Standardsprache umwandeln? Dieser Schritt kann nicht rückgängig gemacht werden.

Wenn {name} unübersetzte Felder hat, gibt es keine gültigen Standardwerte für diese Felder und Inhalte könnten verloren gehen.

", - "language.create": "Neue Sprache anlegen", - "language.default": "Standardsprache", - "language.delete.confirm": "Willst du {name} inklusive aller Übersetzungen wirklich löschen? Dieser Schritt kann nicht rückgängig gemacht werden!", - "language.deleted": "Die Sprache wurde gelöscht", - "language.direction": "Leserichtung", - "language.direction.ltr": "Von links nach rechts", - "language.direction.rtl": "Von rechts nach links", - "language.locale": "PHP locale string", - "language.locale.warning": "Du nutzt ein angepasstes Setup for PHP Locales. Bitte bearbeite dieses direkt in der entsprechenden Sprachdatei in /site/languages", - "language.name": "Name", - "language.secondary": "Sekundäre Sprachen", - "language.settings": "Spracheinstellungen", - "language.updated": "Die Sprache wurde gespeichert", - "language.variables": "Sprachvariablen", - "language.variables.empty": "Keine Übersetzung", - - "language.variable.delete.confirm": "Willst du wirklich die Variable \"{key}\" entfernen?", - "language.variable.key": "Schlüssel", - "language.variable.notFound": "Die Variable konnte nicht gefunden werden", - "language.variable.value": "Wert", - - "languages": "Sprachen", - "languages.default": "Standardsprache", - "languages.empty": "Noch keine Sprachen", - "languages.secondary": "Sekundäre Sprachen", - "languages.secondary.empty": "Noch keine sekundären Sprachen", - - "license": "Lizenz", - "license.activate": "Aktiviere Kirby jetzt", - "license.activate.label": "Bitte aktiviere deine Lizenz", - "license.activate.domain": "Deine Lizenz wird für die Domain {host} aktiviert.", - "license.activate.local": "Du bist dabei, deine Kirby Lizenz für die lokale Domain {host} zu aktivieren. Falls diese Seite später unter einer anderen Domain veröffentlicht wird, solltest du sie erst dort aktivieren. Falls {host} die Domain ist, die du für deine Lizenz nutzen möchtest, fahre bitte fort. ", - "license.activated": "Aktiviert", - "license.buy": "Kaufe eine Lizenz", - "license.code": "Code", - "license.code.help": "Du hast deinen Lizenz Code nach dem Kauf per Email bekommen. Bitte kopiere sie aus der Email und füge sie hier ein. ", - "license.code.label": "Bitte gib deinen Lizenzcode ein", - "license.status.active.info": "Beinhaltet neue Major Versionen bis {date}", - "license.status.active.label": "Gültige Lizenz", - "license.status.demo.info": "Dies ist eine Demo Installation", - "license.status.demo.label": "Demo", - "license.status.inactive.info": "Lizenz erneuern, um auf neue Major Versionen upzudaten", - "license.status.inactive.label": "Keine neuen Major Versionen", - "license.status.legacy.bubble": "Bereit, die Lizenz zu erneuern? ", - "license.status.legacy.info": "Deine Lizenz deckt diese Version nicht ab", - "license.status.legacy.label": "Bitte erneuere deine Lizenz", - "license.status.missing.bubble": "Bereit, deine Seite zu veröffentlichen?", - "license.status.missing.info": "Keine gültige Lizenz", - "license.status.missing.label": "Bitte aktiviere deine Lizenz", - "license.manage": "Verwalte deine Lizenzen", - "license.purchased": "Gekauft", - "license.success": "Vielen Dank für deine Unterstützung", - "license.unregistered.label": "Unregistriert", - - "link": "Link", - "link.text": "Linktext", - - "loading": "Laden", - - "lock.unsaved": "Ungespeicherte Änderungen", - "lock.unsaved.empty": "Keine ungespeicherten Änderungen", - "lock.isLocked": "Ungespeicherte Änderungen von {email}", - "lock.unlock": "Entsperren", - "lock.unlock.submit": "Entsperre und überschreibe ungespeicherte Änderungen von {email}", - "lock.isUnlocked": "Wurde von einem*r anderen Benutzer*in überschrieben", - - "login": "Anmelden", - "login.code.label.login": "Anmeldecode", - "login.code.label.password-reset": "Anmeldecode", - "login.code.placeholder.email": "000 000", - "login.code.placeholder.totp": "000000", - "login.code.text.email": "Wenn deine E-Mail-Adresse registriert ist, wurde der angeforderte Code per E-Mail versendet.", - "login.code.text.totp": "Bitte gib den Einmal-Code von deiner Authentifizierungs-App ein. ", - "login.email.login.body": "Hallo {user.nameOrEmail},\n\ndu hast gerade einen Anmeldecode für das Kirby Panel von {site} angefordert.\n\nDer folgende Anmeldecode ist für die nächsten {timeout} Minuten gültig:\n\n{code}\n\nWenn du keinen Anmeldecode angefordert hast, ignoriere bitte diese E-Mail oder kontaktiere bei Fragen deinen Administrator.\nBitte leite diese E-Mail aus Sicherheitsgründen NICHT weiter.", - "login.email.login.subject": "Dein Anmeldecode", - "login.email.password-reset.body": "Hallo {user.nameOrEmail},\n\ndu hast gerade einen Anmeldecode für das Kirby Panel von {site} angefordert.\n\nDer folgende Anmeldecode ist für die nächsten {timeout} Minuten gültig:\n\n{code}\n\nWenn du keinen Anmeldecode angefordert hast, ignoriere bitte diese E-Mail oder kontaktiere bei Fragen deinen Administrator.\nBitte leite diese E-Mail aus Sicherheitsgründen NICHT weiter.", - "login.email.password-reset.subject": "Dein Anmeldecode", - "login.remember": "Angemeldet bleiben", - "login.reset": "Passwort zurücksetzen", - "login.toggleText.code.email": "Anmelden über E-Mail", - "login.toggleText.code.email-password": "Anmelden mit Passwort", - "login.toggleText.password-reset.email": "Passwort vergessen?", - "login.toggleText.password-reset.email-password": "← Zurück zur Anmeldung", - "login.totp.enable.option": "Einmal-Codes einrichten", - "login.totp.enable.intro": "Authentifizierungs-Apps können Einmal-Codes erstellen, die als zweiter Faktor für die Anmeldung dienen. ", - "login.totp.enable.qr.label": "1. Scanne diesen QR Code", - "login.totp.enable.qr.help": "Scannen funktioniert nicht? Gib den Setup-Schlüssel {secret} manuell in deiner Authentifizierungs-App ein. ", - "login.totp.enable.confirm.headline": "2. Bestätige den erstellten Code.", - "login.totp.enable.confirm.text": "Deine App erstellt alle 30 Sekunden einen neuen Einmal-Code. Gib den aktuellen Code ein, um das Setup abzuschliessen. ", - "login.totp.enable.confirm.label": "Aktueller Code", - "login.totp.enable.confirm.help": "Nach dem Setup werden wir dich bei jeder Anmeldung nach einem Einmal-Code fragen. ", - "login.totp.enable.success": "Einmal-Codes aktiviert", - "login.totp.disable.option": "Einmal-Codes deaktivieren", - "login.totp.disable.label": "Gib dein Passwort ein, um die Einmal-Codes zu deaktivieren. ", - "login.totp.disable.help": "In Zukunft wird bei der Anmeldung ein anderer zweiter Faktor abgefragt. Z.B. ein Login-Code der per Email zugeschickt wird. Du kannst die Einmal-Codes jeder Zeit später wieder neu einrichten. ", - "login.totp.disable.admin": "

Einmal-Codes für {user} werden hiermit deaktiviert.

In Zukunft wird für die Anmeldung ein anderer zweiter Faktor abgefragt. Z.B. ein Login-Code, der per Email zugeschickt wird. {user} kann nach der nächsten Anmeldung jeder Zeit wieder Einmal-Codes für den Account aktivieren.

", - "login.totp.disable.success": "Einmal-Codes deaktiviert", - - "logout": "Abmelden", - - "merge": "Zusammenfügen", - "menu": "Menü", - "meridiem": "AM/PM", - "mime": "Medientyp", - "minutes": "Minuten", - - "month": "Monat", - "months.april": "April", - "months.august": "August", - "months.december": "Dezember", - "months.february": "Februar", - "months.january": "Januar", - "months.july": "Juli", - "months.june": "Juni", - "months.march": "M\u00e4rz", - "months.may": "Mai", - "months.november": "November", - "months.october": "Oktober", - "months.september": "September", - - "more": "Mehr", - "move": "Bewegen", - "name": "Name", - "next": "Nächster Eintrag", - "night": "Nacht", - "no": "nein", - "off": "aus", - "on": "an", - "open": "Öffnen", - "open.newWindow": "In neuem Fenster öffnen", - "option": "Option", - "options": "Optionen", - "options.none": "Keine Optionen", - "options.all": "Zeige alle {count} Optionen", - - "orientation": "Ausrichtung", - "orientation.landscape": "Querformat", - "orientation.portrait": "Hochformat", - "orientation.square": "Quadratisch", - - "page": "Seite", - "page.blueprint": "Du kannst zusätzliche Felder und Bereiche für diese Seite in /site/blueprints/pages/{blueprint}.yml anlegen", - "page.changeSlug": "URL \u00e4ndern", - "page.changeSlug.fromTitle": "Aus Titel erzeugen", - "page.changeStatus": "Status ändern", - "page.changeStatus.position": "Bitte wähle eine Position aus", - "page.changeStatus.select": "Wähle einen neuen Status aus", - "page.changeTemplate": "Vorlage ändern", - "page.changeTemplate.notice": "Das Ändern der Vorlage wird Inhalte entfernen, deren Feldtypen nicht übereinstimmen. Verwende diese Funktion mit Vorsicht.", - "page.create": "Anlegen als \"{status}\"", - "page.delete.confirm": "Willst du die Seite {title} wirklich löschen?", - "page.delete.confirm.subpages": "Diese Seite hat Unterseiten.
Alle Unterseiten werden ebenfalls gelöscht.", - "page.delete.confirm.title": "Gib zur Bestätigung den Seitentitel ein", - "page.duplicate.appendix": "Kopie", - "page.duplicate.files": "Dateien kopieren", - "page.duplicate.pages": "Seiten kopieren", - "page.move": "Seite bewegen", - "page.sort": "Position ändern", - "page.status": "Status", - "page.status.draft": "Entwurf", - "page.status.draft.description": "Die Seite ist im Entwurfsmodus und ist nur nach Anmeldung oder über den geheimen Link sichtbar", - "page.status.listed": "Öffentlich", - "page.status.listed.description": "Die Seite ist öffentlich für alle", - "page.status.unlisted": "Ungelistet", - "page.status.unlisted.description": "Die Seite kann nur über die URL aufgerufen werden", - - "pages": "Seiten", - "pages.empty": "Keine Seiten", - "pages.status.draft": "Entwürfe", - "pages.status.listed": "Veröffentlicht", - "pages.status.unlisted": "Ungelistet", - - "pagination.page": "Seite", - - "password": "Passwort", - "paste": "Einfügen", - "paste.after": "Danach einfügen", - "paste.success": "{count} eingefügt!", - "pixel": "Pixel", - "plugin": "Plugin", - "plugins": "Plugins", - "prev": "Vorheriger Eintrag", - "preview": "Vorschau", - "remove": "Entfernen", - "rename": "Umbenennen", - "renew": "Erneuern", - "replace": "Ersetzen", - "replace.with": "Ersetzen mit", - "retry": "Wiederholen", - "revert": "Verwerfen", - "revert.confirm": "Willst du wirklich alle ungespeicherten Änderungen verwerfen? ", - - "role": "Rolle", - "role.admin.description": "Admins haben alle Rechte", - "role.admin.title": "Admin", - "role.all": "Alle", - "role.empty": "Keine Accounts mit dieser Rolle", - "role.description.placeholder": "Keine Beschreibung", - "role.nobody.description": "Dies ist die Platzhalterrolle ohne Rechte", - "role.nobody.title": "Niemand", - - "save": "Speichern", - "search": "Suchen", - "search.min": "Gib mindestens {min}  Zeichen ein, um zu suchen", - "search.all": "Zeige alle {count} Ergebnisse", - "search.results.none": "Keine Ergebnisse", - - "section.invalid": "Der Bereich ist ungültig", - "section.required": "Der Bereich ist Pflicht", - - "security": "Sicherheit", - "select": "Auswählen", - "server": "Server", - "settings": "Einstellungen", - "show": "Anzeigen", - "site.blueprint": "Du kannst zusätzliche Felder und Bereiche für die Seite in /site/blueprints/site.yml anlegen", - "size": "Größe", - "slug": "URL-Anhang", - "sort": "Sortieren", - "sort.drag": "Bewegen um zu sortieren …", - "split": "Teilen", - - "stats.empty": "Keine Daten", - "status": "Status", - - "system.info.copy": "Info kopieren", - "system.info.copied": "System Info wurde kopiert", - "system.issues.content": "Der content Ordner scheint öffentlich zugänglich zu sein", - "system.issues.eol.kirby": "Deine Kirby Installation ist veraltet und erhält keine weiteren Sicherheitsupdates", - "system.issues.eol.plugin": "Deine Version des { plugin } Plugins ist veraltet und erhält keine weiteren Sicherheitsupdates", - "system.issues.eol.php": "Deine installierte PHP-Version { release } ist veraltet und erhält keinen Sicherheits-Updates mehr", - "system.issues.debug": "Debugging muss im öffentlichen Betrieb ausgeschaltet sein", - "system.issues.git": "Der .git Ordner scheint öffentlich zugänglich zu sein", - "system.issues.https": "Wir empfehlen HTTPS für alle deine Seiten", - "system.issues.kirby": "Der kirby Ordner scheint öffentlich zugänglich zu sein", - "system.issues.site": "Der site Ordner scheint öffentlich zugänglich zu sein", - "system.issues.vulnerability.kirby": "Deine Installation könnte von folgender Sicherheitslücke betroffen sein ({ severity } severity): { description }", - "system.issues.vulnerability.plugin": "Deine Installation könnte von folgender Sicherheitslücke im { plugin } Plugin betroffen sein ({ severity } severity): { description }", - "system.updateStatus": "Update Status", - "system.updateStatus.error": "Update Check nicht möglich", - "system.updateStatus.not-vulnerable": "Keine bekannten Sicherheitslücken", - "system.updateStatus.security-update": "Kostenloses Sicherheitsupdate { version } verfügbar", - "system.updateStatus.security-upgrade": "Upgrade { version } mit Sicherheitsverbesserungen verfügbar ", - "system.updateStatus.unreleased": "Unveröffentlichte Version", - "system.updateStatus.up-to-date": "Aktuell", - "system.updateStatus.update": "Kostenloses Update { version } verfügbar", - "system.updateStatus.upgrade": "Upgrade { version } verfügbar", - - "tel": "Telefon", - "tel.placeholder": "+49123456789", - "template": "Vorlage", - "title": "Titel", - "today": "Heute", - - "toolbar.button.clear": "Formatierung entfernen", - "toolbar.button.code": "Code", - "toolbar.button.bold": "Fetter Text", - "toolbar.button.email": "E-Mail", - "toolbar.button.headings": "Überschriften", - "toolbar.button.heading.1": "Überschrift 1", - "toolbar.button.heading.2": "Überschrift 2", - "toolbar.button.heading.3": "Überschrift 3", - "toolbar.button.heading.4": "Überschrift 4", - "toolbar.button.heading.5": "Überschrift 5", - "toolbar.button.heading.6": "Überschrift 6", - "toolbar.button.italic": "Kursiver Text", - "toolbar.button.file": "Datei", - "toolbar.button.file.select": "Datei auswählen", - "toolbar.button.file.upload": "Datei hochladen", - "toolbar.button.link": "Link", - "toolbar.button.paragraph": "Absatz", - "toolbar.button.strike": "Durchgestrichen", - "toolbar.button.sub": "Tiefgestellt", - "toolbar.button.sup": "Hochgestellt", - "toolbar.button.ol": "Geordnete Liste", - "toolbar.button.underline": "Unterstrichen", - "toolbar.button.ul": "Ungeordnete Liste", - - "translation.author": "Kirby Team", - "translation.direction": "ltr", - "translation.name": "Deutsch", - "translation.locale": "de_DE", - - "type": "Typ", - - "upload": "Hochladen", - "upload.error.cantMove": "Die Datei konnte nicht an ihren Zielort bewegt werden", - "upload.error.cantWrite": "Die Datei konnte nicht auf der Festplatte gespeichert werden", - "upload.error.default": "Die Datei konnte nicht hochgeladen werden", - "upload.error.extension": "Der Dateiupload wurde durch eine Erweiterung verhindert", - "upload.error.formSize": "Die Datei ist größer als die MAX_FILE_SIZE Einstellung im Formular", - "upload.error.iniPostSize": "Die Datei ist größer als die post_max_size Einstellung in der php.ini", - "upload.error.iniSize": "Die Datei ist größer als die upload_max_filesize Einstellung in der php.ini", - "upload.error.noFile": "Es wurde keine Datei hochgeladen", - "upload.error.noFiles": "Es wurden keine Dateien hochgeladen", - "upload.error.partial": "Die Datei wurde nur teilweise hochgeladen", - "upload.error.tmpDir": "Der temporäre Ordner für den Dateiupload existiert leider nicht", - "upload.errors": "Fehler", - "upload.progress": "Hochladen …", - - "url": "Url", - "url.placeholder": "https://beispiel.de", - - "user": "Account", - "user.blueprint": "Du kannst zusätzliche Felder und Bereiche für diese Rolle in /site/blueprints/users/{blueprint}.yml anlegen", - "user.changeEmail": "E-Mail ändern", - "user.changeLanguage": "Sprache ändern", - "user.changeName": "Account umbenennen", - "user.changePassword": "Passwort ändern", - "user.changePassword.new": "Neues Passwort", - "user.changePassword.new.confirm": "Wiederhole das Passwort …", - "user.changeRole": "Rolle ändern", - "user.changeRole.select": "Neue Rolle auswählen", - "user.create": "Neuen Account anlegen", - "user.delete": "Account löschen", - "user.delete.confirm": "Willst du den Account
{email} wirklich löschen?", - - "users": "Accounts", - - "version": "Version", - "version.current": "Aktuelle Version", - "version.latest": "Neueste Version", - "versionInformation": "Informationen zur Version", - - "view.account": "Dein Account", - "view.installation": "Installation", - "view.languages": "Sprachen", - "view.resetPassword": "Passwort zurücksetzen", - "view.site": "Seite", - "view.system": "System", - "view.users": "Accounts", - - "welcome": "Willkommen", - "year": "Jahr", - "yes": "ja" + "account.changeName": "Deinen Namen ändern", + "account.delete": "Deinen Account löschen", + "account.delete.confirm": "Willst du deinen Account wirklich löschen? Du wirst sofort danach abgemeldet. Dein Account kann nicht wieder hergestellt werden. ", + + "add": "Hinzuf\u00fcgen", + "author": "Autor", + "avatar": "Profilbild", + "back": "Zurück", + "cancel": "Abbrechen", + "change": "\u00c4ndern", + "close": "Schlie\u00dfen", + "confirm": "OK", + "collapse": "Zusammenklappen", + "collapse.all": "Alle zusammenklappen", + "copy": "Kopieren", + "copy.all": "Alle kopieren", + "create": "Erstellen", + + "date": "Datum", + "date.select": "Datum auswählen", + + "day": "Tag", + "days.fri": "Fr", + "days.mon": "Mo", + "days.sat": "Sa", + "days.sun": "So", + "days.thu": "Do", + "days.tue": "Di", + "days.wed": "Mi", + + "debugging": "Debugging", + + "delete": "L\u00f6schen", + "delete.all": "Alle löschen", + + "dialog.files.empty": "Keine verfügbaren Dateien", + "dialog.pages.empty": "Keine verfügbaren Seiten", + "dialog.users.empty": "Keine verfügbaren Accounts", + + "dimensions": "Maße", + "disabled": "Gesperrt", + "discard": "Verwerfen", + "download": "Download", + "duplicate": "Duplizieren", + + "edit": "Bearbeiten", + + "email": "E-Mail", + "email.placeholder": "mail@beispiel.de", + + "entries": "Einträge", + "entry": "Eintrag", + + "environment": "Umgebung", + + "error.access.code": "Ungültiger Code", + "error.access.login": "Ungültige Zugangsdaten", + "error.access.panel": "Du hast keinen Zugang zum Panel", + "error.access.view": "Du hast keinen Zugriff auf diesen Teil des Panels", + + "error.avatar.create.fail": "Das Profilbild konnte nicht hochgeladen werden", + "error.avatar.delete.fail": "Das Profilbild konnte nicht gel\u00f6scht werden", + "error.avatar.dimensions.invalid": "Bitte lade ein Profilbild hoch, das nicht breiter oder höher als 3000 Pixel ist.", + "error.avatar.mime.forbidden": "Das Profilbild muss vom Format JPEG oder PNG sein", + + "error.blueprint.notFound": "Das Blueprint \"{name}\" konnte nicht geladen werden.", + + "error.blocks.max.plural": "Bitte füge nicht mehr als {max} Blöcke hinzu", + "error.blocks.max.singular": "Bitte füge nicht mehr als einen Block hinzu", + "error.blocks.min.plural": "Bitte füge mindestens {min} Blöcke hinzu", + "error.blocks.min.singular": "Bitte füge mindestens einen Block hinzu", + "error.blocks.validation": "Fehler in Block {index}", + + "error.email.preset.notFound": "Die E-Mailvorlage \"{name}\" wurde nicht gefunden", + + "error.field.converter.invalid": "Ungültiger Konverter: \"{converter}\"", + + "error.file.changeName.empty": "Bitte gib einen Namen an", + "error.file.changeName.permission": "Du darfst den Dateinamen von \"{filename}\" nicht ändern", + "error.file.duplicate": "Eine Datei mit dem Dateinamen \"{filename}\" besteht bereits", + "error.file.extension.forbidden": "Verbotene Dateiendung \"{extension}\"", + "error.file.extension.invalid": "Verbotene Dateiendung \"{extension}\"", + "error.file.extension.missing": "Du kannst keine Dateien ohne Dateiendung hochladen", + "error.file.maxheight": "Die Bildhöhe darf {height} Pixel nicht überschreiten", + "error.file.maxsize": "Die Datei ist zu groß", + "error.file.maxwidth": "Die Bildbreite darf {width} Pixel nicht überschreiten", + "error.file.mime.differs": "Die Datei muss den Medientyp \"{mime}\" haben.", + "error.file.mime.forbidden": "Der Medientyp \"{mime}\" ist nicht erlaubt", + "error.file.mime.invalid": "Ungültiger Dateityp: {mime}", + "error.file.mime.missing": "Der Medientyp für \"{filename}\" konnte nicht erkannt werden", + "error.file.minheight": "Die Bildhöhe muss mindestens {height} Pixel betragen", + "error.file.minsize": "Die Datei ist zu klein", + "error.file.minwidth": "Die Bildbreite muss mindestens {width} Pixel betragen", + "error.file.name.missing": "Bitte gib einen Dateinamen an", + "error.file.notFound": "Die Datei \"{filename}\" konnte nicht gefunden werden", + "error.file.orientation": "Das Bildformat ist ungültig. Erwartetes Format: \"{orientation}\"", + "error.file.type.forbidden": "Du kannst keinen {type}-Dateien hochladen", + "error.file.type.invalid": "Ungültiger Dateityp: {mime}", + "error.file.undefined": "Die Datei konnte nicht gefunden werden", + + "error.form.incomplete": "Bitte behebe alle Fehler …", + "error.form.notSaved": "Das Formular konnte nicht gespeichert werden", + + "error.language.code": "Bitte gib einen gültigen Code für die Sprache an", + "error.language.duplicate": "Die Sprache besteht bereits", + "error.language.name": "Bitte gib einen gültigen Namen für die Sprache an", + "error.language.notFound": "Die Sprache konnte nicht gefunden werden", + + "error.layout.validation.block": "Fehler in Block {blockIndex} in Layout {layoutIndex}", + "error.layout.validation.settings": "Fehler in den Einstellungen von Layout {index}", + + "error.license.format": "Bitte gib einen gültigen Lizenzschlüssel ein", + "error.license.email": "Bitte gib eine gültige E-Mailadresse an", + "error.license.verification": "Die Lizenz konnte nicht verifiziert werden", + + "error.offline": "Das Panel ist zur Zeit offline", + + "error.page.changeSlug.permission": "Du darfst die URL der Seite \"{slug}\" nicht ändern", + "error.page.changeStatus.incomplete": "Die Seite ist nicht vollständig und kann daher nicht veröffentlicht werden", + "error.page.changeStatus.permission": "Der Status der Seite kann nicht geändert werden", + "error.page.changeStatus.toDraft.invalid": "Die Seite \"{slug}\" kann nicht in einen Entwurf umgewandelt werden", + "error.page.changeTemplate.invalid": "Die Vorlage für die Seite \"{slug}\" kann nicht geändert werden", + "error.page.changeTemplate.permission": "Du kannst die Vorlage für die Seite \"{slug}\" nicht ändern", + "error.page.changeTitle.empty": "Bitte gib einen Titel an", + "error.page.changeTitle.permission": "Du kannst den Titel für die Seite \"{slug}\" nicht ändern", + "error.page.create.permission": "Du kannst die Seite \"{slug}\" nicht anlegen", + "error.page.delete": "Die Seite \"{slug}\" kann nicht gelöscht werden", + "error.page.delete.confirm": "Bitte gib zur Bestätigung den Seitentitel ein", + "error.page.delete.hasChildren": "Die Seite hat Unterseiten und kann nicht gelöscht werden", + "error.page.delete.permission": "Du kannst die Seite \"{slug}\" nicht löschen", + "error.page.draft.duplicate": "Ein Entwurf mit dem URL-Kürzel \"{slug}\" besteht bereits", + "error.page.duplicate": "Eine Seite mit dem URL-Kürzel \"{slug}\" besteht bereits", + "error.page.duplicate.permission": "Du kannst die Seite \"{slug}\" nicht duplizieren", + "error.page.notFound": "Die Seite \"{slug}\" konnte nicht gefunden werden", + "error.page.num.invalid": "Bitte gib eine gültige Sortierungszahl an. Negative Zahlen sind nicht erlaubt.", + "error.page.slug.invalid": "Bitte gib ein gültiges URL-Kürzel an", + "error.page.slug.maxlength": "Die Pfadlänge darf {length} Zeichen nicht überschreiten", + "error.page.sort.permission": "Die Seite \"{slug}\" kann nicht umsortiert werden", + "error.page.status.invalid": "Bitte gib einen gültigen Seitenstatus an", + "error.page.undefined": "Die Seite konnte nicht gefunden werden", + "error.page.update.permission": "Du kannst die Seite \"{slug}\" nicht editieren", + + "error.section.files.max.plural": "Bitte füge nicht mehr als {max} Dateien zum Bereich \"{section}\" hinzu", + "error.section.files.max.singular": "Bitte füge nicht mehr als eine Datei zum Bereich \"{section}\" hinzu", + "error.section.files.min.plural": "Der Bereich \"{section}\" benötigt mindestens {min} Dateien", + "error.section.files.min.singular": "Der Bereich \"{section}\" benötigt mindestens eine Datei", + + "error.section.pages.max.plural": "Bitte füge nicht mehr als {max} Seiten zum Bereich \"{section}\" hinzu", + "error.section.pages.max.singular": "Bitte füge nicht mehr als eine Seite zum Bereich \"{section}\" hinzu", + "error.section.pages.min.plural": "Der Bereich \"{section}\" benötigt mindestens {min} Seiten", + "error.section.pages.min.singular": "Der Bereich \"{section}\" benötigt mindestens eine Seite", + + "error.section.notLoaded": "Der Bereich \"{name}\" konnte nicht geladen werden", + "error.section.type.invalid": "Der Bereichstyp \"{type}\" ist nicht gültig", + + "error.site.changeTitle.empty": "Bitte gib einen Titel an", + "error.site.changeTitle.permission": "Du kannst den Titel der Seite nicht ändern", + "error.site.update.permission": "Du darfst die Seite nicht bearbeiten", + + "error.template.default.notFound": "Die \"Default\"-Vorlage existiert nicht", + + "error.unexpected": "Ein unerwarteter Fehler ist aufgetreten. Aktiviere den Debug Modus für weitere Informationen: https://getkirby.com/docs/reference/system/options/debug", + + "error.user.changeEmail.permission": "Du kannst die E-Mailadresse für den Account \"{name}\" nicht ändern", + "error.user.changeLanguage.permission": "Du kannst die Sprache für den Account \"{name}\" nicht ändern", + "error.user.changeName.permission": "Du kannst den Namen für den Account \"{name}\" nicht ändern", + "error.user.changePassword.permission": "Du kannst das Passwort für den Account \"{name}\" nicht ändern", + "error.user.changeRole.lastAdmin": "Die Rolle des letzten Accounts mit Administrationsrechten kann nicht geändert werden", + "error.user.changeRole.permission": "Du kannst die Rolle für den Benutzer \"{name}\" nicht ändern", + "error.user.changeRole.toAdmin": "Du darfst die Admin-Rolle nicht an andere Accounts vergeben", + "error.user.create.permission": "Du darfst diesen Account nicht anlegen", + "error.user.delete": "Der Account \"{name}\" konnte nicht gelöscht werden", + "error.user.delete.lastAdmin": "Du kannst den letzten Account mit Administrationsrechten nicht löschen", + "error.user.delete.lastUser": "Der letzte Account kann nicht gelöscht werden", + "error.user.delete.permission": "Du darfst den Account \"{name}\" nicht löschen", + "error.user.duplicate": "Ein Account mit der E-Mailadresse \"{email}\" besteht bereits", + "error.user.email.invalid": "Bitte gib eine gültige E-Mailadresse an", + "error.user.language.invalid": "Bitte gib eine gültige Sprache an", + "error.user.notFound": "Der Account \"{name}\" wurde nicht gefunden", + "error.user.password.excessive": "Please enter a valid password. Passwords must not be longer than 1000 characters.", + "error.user.password.invalid": "Bitte gib ein gültiges Passwort ein. Passwörter müssen mindestens 8 Zeichen lang sein.", + "error.user.password.notSame": "Die Passwörter stimmen nicht überein", + "error.user.password.undefined": "Der Account hat kein Passwort", + "error.user.password.wrong": "Falsches Passwort", + "error.user.role.invalid": "Bitte gib eine gültige Rolle an", + "error.user.undefined": "Der Benutzer wurde nicht gefunden", + "error.user.update.permission": "Du darfst den den Account \"{name}\" nicht bearbeiten", + + "error.validation.accepted": "Bitte bestätige", + "error.validation.alpha": "Bitte gib nur Zeichen zwischen A und Z ein", + "error.validation.alphanum": "Bitte gib nur Zeichen zwischen A und Z und Zahlen zwischen 0 und 9 ein", + "error.validation.between": "Bitte gib einen Wert zwischen \"{min}\" und \"{max}\" ein", + "error.validation.boolean": "Bitte bestätige oder lehne ab", + "error.validation.contains": "Bitte gib einen Wert ein, der \"{needle}\" enthält", + "error.validation.date": "Bitte gib ein gültiges Datum ein", + "error.validation.date.after": "Bitte gib ein Datum nach dem {date} ein", + "error.validation.date.before": "Bitte gib ein Datum vor dem {date} ein", + "error.validation.date.between": "Bitte gib ein Datum zwischen dem {min} und dem {max} ein", + "error.validation.denied": "Bitte lehne die Eingabe ab", + "error.validation.different": "Der Wert darf nicht \"{other}\" sein", + "error.validation.email": "Bitte gib eine gültige E-Mailadresse an", + "error.validation.endswith": "Der Wert muss auf \"{end}\" enden", + "error.validation.filename": "Bitte gib einen gültigen Dateinamen ein", + "error.validation.in": "Bitte gib einen der folgenden Werte ein: ({in})", + "error.validation.integer": "Bitte gib eine ganze Zahl ein", + "error.validation.ip": "Bitte gib eine gültige IP Adresse ein", + "error.validation.less": "Bitte gib einen Wert kleiner als {max} ein", + "error.validation.match": "Der Wert entspricht nicht dem erwarteten Muster", + "error.validation.max": "Bitte gib einen Wert ein, der nicht größer als {max} ist", + "error.validation.maxlength": "Bitte gib einen kürzeren Text ein (max. {max} Zeichen)", + "error.validation.maxwords": "Bitte nutze nicht mehr als {max} Wort(e)", + "error.validation.min": "Bitte gib einen Wert ein, der nicht kleiner als {min} ist", + "error.validation.minlength": "Bitte gib einen längeren Text ein. (min. {min} Zeichen)", + "error.validation.minwords": "Bitte nutze mindestens {min} Wort(e)", + "error.validation.more": "Bitte gib einen größeren Wert als {min} ein", + "error.validation.notcontains": "Bitte gib einen Wert ein, der nicht \"{needle}\" enthält", + "error.validation.notin": "Bitte gib keinen der folgenden Werte ein: ({notIn})", + "error.validation.option": "Bitte wähle eine gültige Option aus", + "error.validation.num": "Bitte gib eine gültige Zahl an", + "error.validation.required": "Bitte gib etwas ein", + "error.validation.same": "Bitte gib \"{other}\" ein", + "error.validation.size": "Die Größe des Wertes muss \"{size}\" sein", + "error.validation.startswith": "Der Wert muss mit \"{start}\" beginnen", + "error.validation.time": "Bitte gib eine gültige Uhrzeit ein", + "error.validation.time.after": "Bitte gib eine Zeit nach {time} ein", + "error.validation.time.before": "Bitte gib eine Zeit vor {time} ein", + "error.validation.time.between": "Bitte gib eine Zeit zwischen {min} und {max} ein", + "error.validation.url": "Bitte gib eine gültige URL ein", + + "expand": "Aufklappen", + "expand.all": "Alle aufklappen", + + "field.required": "Das Feld ist Pflicht", + "field.blocks.changeType": "Blocktyp ändern", + "field.blocks.code.name": "Code", + "field.blocks.code.language": "Sprache", + "field.blocks.code.placeholder": "Code …", + "field.blocks.delete.confirm": "Willst du diesen Block wirklich löschen?", + "field.blocks.delete.confirm.all": "Willst du wirklich alle Blöcke löschen?", + "field.blocks.delete.confirm.selected": "Willst du wirklich die ausgewählten Blöcke löschen?", + "field.blocks.empty": "Keine Blöcke", + "field.blocks.fieldsets.label": "Bitte wähle einen Blocktyp aus …", + "field.blocks.fieldsets.paste": "Drücke {{ shortcut }} um Blöcke aus der Zwischenablage zu importieren", + "field.blocks.gallery.name": "Galerie", + "field.blocks.gallery.images.empty": "Keine Bilder", + "field.blocks.gallery.images.label": "Bilder", + "field.blocks.heading.level": "Ebene", + "field.blocks.heading.name": "Überschrift", + "field.blocks.heading.text": "Text", + "field.blocks.heading.placeholder": "Überschrift …", + "field.blocks.image.alt": "Alternativer Text", + "field.blocks.image.caption": "Bildunterschrift", + "field.blocks.image.crop": "Beschneiden", + "field.blocks.image.link": "Link", + "field.blocks.image.location": "Ort", + "field.blocks.image.name": "Bild", + "field.blocks.image.placeholder": "Bild auswählen", + "field.blocks.image.ratio": "Seitenverhältnis", + "field.blocks.image.url": "Bild URL", + "field.blocks.line.name": "Linie", + "field.blocks.list.name": "Liste", + "field.blocks.markdown.name": "Markdown", + "field.blocks.markdown.label": "Text", + "field.blocks.markdown.placeholder": "Markdown …", + "field.blocks.quote.name": "Zitat", + "field.blocks.quote.text.label": "Text", + "field.blocks.quote.text.placeholder": "Zitat …", + "field.blocks.quote.citation.label": "Quelle", + "field.blocks.quote.citation.placeholder": "Quelle …", + "field.blocks.text.name": "Text", + "field.blocks.text.placeholder": "Text …", + "field.blocks.video.caption": "Bildunterschrift", + "field.blocks.video.name": "Video", + "field.blocks.video.placeholder": "Video-URL eingeben", + "field.blocks.video.url.label": "Video-URL", + "field.blocks.video.url.placeholder": "https://youtube.com/?v=", + + "field.files.empty": "Keine Dateien ausgewählt", + + "field.layout.delete": "Layout löschen", + "field.layout.delete.confirm": "Willst du dieses Layout wirklich löschen?", + "field.layout.empty": "Keine Layouts", + "field.layout.select": "Layout auswählen", + + "field.pages.empty": "Keine Seiten ausgewählt", + "field.structure.delete.confirm": "Willst du diesen Eintrag wirklich l\u00f6schen?", + "field.structure.empty": "Es bestehen keine Eintr\u00e4ge.", + "field.users.empty": "Keine Accounts ausgewählt", + + "file.blueprint": "Du kannst zusätzliche Felder und Bereiche für diese Datei in /site/blueprints/files/{blueprint}.yml anlegen", + "file.delete.confirm": "Willst du die Datei {filename}
wirklich löschen?", + "file.sort": "Position ändern", + + "files": "Dateien", + "files.empty": "Keine Dateien", + + "hide": "Verbergen", + "hour": "Stunde", + "import": "Importieren", + "info": "Info", + "insert": "Einf\u00fcgen", + "insert.after": "Danach einfügen", + "insert.before": "Davor einfügen", + "install": "Installieren", + + "installation": "Installation", + "installation.completed": "Das Panel wurde installiert", + "installation.disabled": "Die Panel-Installation ist auf öffentlichen Servern automatisch deaktiviert. Bitte installiere das Panel auf einem lokalen Server oder aktiviere die Installation gezielt mit der panel.install Option. ", + "installation.issues.accounts": "/site/accounts ist nicht beschreibbar", + "installation.issues.content": "/content existiert nicht oder ist nicht beschreibbar", + "installation.issues.curl": "Die CURL Erweiterung wird benötigt", + "installation.issues.headline": "Das Panel kann nicht installiert werden", + "installation.issues.mbstring": "Die MB String Erweiterung wird benötigt", + "installation.issues.media": "Der /media Ordner ist nicht beschreibbar", + "installation.issues.php": "Bitte verwende PHP 7+", + "installation.issues.server": "Kirby benötigt Apache, Nginx or Caddy", + "installation.issues.sessions": "/site/sessions ist nicht beschreibbar", + + "language": "Sprache", + "language.code": "Code", + "language.convert": "Als Standard auswählen", + "language.convert.confirm": "

Willst du {name} wirklich in die Standardsprache umwandeln? Dieser Schritt kann nicht rückgängig gemacht werden.

Wenn {name} unübersetzte Felder hat, gibt es keine gültigen Standardwerte für diese Felder und Inhalte könnten verloren gehen.

", + "language.create": "Neue Sprache anlegen", + "language.delete.confirm": "Willst du {name} inklusive aller Übersetzungen wirklich löschen? Dieser Schritt kann nicht rückgängig gemacht werden!", + "language.deleted": "Die Sprache wurde gelöscht", + "language.direction": "Leserichtung", + "language.direction.ltr": "Von links nach rechts", + "language.direction.rtl": "Von rechts nach links", + "language.locale": "PHP locale string", + "language.locale.warning": "Du nutzt ein angepasstes Setup for PHP Locales. Bitte bearbeite dieses direkt in der entsprechenden Sprachdatei in /site/languages", + "language.name": "Name", + "language.updated": "Die Sprache wurde gespeichert", + + "languages": "Sprachen", + "languages.default": "Standardsprache", + "languages.empty": "Noch keine Sprachen", + "languages.secondary": "Sekundäre Sprachen", + "languages.secondary.empty": "Noch keine sekundären Sprachen", + + "license": "Lizenz", + "license.buy": "Kaufe eine Lizenz", + "license.register": "Registrieren", + "license.manage": "Verwalte deine Lizenzen", + "license.register.help": "Den Lizenzcode findest du in der Bestätigungsmail zu deinem Kauf. Bitte kopiere und füge ihn ein, um Kirby zu registrieren.", + "license.register.label": "Bitte gib deinen Lizenzcode ein", + "license.register.success": "Vielen Dank für deine Unterstützung", + "license.unregistered": "Dies ist eine unregistrierte Kirby-Demo", + "license.unregistered.label": "Unregistriert", + + "link": "Link", + "link.text": "Linktext", + + "loading": "Laden", + + "lock.unsaved": "Ungespeicherte Änderungen", + "lock.unsaved.empty": "Keine ungespeicherten Änderungen", + "lock.isLocked": "Ungespeicherte Änderungen von {email}", + "lock.file.isLocked": "Die Datei wird von {email} bearbeitet und kann nicht geändert werden.", + "lock.page.isLocked": "Die Seite wird von {email} bearbeitet und kann nicht geändert werden.", + "lock.unlock": "Entsperren", + "lock.isUnlocked": "Deine ungespeicherten Änderungen wurden von einem anderen Account überschrieben. Du kannst sie herunterladen, um sie manuell einzufügen. ", + + "login": "Anmelden", + "login.code.label.login": "Anmeldecode", + "login.code.label.password-reset": "Anmeldecode", + "login.code.placeholder.email": "000 000", + "login.code.text.email": "Wenn deine E-Mail-Adresse registriert ist, wurde der angeforderte Code per E-Mail versendet.", + "login.email.login.body": "Hallo {user.nameOrEmail},\n\ndu hast gerade einen Anmeldecode für das Kirby Panel von {site} angefordert.\n\nDer folgende Anmeldecode ist für die nächsten {timeout} Minuten gültig:\n\n{code}\n\nWenn du keinen Anmeldecode angefordert hast, ignoriere bitte diese E-Mail oder kontaktiere bei Fragen deinen Administrator.\nBitte leite diese E-Mail aus Sicherheitsgründen NICHT weiter.", + "login.email.login.subject": "Dein Anmeldecode", + "login.email.password-reset.body": "Hallo {user.nameOrEmail},\n\ndu hast gerade einen Anmeldecode für das Kirby Panel von {site} angefordert.\n\nDer folgende Anmeldecode ist für die nächsten {timeout} Minuten gültig:\n\n{code}\n\nWenn du keinen Anmeldecode angefordert hast, ignoriere bitte diese E-Mail oder kontaktiere bei Fragen deinen Administrator.\nBitte leite diese E-Mail aus Sicherheitsgründen NICHT weiter.", + "login.email.password-reset.subject": "Dein Anmeldecode", + "login.remember": "Angemeldet bleiben", + "login.reset": "Passwort zurücksetzen", + "login.toggleText.code.email": "Anmelden über E-Mail", + "login.toggleText.code.email-password": "Anmelden mit Passwort", + "login.toggleText.password-reset.email": "Passwort vergessen?", + "login.toggleText.password-reset.email-password": "← Zurück zur Anmeldung", + + "logout": "Abmelden", + + "menu": "Menü", + "meridiem": "AM/PM", + "mime": "Medientyp", + "minutes": "Minuten", + + "month": "Monat", + "months.april": "April", + "months.august": "August", + "months.december": "Dezember", + "months.february": "Februar", + "months.january": "Januar", + "months.july": "Juli", + "months.june": "Juni", + "months.march": "M\u00e4rz", + "months.may": "Mai", + "months.november": "November", + "months.october": "Oktober", + "months.september": "September", + + "more": "Mehr", + "name": "Name", + "next": "Nächster Eintrag", + "no": "nein", + "off": "aus", + "on": "an", + "open": "Öffnen", + "open.newWindow": "In neuem Fenster öffnen", + "options": "Optionen", + "options.none": "Keine Optionen", + + "orientation": "Ausrichtung", + "orientation.landscape": "Querformat", + "orientation.portrait": "Hochformat", + "orientation.square": "Quadratisch", + + "page.blueprint": "Du kannst zusätzliche Felder und Bereiche für diese Seite in /site/blueprints/pages/{blueprint}.yml anlegen", + "page.changeSlug": "URL \u00e4ndern", + "page.changeSlug.fromTitle": "Aus Titel erzeugen", + "page.changeStatus": "Status ändern", + "page.changeStatus.position": "Bitte wähle eine Position aus", + "page.changeStatus.select": "Wähle einen neuen Status aus", + "page.changeTemplate": "Vorlage ändern", + "page.delete.confirm": "Willst du die Seite {title} wirklich löschen?", + "page.delete.confirm.subpages": "Diese Seite hat Unterseiten.
Alle Unterseiten werden ebenfalls gelöscht.", + "page.delete.confirm.title": "Gib zur Bestätigung den Seitentitel ein", + "page.draft.create": "Entwurf anlegen", + "page.duplicate.appendix": "Kopie", + "page.duplicate.files": "Dateien kopieren", + "page.duplicate.pages": "Seiten kopieren", + "page.sort": "Position ändern", + "page.status": "Status", + "page.status.draft": "Entwurf", + "page.status.draft.description": "Die Seite ist im Entwurfsmodus und ist nur nach Anmeldung oder über den geheimen Link sichtbar", + "page.status.listed": "Öffentlich", + "page.status.listed.description": "Die Seite ist öffentlich für alle", + "page.status.unlisted": "Ungelistet", + "page.status.unlisted.description": "Die Seite kann nur über die URL aufgerufen werden", + + "pages": "Seiten", + "pages.empty": "Keine Seiten", + "pages.status.draft": "Entwürfe", + "pages.status.listed": "Veröffentlicht", + "pages.status.unlisted": "Ungelistet", + + "pagination.page": "Seite", + + "password": "Passwort", + "paste": "Einfügen", + "paste.after": "Danach einfügen", + "pixel": "Pixel", + "plugins": "Plugins", + "prev": "Vorheriger Eintrag", + "preview": "Vorschau", + "remove": "Entfernen", + "rename": "Umbenennen", + "replace": "Ersetzen", + "retry": "Wiederholen", + "revert": "Verwerfen", + "revert.confirm": "Willst du wirklich alle ungespeicherten Änderungen verwerfen? ", + + "role": "Rolle", + "role.admin.description": "Admins haben alle Rechte", + "role.admin.title": "Admin", + "role.all": "Alle", + "role.empty": "Keine Accounts mit dieser Rolle", + "role.description.placeholder": "Keine Beschreibung", + "role.nobody.description": "Dies ist die Platzhalterrolle ohne Rechte", + "role.nobody.title": "Niemand", + + "save": "Speichern", + "search": "Suchen", + "search.min": "Gib mindestens {min}  Zeichen ein, um zu suchen", + "search.all": "Alles zeigen", + "search.results.none": "Keine Ergebnisse", + + "section.required": "Der Bereich ist Pflicht", + + "security": "Sicherheit", + "select": "Auswählen", + "server": "Server", + "settings": "Einstellungen", + "show": "Anzeigen", + "site.blueprint": "Du kannst zusätzliche Felder und Bereiche für die Seite in /site/blueprints/site.yml anlegen", + "size": "Größe", + "slug": "URL-Anhang", + "sort": "Sortieren", + + "stats.empty": "Keine Daten", + "system.issues.content": "Der content Ordner scheint öffentlich zugänglich zu sein", + "system.issues.debug": "Debugging muss im öffentlichen Betrieb ausgeschaltet sein", + "system.issues.git": "Der .git Ordner scheint öffentlich zugänglich zu sein", + "system.issues.https": "Wir empfehlen HTTPS für alle deine Seiten", + "system.issues.kirby": "Der kirby Ordner scheint öffentlich zugänglich zu sein", + "system.issues.site": "Der site Ordner scheint öffentlich zugänglich zu sein", + + "title": "Titel", + "template": "Vorlage", + "today": "Heute", + + "toolbar.button.code": "Code", + "toolbar.button.bold": "Fetter Text", + "toolbar.button.email": "E-Mail", + "toolbar.button.headings": "Überschriften", + "toolbar.button.heading.1": "Überschrift 1", + "toolbar.button.heading.2": "Überschrift 2", + "toolbar.button.heading.3": "Überschrift 3", + "toolbar.button.heading.4": "Überschrift 4", + "toolbar.button.heading.5": "Überschrift 5", + "toolbar.button.heading.6": "Überschrift 6", + "toolbar.button.italic": "Kursiver Text", + "toolbar.button.file": "Datei", + "toolbar.button.file.select": "Datei auswählen", + "toolbar.button.file.upload": "Datei hochladen", + "toolbar.button.link": "Link", + "toolbar.button.paragraph": "Absatz", + "toolbar.button.strike": "Durchgestrichen", + "toolbar.button.ol": "Geordnete Liste", + "toolbar.button.underline": "Unterstrichen", + "toolbar.button.ul": "Ungeordnete Liste", + + "translation.author": "Kirby Team", + "translation.direction": "ltr", + "translation.name": "Deutsch", + "translation.locale": "de_DE", + + "upload": "Hochladen", + "upload.error.cantMove": "Die Datei konnte nicht an ihren Zielort bewegt werden", + "upload.error.cantWrite": "Die Datei konnte nicht auf der Festplatte gespeichert werden", + "upload.error.default": "Die Datei konnte nicht hochgeladen werden", + "upload.error.extension": "Der Dateiupload wurde durch eine Erweiterung verhindert", + "upload.error.formSize": "Die Datei ist größer als die MAX_FILE_SIZE Einstellung im Formular", + "upload.error.iniPostSize": "Die Datei ist größer als die post_max_size Einstellung in der php.ini", + "upload.error.iniSize": "Die Datei ist größer als die upload_max_filesize Einstellung in der php.ini", + "upload.error.noFile": "Es wurde keine Datei hochgeladen", + "upload.error.noFiles": "Es wurden keine Dateien hochgeladen", + "upload.error.partial": "Die Datei wurde nur teilweise hochgeladen", + "upload.error.tmpDir": "Der temporäre Ordner für den Dateiupload existiert leider nicht", + "upload.errors": "Fehler", + "upload.progress": "Hochladen …", + + "url": "Url", + "url.placeholder": "https://beispiel.de", + + "user": "Account", + "user.blueprint": "Du kannst zusätzliche Felder und Bereiche für diese Rolle in /site/blueprints/users/{blueprint}.yml anlegen", + "user.changeEmail": "E-Mail ändern", + "user.changeLanguage": "Sprache ändern", + "user.changeName": "Account umbenennen", + "user.changePassword": "Passwort ändern", + "user.changePassword.new": "Neues Passwort", + "user.changePassword.new.confirm": "Wiederhole das Passwort …", + "user.changeRole": "Rolle ändern", + "user.changeRole.select": "Neue Rolle auswählen", + "user.create": "Neuen Account anlegen", + "user.delete": "Account löschen", + "user.delete.confirm": "Willst du den Account
{email} wirklich löschen?", + + "users": "Accounts", + + "version": "Version", + + "view.account": "Dein Account", + "view.installation": "Installation", + "view.languages": "Sprachen", + "view.resetPassword": "Passwort zurücksetzen", + "view.site": "Seite", + "view.system": "System", + "view.users": "Accounts", + + "welcome": "Willkommen", + "year": "Jahr", + "yes": "ja" } diff --git a/kirby/i18n/translations/el.json b/kirby/i18n/translations/el.json index 56709da..77dd35b 100644 --- a/kirby/i18n/translations/el.json +++ b/kirby/i18n/translations/el.json @@ -1,730 +1,574 @@ { - "account.changeName": "Change your name", - "account.delete": "Delete your account", - "account.delete.confirm": "Do you really want to delete your account? You will be logged out immediately. Your account cannot be recovered.", - - "activate": "Activate", - "add": "\u03a0\u03c1\u03bf\u03c3\u03b8\u03ae\u03ba\u03b7", - "alpha": "Alpha", - "author": "Author", - "avatar": "\u0395\u03b9\u03ba\u03cc\u03bd\u03b1 \u03c0\u03c1\u03bf\u03c6\u03af\u03bb", - "back": "Πίσω", - "cancel": "\u0391\u03ba\u03cd\u03c1\u03c9\u03c3\u03b7", - "change": "\u0391\u03bb\u03bb\u03b1\u03b3\u03ae", - "close": "\u039a\u03bb\u03b5\u03af\u03c3\u03b9\u03bc\u03bf", - "changes": "Changes", - "confirm": "Εντάξει", - "collapse": "Collapse", - "collapse.all": "Collapse All", - "color": "Color", - "coordinates": "Coordinates", - "copy": "Αντιγραφή", - "copy.all": "Copy all", - "copy.success": "{count} copied!", - "create": "Δημιουργία", - "custom": "Custom", - - "date": "Ημερομηνία", - "date.select": "Επιλογή ημερομηνίας", - - "day": "Ημέρα", - "days.fri": "\u03a0\u03b1\u03c1", - "days.mon": "\u0394\u03b5\u03c5", - "days.sat": "\u03a3\u03ac\u03b2", - "days.sun": "\u039a\u03c5\u03c1", - "days.thu": "\u03a0\u03ad\u03bc", - "days.tue": "\u03a4\u03c1\u03af", - "days.wed": "\u03a4\u03b5\u03c4", - - "debugging": "Debugging", - - "delete": "\u0394\u03b9\u03b1\u03b3\u03c1\u03b1\u03c6\u03ae", - "delete.all": "Delete all", - - "dialog.fields.empty": "This dialog has no fields", - "dialog.files.empty": "No files to select", - "dialog.pages.empty": "No pages to select", - "dialog.text.empty": "This dialog does not define any text", - "dialog.users.empty": "No users to select", - - "dimensions": "Διαστάσεις", - "disable": "Disable", - "disabled": "Disabled", - "discard": "Απόρριψη", - - "drawer.fields.empty": "This drawer has no fields", - - "domain": "Domain", - "download": "Λήψη", - "duplicate": "Αντίγραφο", - - "edit": "\u0395\u03c0\u03b5\u03be\u03b5\u03c1\u03b3\u03b1\u03c3\u03af\u03b1", - - "email": "Διεύθυνση ηλεκτρονικού ταχυδρομείου", - "email.placeholder": "mail@example.com", - - "enter": "Enter", - "entries": "Entries", - "entry": "Entry", - - "environment": "Environment", - - "error": "Error", - "error.access.code": "Mη έγκυρος κωδικός", - "error.access.login": "Mη έγκυρη σύνδεση", - "error.access.panel": "Δεν επιτρέπεται η πρόσβαση στον πίνακα ελέγχου", - "error.access.view": "Δεν επιτρέπεται η πρόσβαση σε αυτό το τμήμα του πίνακα ελέγχου", - - "error.avatar.create.fail": "Δεν ήταν δυνατή η μεταφόρτωση της εικόνας προφίλ", - "error.avatar.delete.fail": "Δεν ήταν δυνατή η διαγραφή της εικόνας προφίλ", - "error.avatar.dimensions.invalid": "Διατηρήστε το πλάτος και το ύψος της εικόνας προφίλ κάτω από 3000 εικονοστοιχεία", - "error.avatar.mime.forbidden": "\u039c\u03b7 \u03b1\u03c0\u03bf\u03b4\u03b5\u03ba\u03c4\u03cc\u03c2 \u03c4\u03cd\u03c0\u03bf\u03c2 \u03b1\u03c1\u03c7\u03b5\u03af\u03bf\u03c5", - - "error.blueprint.notFound": "Δεν ήταν δυνατή η φόρτωση του προσχεδίου \"{name}\"", - - "error.blocks.max.plural": "You must not add more than {max} blocks", - "error.blocks.max.singular": "You must not add more than one block", - "error.blocks.min.plural": "You must add at least {min} blocks", - "error.blocks.min.singular": "You must add at least one block", - "error.blocks.validation": "There's an error on the \"{field}\" field in block {index} using the \"{fieldset}\" block type", - - "error.cache.type.invalid": "Invalid cache type \"{type}\"", - - "error.email.preset.notFound": "Δεν είναι δυνατή η εύρεση της προεπιλογής διεύθινσης ηλεκτρονικού ταχυδρομείου \"{name}\"", - - "error.field.converter.invalid": "Μη έγκυρος μετατροπέας \"{converter}\"", - "error.field.type.missing": "Field \"{ name }\": The field type \"{ type }\" does not exist", - - "error.file.changeName.empty": "The name must not be empty", - "error.file.changeName.permission": "Δεν επιτρέπεται να αλλάξετε το όνομα του \"{filename}\"", - "error.file.changeTemplate.invalid": "The template for the file \"{id}\" cannot be changed to \"{template}\" (valid: \"{blueprints}\")", - "error.file.changeTemplate.permission": "You are not allowed to change the template for the file \"{id}\"", - - "error.file.duplicate": "Ένα αρχείο με το όνομα \"{filename}\" υπάρχει ήδη", - "error.file.extension.forbidden": "\u039c\u03b7 \u03b1\u03c0\u03bf\u03b4\u03b5\u03ba\u03c4\u03ae \u03b5\u03c0\u03ad\u03ba\u03c4\u03b1\u03c3\u03b7 \u03b1\u03c1\u03c7\u03b5\u03af\u03bf\u03c5", - "error.file.extension.invalid": "Invalid extension: {extension}", - "error.file.extension.missing": "Λείπει η επέκταση για το \"{filename}\"", - "error.file.maxheight": "The height of the image must not exceed {height} pixels", - "error.file.maxsize": "The file is too large", - "error.file.maxwidth": "The width of the image must not exceed {width} pixels", - "error.file.mime.differs": "Το αρχείο πρέπει να είναι του ίδιου τύπου mime \"{mime}\"", - "error.file.mime.forbidden": "Ο τύπος μέσου \"{mime}\" δεν επιτρέπεται", - "error.file.mime.invalid": "Invalid mime type: {mime}", - "error.file.mime.missing": "Δεν είναι δυνατό να εντοπιστεί ο τύπος μέσου για το \"{filename}\"", - "error.file.minheight": "The height of the image must be at least {height} pixels", - "error.file.minsize": "The file is too small", - "error.file.minwidth": "The width of the image must be at least {width} pixels", - "error.file.name.unique": "The filename must be unique", - "error.file.name.missing": "Το όνομα αρχείου δεν μπορεί να είναι άδειο", - "error.file.notFound": "Δεν είναι δυνατό να βρεθεί το αρχείο \"{filename}\"", - "error.file.orientation": "The orientation of the image must be \"{orientation}\"", - "error.file.type.forbidden": "Δεν επιτρέπεται η μεταφόρτωση αρχείων {type}", - "error.file.type.invalid": "Invalid file type: {type}", - "error.file.undefined": "Δεν ήταν δυνατή η εύρεση του αρχείου", - - "error.form.incomplete": "Παρακαλώ διορθώστε τα σφάλματα στη φόρμα...", - "error.form.notSaved": "Δεν ήταν δυνατή η αποθήκευση της φόρμας", - - "error.language.code": "Please enter a valid code for the language", - "error.language.duplicate": "The language already exists", - "error.language.name": "Please enter a valid name for the language", - "error.language.notFound": "The language could not be found", - - "error.layout.validation.block": "There's an error on the \"{field}\" field in block {blockIndex} using the \"{fieldset}\" block type in layout {layoutIndex}", - "error.layout.validation.settings": "There's an error in layout {index} settings", - - "error.license.domain": "The domain for the license is missing", - "error.license.email": "Παρακαλώ εισάγετε μια έγκυρη διεύθυνση ηλεκτρονικού ταχυδρομείου", - "error.license.format": "Please enter a valid license code", - "error.license.verification": "The license could not be verified", - - "error.login.totp.confirm.invalid": "Mη έγκυρος κωδικός", - "error.login.totp.confirm.missing": "Please enter the current code", - - "error.object.validation": "There’s an error in the \"{label}\" field:\n{message}", - - "error.offline": "The Panel is currently offline", - - "error.page.changeSlug.permission": "Δεν επιτρέπεται να αλλάξετε το URL της σελίδας \"{slug}\"", - "error.page.changeSlug.reserved": "The path of top-level pages must not start with \"{path}\"", - "error.page.changeStatus.incomplete": "Δεν ήταν δυνατή η δημοσίευση της σελίδας καθώς περιέχει σφάλματα", - "error.page.changeStatus.permission": "Δεν είναι δυνατή η αλλαγή κατάστασης για αυτή τη σελίδα", - "error.page.changeStatus.toDraft.invalid": "Δεν είναι δυνατή η μετατροπή της σελίδας \"{slug}\" σε προσχέδιο", - "error.page.changeTemplate.invalid": "Δεν είναι δυνατή η αλλαγή προτύπου για τη σελίδα \"{slug}\"", - "error.page.changeTemplate.permission": "Δεν επιτρέπεται να αλλάξετε το πρότυπο για τη σελίδα \"{slug}\"", - "error.page.changeTitle.empty": "Ο τίτλος δεν μπορεί να είναι κενός", - "error.page.changeTitle.permission": "Δεν επιτρέπεται να αλλάξετε τον τίτλο για τη σελίδα \"{slug}\"", - "error.page.create.permission": "Δεν επιτρέπεται να δημιουργήσετε τη σελίδα \"{slug}\"", - "error.page.delete": "Δεν είναι δυνατή η διαγραφή της σελίδας \"{slug}\"", - "error.page.delete.confirm": "Παρακαλώ εισάγετε τον τίτλο της σελίδας για επιβεβαίωση", - "error.page.delete.hasChildren": "Δεν είναι δυνατή η διαγραφή της σελίδας καθώς περιέχει υποσελίδες", - "error.page.delete.permission": "Δεν επιτρέπεται η διαγραφή της σελίδας \"{slug}\"", - "error.page.draft.duplicate": "Υπάρχει ήδη ένα προσχέδιο σελίδας με την διεύθυνση URL \"{slug}\"", - "error.page.duplicate": "Υπάρχει ήδη μια σελίδα με την διεύθυνση URL \"{slug}\"", - "error.page.duplicate.permission": "You are not allowed to duplicate \"{slug}\"", - "error.page.move.ancestor": "The page cannot be moved into itself", - "error.page.move.directory": "The page directory cannot be moved", - "error.page.move.duplicate": "A sub page with the URL appendix \"{slug}\" already exists", - "error.page.move.notFound": "The moved page could not be found", - "error.page.move.permission": "You are not allowed to move \"{slug}\"", - "error.page.move.template": "The \"{template}\" template is not accepted as a subpage of \"{parent}\"", - "error.page.notFound": "Δεν ήταν δυνατή η εύρεση της σελίδας \"{slug}\"", - "error.page.num.invalid": "Παρακαλώ εισάγετε έναν έγκυρο αριθμό ταξινόμησης. Οι αριθμοί δεν μπορεί να είναι αρνητικοί.", - "error.page.slug.invalid": "Please enter a valid URL appendix", - "error.page.slug.maxlength": "Slug length must be less than \"{length}\" characters", - "error.page.sort.permission": "Δεν είναι δυνατή η ταξινόμηση της σελίδας \"{slug}\"", - "error.page.status.invalid": "Ορίστε μια έγκυρη κατάσταση σελίδας", - "error.page.undefined": "Δεν ήταν δυνατή η εύρεση της σελίδας", - "error.page.update.permission": "Δεν επιτρέπεται η ενημέρωση της σελίδας \"{slug}\"", - - "error.section.files.max.plural": "Δεν πρέπει να προσθέσετε περισσότερα από {max} αρχεία στην ενότητα \"{section}\"", - "error.section.files.max.singular": "Δεν πρέπει να προσθέσετε περισσότερα από ένα αρχεία στην ενότητα \"{section}\"", - "error.section.files.min.plural": "The \"{section}\" section requires at least {min} files", - "error.section.files.min.singular": "The \"{section}\" section requires at least one file", - - "error.section.pages.max.plural": "Δεν μπορείτε να προσθέσετε περισσότερες από {max} σελίδες στην ενότητα \"{section}\"", - "error.section.pages.max.singular": "Δεν μπορείτε να προσθέσετε περισσότερες από μία σελίδες στην ενότητα \"{section}\"", - "error.section.pages.min.plural": "The \"{section}\" section requires at least {min} pages", - "error.section.pages.min.singular": "The \"{section}\" section requires at least one page", - - "error.section.notLoaded": "Δεν ήταν δυνατή η φόρτωση της ενότητας \"{name}\"", - "error.section.type.invalid": "Ο τύπος ενότητας \"{type}\" δεν είναι έγκυρος", - - "error.site.changeTitle.empty": "Ο τίτλος δεν μπορεί να είναι κενός", - "error.site.changeTitle.permission": "Δεν επιτρέπεται να αλλάξετε τον τίτλο του ιστότοπου", - "error.site.update.permission": "Δεν επιτρέπεται η ενημέρωση του ιστότοπου", - - "error.structure.validation": "There's an error on the \"{field}\" field in row {index}", - - "error.template.default.notFound": "Το προεπιλεγμένο πρότυπο δεν υπάρχει", - - "error.unexpected": "An unexpected error occurred! Enable debug mode for more info: https://getkirby.com/docs/reference/system/options/debug", - - "error.user.changeEmail.permission": "Δεν επιτρέπεται να αλλάξετε τη διεύθινση ηλεκτρονικού ταχυδρομείου για τον χρήστη \"{name}\"", - "error.user.changeLanguage.permission": "Δεν επιτρέπεται να αλλάξετε τη γλώσσα για τον χρήστη \"{name}\"", - "error.user.changeName.permission": "Δεν επιτρέπεται να αλλάξετε το όνομα του χρήστη \"{name}", - "error.user.changePassword.permission": "Δεν επιτρέπεται να αλλάξετε τον κωδικό πρόσβασης για τον χρήστη \"{name}\"", - "error.user.changeRole.lastAdmin": "Ο ρόλος του τελευταίου διαχειριστή δεν μπορεί να αλλάξει", - "error.user.changeRole.permission": "Δεν επιτρέπεται να αλλάξετε το ρόλο του χρήστη \"{name}\"", - "error.user.changeRole.toAdmin": "You are not allowed to promote someone to the admin role", - "error.user.create.permission": "Δεν επιτρέπεται η δημιουργία αυτού του χρήστη", - "error.user.delete": "\u039f \u03c7\u03c1\u03ae\u03c3\u03c4\u03b7\u03c2 \u03b4\u03b5\u03bd \u03bc\u03c0\u03bf\u03c1\u03bf\u03cd\u03c3\u03b5 \u03bd\u03b1 \u03b4\u03b9\u03b1\u03b3\u03c1\u03b1\u03c6\u03b5\u03af", - "error.user.delete.lastAdmin": "Δεν είναι δυνατή η διαγραφή του τελευταίου διαχειριστή", - "error.user.delete.lastUser": "Δεν είναι δυνατή η διαγραφή του τελευταίου χρήστη", - "error.user.delete.permission": "Δεν επιτρέπεται να διαγράψετ τον χρήστη \"{name}\"", - "error.user.duplicate": "Ένας χρήστης με τη διεύθυνση ηλεκτρονικού ταχυδρομείου \"{email}\" υπάρχει ήδη", - "error.user.email.invalid": "Παρακαλώ εισάγετε μια έγκυρη διεύθυνση ηλεκτρονικού ταχυδρομείου", - "error.user.language.invalid": "Παρακαλώ εισαγάγετε μια έγκυρη γλώσσα", - "error.user.notFound": "Δεν είναι δυνατή η εύρεση του χρήστη \"{name}\"", - "error.user.password.excessive": "Please enter a valid password. Passwords must not be longer than 1000 characters.", - "error.user.password.invalid": "Παρακαλώ εισάγετε έναν έγκυρο κωδικό πρόσβασης. Οι κωδικοί πρόσβασης πρέπει να έχουν μήκος τουλάχιστον 8 χαρακτήρων.", - "error.user.password.notSame": "\u03a0\u03b1\u03c1\u03b1\u03ba\u03b1\u03bb\u03bf\u03cd\u03bc\u03b5 \u03b5\u03c0\u03b9\u03b2\u03b5\u03b2\u03b1\u03b9\u03ce\u03c3\u03c4\u03b5 \u03c4\u03bf\u03bd \u039a\u03c9\u03b4\u03b9\u03ba\u03cc \u03a0\u03c1\u03cc\u03c3\u03b2\u03b1\u03c3\u03b7\u03c2", - "error.user.password.undefined": "Ο χρήστης δεν έχει κωδικό πρόσβασης", - "error.user.password.wrong": "Wrong password", - "error.user.role.invalid": "Παρακαλώ εισαγάγετε έναν έγκυρο ρόλο", - "error.user.undefined": "Δεν είναι δυνατή η εύρεση του χρήστη", - "error.user.update.permission": "Δεν επιτρέπεται η ενημέρωση του χρήστη \"{name}\"", - - "error.validation.accepted": "Παρακαλώ επιβεβαιώστε", - "error.validation.alpha": "Παρακαλώ εισάγετε μόνο χαρακτήρες μεταξύ των a-z", - "error.validation.alphanum": "Παρακαλώ εισάγετε μόνο χαρακτήρες μεταξύ των a-z ή αριθμούς απο το 0 έως το 9", - "error.validation.anchor": "Please enter a correct link anchor", - "error.validation.between": "Παρακαλώ εισάγετε μια τιμή μεταξύ \"{min}\" και \"{max}\"", - "error.validation.boolean": "Παρακαλώ επιβεβαιώστε ή αρνηθείτε", - "error.validation.color": "Please enter a valid color in the {format} format", - "error.validation.contains": "Παρακαλώ καταχωρίστε μια τιμή που περιέχει \"{needle}\"", - "error.validation.date": "Παρακαλώ εισάγετε μία έγκυρη ημερομηνία", - "error.validation.date.after": "Please enter a date after {date}", - "error.validation.date.before": "Please enter a date before {date}", - "error.validation.date.between": "Please enter a date between {min} and {max}", - "error.validation.denied": "Παρακαλώ αρνηθείτε", - "error.validation.different": "Η τιμή δεν μπορεί να είναι \"{other}\"", - "error.validation.email": "Παρακαλώ εισάγετε μια έγκυρη διεύθυνση ηλεκτρονικού ταχυδρομείου", - "error.validation.endswith": "Η τιμή πρέπει να τελειώνει με \"{end}\"", - "error.validation.filename": "Παρακαλώ εισάγετε ένα έγκυρο όνομα αρχείου", - "error.validation.in": "Παρακαλώ εισάγετε ένα από τα παρακάτω: ({in})", - "error.validation.integer": "Παρακαλώ εισάγετε έναν έγκυρο ακέραιο αριθμό", - "error.validation.ip": "Παρακαλώ εισάγετε μια έγκυρη διεύθυνση IP", - "error.validation.less": "Παρακαλώ εισάγετε μια τιμή μικρότερη από {max}", - "error.validation.linkType": "The link type is not allowed", - "error.validation.match": "Η τιμή δεν ταιριάζει με το αναμενόμενο πρότυπο", - "error.validation.max": "Παρακαλώ εισάγετε μια τιμή ίση ή μικρότερη από {max}", - "error.validation.maxlength": "Παρακαλώ εισάγετε μια μικρότερη τιμή. (max. {max} χαρακτήρες)", - "error.validation.maxwords": "Παρακαλώ εισάγετε το πολύ {max} λέξεις", - "error.validation.min": "Παρακαλώ εισάγετε μια τιμή ίση ή μεγαλύτερη από {min}", - "error.validation.minlength": "Παρακαλώ εισάγετε μεγαλύτερη τιμή. (τουλάχιστον {min} χαρακτήρες)", - "error.validation.minwords": "Παρακαλώ εισάγετε τουλάχιστον {min} λέξεις", - "error.validation.more": "Παρακαλώ εισάγετε τουλάχιστον {min} λέξεις", - "error.validation.notcontains": "Παρακαλώ εισάγετε μια τιμή που δεν περιέχει \"{needle}\"", - "error.validation.notin": "Παρακαλώ μην εισάγετε κανένα από τα παρακάτω: ({notIn})", - "error.validation.option": "Παρακαλώ κάντε μια έγκυρη επιλογή", - "error.validation.num": "Παρακαλώ εισάγετε έναν έγκυρο αριθμό", - "error.validation.required": "Παρακαλώ εισάγετε κάτι", - "error.validation.same": "Παρακαλώ εισάγετε \"{other}\"", - "error.validation.size": "Το μέγεθος της τιμής πρέπει να είναι \"{size}\"", - "error.validation.startswith": "Η τιμή πρέπει να αρχίζει με \"{start}\"", - "error.validation.tel": "Please enter an unformatted phone number", - "error.validation.time": "Παρακαλώ εισάγετε μια έγκυρη ώρα", - "error.validation.time.after": "Please enter a time after {time}", - "error.validation.time.before": "Please enter a time before {time}", - "error.validation.time.between": "Please enter a time between {min} and {max}", - "error.validation.uuid": "Please enter a valid UUID", - "error.validation.url": "Παρακαλώ εισάγετε μια έγκυρη διεύθυνση URL", - - "expand": "Expand", - "expand.all": "Expand All", - - "field.invalid": "The field is invalid", - "field.required": "The field is required", - "field.blocks.changeType": "Change type", - "field.blocks.code.name": "Κώδικας", - "field.blocks.code.language": "Γλώσσα", - "field.blocks.code.placeholder": "Your code …", - "field.blocks.delete.confirm": "Do you really want to delete this block?", - "field.blocks.delete.confirm.all": "Do you really want to delete all blocks?", - "field.blocks.delete.confirm.selected": "Do you really want to delete the selected blocks?", - "field.blocks.empty": "No blocks yet", - "field.blocks.fieldsets.empty": "No fieldsets yet", - "field.blocks.fieldsets.label": "Please select a block type …", - "field.blocks.fieldsets.paste": "Press {{ shortcut }} to import layouts/blocks from your clipboard Only those allowed in the current field will get inserted.", - "field.blocks.gallery.name": "Gallery", - "field.blocks.gallery.images.empty": "No images yet", - "field.blocks.gallery.images.label": "Images", - "field.blocks.heading.level": "Level", - "field.blocks.heading.name": "Heading", - "field.blocks.heading.text": "Text", - "field.blocks.heading.placeholder": "Heading …", - "field.blocks.image.alt": "Alternative text", - "field.blocks.image.caption": "Caption", - "field.blocks.image.crop": "Crop", - "field.blocks.image.link": "Σύνδεσμος", - "field.blocks.image.location": "Location", - "field.blocks.image.location.internal": "This website", - "field.blocks.image.location.external": "External source", - "field.blocks.image.name": "Εικόνα", - "field.blocks.image.placeholder": "Select an image", - "field.blocks.image.ratio": "Ratio", - "field.blocks.image.url": "Image URL", - "field.blocks.line.name": "Line", - "field.blocks.list.name": "List", - "field.blocks.markdown.name": "Markdown", - "field.blocks.markdown.label": "Text", - "field.blocks.markdown.placeholder": "Markdown …", - "field.blocks.quote.name": "Quote", - "field.blocks.quote.text.label": "Text", - "field.blocks.quote.text.placeholder": "Quote …", - "field.blocks.quote.citation.label": "Citation", - "field.blocks.quote.citation.placeholder": "by …", - "field.blocks.text.name": "Text", - "field.blocks.text.placeholder": "Text …", - "field.blocks.video.autoplay": "Autoplay", - "field.blocks.video.caption": "Caption", - "field.blocks.video.controls": "Controls", - "field.blocks.video.location": "Location", - "field.blocks.video.loop": "Loop", - "field.blocks.video.muted": "Muted", - "field.blocks.video.name": "Video", - "field.blocks.video.placeholder": "Enter a video URL", - "field.blocks.video.poster": "Poster", - "field.blocks.video.preload": "Preload", - "field.blocks.video.url.label": "Video-URL", - "field.blocks.video.url.placeholder": "https://youtube.com/?v=", - - "field.files.empty": "Δεν έχουν επιλεγεί αρχεία ακόμα", - - "field.layout.change": "Change layout", - "field.layout.delete": "Delete layout", - "field.layout.delete.confirm": "Do you really want to delete this layout?", - "field.layout.delete.confirm.all": "Do you really want to delete all layouts?", - "field.layout.empty": "No rows yet", - "field.layout.select": "Select a layout", - - "field.object.empty": "No information yet", - - "field.pages.empty": "Δεν έχουν επιλεγεί ακόμη σελίδες", - - "field.structure.delete.confirm": "\u0395\u03af\u03c3\u03c4\u03b5 \u03c3\u03af\u03b3\u03bf\u03c5\u03c1\u03bf\u03c2 \u03cc\u03c4\u03b9 \u03b8\u03ad\u03bb\u03b5\u03c4\u03b5 \u03bd\u03b1 \u03b4\u03b9\u03b1\u03b3\u03c1\u03ac\u03c8\u03b5\u03c4\u03b5 \u03b1\u03c5\u03c4\u03ae\u03bd \u03c4\u03b7\u03bd \u03ba\u03b1\u03c4\u03b1\u03c7\u03ce\u03c1\u03b9\u03c3\u03b7;", - "field.structure.delete.confirm.all": "Do you really want to delete all entries?", - "field.structure.empty": "\u0394\u03b5\u03bd \u03c5\u03c0\u03ac\u03c1\u03c7\u03bf\u03c5\u03bd \u03b1\u03ba\u03cc\u03bc\u03b7 \u03ba\u03b1\u03c4\u03b1\u03c7\u03c9\u03c1\u03af\u03c3\u03b5\u03b9\u03c2.", - - "field.users.empty": "Δεν έχουν επιλεγεί ακόμη χρήστες", - - "fields.empty": "No fields yet", - - "file": "Αρχείο", - "file.blueprint": "This file has no blueprint yet. You can define the setup in /site/blueprints/files/{blueprint}.yml", - "file.changeTemplate": "Αλλαγή προτύπου", - "file.changeTemplate.notice": "Changing the file's template will remove content for fields that don't match in type. If the new template defines certain rules, e.g. image dimensions, those will also be applied irreversibly. Use with caution.", - "file.delete.confirm": "\u0398\u03ad\u03bb\u03b5\u03c4\u03b5 \u03c3\u03af\u03b3\u03bf\u03c5\u03c1\u03b1 \u03bd\u03b1 \u03b4\u03b9\u03b1\u03b3\u03c1\u03ac\u03c8\u03b5\u03c4\u03b5 \u03b1\u03c5\u03c4\u03cc \u03c4\u03bf \u03b1\u03c1\u03c7\u03b5\u03af\u03bf;", - "file.focus.placeholder": "Set focal point", - "file.focus.reset": "Remove focal point", - "file.focus.title": "Focus", - "file.sort": "Change position", - - "files": "Αρχεία", - "files.empty": "Δεν υπάρχουν ακόμα αρχεία", - - "filter": "Filter", - - "hide": "Hide", - "hour": "Ώρα", - "hue": "Hue", - "import": "Import", - "info": "Info", - "insert": "\u0395\u03b9\u03c3\u03b1\u03b3\u03c9\u03b3\u03ae", - "insert.after": "Insert after", - "insert.before": "Insert before", - "install": "Εγκατάσταση", - - "installation": "Εγκατάσταση", - "installation.completed": "Ο πίνακας ελέγχου έχει εγκατασταθεί", - "installation.disabled": "Η εγκατάσταση του πίνακα ελέγχου είναι απενεργοποιημένη για δημόσιους διακομιστές από προεπιλογή. Εκτελέστε την εγκατάσταση σε ένα τοπικό μηχάνημα ή ενεργοποιήστε την με την επιλογή panel.install.", - "installation.issues.accounts": "\u039f \u03c6\u03ac\u03ba\u03b5\u03bb\u03bf\u03c2 \/site\/accounts \u03b4\u03b5\u03bd \u03b5\u03af\u03bd\u03b1\u03b9 \u03b5\u03b3\u03b3\u03c1\u03ac\u03c8\u03b9\u03bc\u03bf\u03c2", - "installation.issues.content": "\u039f \u03c6\u03ac\u03ba\u03b5\u03bb\u03bf\u03c2 content \u03ba\u03b1\u03b9 \u03cc\u03bb\u03bf\u03b9 \u03bf\u03b9 \u03c5\u03c0\u03bf\u03c6\u03ac\u03ba\u03b5\u03bb\u03bf\u03b9 \u03c0\u03c1\u03ad\u03c0\u03b5\u03b9 \u03bd\u03b1 \u03b5\u03af\u03bd\u03b1\u03b9 \u03b5\u03b3\u03b3\u03c1\u03ac\u03c8\u03b9\u03bc\u03bf\u03b9.", - "installation.issues.curl": "Απαιτείται η επέκταση CURL", - "installation.issues.headline": "Ο πίνακας ελέγχου δεν μπορεί να εγκατασταθεί", - "installation.issues.mbstring": "Απαιτείται η επέκταση MB String ", - "installation.issues.media": "Ο φάκελος /media δεν υπάρχει ή δεν είναι εγγράψιμος", - "installation.issues.php": "Βεβαιωθείτε ότι χρησιμοποιήτε PHP 8+", - "installation.issues.sessions": "Ο φάκελος /site/sessions δεν υπάρχει ή δεν είναι εγγράψιμος", - - "language": "\u0393\u03bb\u03ce\u03c3\u03c3\u03b1", - "language.code": "Κώδικας", - "language.convert": "Χρήση ως προεπιλογή", - "language.convert.confirm": "

Θέλετε πραγματικά να μετατρέψετε τη {name} στην προεπιλεγμένη γλώσσα; Αυτό δεν μπορεί να ανακληθεί.

Αν το {name} χει μη μεταφρασμένο περιεχόμενο, δεν θα υπάρχει πλέον έγκυρη εναλλακτική λύση και τμήματα του ιστότοπού σας ενδέχεται να είναι κενά.

", - "language.create": "Προσθέστε μια νέα γλώσσα", - "language.default": "Προεπιλεγμένη γλώσσα", - "language.delete.confirm": "Θέλετε πραγματικά να διαγράψετε τη γλώσσα {name} συμπεριλαμβανομένων όλων των μεταφράσεων; Αυτό δεν μπορεί να αναιρεθεί!", - "language.deleted": "Η γλώσσα έχει διαγραφεί", - "language.direction": "Κατεύθυνση ανάγνωσης", - "language.direction.ltr": "Αριστερά προς τα δεξιά", - "language.direction.rtl": "Δεξιά προς τα αριστερά", - "language.locale": "Συμβολοσειρά τοπικής γλώσσας PHP", - "language.locale.warning": "You are using a custom locale set up. Please modify it in the language file in /site/languages", - "language.name": "Ονομασία", - "language.secondary": "Secondary language", - "language.settings": "Language settings", - "language.updated": "Η γλώσσα έχει ενημερωθεί", - "language.variables": "Language variables", - "language.variables.empty": "No translations yet", - - "language.variable.delete.confirm": "Do you really want to delete the variable for {key}?", - "language.variable.key": "Key", - "language.variable.notFound": "The variable could not be found", - "language.variable.value": "Value", - - "languages": "Γλώσσες", - "languages.default": "Προεπιλεγμένη γλώσσα", - "languages.empty": "Δεν υπάρχουν ακόμη γλώσσες", - "languages.secondary": "Δευτερεύουσες γλώσσες", - "languages.secondary.empty": "Δεν υπάρχουν ακόμα δευτερεύουσες γλώσσες", - - "license": "\u0386\u03b4\u03b5\u03b9\u03b1 \u03a7\u03c1\u03ae\u03c3\u03b7\u03c2 \u03c4\u03bf\u03c5 Kirby", - "license.activate": "Activate it now", - "license.activate.label": "Please activate your license", - "license.activate.domain": "Your license will be activated for {host}.", - "license.activate.local": "You are about to activate your Kirby license for your local domain {host}. If this site will be deployed to a public domain, please activate it there instead. If {host} is the domain you want to use your license for, please continue.", - "license.activated": "Activated", - "license.buy": "Αγοράστε μια άδεια", - "license.code": "Κώδικας", - "license.code.help": "You received your license code after the purchase via email. Please copy and paste it here.", - "license.code.label": "Παρακαλώ εισαγάγετε τον κωδικό άδειας χρήσης", - "license.status.active.info": "Includes new major versions until {date}", - "license.status.active.label": "Valid license", - "license.status.demo.info": "This is a demo installation", - "license.status.demo.label": "Demo", - "license.status.inactive.info": "Renew license to update to new major versions", - "license.status.inactive.label": "No new major versions", - "license.status.legacy.bubble": "Ready to renew your license?", - "license.status.legacy.info": "Your license does not cover this version", - "license.status.legacy.label": "Please renew your license", - "license.status.missing.bubble": "Ready to launch your site?", - "license.status.missing.info": "No valid license", - "license.status.missing.label": "Please activate your license", - "license.manage": "Manage your licenses", - "license.purchased": "Purchased", - "license.success": "Σας ευχαριστούμε για την υποστήριξη του Kirby", - "license.unregistered.label": "Unregistered", - - "link": "\u03a3\u03cd\u03bd\u03b4\u03b5\u03c3\u03bc\u03bf\u03c2", - "link.text": "\u039a\u03b5\u03af\u03bc\u03b5\u03bd\u03bf \u03c3\u03c5\u03bd\u03b4\u03ad\u03c3\u03bc\u03bf\u03c5", - - "loading": "Φόρτωση", - - "lock.unsaved": "Unsaved changes", - "lock.unsaved.empty": "There are no more unsaved changes", - "lock.isLocked": "Unsaved changes by {email}", - "lock.unlock": "Unlock", - "lock.unlock.submit": "Unlock and overwrite unsaved changes by {email}", - "lock.isUnlocked": "Was unlocked by another user", - - "login": "Σύνδεση", - "login.code.label.login": "Login code", - "login.code.label.password-reset": "Password reset code", - "login.code.placeholder.email": "000 000", - "login.code.placeholder.totp": "000000", - "login.code.text.email": "If your email address is registered, the requested code was sent via email.", - "login.code.text.totp": "Please enter the one‑time code from your authenticator app.", - "login.email.login.body": "Hi {user.nameOrEmail},\n\nYou recently requested a login code for the Panel of {site}.\nThe following login code will be valid for {timeout} minutes:\n\n{code}\n\nIf you did not request a login code, please ignore this email or contact your administrator if you have questions.\nFor security, please DO NOT forward this email.", - "login.email.login.subject": "Your login code", - "login.email.password-reset.body": "Hi {user.nameOrEmail},\n\nYou recently requested a password reset code for the Panel of {site}.\nThe following password reset code will be valid for {timeout} minutes:\n\n{code}\n\nIf you did not request a password reset code, please ignore this email or contact your administrator if you have questions.\nFor security, please DO NOT forward this email.", - "login.email.password-reset.subject": "Your password reset code", - "login.remember": "Κρατήστε με συνδεδεμένο", - "login.reset": "Reset password", - "login.toggleText.code.email": "Login via email", - "login.toggleText.code.email-password": "Login with password", - "login.toggleText.password-reset.email": "Forgot your password?", - "login.toggleText.password-reset.email-password": "← Back to login", - "login.totp.enable.option": "Set up one‑time codes", - "login.totp.enable.intro": "Authenticator apps can generate one‑time codes that are used as a second factor when signing into your account.", - "login.totp.enable.qr.label": "1. Scan this QR code", - "login.totp.enable.qr.help": "Unable to scan? Add the setup key {secret} manually to your authenticator app.", - "login.totp.enable.confirm.headline": "2. Confirm with generated code", - "login.totp.enable.confirm.text": "Your app generates a new one‑time code every 30 seconds. Enter the current code to complete the setup:", - "login.totp.enable.confirm.label": "Current code", - "login.totp.enable.confirm.help": "After this setup, we will ask you for a one‑time code every time you log in.", - "login.totp.enable.success": "One‑time codes enabled", - "login.totp.disable.option": "Disable one‑time codes", - "login.totp.disable.label": "Enter your password to disable one‑time codes", - "login.totp.disable.help": "In the future, a different second factor like a login code sent via email will be requested when you log in. You can always set up one‑time codes again later.", - "login.totp.disable.admin": "

This will disable one‑time codes for {user}.

In the future, a different second factor like a login code sent via email will be requested when they log in. {user} can set up one‑time codes again after their next login.

", - "login.totp.disable.success": "One‑time codes disabled", - - "logout": "Αποσύνδεση", - - "merge": "Merge", - "menu": "Μενού", - "meridiem": "Π.Μ./Μ.Μ", - "mime": "Τύπος πολυμέσων", - "minutes": "Λεπτά", - - "month": "Μήνας", - "months.april": "\u0391\u03c0\u03c1\u03af\u03bb\u03b9\u03bf\u03c2", - "months.august": "\u0391\u03cd\u03b3\u03bf\u03c5\u03c3\u03c4\u03bf\u03c2", - "months.december": "\u0394\u03b5\u03ba\u03ad\u03bc\u03b2\u03c1\u03b9\u03bf\u03c2", - "months.february": "Φεβρουάριος", - "months.january": "\u0399\u03b1\u03bd\u03bf\u03c5\u03ac\u03c1\u03b9\u03bf\u03c2", - "months.july": "\u0399\u03bf\u03cd\u03bb\u03b9\u03bf\u03c2", - "months.june": "\u0399\u03bf\u03cd\u03bd\u03b9\u03bf\u03c2", - "months.march": "\u039c\u03ac\u03c1\u03c4\u03b9\u03bf\u03c2", - "months.may": "\u039c\u03ac\u03b9\u03bf\u03c2", - "months.november": "\u039d\u03bf\u03ad\u03bc\u03b2\u03c1\u03b9\u03bf\u03c2", - "months.october": "\u039f\u03ba\u03c4\u03ce\u03b2\u03c1\u03b9\u03bf\u03c2", - "months.september": "\u03a3\u03b5\u03c0\u03c4\u03ad\u03bc\u03b2\u03c1\u03b9\u03bf\u03c2", - - "more": "Περισσότερα", - "move": "Move", - "name": "Ονομασία", - "next": "Επόμενο", - "night": "Night", - "no": "no", - "off": "off", - "on": "on", - "open": "Άνοιγμα", - "open.newWindow": "Open in new window", - "option": "Option", - "options": "Eπιλογές", - "options.none": "No options", - "options.all": "Show all {count} options", - - "orientation": "Προσανατολισμός", - "orientation.landscape": "Οριζόντιος", - "orientation.portrait": "Κάθετος", - "orientation.square": "Τετράγωνος", - - "page": "Page", - "page.blueprint": "This page has no blueprint yet. You can define the setup in /site/blueprints/pages/{blueprint}.yml", - "page.changeSlug": "\u0391\u03bb\u03bb\u03b1\u03b3\u03ae URL", - "page.changeSlug.fromTitle": "\u0394\u03b7\u03bc\u03b9\u03bf\u03c5\u03c1\u03b3\u03af\u03b1 \u03b1\u03c0\u03cc \u03c4\u03bf\u03bd \u03c4\u03af\u03c4\u03bb\u03bf", - "page.changeStatus": "Αλλαγή κατάστασης", - "page.changeStatus.position": "Επιλέξτε μια θέση", - "page.changeStatus.select": "Επιλέξτε μια νέα κατάσταση", - "page.changeTemplate": "Αλλαγή προτύπου", - "page.changeTemplate.notice": "Changing the page's template will remove content for fields that don't match in type. Use with caution.", - "page.create": "Create as {status}", - "page.delete.confirm": "\u0398\u03ad\u03bb\u03b5\u03c4\u03b5 \u03c3\u03af\u03b3\u03bf\u03c5\u03c1\u03b1 \u03bd\u03b1 \u03b4\u03b9\u03b1\u03b3\u03c1\u03ac\u03c8\u03b5\u03c4\u03b5 \u03b1\u03c5\u03c4\u03ae\u03bd \u03c4\u03b7 \u03c3\u03b5\u03bb\u03af\u03b4\u03b1;", - "page.delete.confirm.subpages": "Αυτή η σελίδα έχει υποσελίδες.
Όλες οι υποσελίδες θα διαγραφούν επίσης.", - "page.delete.confirm.title": "Εισάγετε τον τίτλο της σελίδας για επιβεβαίωση", - "page.duplicate.appendix": "Αντιγραφή", - "page.duplicate.files": "Copy files", - "page.duplicate.pages": "Copy pages", - "page.move": "Move page", - "page.sort": "Change position", - "page.status": "Kατάσταση", - "page.status.draft": "Προσχέδιο", - "page.status.draft.description": "The page is in draft mode and only visible for logged in editors or via secret link", - "page.status.listed": "Δημοσιευμένο", - "page.status.listed.description": "Αυτή η σελίδα είναι δημοσιευμένη για οποιονδήποτε", - "page.status.unlisted": "Μη καταχωρημένο", - "page.status.unlisted.description": "Η σελίδα είναι προσβάσιμη μόνο μέσω της διεύθυνσης URL", - - "pages": "Σελίδες", - "pages.empty": "Δεν υπάρχουν ακόμα σελίδες", - "pages.status.draft": "Προσχέδια", - "pages.status.listed": "Δημοσιευμένο", - "pages.status.unlisted": "Μη καταχωρημένο", - - "pagination.page": "Σελίδα", - - "password": "\u039a\u03c9\u03b4\u03b9\u03ba\u03cc\u03c2 \u03a0\u03c1\u03cc\u03c3\u03b2\u03b1\u03c3\u03b7\u03c2", - "paste": "Paste", - "paste.after": "Paste after", - "paste.success": "{count} pasted!", - "pixel": "Εικονοστοιχέιο", - "plugin": "Plugin", - "plugins": "Plugins", - "prev": "Προηγούμενο", - "preview": "Preview", - "remove": "Αφαίρεση", - "rename": "Μετονομασία", - "renew": "Renew", - "replace": "\u0391\u03bd\u03c4\u03b9\u03ba\u03b1\u03c4\u03ac\u03c3\u03c4\u03b1\u03c3\u03b7", - "replace.with": "Replace with", - "retry": "\u0395\u03c0\u03b1\u03bd\u03ac\u03bb\u03b7\u03c8\u03b7", - "revert": "\u0391\u03b3\u03bd\u03cc\u03b7\u03c3\u03b7", - "revert.confirm": "Do you really want to delete all unsaved changes?", - - "role": "\u03a1\u03cc\u03bb\u03bf\u03c2", - "role.admin.description": "The admin has all rights", - "role.admin.title": "Admin", - "role.all": "Όλα", - "role.empty": "Δεν υπάρχουν χρήστες με αυτόν τον ρόλο", - "role.description.placeholder": "Χωρίς περιγραφή", - "role.nobody.description": "This is a fallback role without any permissions", - "role.nobody.title": "Nobody", - - "save": "\u0391\u03c0\u03bf\u03b8\u03ae\u03ba\u03b5\u03c5\u03c3\u03b7", - "search": "Αναζήτηση", - "search.min": "Enter {min} characters to search", - "search.all": "Show all {count} results", - "search.results.none": "No results", - - "section.invalid": "The section is invalid", - "section.required": "The section is required", - - "security": "Security", - "select": "Επιλογή", - "server": "Server", - "settings": "Ρυθμίσεις", - "show": "Show", - "site.blueprint": "The site has no blueprint yet. You can define the setup in /site/blueprints/site.yml", - "size": "Μέγεθος", - "slug": "\u0395\u03c0\u03af\u03b8\u03b5\u03bc\u03b1 URL", - "sort": "Ταξινόμηση", - "sort.drag": "Drag to sort …", - "split": "Split", - - "stats.empty": "No reports", - "status": "Kατάσταση", - - "system.info.copy": "Copy info", - "system.info.copied": "System info copied", - "system.issues.content": "The content folder seems to be exposed", - "system.issues.eol.kirby": "Your installed Kirby version has reached end-of-life and will not receive further security updates", - "system.issues.eol.plugin": "Your installed version of the { plugin } plugin is has reached end-of-life and will not receive further security updates", - "system.issues.eol.php": "Your installed PHP release { release } has reached end-of-life and will not receive further security updates", - "system.issues.debug": "Debugging must be turned off in production", - "system.issues.git": "The .git folder seems to be exposed", - "system.issues.https": "We recommend HTTPS for all your sites", - "system.issues.kirby": "The kirby folder seems to be exposed", - "system.issues.site": "The site folder seems to be exposed", - "system.issues.vulnerability.kirby": "Your installation might be affected by the following vulnerability ({ severity } severity): { description }", - "system.issues.vulnerability.plugin": "Your installation might be affected by the following vulnerability in the { plugin } plugin ({ severity } severity): { description }", - "system.updateStatus": "Update status", - "system.updateStatus.error": "Could not check for updates", - "system.updateStatus.not-vulnerable": "No known vulnerabilities", - "system.updateStatus.security-update": "Free security update { version } available", - "system.updateStatus.security-upgrade": "Upgrade { version } with security fixes available", - "system.updateStatus.unreleased": "Unreleased version", - "system.updateStatus.up-to-date": "Up to date", - "system.updateStatus.update": "Free update { version } available", - "system.updateStatus.upgrade": "Upgrade { version } available", - - "tel": "Phone", - "tel.placeholder": "+49123456789", - "template": "\u03a0\u03c1\u03cc\u03c4\u03c5\u03c0\u03bf", - "title": "Τίτλος", - "today": "Σήμερα", - - "toolbar.button.clear": "Clear formatting", - "toolbar.button.code": "Κώδικας", - "toolbar.button.bold": "\u0388\u03bd\u03c4\u03bf\u03bd\u03b7 \u03b3\u03c1\u03b1\u03c6\u03ae", - "toolbar.button.email": "Email", - "toolbar.button.headings": "Επικεφαλίδες", - "toolbar.button.heading.1": "Επικεφαλίδα 1", - "toolbar.button.heading.2": "Επικεφαλίδα 2", - "toolbar.button.heading.3": "Επικεφαλίδα 3", - "toolbar.button.heading.4": "Heading 4", - "toolbar.button.heading.5": "Heading 5", - "toolbar.button.heading.6": "Heading 6", - "toolbar.button.italic": "\u03a0\u03bb\u03ac\u03b3\u03b9\u03b1 \u03b3\u03c1\u03b1\u03c6\u03ae", - "toolbar.button.file": "Αρχείο", - "toolbar.button.file.select": "Select a file", - "toolbar.button.file.upload": "Upload a file", - "toolbar.button.link": "\u03a3\u03cd\u03bd\u03b4\u03b5\u03c3\u03bc\u03bf\u03c2", - "toolbar.button.paragraph": "Paragraph", - "toolbar.button.strike": "Strike-through", - "toolbar.button.sub": "Subscript", - "toolbar.button.sup": "Superscript", - "toolbar.button.ol": "Ταξινομημένη λίστα", - "toolbar.button.underline": "Underline", - "toolbar.button.ul": "Λίστα κουκκίδων", - - "translation.author": "Ομάδα Kirby", - "translation.direction": "ltr", - "translation.name": "\u0395\u03bb\u03bb\u03b7\u03bd\u03b9\u03ba\u03ac", - "translation.locale": "el_GR", - - "type": "Type", - - "upload": "Μεταφόρτωση", - "upload.error.cantMove": "The uploaded file could not be moved", - "upload.error.cantWrite": "Failed to write file to disk", - "upload.error.default": "The file could not be uploaded", - "upload.error.extension": "File upload stopped by extension", - "upload.error.formSize": "The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the form", - "upload.error.iniPostSize": "The uploaded file exceeds the post_max_size directive in php.ini", - "upload.error.iniSize": "The uploaded file exceeds the upload_max_filesize directive in php.ini", - "upload.error.noFile": "No file was uploaded", - "upload.error.noFiles": "No files were uploaded", - "upload.error.partial": "The uploaded file was only partially uploaded", - "upload.error.tmpDir": "Missing a temporary folder", - "upload.errors": "Σφάλμα", - "upload.progress": "Μεταφόρτωση...", - - "url": "Διεύθινση url", - "url.placeholder": "https://example.com", - - "user": "Χρήστης", - "user.blueprint": "You can define additional sections and form fields for this user role in /site/blueprints/users/{blueprint}.yml", - "user.changeEmail": "Αλλαγή διεύθινσης ηλεκτρονικού ταχυδρομείου", - "user.changeLanguage": "Αλλαγή γλώσσας", - "user.changeName": "Μετονομασία χρήστη", - "user.changePassword": "Αλλαγή κωδικού πρόσβασης", - "user.changePassword.new": "Νέος Κωδικός Πρόσβασης", - "user.changePassword.new.confirm": "Επαληθεύση κωδικού πρόσβασης", - "user.changeRole": "Αλλαγή ρόλου", - "user.changeRole.select": "Επιλογή νέου ρόλου", - "user.create": "Προσθήκη νέου χρήστη", - "user.delete": "Διαγραφή χρήστη", - "user.delete.confirm": "\u0398\u03ad\u03bb\u03b5\u03c4\u03b5 \u03c3\u03af\u03b3\u03bf\u03c5\u03c1\u03b1 \u03bd\u03b1 \u03b4\u03b9\u03b1\u03b3\u03c1\u03ac\u03c8\u03b5\u03c4\u03b5 \u03b1\u03c5\u03c4\u03cc\u03bd \u03c4\u03bf\u03bd \u03c7\u03c1\u03ae\u03c3\u03c4\u03b7;", - - "users": "Χρήστες", - - "version": "\u0388\u03ba\u03b4\u03bf\u03c3\u03b7 Kirby", - "version.current": "Current version", - "version.latest": "Latest version", - "versionInformation": "Version information", - - "view.account": "\u039f \u03bb\u03bf\u03b3\u03b1\u03c1\u03b9\u03b1\u03c3\u03bc\u03cc\u03c2 \u03c3\u03b1\u03c2", - "view.installation": "\u0395\u03b3\u03ba\u03b1\u03c4\u03ac\u03c3\u03c4\u03b1\u03c3\u03b7", - "view.languages": "Γλώσσες", - "view.resetPassword": "Reset password", - "view.site": "Iστοσελίδα", - "view.system": "System", - "view.users": "\u03a7\u03c1\u03ae\u03c3\u03c4\u03b5\u03c2", - - "welcome": "Καλώς ήρθατε", - "year": "Έτος", - "yes": "yes" + "account.changeName": "Change your name", + "account.delete": "Delete your account", + "account.delete.confirm": "Do you really want to delete your account? You will be logged out immediately. Your account cannot be recovered.", + + "add": "\u03a0\u03c1\u03bf\u03c3\u03b8\u03ae\u03ba\u03b7", + "author": "Author", + "avatar": "\u0395\u03b9\u03ba\u03cc\u03bd\u03b1 \u03c0\u03c1\u03bf\u03c6\u03af\u03bb", + "back": "Πίσω", + "cancel": "\u0391\u03ba\u03cd\u03c1\u03c9\u03c3\u03b7", + "change": "\u0391\u03bb\u03bb\u03b1\u03b3\u03ae", + "close": "\u039a\u03bb\u03b5\u03af\u03c3\u03b9\u03bc\u03bf", + "confirm": "Εντάξει", + "collapse": "Collapse", + "collapse.all": "Collapse All", + "copy": "Αντιγραφή", + "copy.all": "Copy all", + "create": "Δημιουργία", + + "date": "Ημερομηνία", + "date.select": "Επιλογή ημερομηνίας", + + "day": "Ημέρα", + "days.fri": "\u03a0\u03b1\u03c1", + "days.mon": "\u0394\u03b5\u03c5", + "days.sat": "\u03a3\u03ac\u03b2", + "days.sun": "\u039a\u03c5\u03c1", + "days.thu": "\u03a0\u03ad\u03bc", + "days.tue": "\u03a4\u03c1\u03af", + "days.wed": "\u03a4\u03b5\u03c4", + + "debugging": "Debugging", + + "delete": "\u0394\u03b9\u03b1\u03b3\u03c1\u03b1\u03c6\u03ae", + "delete.all": "Delete all", + + "dialog.files.empty": "No files to select", + "dialog.pages.empty": "No pages to select", + "dialog.users.empty": "No users to select", + + "dimensions": "Διαστάσεις", + "disabled": "Disabled", + "discard": "Απόρριψη", + "download": "Λήψη", + "duplicate": "Αντίγραφο", + + "edit": "\u0395\u03c0\u03b5\u03be\u03b5\u03c1\u03b3\u03b1\u03c3\u03af\u03b1", + + "email": "Διεύθυνση ηλεκτρονικού ταχυδρομείου", + "email.placeholder": "mail@example.com", + + "entries": "Entries", + "entry": "Entry", + + "environment": "Environment", + + "error.access.code": "Mη έγκυρος κωδικός", + "error.access.login": "Mη έγκυρη σύνδεση", + "error.access.panel": "Δεν επιτρέπεται η πρόσβαση στον πίνακα ελέγχου", + "error.access.view": "Δεν επιτρέπεται η πρόσβαση σε αυτό το τμήμα του πίνακα ελέγχου", + + "error.avatar.create.fail": "Δεν ήταν δυνατή η μεταφόρτωση της εικόνας προφίλ", + "error.avatar.delete.fail": "Δεν ήταν δυνατή η διαγραφή της εικόνας προφίλ", + "error.avatar.dimensions.invalid": "Διατηρήστε το πλάτος και το ύψος της εικόνας προφίλ κάτω από 3000 εικονοστοιχεία", + "error.avatar.mime.forbidden": "\u039c\u03b7 \u03b1\u03c0\u03bf\u03b4\u03b5\u03ba\u03c4\u03cc\u03c2 \u03c4\u03cd\u03c0\u03bf\u03c2 \u03b1\u03c1\u03c7\u03b5\u03af\u03bf\u03c5", + + "error.blueprint.notFound": "Δεν ήταν δυνατή η φόρτωση του προσχεδίου \"{name}\"", + + "error.blocks.max.plural": "You must not add more than {max} blocks", + "error.blocks.max.singular": "You must not add more than one block", + "error.blocks.min.plural": "You must add at least {min} blocks", + "error.blocks.min.singular": "You must add at least one block", + "error.blocks.validation": "There's an error in block {index}", + + "error.email.preset.notFound": "Δεν είναι δυνατή η εύρεση της προεπιλογής διεύθινσης ηλεκτρονικού ταχυδρομείου \"{name}\"", + + "error.field.converter.invalid": "Μη έγκυρος μετατροπέας \"{converter}\"", + + "error.file.changeName.empty": "The name must not be empty", + "error.file.changeName.permission": "Δεν επιτρέπεται να αλλάξετε το όνομα του \"{filename}\"", + "error.file.duplicate": "Ένα αρχείο με το όνομα \"{filename}\" υπάρχει ήδη", + "error.file.extension.forbidden": "\u039c\u03b7 \u03b1\u03c0\u03bf\u03b4\u03b5\u03ba\u03c4\u03ae \u03b5\u03c0\u03ad\u03ba\u03c4\u03b1\u03c3\u03b7 \u03b1\u03c1\u03c7\u03b5\u03af\u03bf\u03c5", + "error.file.extension.invalid": "Invalid extension: {extension}", + "error.file.extension.missing": "Λείπει η επέκταση για το \"{filename}\"", + "error.file.maxheight": "The height of the image must not exceed {height} pixels", + "error.file.maxsize": "The file is too large", + "error.file.maxwidth": "The width of the image must not exceed {width} pixels", + "error.file.mime.differs": "Το αρχείο πρέπει να είναι του ίδιου τύπου mime \"{mime}\"", + "error.file.mime.forbidden": "Ο τύπος μέσου \"{mime}\" δεν επιτρέπεται", + "error.file.mime.invalid": "Invalid mime type: {mime}", + "error.file.mime.missing": "Δεν είναι δυνατό να εντοπιστεί ο τύπος μέσου για το \"{filename}\"", + "error.file.minheight": "The height of the image must be at least {height} pixels", + "error.file.minsize": "The file is too small", + "error.file.minwidth": "The width of the image must be at least {width} pixels", + "error.file.name.missing": "Το όνομα αρχείου δεν μπορεί να είναι άδειο", + "error.file.notFound": "Δεν είναι δυνατό να βρεθεί το αρχείο \"{filename}\"", + "error.file.orientation": "The orientation of the image must be \"{orientation}\"", + "error.file.type.forbidden": "Δεν επιτρέπεται η μεταφόρτωση αρχείων {type}", + "error.file.type.invalid": "Invalid file type: {type}", + "error.file.undefined": "Δεν ήταν δυνατή η εύρεση του αρχείου", + + "error.form.incomplete": "Παρακαλώ διορθώστε τα σφάλματα στη φόρμα...", + "error.form.notSaved": "Δεν ήταν δυνατή η αποθήκευση της φόρμας", + + "error.language.code": "Please enter a valid code for the language", + "error.language.duplicate": "The language already exists", + "error.language.name": "Please enter a valid name for the language", + "error.language.notFound": "The language could not be found", + + "error.layout.validation.block": "There's an error in block {blockIndex} in layout {layoutIndex}", + "error.layout.validation.settings": "There's an error in layout {index} settings", + + "error.license.format": "Please enter a valid license key", + "error.license.email": "Παρακαλώ εισάγετε μια έγκυρη διεύθυνση ηλεκτρονικού ταχυδρομείου", + "error.license.verification": "The license could not be verified", + + "error.offline": "The Panel is currently offline", + + "error.page.changeSlug.permission": "Δεν επιτρέπεται να αλλάξετε το URL της σελίδας \"{slug}\"", + "error.page.changeStatus.incomplete": "Δεν ήταν δυνατή η δημοσίευση της σελίδας καθώς περιέχει σφάλματα", + "error.page.changeStatus.permission": "Δεν είναι δυνατή η αλλαγή κατάστασης για αυτή τη σελίδα", + "error.page.changeStatus.toDraft.invalid": "Δεν είναι δυνατή η μετατροπή της σελίδας \"{slug}\" σε προσχέδιο", + "error.page.changeTemplate.invalid": "Δεν είναι δυνατή η αλλαγή προτύπου για τη σελίδα \"{slug}\"", + "error.page.changeTemplate.permission": "Δεν επιτρέπεται να αλλάξετε το πρότυπο για τη σελίδα \"{slug}\"", + "error.page.changeTitle.empty": "Ο τίτλος δεν μπορεί να είναι κενός", + "error.page.changeTitle.permission": "Δεν επιτρέπεται να αλλάξετε τον τίτλο για τη σελίδα \"{slug}\"", + "error.page.create.permission": "Δεν επιτρέπεται να δημιουργήσετε τη σελίδα \"{slug}\"", + "error.page.delete": "Δεν είναι δυνατή η διαγραφή της σελίδας \"{slug}\"", + "error.page.delete.confirm": "Παρακαλώ εισάγετε τον τίτλο της σελίδας για επιβεβαίωση", + "error.page.delete.hasChildren": "Δεν είναι δυνατή η διαγραφή της σελίδας καθώς περιέχει υποσελίδες", + "error.page.delete.permission": "Δεν επιτρέπεται η διαγραφή της σελίδας \"{slug}\"", + "error.page.draft.duplicate": "Υπάρχει ήδη ένα προσχέδιο σελίδας με την διεύθυνση URL \"{slug}\"", + "error.page.duplicate": "Υπάρχει ήδη μια σελίδα με την διεύθυνση URL \"{slug}\"", + "error.page.duplicate.permission": "You are not allowed to duplicate \"{slug}\"", + "error.page.notFound": "Δεν ήταν δυνατή η εύρεση της σελίδας \"{slug}\"", + "error.page.num.invalid": "Παρακαλώ εισάγετε έναν έγκυρο αριθμό ταξινόμησης. Οι αριθμοί δεν μπορεί να είναι αρνητικοί.", + "error.page.slug.invalid": "Please enter a valid URL appendix", + "error.page.slug.maxlength": "Slug length must be less than \"{length}\" characters", + "error.page.sort.permission": "Δεν είναι δυνατή η ταξινόμηση της σελίδας \"{slug}\"", + "error.page.status.invalid": "Ορίστε μια έγκυρη κατάσταση σελίδας", + "error.page.undefined": "Δεν ήταν δυνατή η εύρεση της σελίδας", + "error.page.update.permission": "Δεν επιτρέπεται η ενημέρωση της σελίδας \"{slug}\"", + + "error.section.files.max.plural": "Δεν πρέπει να προσθέσετε περισσότερα από {max} αρχεία στην ενότητα \"{section}\"", + "error.section.files.max.singular": "Δεν πρέπει να προσθέσετε περισσότερα από ένα αρχεία στην ενότητα \"{section}\"", + "error.section.files.min.plural": "The \"{section}\" section requires at least {min} files", + "error.section.files.min.singular": "The \"{section}\" section requires at least one file", + + "error.section.pages.max.plural": "Δεν μπορείτε να προσθέσετε περισσότερες από {max} σελίδες στην ενότητα \"{section}\"", + "error.section.pages.max.singular": "Δεν μπορείτε να προσθέσετε περισσότερες από μία σελίδες στην ενότητα \"{section}\"", + "error.section.pages.min.plural": "The \"{section}\" section requires at least {min} pages", + "error.section.pages.min.singular": "The \"{section}\" section requires at least one page", + + "error.section.notLoaded": "Δεν ήταν δυνατή η φόρτωση της ενότητας \"{name}\"", + "error.section.type.invalid": "Ο τύπος ενότητας \"{type}\" δεν είναι έγκυρος", + + "error.site.changeTitle.empty": "Ο τίτλος δεν μπορεί να είναι κενός", + "error.site.changeTitle.permission": "Δεν επιτρέπεται να αλλάξετε τον τίτλο του ιστότοπου", + "error.site.update.permission": "Δεν επιτρέπεται η ενημέρωση του ιστότοπου", + + "error.template.default.notFound": "Το προεπιλεγμένο πρότυπο δεν υπάρχει", + + "error.unexpected": "An unexpected error occurred! Enable debug mode for more info: https://getkirby.com/docs/reference/system/options/debug", + + "error.user.changeEmail.permission": "Δεν επιτρέπεται να αλλάξετε τη διεύθινση ηλεκτρονικού ταχυδρομείου για τον χρήστη \"{name}\"", + "error.user.changeLanguage.permission": "Δεν επιτρέπεται να αλλάξετε τη γλώσσα για τον χρήστη \"{name}\"", + "error.user.changeName.permission": "Δεν επιτρέπεται να αλλάξετε το όνομα του χρήστη \"{name}", + "error.user.changePassword.permission": "Δεν επιτρέπεται να αλλάξετε τον κωδικό πρόσβασης για τον χρήστη \"{name}\"", + "error.user.changeRole.lastAdmin": "Ο ρόλος του τελευταίου διαχειριστή δεν μπορεί να αλλάξει", + "error.user.changeRole.permission": "Δεν επιτρέπεται να αλλάξετε το ρόλο του χρήστη \"{name}\"", + "error.user.changeRole.toAdmin": "You are not allowed to promote someone to the admin role", + "error.user.create.permission": "Δεν επιτρέπεται η δημιουργία αυτού του χρήστη", + "error.user.delete": "\u039f \u03c7\u03c1\u03ae\u03c3\u03c4\u03b7\u03c2 \u03b4\u03b5\u03bd \u03bc\u03c0\u03bf\u03c1\u03bf\u03cd\u03c3\u03b5 \u03bd\u03b1 \u03b4\u03b9\u03b1\u03b3\u03c1\u03b1\u03c6\u03b5\u03af", + "error.user.delete.lastAdmin": "Δεν είναι δυνατή η διαγραφή του τελευταίου διαχειριστή", + "error.user.delete.lastUser": "Δεν είναι δυνατή η διαγραφή του τελευταίου χρήστη", + "error.user.delete.permission": "Δεν επιτρέπεται να διαγράψετ τον χρήστη \"{name}\"", + "error.user.duplicate": "Ένας χρήστης με τη διεύθυνση ηλεκτρονικού ταχυδρομείου \"{email}\" υπάρχει ήδη", + "error.user.email.invalid": "Παρακαλώ εισάγετε μια έγκυρη διεύθυνση ηλεκτρονικού ταχυδρομείου", + "error.user.language.invalid": "Παρακαλώ εισαγάγετε μια έγκυρη γλώσσα", + "error.user.notFound": "Δεν είναι δυνατή η εύρεση του χρήστη \"{name}\"", + "error.user.password.excessive": "Please enter a valid password. Passwords must not be longer than 1000 characters.", + "error.user.password.invalid": "Παρακαλώ εισάγετε έναν έγκυρο κωδικό πρόσβασης. Οι κωδικοί πρόσβασης πρέπει να έχουν μήκος τουλάχιστον 8 χαρακτήρων.", + "error.user.password.notSame": "\u03a0\u03b1\u03c1\u03b1\u03ba\u03b1\u03bb\u03bf\u03cd\u03bc\u03b5 \u03b5\u03c0\u03b9\u03b2\u03b5\u03b2\u03b1\u03b9\u03ce\u03c3\u03c4\u03b5 \u03c4\u03bf\u03bd \u039a\u03c9\u03b4\u03b9\u03ba\u03cc \u03a0\u03c1\u03cc\u03c3\u03b2\u03b1\u03c3\u03b7\u03c2", + "error.user.password.undefined": "Ο χρήστης δεν έχει κωδικό πρόσβασης", + "error.user.password.wrong": "Wrong password", + "error.user.role.invalid": "Παρακαλώ εισαγάγετε έναν έγκυρο ρόλο", + "error.user.undefined": "Δεν είναι δυνατή η εύρεση του χρήστη", + "error.user.update.permission": "Δεν επιτρέπεται η ενημέρωση του χρήστη \"{name}\"", + + "error.validation.accepted": "Παρακαλώ επιβεβαιώστε", + "error.validation.alpha": "Παρακαλώ εισάγετε μόνο χαρακτήρες μεταξύ των a-z", + "error.validation.alphanum": "Παρακαλώ εισάγετε μόνο χαρακτήρες μεταξύ των a-z ή αριθμούς απο το 0 έως το 9", + "error.validation.between": "Παρακαλώ εισάγετε μια τιμή μεταξύ \"{min}\" και \"{max}\"", + "error.validation.boolean": "Παρακαλώ επιβεβαιώστε ή αρνηθείτε", + "error.validation.contains": "Παρακαλώ καταχωρίστε μια τιμή που περιέχει \"{needle}\"", + "error.validation.date": "Παρακαλώ εισάγετε μία έγκυρη ημερομηνία", + "error.validation.date.after": "Please enter a date after {date}", + "error.validation.date.before": "Please enter a date before {date}", + "error.validation.date.between": "Please enter a date between {min} and {max}", + "error.validation.denied": "Παρακαλώ αρνηθείτε", + "error.validation.different": "Η τιμή δεν μπορεί να είναι \"{other}\"", + "error.validation.email": "Παρακαλώ εισάγετε μια έγκυρη διεύθυνση ηλεκτρονικού ταχυδρομείου", + "error.validation.endswith": "Η τιμή πρέπει να τελειώνει με \"{end}\"", + "error.validation.filename": "Παρακαλώ εισάγετε ένα έγκυρο όνομα αρχείου", + "error.validation.in": "Παρακαλώ εισάγετε ένα από τα παρακάτω: ({in})", + "error.validation.integer": "Παρακαλώ εισάγετε έναν έγκυρο ακέραιο αριθμό", + "error.validation.ip": "Παρακαλώ εισάγετε μια έγκυρη διεύθυνση IP", + "error.validation.less": "Παρακαλώ εισάγετε μια τιμή μικρότερη από {max}", + "error.validation.match": "Η τιμή δεν ταιριάζει με το αναμενόμενο πρότυπο", + "error.validation.max": "Παρακαλώ εισάγετε μια τιμή ίση ή μικρότερη από {max}", + "error.validation.maxlength": "Παρακαλώ εισάγετε μια μικρότερη τιμή. (max. {max} χαρακτήρες)", + "error.validation.maxwords": "Παρακαλώ εισάγετε το πολύ {max} λέξεις", + "error.validation.min": "Παρακαλώ εισάγετε μια τιμή ίση ή μεγαλύτερη από {min}", + "error.validation.minlength": "Παρακαλώ εισάγετε μεγαλύτερη τιμή. (τουλάχιστον {min} χαρακτήρες)", + "error.validation.minwords": "Παρακαλώ εισάγετε τουλάχιστον {min} λέξεις", + "error.validation.more": "Παρακαλώ εισάγετε τουλάχιστον {min} λέξεις", + "error.validation.notcontains": "Παρακαλώ εισάγετε μια τιμή που δεν περιέχει \"{needle}\"", + "error.validation.notin": "Παρακαλώ μην εισάγετε κανένα από τα παρακάτω: ({notIn})", + "error.validation.option": "Παρακαλώ κάντε μια έγκυρη επιλογή", + "error.validation.num": "Παρακαλώ εισάγετε έναν έγκυρο αριθμό", + "error.validation.required": "Παρακαλώ εισάγετε κάτι", + "error.validation.same": "Παρακαλώ εισάγετε \"{other}\"", + "error.validation.size": "Το μέγεθος της τιμής πρέπει να είναι \"{size}\"", + "error.validation.startswith": "Η τιμή πρέπει να αρχίζει με \"{start}\"", + "error.validation.time": "Παρακαλώ εισάγετε μια έγκυρη ώρα", + "error.validation.time.after": "Please enter a time after {time}", + "error.validation.time.before": "Please enter a time before {time}", + "error.validation.time.between": "Please enter a time between {min} and {max}", + "error.validation.url": "Παρακαλώ εισάγετε μια έγκυρη διεύθυνση URL", + + "expand": "Expand", + "expand.all": "Expand All", + + "field.required": "The field is required", + "field.blocks.changeType": "Change type", + "field.blocks.code.name": "Κώδικας", + "field.blocks.code.language": "Γλώσσα", + "field.blocks.code.placeholder": "Your code …", + "field.blocks.delete.confirm": "Do you really want to delete this block?", + "field.blocks.delete.confirm.all": "Do you really want to delete all blocks?", + "field.blocks.delete.confirm.selected": "Do you really want to delete the selected blocks?", + "field.blocks.empty": "No blocks yet", + "field.blocks.fieldsets.label": "Please select a block type …", + "field.blocks.fieldsets.paste": "Press {{ shortcut }} to paste/import blocks from your clipboard", + "field.blocks.gallery.name": "Gallery", + "field.blocks.gallery.images.empty": "No images yet", + "field.blocks.gallery.images.label": "Images", + "field.blocks.heading.level": "Level", + "field.blocks.heading.name": "Heading", + "field.blocks.heading.text": "Text", + "field.blocks.heading.placeholder": "Heading …", + "field.blocks.image.alt": "Alternative text", + "field.blocks.image.caption": "Caption", + "field.blocks.image.crop": "Crop", + "field.blocks.image.link": "Σύνδεσμος", + "field.blocks.image.location": "Location", + "field.blocks.image.name": "Εικόνα", + "field.blocks.image.placeholder": "Select an image", + "field.blocks.image.ratio": "Ratio", + "field.blocks.image.url": "Image URL", + "field.blocks.line.name": "Line", + "field.blocks.list.name": "List", + "field.blocks.markdown.name": "Markdown", + "field.blocks.markdown.label": "Text", + "field.blocks.markdown.placeholder": "Markdown …", + "field.blocks.quote.name": "Quote", + "field.blocks.quote.text.label": "Text", + "field.blocks.quote.text.placeholder": "Quote …", + "field.blocks.quote.citation.label": "Citation", + "field.blocks.quote.citation.placeholder": "by …", + "field.blocks.text.name": "Text", + "field.blocks.text.placeholder": "Text …", + "field.blocks.video.caption": "Caption", + "field.blocks.video.name": "Video", + "field.blocks.video.placeholder": "Enter a video URL", + "field.blocks.video.url.label": "Video-URL", + "field.blocks.video.url.placeholder": "https://youtube.com/?v=", + + "field.files.empty": "Δεν έχουν επιλεγεί αρχεία ακόμα", + + "field.layout.delete": "Delete layout", + "field.layout.delete.confirm": "Do you really want to delete this layout?", + "field.layout.empty": "No rows yet", + "field.layout.select": "Select a layout", + + "field.pages.empty": "Δεν έχουν επιλεγεί ακόμη σελίδες", + "field.structure.delete.confirm": "\u0395\u03af\u03c3\u03c4\u03b5 \u03c3\u03af\u03b3\u03bf\u03c5\u03c1\u03bf\u03c2 \u03cc\u03c4\u03b9 \u03b8\u03ad\u03bb\u03b5\u03c4\u03b5 \u03bd\u03b1 \u03b4\u03b9\u03b1\u03b3\u03c1\u03ac\u03c8\u03b5\u03c4\u03b5 \u03b1\u03c5\u03c4\u03ae\u03bd \u03c4\u03b7\u03bd \u03ba\u03b1\u03c4\u03b1\u03c7\u03ce\u03c1\u03b9\u03c3\u03b7;", + "field.structure.empty": "\u0394\u03b5\u03bd \u03c5\u03c0\u03ac\u03c1\u03c7\u03bf\u03c5\u03bd \u03b1\u03ba\u03cc\u03bc\u03b7 \u03ba\u03b1\u03c4\u03b1\u03c7\u03c9\u03c1\u03af\u03c3\u03b5\u03b9\u03c2.", + "field.users.empty": "Δεν έχουν επιλεγεί ακόμη χρήστες", + + "file.blueprint": "This file has no blueprint yet. You can define the setup in /site/blueprints/files/{blueprint}.yml", + "file.delete.confirm": "\u0398\u03ad\u03bb\u03b5\u03c4\u03b5 \u03c3\u03af\u03b3\u03bf\u03c5\u03c1\u03b1 \u03bd\u03b1 \u03b4\u03b9\u03b1\u03b3\u03c1\u03ac\u03c8\u03b5\u03c4\u03b5 \u03b1\u03c5\u03c4\u03cc \u03c4\u03bf \u03b1\u03c1\u03c7\u03b5\u03af\u03bf;", + "file.sort": "Change position", + + "files": "Αρχεία", + "files.empty": "Δεν υπάρχουν ακόμα αρχεία", + + "hide": "Hide", + "hour": "Ώρα", + "import": "Import", + "info": "Info", + "insert": "\u0395\u03b9\u03c3\u03b1\u03b3\u03c9\u03b3\u03ae", + "insert.after": "Insert after", + "insert.before": "Insert before", + "install": "Εγκατάσταση", + + "installation": "Εγκατάσταση", + "installation.completed": "Ο πίνακας ελέγχου έχει εγκατασταθεί", + "installation.disabled": "Η εγκατάσταση του πίνακα ελέγχου είναι απενεργοποιημένη για δημόσιους διακομιστές από προεπιλογή. Εκτελέστε την εγκατάσταση σε ένα τοπικό μηχάνημα ή ενεργοποιήστε την με την επιλογή panel.install.", + "installation.issues.accounts": "\u039f \u03c6\u03ac\u03ba\u03b5\u03bb\u03bf\u03c2 \/site\/accounts \u03b4\u03b5\u03bd \u03b5\u03af\u03bd\u03b1\u03b9 \u03b5\u03b3\u03b3\u03c1\u03ac\u03c8\u03b9\u03bc\u03bf\u03c2", + "installation.issues.content": "\u039f \u03c6\u03ac\u03ba\u03b5\u03bb\u03bf\u03c2 content \u03ba\u03b1\u03b9 \u03cc\u03bb\u03bf\u03b9 \u03bf\u03b9 \u03c5\u03c0\u03bf\u03c6\u03ac\u03ba\u03b5\u03bb\u03bf\u03b9 \u03c0\u03c1\u03ad\u03c0\u03b5\u03b9 \u03bd\u03b1 \u03b5\u03af\u03bd\u03b1\u03b9 \u03b5\u03b3\u03b3\u03c1\u03ac\u03c8\u03b9\u03bc\u03bf\u03b9.", + "installation.issues.curl": "Απαιτείται η επέκταση CURL", + "installation.issues.headline": "Ο πίνακας ελέγχου δεν μπορεί να εγκατασταθεί", + "installation.issues.mbstring": "Απαιτείται η επέκταση MB String ", + "installation.issues.media": "Ο φάκελος /media δεν υπάρχει ή δεν είναι εγγράψιμος", + "installation.issues.php": "Βεβαιωθείτε ότι χρησιμοποιήτε PHP 7+", + "installation.issues.server": "To Kirby απαιτεί Apache, Nginx ή Caddy", + "installation.issues.sessions": "Ο φάκελος /site/sessions δεν υπάρχει ή δεν είναι εγγράψιμος", + + "language": "\u0393\u03bb\u03ce\u03c3\u03c3\u03b1", + "language.code": "Κώδικας", + "language.convert": "Χρήση ως προεπιλογή", + "language.convert.confirm": "

Θέλετε πραγματικά να μετατρέψετε τη {name} στην προεπιλεγμένη γλώσσα; Αυτό δεν μπορεί να ανακληθεί.

Αν το {name} χει μη μεταφρασμένο περιεχόμενο, δεν θα υπάρχει πλέον έγκυρη εναλλακτική λύση και τμήματα του ιστότοπού σας ενδέχεται να είναι κενά.

", + "language.create": "Προσθέστε μια νέα γλώσσα", + "language.delete.confirm": "Θέλετε πραγματικά να διαγράψετε τη γλώσσα {name} συμπεριλαμβανομένων όλων των μεταφράσεων; Αυτό δεν μπορεί να αναιρεθεί!", + "language.deleted": "Η γλώσσα έχει διαγραφεί", + "language.direction": "Κατεύθυνση ανάγνωσης", + "language.direction.ltr": "Αριστερά προς τα δεξιά", + "language.direction.rtl": "Δεξιά προς τα αριστερά", + "language.locale": "Συμβολοσειρά τοπικής γλώσσας PHP", + "language.locale.warning": "You are using a custom locale set up. Please modify it in the language file in /site/languages", + "language.name": "Ονομασία", + "language.updated": "Η γλώσσα έχει ενημερωθεί", + + "languages": "Γλώσσες", + "languages.default": "Προεπιλεγμένη γλώσσα", + "languages.empty": "Δεν υπάρχουν ακόμη γλώσσες", + "languages.secondary": "Δευτερεύουσες γλώσσες", + "languages.secondary.empty": "Δεν υπάρχουν ακόμα δευτερεύουσες γλώσσες", + + "license": "\u0386\u03b4\u03b5\u03b9\u03b1 \u03a7\u03c1\u03ae\u03c3\u03b7\u03c2 \u03c4\u03bf\u03c5 Kirby", + "license.buy": "Αγοράστε μια άδεια", + "license.register": "Εγγραφή", + "license.manage": "Manage your licenses", + "license.register.help": "Έχετε λάβει τον κωδικό άδειας χρήσης μετά την αγορά μέσω ηλεκτρονικού ταχυδρομείου. Παρακαλώ αντιγράψτε και επικολλήστε τον για να εγγραφείτε.", + "license.register.label": "Παρακαλώ εισαγάγετε τον κωδικό άδειας χρήσης", + "license.register.success": "Σας ευχαριστούμε για την υποστήριξη του Kirby", + "license.unregistered": "Αυτό είναι ένα μη καταχωρημένο demo του Kirby", + "license.unregistered.label": "Unregistered", + + "link": "\u03a3\u03cd\u03bd\u03b4\u03b5\u03c3\u03bc\u03bf\u03c2", + "link.text": "\u039a\u03b5\u03af\u03bc\u03b5\u03bd\u03bf \u03c3\u03c5\u03bd\u03b4\u03ad\u03c3\u03bc\u03bf\u03c5", + + "loading": "Φόρτωση", + + "lock.unsaved": "Unsaved changes", + "lock.unsaved.empty": "There are no more unsaved changes", + "lock.isLocked": "Unsaved changes by {email}", + "lock.file.isLocked": "The file is currently being edited by {email} and cannot be changed.", + "lock.page.isLocked": "The page is currently being edited by {email} and cannot be changed.", + "lock.unlock": "Unlock", + "lock.isUnlocked": "Your unsaved changes have been overwritten by another user. You can download your changes to merge them manually.", + + "login": "Σύνδεση", + "login.code.label.login": "Login code", + "login.code.label.password-reset": "Password reset code", + "login.code.placeholder.email": "000 000", + "login.code.text.email": "If your email address is registered, the requested code was sent via email.", + "login.email.login.body": "Hi {user.nameOrEmail},\n\nYou recently requested a login code for the Panel of {site}.\nThe following login code will be valid for {timeout} minutes:\n\n{code}\n\nIf you did not request a login code, please ignore this email or contact your administrator if you have questions.\nFor security, please DO NOT forward this email.", + "login.email.login.subject": "Your login code", + "login.email.password-reset.body": "Hi {user.nameOrEmail},\n\nYou recently requested a password reset code for the Panel of {site}.\nThe following password reset code will be valid for {timeout} minutes:\n\n{code}\n\nIf you did not request a password reset code, please ignore this email or contact your administrator if you have questions.\nFor security, please DO NOT forward this email.", + "login.email.password-reset.subject": "Your password reset code", + "login.remember": "Κρατήστε με συνδεδεμένο", + "login.reset": "Reset password", + "login.toggleText.code.email": "Login via email", + "login.toggleText.code.email-password": "Login with password", + "login.toggleText.password-reset.email": "Forgot your password?", + "login.toggleText.password-reset.email-password": "← Back to login", + + "logout": "\u0391\u03c0\u03bf\u03c3\u03cd\u03bd\u03b4\u03b5\u03c3\u03b7", + + "menu": "Μενού", + "meridiem": "Π.Μ./Μ.Μ", + "mime": "Τύπος πολυμέσων", + "minutes": "Λεπτά", + + "month": "Μήνας", + "months.april": "\u0391\u03c0\u03c1\u03af\u03bb\u03b9\u03bf\u03c2", + "months.august": "\u0391\u03cd\u03b3\u03bf\u03c5\u03c3\u03c4\u03bf\u03c2", + "months.december": "\u0394\u03b5\u03ba\u03ad\u03bc\u03b2\u03c1\u03b9\u03bf\u03c2", + "months.february": "Φεβρουάριος", + "months.january": "\u0399\u03b1\u03bd\u03bf\u03c5\u03ac\u03c1\u03b9\u03bf\u03c2", + "months.july": "\u0399\u03bf\u03cd\u03bb\u03b9\u03bf\u03c2", + "months.june": "\u0399\u03bf\u03cd\u03bd\u03b9\u03bf\u03c2", + "months.march": "\u039c\u03ac\u03c1\u03c4\u03b9\u03bf\u03c2", + "months.may": "\u039c\u03ac\u03b9\u03bf\u03c2", + "months.november": "\u039d\u03bf\u03ad\u03bc\u03b2\u03c1\u03b9\u03bf\u03c2", + "months.october": "\u039f\u03ba\u03c4\u03ce\u03b2\u03c1\u03b9\u03bf\u03c2", + "months.september": "\u03a3\u03b5\u03c0\u03c4\u03ad\u03bc\u03b2\u03c1\u03b9\u03bf\u03c2", + + "more": "Περισσότερα", + "name": "Ονομασία", + "next": "Επόμενο", + "no": "no", + "off": "off", + "on": "on", + "open": "Άνοιγμα", + "open.newWindow": "Open in new window", + "options": "Eπιλογές", + "options.none": "No options", + + "orientation": "Προσανατολισμός", + "orientation.landscape": "Οριζόντιος", + "orientation.portrait": "Κάθετος", + "orientation.square": "Τετράγωνος", + + "page.blueprint": "This page has no blueprint yet. You can define the setup in /site/blueprints/pages/{blueprint}.yml", + "page.changeSlug": "\u0391\u03bb\u03bb\u03b1\u03b3\u03ae URL", + "page.changeSlug.fromTitle": "\u0394\u03b7\u03bc\u03b9\u03bf\u03c5\u03c1\u03b3\u03af\u03b1 \u03b1\u03c0\u03cc \u03c4\u03bf\u03bd \u03c4\u03af\u03c4\u03bb\u03bf", + "page.changeStatus": "Αλλαγή κατάστασης", + "page.changeStatus.position": "Επιλέξτε μια θέση", + "page.changeStatus.select": "Επιλέξτε μια νέα κατάσταση", + "page.changeTemplate": "Αλλαγή προτύπου", + "page.delete.confirm": "\u0398\u03ad\u03bb\u03b5\u03c4\u03b5 \u03c3\u03af\u03b3\u03bf\u03c5\u03c1\u03b1 \u03bd\u03b1 \u03b4\u03b9\u03b1\u03b3\u03c1\u03ac\u03c8\u03b5\u03c4\u03b5 \u03b1\u03c5\u03c4\u03ae\u03bd \u03c4\u03b7 \u03c3\u03b5\u03bb\u03af\u03b4\u03b1;", + "page.delete.confirm.subpages": "Αυτή η σελίδα έχει υποσελίδες.
Όλες οι υποσελίδες θα διαγραφούν επίσης.", + "page.delete.confirm.title": "Εισάγετε τον τίτλο της σελίδας για επιβεβαίωση", + "page.draft.create": "Δημιουργία προσχεδίου", + "page.duplicate.appendix": "Αντιγραφή", + "page.duplicate.files": "Copy files", + "page.duplicate.pages": "Copy pages", + "page.sort": "Change position", + "page.status": "Kατάσταση", + "page.status.draft": "Προσχέδιο", + "page.status.draft.description": "The page is in draft mode and only visible for logged in editors or via secret link", + "page.status.listed": "Δημοσιευμένο", + "page.status.listed.description": "Αυτή η σελίδα είναι δημοσιευμένη για οποιονδήποτε", + "page.status.unlisted": "Μη καταχωρημένο", + "page.status.unlisted.description": "Η σελίδα είναι προσβάσιμη μόνο μέσω της διεύθυνσης URL", + + "pages": "Σελίδες", + "pages.empty": "Δεν υπάρχουν ακόμα σελίδες", + "pages.status.draft": "Προσχέδια", + "pages.status.listed": "Δημοσιευμένο", + "pages.status.unlisted": "Μη καταχωρημένο", + + "pagination.page": "Σελίδα", + + "password": "\u039a\u03c9\u03b4\u03b9\u03ba\u03cc\u03c2 \u03a0\u03c1\u03cc\u03c3\u03b2\u03b1\u03c3\u03b7\u03c2", + "paste": "Paste", + "paste.after": "Paste after", + "pixel": "Εικονοστοιχέιο", + "plugins": "Plugins", + "prev": "Προηγούμενο", + "preview": "Preview", + "remove": "Αφαίρεση", + "rename": "Μετονομασία", + "replace": "\u0391\u03bd\u03c4\u03b9\u03ba\u03b1\u03c4\u03ac\u03c3\u03c4\u03b1\u03c3\u03b7", + "retry": "\u0395\u03c0\u03b1\u03bd\u03ac\u03bb\u03b7\u03c8\u03b7", + "revert": "\u0391\u03b3\u03bd\u03cc\u03b7\u03c3\u03b7", + "revert.confirm": "Do you really want to delete all unsaved changes?", + + "role": "\u03a1\u03cc\u03bb\u03bf\u03c2", + "role.admin.description": "The admin has all rights", + "role.admin.title": "Admin", + "role.all": "Όλα", + "role.empty": "Δεν υπάρχουν χρήστες με αυτόν τον ρόλο", + "role.description.placeholder": "Χωρίς περιγραφή", + "role.nobody.description": "This is a fallback role without any permissions", + "role.nobody.title": "Nobody", + + "save": "\u0391\u03c0\u03bf\u03b8\u03ae\u03ba\u03b5\u03c5\u03c3\u03b7", + "search": "Αναζήτηση", + "search.min": "Enter {min} characters to search", + "search.all": "Show all", + "search.results.none": "No results", + + "section.required": "The section is required", + + "security": "Security", + "select": "Επιλογή", + "server": "Server", + "settings": "Ρυθμίσεις", + "show": "Show", + "site.blueprint": "The site has no blueprint yet. You can define the setup in /site/blueprints/site.yml", + "size": "Μέγεθος", + "slug": "\u0395\u03c0\u03af\u03b8\u03b5\u03bc\u03b1 URL", + "sort": "Ταξινόμηση", + + "stats.empty": "No reports", + "system.issues.content": "The content folder seems to be exposed", + "system.issues.debug": "Debugging must be turned off in production", + "system.issues.git": "The .git folder seems to be exposed", + "system.issues.https": "We recommend HTTPS for all your sites", + "system.issues.kirby": "The kirby folder seems to be exposed", + "system.issues.site": "The site folder seems to be exposed", + + "title": "Τίτλος", + "template": "\u03a0\u03c1\u03cc\u03c4\u03c5\u03c0\u03bf", + "today": "Σήμερα", + + "toolbar.button.code": "Κώδικας", + "toolbar.button.bold": "\u0388\u03bd\u03c4\u03bf\u03bd\u03b7 \u03b3\u03c1\u03b1\u03c6\u03ae", + "toolbar.button.email": "Email", + "toolbar.button.headings": "Επικεφαλίδες", + "toolbar.button.heading.1": "Επικεφαλίδα 1", + "toolbar.button.heading.2": "Επικεφαλίδα 2", + "toolbar.button.heading.3": "Επικεφαλίδα 3", + "toolbar.button.heading.4": "Heading 4", + "toolbar.button.heading.5": "Heading 5", + "toolbar.button.heading.6": "Heading 6", + "toolbar.button.italic": "\u03a0\u03bb\u03ac\u03b3\u03b9\u03b1 \u03b3\u03c1\u03b1\u03c6\u03ae", + "toolbar.button.file": "Αρχείο", + "toolbar.button.file.select": "Select a file", + "toolbar.button.file.upload": "Upload a file", + "toolbar.button.link": "\u03a3\u03cd\u03bd\u03b4\u03b5\u03c3\u03bc\u03bf\u03c2", + "toolbar.button.paragraph": "Paragraph", + "toolbar.button.strike": "Strike-through", + "toolbar.button.ol": "Ταξινομημένη λίστα", + "toolbar.button.underline": "Underline", + "toolbar.button.ul": "Λίστα κουκκίδων", + + "translation.author": "Ομάδα Kirby", + "translation.direction": "ltr", + "translation.name": "\u0395\u03bb\u03bb\u03b7\u03bd\u03b9\u03ba\u03ac", + "translation.locale": "el_GR", + + "upload": "Μεταφόρτωση", + "upload.error.cantMove": "The uploaded file could not be moved", + "upload.error.cantWrite": "Failed to write file to disk", + "upload.error.default": "The file could not be uploaded", + "upload.error.extension": "File upload stopped by extension", + "upload.error.formSize": "The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the form", + "upload.error.iniPostSize": "The uploaded file exceeds the post_max_size directive in php.ini", + "upload.error.iniSize": "The uploaded file exceeds the upload_max_filesize directive in php.ini", + "upload.error.noFile": "No file was uploaded", + "upload.error.noFiles": "No files were uploaded", + "upload.error.partial": "The uploaded file was only partially uploaded", + "upload.error.tmpDir": "Missing a temporary folder", + "upload.errors": "Σφάλμα", + "upload.progress": "Μεταφόρτωση...", + + "url": "Διεύθινση url", + "url.placeholder": "https://example.com", + + "user": "Χρήστης", + "user.blueprint": "You can define additional sections and form fields for this user role in /site/blueprints/users/{blueprint}.yml", + "user.changeEmail": "Αλλαγή διεύθινσης ηλεκτρονικού ταχυδρομείου", + "user.changeLanguage": "Αλλαγή γλώσσας", + "user.changeName": "Μετονομασία χρήστη", + "user.changePassword": "Αλλαγή κωδικού πρόσβασης", + "user.changePassword.new": "Νέος Κωδικός Πρόσβασης", + "user.changePassword.new.confirm": "Επαληθεύση κωδικού πρόσβασης", + "user.changeRole": "Αλλαγή ρόλου", + "user.changeRole.select": "Επιλογή νέου ρόλου", + "user.create": "Προσθήκη νέου χρήστη", + "user.delete": "Διαγραφή χρήστη", + "user.delete.confirm": "\u0398\u03ad\u03bb\u03b5\u03c4\u03b5 \u03c3\u03af\u03b3\u03bf\u03c5\u03c1\u03b1 \u03bd\u03b1 \u03b4\u03b9\u03b1\u03b3\u03c1\u03ac\u03c8\u03b5\u03c4\u03b5 \u03b1\u03c5\u03c4\u03cc\u03bd \u03c4\u03bf\u03bd \u03c7\u03c1\u03ae\u03c3\u03c4\u03b7;", + + "users": "Χρήστες", + + "version": "\u0388\u03ba\u03b4\u03bf\u03c3\u03b7 Kirby", + + "view.account": "\u039f \u03bb\u03bf\u03b3\u03b1\u03c1\u03b9\u03b1\u03c3\u03bc\u03cc\u03c2 \u03c3\u03b1\u03c2", + "view.installation": "\u0395\u03b3\u03ba\u03b1\u03c4\u03ac\u03c3\u03c4\u03b1\u03c3\u03b7", + "view.languages": "Γλώσσες", + "view.resetPassword": "Reset password", + "view.site": "Iστοσελίδα", + "view.system": "System", + "view.users": "\u03a7\u03c1\u03ae\u03c3\u03c4\u03b5\u03c2", + + "welcome": "Καλώς ήρθατε", + "year": "Έτος", + "yes": "yes" } diff --git a/kirby/i18n/translations/en.json b/kirby/i18n/translations/en.json index d43474d..3c93a29 100644 --- a/kirby/i18n/translations/en.json +++ b/kirby/i18n/translations/en.json @@ -1,733 +1,577 @@ { - "account.changeName": "Change your name", - "account.delete": "Delete your account", - "account.delete.confirm": "Do you really want to delete your account? You will be logged out immediately. Your account cannot be recovered.", - - "activate": "Activate", - "add": "Add", - "alpha": "Alpha", - "author": "Author", - "avatar": "Profile picture", - "back": "Back", - "cancel": "Cancel", - "change": "Change", - "close": "Close", - "changes": "Changes", - "confirm": "Ok", - "collapse": "Collapse", - "collapse.all": "Collapse All", - "color": "Color", - "coordinates": "Coordinates", - "copy": "Copy", - "copy.all": "Copy all", - "copy.success": "{count} copied!", - "create": "Create", - "custom": "Custom", - - "date": "Date", - "date.select": "Select a date", - - "day": "Day", - "days.fri": "Fri", - "days.mon": "Mon", - "days.sat": "Sat", - "days.sun": "Sun", - "days.thu": "Thu", - "days.tue": "Tue", - "days.wed": "Wed", - - "debugging": "Debugging", - - "delete": "Delete", - "delete.all": "Delete all", - - "dialog.fields.empty": "This dialog has no fields", - "dialog.files.empty": "No files to select", - "dialog.pages.empty": "No pages to select", - "dialog.text.empty": "This dialog does not define any text", - "dialog.users.empty": "No users to select", - - "dimensions": "Dimensions", - "disable": "Disable", - "disabled": "Disabled", - "discard": "Discard", - - "drawer.fields.empty": "This drawer has no fields", - - "domain": "Domain", - "download": "Download", - "duplicate": "Duplicate", - - "edit": "Edit", - - "email": "Email", - "email.placeholder": "mail@example.com", - - "enter": "Enter", - "entries": "Entries", - "entry": "Entry", - - "environment": "Environment", - - "error": "Error", - "error.access.code": "Invalid code", - "error.access.login": "Invalid login", - "error.access.panel": "You are not allowed to access the panel", - "error.access.view": "You are not allowed to access this part of the panel", - - "error.avatar.create.fail": "The profile picture could not be uploaded", - "error.avatar.delete.fail": "The profile picture could not be deleted", - "error.avatar.dimensions.invalid": "Please keep the width and height of the profile picture under 3000 pixels", - "error.avatar.mime.forbidden": "The profile picture must be JPEG or PNG files", - - "error.blueprint.notFound": "The blueprint \"{name}\" could not be loaded", - - "error.blocks.max.plural": "You must not add more than {max} blocks", - "error.blocks.max.singular": "You must not add more than one block", - "error.blocks.min.plural": "You must add at least {min} blocks", - "error.blocks.min.singular": "You must add at least one block", - "error.blocks.validation": "There's an error on the \"{field}\" field in block {index} using the \"{fieldset}\" block type", - - "error.cache.type.invalid": "Invalid cache type \"{type}\"", - - "error.email.preset.notFound": "The email preset \"{name}\" cannot be found", - - "error.field.converter.invalid": "Invalid converter \"{converter}\"", - "error.field.type.missing": "Field \"{ name }\": The field type \"{ type }\" does not exist", - - "error.file.changeName.empty": "The name must not be empty", - "error.file.changeName.permission": "You are not allowed to change the name of \"{filename}\"", - "error.file.changeTemplate.invalid": "The template for the file \"{id}\" cannot be changed to \"{template}\" (valid: \"{blueprints}\")", - "error.file.changeTemplate.permission": "You are not allowed to change the template for the file \"{id}\"", - - "error.file.duplicate": "A file with the name \"{filename}\" already exists", - "error.file.extension.forbidden": "The extension \"{extension}\" is not allowed", - "error.file.extension.invalid": "Invalid extension: {extension}", - "error.file.extension.missing": "The extensions for \"{filename}\" is missing", - "error.file.maxheight": "The height of the image must not exceed {height} pixels", - "error.file.maxsize": "The file is too large", - "error.file.maxwidth": "The width of the image must not exceed {width} pixels", - "error.file.mime.differs": "The uploaded file must be of the same mime type \"{mime}\"", - "error.file.mime.forbidden": "The media type \"{mime}\" is not allowed", - "error.file.mime.invalid": "Invalid mime type: {mime}", - "error.file.mime.missing": "The media type for \"{filename}\" cannot be detected", - "error.file.minheight": "The height of the image must be at least {height} pixels", - "error.file.minsize": "The file is too small", - "error.file.minwidth": "The width of the image must be at least {width} pixels", - "error.file.name.unique": "The filename must be unique", - "error.file.name.missing": "The filename must not be empty", - "error.file.notFound": "The file \"{filename}\" cannot be found", - "error.file.orientation": "The orientation of the image must be \"{orientation}\"", - "error.file.type.forbidden": "You are not allowed to upload {type} files", - "error.file.type.invalid": "Invalid file type: {type}", - "error.file.undefined": "The file cannot be found", - - "error.form.incomplete": "Please fix all form errors…", - "error.form.notSaved": "The form could not be saved", - - "error.language.code": "Please enter a valid code for the language", - "error.language.create.permission": "You are not allowed to create a language", - "error.language.delete.permission": "You are not allowed to delete the language", - "error.language.duplicate": "The language already exists", - "error.language.name": "Please enter a valid name for the language", - "error.language.notFound": "The language could not be found", - "error.language.update.permission": "You are not allowed to update the language", - - "error.layout.validation.block": "There's an error on the \"{field}\" field in block {blockIndex} using the \"{fieldset}\" block type in layout {layoutIndex}", - "error.layout.validation.settings": "There's an error in layout {index} settings", - - "error.license.domain": "The domain for the license is missing", - "error.license.email": "Please enter a valid email address", - "error.license.format": "Please enter a valid license code", - "error.license.verification": "The license could not be verified", - - "error.login.totp.confirm.invalid": "Invalid code", - "error.login.totp.confirm.missing": "Please enter the current code", - - "error.object.validation": "There’s an error in the \"{label}\" field:\n{message}", - - "error.offline": "The Panel is currently offline", - - "error.page.changeSlug.permission": "You are not allowed to change the URL appendix for \"{slug}\"", - "error.page.changeSlug.reserved": "The path of top-level pages must not start with \"{path}\"", - "error.page.changeStatus.incomplete": "The page has errors and cannot be published", - "error.page.changeStatus.permission": "The status for this page cannot be changed", - "error.page.changeStatus.toDraft.invalid": "The page \"{slug}\" cannot be converted to a draft", - "error.page.changeTemplate.invalid": "The template for the page \"{slug}\" cannot be changed", - "error.page.changeTemplate.permission": "You are not allowed to change the template for \"{slug}\"", - "error.page.changeTitle.empty": "The title must not be empty", - "error.page.changeTitle.permission": "You are not allowed to change the title for \"{slug}\"", - "error.page.create.permission": "You are not allowed to create \"{slug}\"", - "error.page.delete": "The page \"{slug}\" cannot be deleted", - "error.page.delete.confirm": "Please enter the page title to confirm", - "error.page.delete.hasChildren": "The page has subpages and cannot be deleted", - "error.page.delete.permission": "You are not allowed to delete \"{slug}\"", - "error.page.draft.duplicate": "A page draft with the URL appendix \"{slug}\" already exists", - "error.page.duplicate": "A page with the URL appendix \"{slug}\" already exists", - "error.page.duplicate.permission": "You are not allowed to duplicate \"{slug}\"", - "error.page.move.ancestor": "The page cannot be moved into itself", - "error.page.move.directory": "The page directory cannot be moved", - "error.page.move.duplicate": "A sub page with the URL appendix \"{slug}\" already exists", - "error.page.move.notFound": "The moved page could not be found", - "error.page.move.permission": "You are not allowed to move \"{slug}\"", - "error.page.move.template": "The \"{template}\" template is not accepted as a subpage of \"{parent}\"", - "error.page.notFound": "The page \"{slug}\" cannot be found", - "error.page.num.invalid": "Please enter a valid sorting number. Numbers must not be negative.", - "error.page.slug.invalid": "Please enter a valid URL appendix", - "error.page.slug.maxlength": "Slug length must be less than \"{length}\" characters", - "error.page.sort.permission": "The page \"{slug}\" cannot be sorted", - "error.page.status.invalid": "Please set a valid page status", - "error.page.undefined": "The page cannot be found", - "error.page.update.permission": "You are not allowed to update \"{slug}\"", - - "error.section.files.max.plural": "You must not add more than {max} files to the \"{section}\" section", - "error.section.files.max.singular": "You must not add more than one file to the \"{section}\" section", - "error.section.files.min.plural": "The \"{section}\" section requires at least {min} files", - "error.section.files.min.singular": "The \"{section}\" section requires at least one file", - - "error.section.pages.max.plural": "You must not add more than {max} pages to the \"{section}\" section", - "error.section.pages.max.singular": "You must not add more than one page to the \"{section}\" section", - "error.section.pages.min.plural": "The \"{section}\" section requires at least {min} pages", - "error.section.pages.min.singular": "The \"{section}\" section requires at least one page", - - "error.section.notLoaded": "The section \"{name}\" could not be loaded", - "error.section.type.invalid": "The section type \"{type}\" is not valid", - - "error.site.changeTitle.empty": "The title must not be empty", - "error.site.changeTitle.permission": "You are not allowed to change the title of the site", - "error.site.update.permission": "You are not allowed to update the site", - - "error.structure.validation": "There's an error on the \"{field}\" field in row {index}", - - "error.template.default.notFound": "The default template does not exist", - - "error.unexpected": "An unexpected error occurred! Enable debug mode for more info: https://getkirby.com/docs/reference/system/options/debug", - - "error.user.changeEmail.permission": "You are not allowed to change the email for the user \"{name}\"", - "error.user.changeLanguage.permission": "You are not allowed to change the language for the user \"{name}\"", - "error.user.changeName.permission": "You are not allowed to change the name for the user \"{name}\"", - "error.user.changePassword.permission": "You are not allowed to change the password for the user \"{name}\"", - "error.user.changeRole.lastAdmin": "The role for the last admin cannot be changed", - "error.user.changeRole.permission": "You are not allowed to change the role for the user \"{name}\"", - "error.user.changeRole.toAdmin": "You are not allowed to promote someone to the admin role", - "error.user.create.permission": "You are not allowed to create this user", - "error.user.delete": "The user \"{name}\" cannot be deleted", - "error.user.delete.lastAdmin": "The last admin cannot be deleted", - "error.user.delete.lastUser": "The last user cannot be deleted", - "error.user.delete.permission": "You are not allowed to delete the user \"{name}\"", - "error.user.duplicate": "A user with the email address \"{email}\" already exists", - "error.user.email.invalid": "Please enter a valid email address", - "error.user.language.invalid": "Please enter a valid language", - "error.user.notFound": "The user \"{name}\" cannot be found", - "error.user.password.excessive": "Please enter a valid password. Passwords must not be longer than 1000 characters.", - "error.user.password.invalid": "Please enter a valid password. Passwords must be at least 8 characters long.", - "error.user.password.notSame": "The passwords do not match", - "error.user.password.undefined": "The user does not have a password", - "error.user.password.wrong": "Wrong password", - "error.user.role.invalid": "Please enter a valid role", - "error.user.undefined": "The user cannot be found", - "error.user.update.permission": "You are not allowed to update the user \"{name}\"", - - "error.validation.accepted": "Please confirm", - "error.validation.alpha": "Please only enter characters between a-z", - "error.validation.alphanum": "Please only enter characters between a-z or numerals 0-9", - "error.validation.anchor": "Please enter a correct link anchor", - "error.validation.between": "Please enter a value between \"{min}\" and \"{max}\"", - "error.validation.boolean": "Please confirm or deny", - "error.validation.color": "Please enter a valid color in the {format} format", - "error.validation.contains": "Please enter a value that contains \"{needle}\"", - "error.validation.date": "Please enter a valid date", - "error.validation.date.after": "Please enter a date after {date}", - "error.validation.date.before": "Please enter a date before {date}", - "error.validation.date.between": "Please enter a date between {min} and {max}", - "error.validation.denied": "Please deny", - "error.validation.different": "The value must not be \"{other}\"", - "error.validation.email": "Please enter a valid email address", - "error.validation.endswith": "The value must end with \"{end}\"", - "error.validation.filename": "Please enter a valid filename", - "error.validation.in": "Please enter one of the following: ({in})", - "error.validation.integer": "Please enter a valid integer", - "error.validation.ip": "Please enter a valid IP address", - "error.validation.less": "Please enter a value lower than {max}", - "error.validation.linkType": "The link type is not allowed", - "error.validation.match": "The value does not match the expected pattern", - "error.validation.max": "Please enter a value equal to or lower than {max}", - "error.validation.maxlength": "Please enter a shorter value. (max. {max} characters)", - "error.validation.maxwords": "Please enter no more than {max} word(s)", - "error.validation.min": "Please enter a value equal to or greater than {min}", - "error.validation.minlength": "Please enter a longer value. (min. {min} characters)", - "error.validation.minwords": "Please enter at least {min} word(s)", - "error.validation.more": "Please enter a greater value than {min}", - "error.validation.notcontains": "Please enter a value that does not contain \"{needle}\"", - "error.validation.notin": "Please don't enter any of the following: ({notIn})", - "error.validation.option": "Please select a valid option", - "error.validation.num": "Please enter a valid number", - "error.validation.required": "Please enter something", - "error.validation.same": "Please enter \"{other}\"", - "error.validation.size": "The size of the value must be \"{size}\"", - "error.validation.startswith": "The value must start with \"{start}\"", - "error.validation.tel": "Please enter an unformatted phone number", - "error.validation.time": "Please enter a valid time", - "error.validation.time.after": "Please enter a time after {time}", - "error.validation.time.before": "Please enter a time before {time}", - "error.validation.time.between": "Please enter a time between {min} and {max}", - "error.validation.uuid": "Please enter a valid UUID", - "error.validation.url": "Please enter a valid URL", - - "expand": "Expand", - "expand.all": "Expand All", - - "field.invalid": "The field is invalid", - "field.required": "The field is required", - "field.blocks.changeType": "Change type", - "field.blocks.code.name": "Code", - "field.blocks.code.language": "Language", - "field.blocks.code.placeholder": "Your code …", - "field.blocks.delete.confirm": "Do you really want to delete this block?", - "field.blocks.delete.confirm.all": "Do you really want to delete all blocks?", - "field.blocks.delete.confirm.selected": "Do you really want to delete the selected blocks?", - "field.blocks.empty": "No blocks yet", - "field.blocks.fieldsets.empty": "No fieldsets yet", - "field.blocks.fieldsets.label": "Please select a block type …", - "field.blocks.fieldsets.paste": "Press {{ shortcut }} to import layouts/blocks from your clipboard Only those allowed in the current field will get inserted.", - "field.blocks.gallery.name": "Gallery", - "field.blocks.gallery.images.empty": "No images yet", - "field.blocks.gallery.images.label": "Images", - "field.blocks.heading.level": "Level", - "field.blocks.heading.name": "Heading", - "field.blocks.heading.text": "Text", - "field.blocks.heading.placeholder": "Heading …", - "field.blocks.image.alt": "Alternative text", - "field.blocks.image.caption": "Caption", - "field.blocks.image.crop": "Crop", - "field.blocks.image.link": "Link", - "field.blocks.image.location": "Location", - "field.blocks.image.location.internal": "This website", - "field.blocks.image.location.external": "External source", - "field.blocks.image.name": "Image", - "field.blocks.image.placeholder": "Select an image", - "field.blocks.image.ratio": "Ratio", - "field.blocks.image.url": "Image URL", - "field.blocks.line.name": "Line", - "field.blocks.list.name": "List", - "field.blocks.markdown.name": "Markdown", - "field.blocks.markdown.label": "Text", - "field.blocks.markdown.placeholder": "Markdown …", - "field.blocks.quote.name": "Quote", - "field.blocks.quote.text.label": "Text", - "field.blocks.quote.text.placeholder": "Quote …", - "field.blocks.quote.citation.label": "Citation", - "field.blocks.quote.citation.placeholder": "by …", - "field.blocks.text.name": "Text", - "field.blocks.text.placeholder": "Text …", - "field.blocks.video.autoplay": "Autoplay", - "field.blocks.video.caption": "Caption", - "field.blocks.video.controls": "Controls", - "field.blocks.video.location": "Location", - "field.blocks.video.loop": "Loop", - "field.blocks.video.muted": "Muted", - "field.blocks.video.name": "Video", - "field.blocks.video.placeholder": "Enter a video URL", - "field.blocks.video.poster": "Poster", - "field.blocks.video.preload": "Preload", - "field.blocks.video.url.label": "Video-URL", - "field.blocks.video.url.placeholder": "https://youtube.com/?v=", - - "field.files.empty": "No files selected yet", - - "field.layout.change": "Change layout", - "field.layout.delete": "Delete layout", - "field.layout.delete.confirm": "Do you really want to delete this layout?", - "field.layout.delete.confirm.all": "Do you really want to delete all layouts?", - "field.layout.empty": "No rows yet", - "field.layout.select": "Select a layout", - - "field.object.empty": "No information yet", - - "field.pages.empty": "No pages selected yet", - - "field.structure.delete.confirm": "Do you really want to delete this row?", - "field.structure.delete.confirm.all": "Do you really want to delete all entries?", - "field.structure.empty": "No entries yet", - - "field.users.empty": "No users selected yet", - - "fields.empty": "No fields yet", - - "file": "File", - "file.blueprint": "This file has no blueprint yet. You can define the setup in /site/blueprints/files/{blueprint}.yml", - "file.changeTemplate": "Change template", - "file.changeTemplate.notice": "Changing the file's template will remove content for fields that don't match in type. If the new template defines certain rules, e.g. image dimensions, those will also be applied irreversibly. Use with caution.", - "file.delete.confirm": "Do you really want to delete
{filename}?", - "file.focus.placeholder": "Set focal point", - "file.focus.reset": "Remove focal point", - "file.focus.title": "Focus", - "file.sort": "Change position", - - "files": "Files", - "files.empty": "No files yet", - - "filter": "Filter", - - "hide": "Hide", - "hour": "Hour", - "hue": "Hue", - "import": "Import", - "info": "Info", - "insert": "Insert", - "insert.after": "Insert after", - "insert.before": "Insert before", - "install": "Install", - - "installation": "Installation", - "installation.completed": "The panel has been installed", - "installation.disabled": "The panel installer is disabled on public servers by default. Please run the installer on a local machine or enable it with the panel.install option.", - "installation.issues.accounts": "The /site/accounts folder does not exist or is not writable", - "installation.issues.content": "The /content folder does not exist or is not writable", - "installation.issues.curl": "The CURL extension is required", - "installation.issues.headline": "The panel cannot be installed", - "installation.issues.mbstring": "The MB String extension is required", - "installation.issues.media": "The /media folder does not exist or is not writable", - "installation.issues.php": "Make sure to use PHP 8+", - "installation.issues.sessions": "The /site/sessions folder does not exist or is not writable", - - "language": "Language", - "language.code": "Code", - "language.convert": "Make default", - "language.convert.confirm": "

Do you really want to convert {name} to the default language? This cannot be undone.

If {name} has untranslated content, there will no longer be a valid fallback and parts of your site might be empty.

", - "language.create": "Add a new language", - "language.default": "Default language", - "language.delete.confirm": "Do you really want to delete the language {name} including all translations? This cannot be undone!", - "language.deleted": "The language has been deleted", - "language.direction": "Reading direction", - "language.direction.ltr": "Left to right", - "language.direction.rtl": "Right to left", - "language.locale": "PHP locale string", - "language.locale.warning": "You are using a custom locale set up. Please modify it in the language file in /site/languages", - "language.name": "Name", - "language.secondary": "Secondary language", - "language.settings": "Language settings", - "language.updated": "The language has been updated", - "language.variables": "Language variables", - "language.variables.empty": "No translations yet", - - "language.variable.delete.confirm": "Do you really want to delete the variable for {key}?", - "language.variable.key": "Key", - "language.variable.notFound": "The variable could not be found", - "language.variable.value": "Value", - - "languages": "Languages", - "languages.default": "Default language", - "languages.empty": "There are no languages yet", - "languages.secondary": "Secondary languages", - "languages.secondary.empty": "There are no secondary languages yet", - - "license": "License", - "license.activate": "Activate it now", - "license.activate.label": "Please activate your license", - "license.activate.domain": "Your license will be activated for {host}.", - "license.activate.local": "You are about to activate your Kirby license for your local domain {host}. If this site will be deployed to a public domain, please activate it there instead. If {host} is the domain you want to use your license for, please continue.", - "license.activated": "Activated", - "license.buy": "Buy a license", - "license.code": "Code", - "license.code.help": "You received your license code after the purchase via email. Please copy and paste it here.", - "license.code.label": "Please enter your license code", - "license.status.active.info": "Includes new major versions until {date}", - "license.status.active.label": "Valid license", - "license.status.demo.info": "This is a demo installation", - "license.status.demo.label": "Demo", - "license.status.inactive.info": "Renew license to update to new major versions", - "license.status.inactive.label": "No new major versions", - "license.status.legacy.bubble": "Ready to renew your license?", - "license.status.legacy.info": "Your license does not cover this version", - "license.status.legacy.label": "Please renew your license", - "license.status.missing.bubble": "Ready to launch your site?", - "license.status.missing.info": "No valid license", - "license.status.missing.label": "Please activate your license", - "license.manage": "Manage your licenses", - "license.purchased": "Purchased", - "license.success": "Thank you for supporting Kirby", - "license.unregistered.label": "Unregistered", - - "link": "Link", - "link.text": "Link text", - - "loading": "Loading", - - "lock.unsaved": "Unsaved changes", - "lock.unsaved.empty": "There are no more unsaved changes", - "lock.isLocked": "Unsaved changes by {email}", - "lock.unlock": "Unlock", - "lock.unlock.submit": "Unlock and overwrite unsaved changes by {email}", - "lock.isUnlocked": "Was unlocked by another user", - - "login": "Log in", - "login.code.label.login": "Login code", - "login.code.label.password-reset": "Password reset code", - "login.code.placeholder.email": "000 000", - "login.code.placeholder.totp": "000000", - "login.code.text.email": "If your email address is registered, the requested code was sent via email.", - "login.code.text.totp": "Please enter the one‑time code from your authenticator app.", - "login.email.login.body": "Hi {user.nameOrEmail},\n\nYou recently requested a login code for the Panel of {site}.\nThe following login code will be valid for {timeout} minutes:\n\n{code}\n\nIf you did not request a login code, please ignore this email or contact your administrator if you have questions.\nFor security, please DO NOT forward this email.", - "login.email.login.subject": "Your login code", - "login.email.password-reset.body": "Hi {user.nameOrEmail},\n\nYou recently requested a password reset code for the Panel of {site}.\nThe following password reset code will be valid for {timeout} minutes:\n\n{code}\n\nIf you did not request a password reset code, please ignore this email or contact your administrator if you have questions.\nFor security, please DO NOT forward this email.", - "login.email.password-reset.subject": "Your password reset code", - "login.remember": "Keep me logged in", - "login.reset": "Reset password", - "login.toggleText.code.email": "Login via email", - "login.toggleText.code.email-password": "Login with password", - "login.toggleText.password-reset.email": "Forgot your password?", - "login.toggleText.password-reset.email-password": "← Back to login", - "login.totp.enable.option": "Set up one‑time codes", - "login.totp.enable.intro": "Authenticator apps can generate one‑time codes that are used as a second factor when signing into your account.", - "login.totp.enable.qr.label": "1. Scan this QR code", - "login.totp.enable.qr.help": "Unable to scan? Add the setup key {secret} manually to your authenticator app.", - "login.totp.enable.confirm.headline": "2. Confirm with generated code", - "login.totp.enable.confirm.text": "Your app generates a new one‑time code every 30 seconds. Enter the current code to complete the setup:", - "login.totp.enable.confirm.label": "Current code", - "login.totp.enable.confirm.help": "After this setup, we will ask you for a one‑time code every time you log in.", - "login.totp.enable.success": "One‑time codes enabled", - "login.totp.disable.option": "Disable one‑time codes", - "login.totp.disable.label": "Enter your password to disable one‑time codes", - "login.totp.disable.help": "In the future, a different second factor like a login code sent via email will be requested when you log in. You can always set up one‑time codes again later.", - "login.totp.disable.admin": "

This will disable one‑time codes for {user}.

In the future, a different second factor like a login code sent via email will be requested when they log in. {user} can set up one‑time codes again after their next login.

", - "login.totp.disable.success": "One‑time codes disabled", - - "logout": "Log out", - - "merge": "Merge", - "menu": "Menu", - "meridiem": "AM/PM", - "mime": "Media Type", - "minutes": "Minutes", - - "month": "Month", - "months.april": "April", - "months.august": "August", - "months.december": "December", - "months.february": "February", - "months.january": "January", - "months.july": "July", - "months.june": "June", - "months.march": "March", - "months.may": "May", - "months.november": "November", - "months.october": "October", - "months.september": "September", - - "more": "More", - "move": "Move", - "name": "Name", - "next": "Next", - "night": "Night", - "no": "no", - "off": "off", - "on": "on", - "open": "Open", - "open.newWindow": "Open in new window", - "option": "Option", - "options": "Options", - "options.none": "No options", - "options.all": "Show all {count} options", - - "orientation": "Orientation", - "orientation.landscape": "Landscape", - "orientation.portrait": "Portrait", - "orientation.square": "Square", - - "page": "Page", - "page.blueprint": "This page has no blueprint yet. You can define the setup in /site/blueprints/pages/{blueprint}.yml", - "page.changeSlug": "Change URL", - "page.changeSlug.fromTitle": "Create from title", - "page.changeStatus": "Change status", - "page.changeStatus.position": "Please select a position", - "page.changeStatus.select": "Select a new status", - "page.changeTemplate": "Change template", - "page.changeTemplate.notice": "Changing the page's template will remove content for fields that don't match in type. Use with caution.", - "page.create": "Create as {status}", - "page.delete.confirm": "Do you really want to delete {title}?", - "page.delete.confirm.subpages": "This page has subpages.
All subpages will be deleted as well.", - "page.delete.confirm.title": "Enter the page title to confirm", - "page.duplicate.appendix": "Copy", - "page.duplicate.files": "Copy files", - "page.duplicate.pages": "Copy pages", - "page.move": "Move page", - "page.sort": "Change position", - "page.status": "Status", - "page.status.draft": "Draft", - "page.status.draft.description": "The page is in draft mode and only visible for logged in editors or via secret link", - "page.status.listed": "Public", - "page.status.listed.description": "The page is public for anyone", - "page.status.unlisted": "Unlisted", - "page.status.unlisted.description": "The page is only accessible via URL", - - "pages": "Pages", - "pages.empty": "No pages yet", - "pages.status.draft": "Drafts", - "pages.status.listed": "Published", - "pages.status.unlisted": "Unlisted", - - "pagination.page": "Page", - - "password": "Password", - "paste": "Paste", - "paste.after": "Paste after", - "paste.success": "{count} pasted!", - "pixel": "Pixel", - "plugin": "Plugin", - "plugins": "Plugins", - "prev": "Previous", - "preview": "Preview", - "remove": "Remove", - "rename": "Rename", - "renew": "Renew", - "replace": "Replace", - "replace.with": "Replace with", - "retry": "Try again", - "revert": "Revert", - "revert.confirm": "Do you really want to delete all unsaved changes?", - - "role": "Role", - "role.admin.description": "The admin has all rights", - "role.admin.title": "Admin", - "role.all": "All", - "role.empty": "There are no users with this role", - "role.description.placeholder": "No description", - "role.nobody.description": "This is a fallback role without any permissions", - "role.nobody.title": "Nobody", - - "save": "Save", - "search": "Search", - "search.min": "Enter {min} characters to search", - "search.all": "Show all {count} results", - "search.results.none": "No results", - - "section.invalid": "The section is invalid", - "section.required": "The section is required", - - "security": "Security", - "select": "Select", - "server": "Server", - "settings": "Settings", - "show": "Show", - "site.blueprint": "The site has no blueprint yet. You can define the setup in /site/blueprints/site.yml", - "size": "Size", - "slug": "URL appendix", - "sort": "Sort", - "sort.drag": "Drag to sort …", - "split": "Split", - - "stats.empty": "No reports", - "status": "Status", - - "system.info.copy": "Copy info", - "system.info.copied": "System info copied", - "system.issues.content": "The content folder seems to be exposed", - "system.issues.eol.kirby": "Your installed Kirby version has reached end-of-life and will not receive further security updates", - "system.issues.eol.plugin": "Your installed version of the { plugin } plugin is has reached end-of-life and will not receive further security updates", - "system.issues.eol.php": "Your installed PHP release { release } has reached end-of-life and will not receive further security updates", - "system.issues.debug": "Debugging must be turned off in production", - "system.issues.git": "The .git folder seems to be exposed", - "system.issues.https": "We recommend HTTPS for all your sites", - "system.issues.kirby": "The kirby folder seems to be exposed", - "system.issues.site": "The site folder seems to be exposed", - "system.issues.vulnerability.kirby": "Your installation might be affected by the following vulnerability ({ severity } severity): { description }", - "system.issues.vulnerability.plugin": "Your installation might be affected by the following vulnerability in the { plugin } plugin ({ severity } severity): { description }", - "system.updateStatus": "Update status", - "system.updateStatus.error": "Could not check for updates", - "system.updateStatus.not-vulnerable": "No known vulnerabilities", - "system.updateStatus.security-update": "Free security update { version } available", - "system.updateStatus.security-upgrade": "Upgrade { version } with security fixes available", - "system.updateStatus.unreleased": "Unreleased version", - "system.updateStatus.up-to-date": "Up to date", - "system.updateStatus.update": "Free update { version } available", - "system.updateStatus.upgrade": "Upgrade { version } available", - - "tel": "Phone", - "tel.placeholder": "+49123456789", - "template": "Template", - "title": "Title", - "today": "Today", - - "toolbar.button.clear": "Clear formatting", - "toolbar.button.code": "Code", - "toolbar.button.bold": "Bold", - "toolbar.button.email": "Email", - "toolbar.button.headings": "Headings", - "toolbar.button.heading.1": "Heading 1", - "toolbar.button.heading.2": "Heading 2", - "toolbar.button.heading.3": "Heading 3", - "toolbar.button.heading.4": "Heading 4", - "toolbar.button.heading.5": "Heading 5", - "toolbar.button.heading.6": "Heading 6", - "toolbar.button.italic": "Italic", - "toolbar.button.file": "File", - "toolbar.button.file.select": "Select a file", - "toolbar.button.file.upload": "Upload a file", - "toolbar.button.link": "Link", - "toolbar.button.paragraph": "Paragraph", - "toolbar.button.strike": "Strike-through", - "toolbar.button.sub": "Subscript", - "toolbar.button.sup": "Superscript", - "toolbar.button.ol": "Ordered list", - "toolbar.button.underline": "Underline", - "toolbar.button.ul": "Bullet list", - - "translation.author": "Kirby Team", - "translation.direction": "ltr", - "translation.name": "English", - "translation.locale": "en_US", - - "type": "Type", - - "upload": "Upload", - "upload.error.cantMove": "The uploaded file could not be moved", - "upload.error.cantWrite": "Failed to write file to disk", - "upload.error.default": "The file could not be uploaded", - "upload.error.extension": "File upload stopped by extension", - "upload.error.formSize": "The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the form", - "upload.error.iniPostSize": "The uploaded file exceeds the post_max_size directive in php.ini", - "upload.error.iniSize": "The uploaded file exceeds the upload_max_filesize directive in php.ini", - "upload.error.noFile": "No file was uploaded", - "upload.error.noFiles": "No files were uploaded", - "upload.error.partial": "The uploaded file was only partially uploaded", - "upload.error.tmpDir": "Missing a temporary folder", - "upload.errors": "Error", - "upload.progress": "Uploading…", - - "url": "Url", - "url.placeholder": "https://example.com", - - "user": "User", - "user.blueprint": "You can define additional sections and form fields for this user role in /site/blueprints/users/{blueprint}.yml", - "user.changeEmail": "Change email", - "user.changeLanguage": "Change language", - "user.changeName": "Rename this user", - "user.changePassword": "Change password", - "user.changePassword.new": "New password", - "user.changePassword.new.confirm": "Confirm the new password…", - "user.changeRole": "Change role", - "user.changeRole.select": "Select a new role", - "user.create": "Add a new user", - "user.delete": "Delete this user", - "user.delete.confirm": "Do you really want to delete
{email}?", - - "users": "Users", - - "version": "Version", - "version.current": "Current version", - "version.latest": "Latest version", - "versionInformation": "Version information", - - "view.account": "Your account", - "view.installation": "Installation", - "view.languages": "Languages", - "view.resetPassword": "Reset password", - "view.site": "Site", - "view.system": "System", - "view.users": "Users", - - "welcome": "Welcome", - "year": "Year", - "yes": "yes" + "account.changeName": "Change your name", + "account.delete": "Delete your account", + "account.delete.confirm": "Do you really want to delete your account? You will be logged out immediately. Your account cannot be recovered.", + + "add": "Add", + "author": "Author", + "avatar": "Profile picture", + "back": "Back", + "cancel": "Cancel", + "change": "Change", + "close": "Close", + "confirm": "Ok", + "collapse": "Collapse", + "collapse.all": "Collapse All", + "copy": "Copy", + "copy.all": "Copy all", + "create": "Create", + + "date": "Date", + "date.select": "Select a date", + + "day": "Day", + "days.fri": "Fri", + "days.mon": "Mon", + "days.sat": "Sat", + "days.sun": "Sun", + "days.thu": "Thu", + "days.tue": "Tue", + "days.wed": "Wed", + + "debugging": "Debugging", + + "delete": "Delete", + "delete.all": "Delete all", + + "dialog.files.empty": "No files to select", + "dialog.pages.empty": "No pages to select", + "dialog.users.empty": "No users to select", + + "dimensions": "Dimensions", + "disabled": "Disabled", + "discard": "Discard", + "download": "Download", + "duplicate": "Duplicate", + + "edit": "Edit", + + "email": "Email", + "email.placeholder": "mail@example.com", + + "entries": "Entries", + "entry": "Entry", + + "environment": "Environment", + + "error.access.code": "Invalid code", + "error.access.login": "Invalid login", + "error.access.panel": "You are not allowed to access the panel", + "error.access.view": "You are not allowed to access this part of the panel", + + "error.avatar.create.fail": "The profile picture could not be uploaded", + "error.avatar.delete.fail": "The profile picture could not be deleted", + "error.avatar.dimensions.invalid": "Please keep the width and height of the profile picture under 3000 pixels", + "error.avatar.mime.forbidden": "The profile picture must be JPEG or PNG files", + + "error.blueprint.notFound": "The blueprint \"{name}\" could not be loaded", + + "error.blocks.max.plural": "You must not add more than {max} blocks", + "error.blocks.max.singular": "You must not add more than one block", + "error.blocks.min.plural": "You must add at least {min} blocks", + "error.blocks.min.singular": "You must add at least one block", + "error.blocks.validation": "There's an error in block {index}", + + "error.email.preset.notFound": "The email preset \"{name}\" cannot be found", + + "error.field.converter.invalid": "Invalid converter \"{converter}\"", + + "error.file.changeName.empty": "The name must not be empty", + "error.file.changeName.permission": "You are not allowed to change the name of \"{filename}\"", + "error.file.duplicate": "A file with the name \"{filename}\" already exists", + "error.file.extension.forbidden": "The extension \"{extension}\" is not allowed", + "error.file.extension.invalid": "Invalid extension: {extension}", + "error.file.extension.missing": "The extensions for \"{filename}\" is missing", + "error.file.maxheight": "The height of the image must not exceed {height} pixels", + "error.file.maxsize": "The file is too large", + "error.file.maxwidth": "The width of the image must not exceed {width} pixels", + "error.file.mime.differs": "The uploaded file must be of the same mime type \"{mime}\"", + "error.file.mime.forbidden": "The media type \"{mime}\" is not allowed", + "error.file.mime.invalid": "Invalid mime type: {mime}", + "error.file.mime.missing": "The media type for \"{filename}\" cannot be detected", + "error.file.minheight": "The height of the image must be at least {height} pixels", + "error.file.minsize": "The file is too small", + "error.file.minwidth": "The width of the image must be at least {width} pixels", + "error.file.name.missing": "The filename must not be empty", + "error.file.notFound": "The file \"{filename}\" cannot be found", + "error.file.orientation": "The orientation of the image must be \"{orientation}\"", + "error.file.type.forbidden": "You are not allowed to upload {type} files", + "error.file.type.invalid": "Invalid file type: {type}", + "error.file.undefined": "The file cannot be found", + + "error.form.incomplete": "Please fix all form errors…", + "error.form.notSaved": "The form could not be saved", + + "error.language.code": "Please enter a valid code for the language", + "error.language.create.permission": "You are not allowed to create a language", + "error.language.delete.permission": "You are not allowed to delete the language", + "error.language.duplicate": "The language already exists", + "error.language.name": "Please enter a valid name for the language", + "error.language.notFound": "The language could not be found", + "error.language.update.permission": "You are not allowed to update the language", + + "error.layout.validation.block": "There's an error in block {blockIndex} in layout {layoutIndex}", + "error.layout.validation.settings": "There's an error in layout {index} settings", + + "error.license.format": "Please enter a valid license key", + "error.license.email": "Please enter a valid email address", + "error.license.verification": "The license could not be verified", + + "error.offline": "The Panel is currently offline", + + "error.page.changeSlug.permission": "You are not allowed to change the URL appendix for \"{slug}\"", + "error.page.changeStatus.incomplete": "The page has errors and cannot be published", + "error.page.changeStatus.permission": "The status for this page cannot be changed", + "error.page.changeStatus.toDraft.invalid": "The page \"{slug}\" cannot be converted to a draft", + "error.page.changeTemplate.invalid": "The template for the page \"{slug}\" cannot be changed", + "error.page.changeTemplate.permission": "You are not allowed to change the template for \"{slug}\"", + "error.page.changeTitle.empty": "The title must not be empty", + "error.page.changeTitle.permission": "You are not allowed to change the title for \"{slug}\"", + "error.page.create.permission": "You are not allowed to create \"{slug}\"", + "error.page.delete": "The page \"{slug}\" cannot be deleted", + "error.page.delete.confirm": "Please enter the page title to confirm", + "error.page.delete.hasChildren": "The page has subpages and cannot be deleted", + "error.page.delete.permission": "You are not allowed to delete \"{slug}\"", + "error.page.draft.duplicate": "A page draft with the URL appendix \"{slug}\" already exists", + "error.page.duplicate": "A page with the URL appendix \"{slug}\" already exists", + "error.page.duplicate.permission": "You are not allowed to duplicate \"{slug}\"", + "error.page.notFound": "The page \"{slug}\" cannot be found", + "error.page.num.invalid": "Please enter a valid sorting number. Numbers must not be negative.", + "error.page.slug.invalid": "Please enter a valid URL appendix", + "error.page.slug.maxlength": "Slug length must be less than \"{length}\" characters", + "error.page.sort.permission": "The page \"{slug}\" cannot be sorted", + "error.page.status.invalid": "Please set a valid page status", + "error.page.undefined": "The page cannot be found", + "error.page.update.permission": "You are not allowed to update \"{slug}\"", + + "error.section.files.max.plural": "You must not add more than {max} files to the \"{section}\" section", + "error.section.files.max.singular": "You must not add more than one file to the \"{section}\" section", + "error.section.files.min.plural": "The \"{section}\" section requires at least {min} files", + "error.section.files.min.singular": "The \"{section}\" section requires at least one file", + + "error.section.pages.max.plural": "You must not add more than {max} pages to the \"{section}\" section", + "error.section.pages.max.singular": "You must not add more than one page to the \"{section}\" section", + "error.section.pages.min.plural": "The \"{section}\" section requires at least {min} pages", + "error.section.pages.min.singular": "The \"{section}\" section requires at least one page", + + "error.section.notLoaded": "The section \"{name}\" could not be loaded", + "error.section.type.invalid": "The section type \"{type}\" is not valid", + + "error.site.changeTitle.empty": "The title must not be empty", + "error.site.changeTitle.permission": "You are not allowed to change the title of the site", + "error.site.update.permission": "You are not allowed to update the site", + + "error.template.default.notFound": "The default template does not exist", + + "error.unexpected": "An unexpected error occurred! Enable debug mode for more info: https://getkirby.com/docs/reference/system/options/debug", + + "error.user.changeEmail.permission": "You are not allowed to change the email for the user \"{name}\"", + "error.user.changeLanguage.permission": "You are not allowed to change the language for the user \"{name}\"", + "error.user.changeName.permission": "You are not allowed to change the name for the user \"{name}\"", + "error.user.changePassword.permission": "You are not allowed to change the password for the user \"{name}\"", + "error.user.changeRole.lastAdmin": "The role for the last admin cannot be changed", + "error.user.changeRole.permission": "You are not allowed to change the role for the user \"{name}\"", + "error.user.changeRole.toAdmin": "You are not allowed to promote someone to the admin role", + "error.user.create.permission": "You are not allowed to create this user", + "error.user.delete": "The user \"{name}\" cannot be deleted", + "error.user.delete.lastAdmin": "The last admin cannot be deleted", + "error.user.delete.lastUser": "The last user cannot be deleted", + "error.user.delete.permission": "You are not allowed to delete the user \"{name}\"", + "error.user.duplicate": "A user with the email address \"{email}\" already exists", + "error.user.email.invalid": "Please enter a valid email address", + "error.user.language.invalid": "Please enter a valid language", + "error.user.notFound": "The user \"{name}\" cannot be found", + "error.user.password.excessive": "Please enter a valid password. Passwords must not be longer than 1000 characters.", + "error.user.password.invalid": "Please enter a valid password. Passwords must be at least 8 characters long.", + "error.user.password.notSame": "The passwords do not match", + "error.user.password.undefined": "The user does not have a password", + "error.user.password.wrong": "Wrong password", + "error.user.role.invalid": "Please enter a valid role", + "error.user.undefined": "The user cannot be found", + "error.user.update.permission": "You are not allowed to update the user \"{name}\"", + + "error.validation.accepted": "Please confirm", + "error.validation.alpha": "Please only enter characters between a-z", + "error.validation.alphanum": "Please only enter characters between a-z or numerals 0-9", + "error.validation.between": "Please enter a value between \"{min}\" and \"{max}\"", + "error.validation.boolean": "Please confirm or deny", + "error.validation.contains": "Please enter a value that contains \"{needle}\"", + "error.validation.date": "Please enter a valid date", + "error.validation.date.after": "Please enter a date after {date}", + "error.validation.date.before": "Please enter a date before {date}", + "error.validation.date.between": "Please enter a date between {min} and {max}", + "error.validation.denied": "Please deny", + "error.validation.different": "The value must not be \"{other}\"", + "error.validation.email": "Please enter a valid email address", + "error.validation.endswith": "The value must end with \"{end}\"", + "error.validation.filename": "Please enter a valid filename", + "error.validation.in": "Please enter one of the following: ({in})", + "error.validation.integer": "Please enter a valid integer", + "error.validation.ip": "Please enter a valid IP address", + "error.validation.less": "Please enter a value lower than {max}", + "error.validation.match": "The value does not match the expected pattern", + "error.validation.max": "Please enter a value equal to or lower than {max}", + "error.validation.maxlength": "Please enter a shorter value. (max. {max} characters)", + "error.validation.maxwords": "Please enter no more than {max} word(s)", + "error.validation.min": "Please enter a value equal to or greater than {min}", + "error.validation.minlength": "Please enter a longer value. (min. {min} characters)", + "error.validation.minwords": "Please enter at least {min} word(s)", + "error.validation.more": "Please enter a greater value than {min}", + "error.validation.notcontains": "Please enter a value that does not contain \"{needle}\"", + "error.validation.notin": "Please don't enter any of the following: ({notIn})", + "error.validation.option": "Please select a valid option", + "error.validation.num": "Please enter a valid number", + "error.validation.required": "Please enter something", + "error.validation.same": "Please enter \"{other}\"", + "error.validation.size": "The size of the value must be \"{size}\"", + "error.validation.startswith": "The value must start with \"{start}\"", + "error.validation.time": "Please enter a valid time", + "error.validation.time.after": "Please enter a time after {time}", + "error.validation.time.before": "Please enter a time before {time}", + "error.validation.time.between": "Please enter a time between {min} and {max}", + "error.validation.url": "Please enter a valid URL", + + "expand": "Expand", + "expand.all": "Expand All", + + "field.required": "The field is required", + "field.blocks.changeType": "Change type", + "field.blocks.code.name": "Code", + "field.blocks.code.language": "Language", + "field.blocks.code.placeholder": "Your code …", + "field.blocks.delete.confirm": "Do you really want to delete this block?", + "field.blocks.delete.confirm.all": "Do you really want to delete all blocks?", + "field.blocks.delete.confirm.selected": "Do you really want to delete the selected blocks?", + "field.blocks.empty": "No blocks yet", + "field.blocks.fieldsets.label": "Please select a block type …", + "field.blocks.fieldsets.paste": "Press {{ shortcut }} to paste/import blocks from your clipboard", + "field.blocks.gallery.name": "Gallery", + "field.blocks.gallery.images.empty": "No images yet", + "field.blocks.gallery.images.label": "Images", + "field.blocks.heading.level": "Level", + "field.blocks.heading.name": "Heading", + "field.blocks.heading.text": "Text", + "field.blocks.heading.placeholder": "Heading …", + "field.blocks.image.alt": "Alternative text", + "field.blocks.image.caption": "Caption", + "field.blocks.image.crop": "Crop", + "field.blocks.image.link": "Link", + "field.blocks.image.location": "Location", + "field.blocks.image.name": "Image", + "field.blocks.image.placeholder": "Select an image", + "field.blocks.image.ratio": "Ratio", + "field.blocks.image.url": "Image URL", + "field.blocks.line.name": "Line", + "field.blocks.list.name": "List", + "field.blocks.markdown.name": "Markdown", + "field.blocks.markdown.label": "Text", + "field.blocks.markdown.placeholder": "Markdown …", + "field.blocks.quote.name": "Quote", + "field.blocks.quote.text.label": "Text", + "field.blocks.quote.text.placeholder": "Quote …", + "field.blocks.quote.citation.label": "Citation", + "field.blocks.quote.citation.placeholder": "by …", + "field.blocks.text.name": "Text", + "field.blocks.text.placeholder": "Text …", + "field.blocks.video.caption": "Caption", + "field.blocks.video.name": "Video", + "field.blocks.video.placeholder": "Enter a video URL", + "field.blocks.video.url.label": "Video-URL", + "field.blocks.video.url.placeholder": "https://youtube.com/?v=", + + "field.files.empty": "No files selected yet", + + "field.layout.delete": "Delete layout", + "field.layout.delete.confirm": "Do you really want to delete this layout?", + "field.layout.empty": "No rows yet", + "field.layout.select": "Select a layout", + + "field.pages.empty": "No pages selected yet", + "field.structure.delete.confirm": "Do you really want to delete this row?", + "field.structure.empty": "No entries yet", + "field.users.empty": "No users selected yet", + + "file.blueprint": "This file has no blueprint yet. You can define the setup in /site/blueprints/files/{blueprint}.yml", + "file.delete.confirm": "Do you really want to delete
{filename}?", + "file.sort": "Change position", + + "files": "Files", + "files.empty": "No files yet", + + "hide": "Hide", + "hour": "Hour", + "import": "Import", + "info": "Info", + "insert": "Insert", + "insert.after": "Insert after", + "insert.before": "Insert before", + "install": "Install", + + "installation": "Installation", + "installation.completed": "The panel has been installed", + "installation.disabled": "The panel installer is disabled on public servers by default. Please run the installer on a local machine or enable it with the panel.install option.", + "installation.issues.accounts": "The /site/accounts folder does not exist or is not writable", + "installation.issues.content": "The /content folder does not exist or is not writable", + "installation.issues.curl": "The CURL extension is required", + "installation.issues.headline": "The panel cannot be installed", + "installation.issues.mbstring": "The MB String extension is required", + "installation.issues.media": "The /media folder does not exist or is not writable", + "installation.issues.php": "Make sure to use PHP 7+", + "installation.issues.server": "Kirby requires Apache, Nginx or Caddy", + "installation.issues.sessions": "The /site/sessions folder does not exist or is not writable", + + "language": "Language", + "language.code": "Code", + "language.convert": "Make default", + "language.convert.confirm": "

Do you really want to convert {name} to the default language? This cannot be undone.

If {name} has untranslated content, there will no longer be a valid fallback and parts of your site might be empty.

", + "language.create": "Add a new language", + "language.delete.confirm": "Do you really want to delete the language {name} including all translations? This cannot be undone!", + "language.deleted": "The language has been deleted", + "language.direction": "Reading direction", + "language.direction.ltr": "Left to right", + "language.direction.rtl": "Right to left", + "language.locale": "PHP locale string", + "language.locale.warning": "You are using a custom locale set up. Please modify it in the language file in /site/languages", + "language.name": "Name", + "language.updated": "The language has been updated", + + "languages": "Languages", + "languages.default": "Default language", + "languages.empty": "There are no languages yet", + "languages.secondary": "Secondary languages", + "languages.secondary.empty": "There are no secondary languages yet", + + "license": "License", + "license.buy": "Buy a license", + "license.register": "Register", + "license.manage": "Manage your licenses", + "license.register.help": "You received your license code after the purchase via email. Please copy and paste it to register.", + "license.register.label": "Please enter your license code", + "license.register.success": "Thank you for supporting Kirby", + "license.unregistered": "This is an unregistered demo of Kirby", + "license.unregistered.label": "Unregistered", + + "link": "Link", + "link.text": "Link text", + + "loading": "Loading", + + "lock.unsaved": "Unsaved changes", + "lock.unsaved.empty": "There are no more unsaved changes", + "lock.isLocked": "Unsaved changes by {email}", + "lock.file.isLocked": "The file is currently being edited by {email} and cannot be changed.", + "lock.page.isLocked": "The page is currently being edited by {email} and cannot be changed.", + "lock.unlock": "Unlock", + "lock.isUnlocked": "Your unsaved changes have been overwritten by another user. You can download your changes to merge them manually.", + + "login": "Log in", + "login.code.label.login": "Login code", + "login.code.label.password-reset": "Password reset code", + "login.code.placeholder.email": "000 000", + "login.code.text.email": "If your email address is registered, the requested code was sent via email.", + "login.email.login.body": "Hi {user.nameOrEmail},\n\nYou recently requested a login code for the Panel of {site}.\nThe following login code will be valid for {timeout} minutes:\n\n{code}\n\nIf you did not request a login code, please ignore this email or contact your administrator if you have questions.\nFor security, please DO NOT forward this email.", + "login.email.login.subject": "Your login code", + "login.email.password-reset.body": "Hi {user.nameOrEmail},\n\nYou recently requested a password reset code for the Panel of {site}.\nThe following password reset code will be valid for {timeout} minutes:\n\n{code}\n\nIf you did not request a password reset code, please ignore this email or contact your administrator if you have questions.\nFor security, please DO NOT forward this email.", + "login.email.password-reset.subject": "Your password reset code", + "login.remember": "Keep me logged in", + "login.reset": "Reset password", + "login.toggleText.code.email": "Login via email", + "login.toggleText.code.email-password": "Login with password", + "login.toggleText.password-reset.email": "Forgot your password?", + "login.toggleText.password-reset.email-password": "← Back to login", + + "logout": "Logout", + + "menu": "Menu", + "meridiem": "AM/PM", + "mime": "Media Type", + "minutes": "Minutes", + + "month": "Month", + "months.april": "April", + "months.august": "August", + "months.december": "December", + "months.february": "Feburary", + "months.january": "January", + "months.july": "July", + "months.june": "June", + "months.march": "March", + "months.may": "May", + "months.november": "November", + "months.october": "October", + "months.september": "September", + + "more": "More", + "name": "Name", + "next": "Next", + "no": "no", + "off": "off", + "on": "on", + "open": "Open", + "open.newWindow": "Open in new window", + "options": "Options", + "options.none": "No options", + + "orientation": "Orientation", + "orientation.landscape": "Landscape", + "orientation.portrait": "Portrait", + "orientation.square": "Square", + + "page.blueprint": "This page has no blueprint yet. You can define the setup in /site/blueprints/pages/{blueprint}.yml", + "page.changeSlug": "Change URL", + "page.changeSlug.fromTitle": "Create from title", + "page.changeStatus": "Change status", + "page.changeStatus.position": "Please select a position", + "page.changeStatus.select": "Select a new status", + "page.changeTemplate": "Change template", + "page.delete.confirm": "Do you really want to delete {title}?", + "page.delete.confirm.subpages": "This page has subpages.
All subpages will be deleted as well.", + "page.delete.confirm.title": "Enter the page title to confirm", + "page.draft.create": "Create draft", + "page.duplicate.appendix": "Copy", + "page.duplicate.files": "Copy files", + "page.duplicate.pages": "Copy pages", + "page.sort": "Change position", + "page.status": "Status", + "page.status.draft": "Draft", + "page.status.draft.description": "The page is in draft mode and only visible for logged in editors or via secret link", + "page.status.listed": "Public", + "page.status.listed.description": "The page is public for anyone", + "page.status.unlisted": "Unlisted", + "page.status.unlisted.description": "The page is only accessible via URL", + + "pages": "Pages", + "pages.empty": "No pages yet", + "pages.status.draft": "Drafts", + "pages.status.listed": "Published", + "pages.status.unlisted": "Unlisted", + + "pagination.page": "Page", + + "password": "Password", + "paste": "Paste", + "paste.after": "Paste after", + "pixel": "Pixel", + "plugins": "Plugins", + "prev": "Previous", + "preview": "Preview", + "remove": "Remove", + "rename": "Rename", + "replace": "Replace", + "retry": "Try again", + "revert": "Revert", + "revert.confirm": "Do you really want to delete all unsaved changes?", + + "role": "Role", + "role.admin.description": "The admin has all rights", + "role.admin.title": "Admin", + "role.all": "All", + "role.empty": "There are no users with this role", + "role.description.placeholder": "No description", + "role.nobody.description": "This is a fallback role without any permissions", + "role.nobody.title": "Nobody", + + "save": "Save", + "search": "Search", + "search.min": "Enter {min} characters to search", + "search.all": "Show all", + "search.results.none": "No results", + + "section.required": "The section is required", + + "security": "Security", + "select": "Select", + "server": "Server", + "settings": "Settings", + "show": "Show", + "site.blueprint": "The site has no blueprint yet. You can define the setup in /site/blueprints/site.yml", + "size": "Size", + "slug": "URL appendix", + "sort": "Sort", + + "stats.empty": "No reports", + "system.issues.content": "The content folder seems to be exposed", + "system.issues.debug": "Debugging must be turned off in production", + "system.issues.git": "The .git folder seems to be exposed", + "system.issues.https": "We recommend HTTPS for all your sites", + "system.issues.kirby": "The kirby folder seems to be exposed", + "system.issues.site": "The site folder seems to be exposed", + + "title": "Title", + "template": "Template", + "today": "Today", + + "toolbar.button.code": "Code", + "toolbar.button.bold": "Bold", + "toolbar.button.email": "Email", + "toolbar.button.headings": "Headings", + "toolbar.button.heading.1": "Heading 1", + "toolbar.button.heading.2": "Heading 2", + "toolbar.button.heading.3": "Heading 3", + "toolbar.button.heading.4": "Heading 4", + "toolbar.button.heading.5": "Heading 5", + "toolbar.button.heading.6": "Heading 6", + "toolbar.button.italic": "Italic", + "toolbar.button.file": "File", + "toolbar.button.file.select": "Select a file", + "toolbar.button.file.upload": "Upload a file", + "toolbar.button.link": "Link", + "toolbar.button.paragraph": "Paragraph", + "toolbar.button.strike": "Strike-through", + "toolbar.button.ol": "Ordered list", + "toolbar.button.underline": "Underline", + "toolbar.button.ul": "Bullet list", + + "translation.author": "Kirby Team", + "translation.direction": "ltr", + "translation.name": "English", + "translation.locale": "en_US", + + "upload": "Upload", + "upload.error.cantMove": "The uploaded file could not be moved", + "upload.error.cantWrite": "Failed to write file to disk", + "upload.error.default": "The file could not be uploaded", + "upload.error.extension": "File upload stopped by extension", + "upload.error.formSize": "The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the form", + "upload.error.iniPostSize": "The uploaded file exceeds the post_max_size directive in php.ini", + "upload.error.iniSize": "The uploaded file exceeds the upload_max_filesize directive in php.ini", + "upload.error.noFile": "No file was uploaded", + "upload.error.noFiles": "No files were uploaded", + "upload.error.partial": "The uploaded file was only partially uploaded", + "upload.error.tmpDir": "Missing a temporary folder", + "upload.errors": "Error", + "upload.progress": "Uploading…", + + "url": "Url", + "url.placeholder": "https://example.com", + + "user": "User", + "user.blueprint": "You can define additional sections and form fields for this user role in /site/blueprints/users/{blueprint}.yml", + "user.changeEmail": "Change email", + "user.changeLanguage": "Change language", + "user.changeName": "Rename this user", + "user.changePassword": "Change password", + "user.changePassword.new": "New password", + "user.changePassword.new.confirm": "Confirm the new password…", + "user.changeRole": "Change role", + "user.changeRole.select": "Select a new role", + "user.create": "Add a new user", + "user.delete": "Delete this user", + "user.delete.confirm": "Do you really want to delete
{email}?", + + "users": "Users", + + "version": "Version", + + "view.account": "Your account", + "view.installation": "Installation", + "view.languages": "Languages", + "view.resetPassword": "Reset password", + "view.site": "Site", + "view.system": "System", + "view.users": "Users", + + "welcome": "Welcome", + "year": "Year", + "yes": "yes" } diff --git a/kirby/i18n/translations/eo.json b/kirby/i18n/translations/eo.json index c1bf5b9..52c38a5 100644 --- a/kirby/i18n/translations/eo.json +++ b/kirby/i18n/translations/eo.json @@ -1,730 +1,574 @@ { - "account.changeName": "Ŝanĝi vian nomon", - "account.delete": "Forigi vian konton", - "account.delete.confirm": "Ĉu vi certe deziras forigi vian konton? Vi estos tuj elsalutita. Ne eblos malforigi vian konton.", - - "activate": "Activate", - "add": "Aldoni", - "alpha": "Alpha", - "author": "Aŭtoro", - "avatar": "Profilbildo", - "back": "Reen", - "cancel": "Nuligi", - "change": "Ŝanĝi", - "close": "Fermi", - "changes": "Changes", - "confirm": "Bone", - "collapse": "Fermi", - "collapse.all": "Fermi ĉiujn", - "color": "Color", - "coordinates": "Coordinates", - "copy": "Kopii", - "copy.all": "Kopii ĉiujn", - "copy.success": "{count} copied!", - "create": "Krei", - "custom": "Custom", - - "date": "Dato", - "date.select": "Elekti daton", - - "day": "Tago", - "days.fri": "Ven", - "days.mon": "Lun", - "days.sat": "Sab", - "days.sun": "Dim", - "days.thu": "Ĵaŭ", - "days.tue": "Mar", - "days.wed": "Mer", - - "debugging": "Sencimigado", - - "delete": "Forigi", - "delete.all": "Forigi ĉiujn", - - "dialog.fields.empty": "This dialog has no fields", - "dialog.files.empty": "Neniu dosiero por elekti", - "dialog.pages.empty": "Neniu paĝo por elekti", - "dialog.text.empty": "This dialog does not define any text", - "dialog.users.empty": "Neniu uzanto por elekti", - - "dimensions": "Dimensioj", - "disable": "Disable", - "disabled": "Malebligita", - "discard": "Forĵeti", - - "drawer.fields.empty": "This drawer has no fields", - - "domain": "Domain", - "download": "Elŝuti", - "duplicate": "Duobligi", - - "edit": "Modifi", - - "email": "Retpoŝto", - "email.placeholder": "retpoŝto@ekzemplo.com", - - "enter": "Enter", - "entries": "Entries", - "entry": "Entry", - - "environment": "Medio", - - "error": "Eraro", - "error.access.code": "Nevalida kodo", - "error.access.login": "Nevalida ensaluto", - "error.access.panel": "Vi ne rajtas eniri la administran panelon", - "error.access.view": "Vi ne rajtas eniri ĉi tiun areon de la panelo", - - "error.avatar.create.fail": "La profilbildo ne povis esti alŝutita", - "error.avatar.delete.fail": "La profilbildo ne povis esti forigita", - "error.avatar.dimensions.invalid": "Bonvolu certigi ke la profilbildo ne estas pli ol 3000 bilderojn larĝa kaj alta", - "error.avatar.mime.forbidden": "La profilbildo devas esti dosiero en dosierformo aŭ JPEG aŭ PNG", - - "error.blueprint.notFound": "La plano \"{name}\" ne povis esti ŝargita", - - "error.blocks.max.plural": "Oni devas ne aldoni pli ol {max} blokoj", - "error.blocks.max.singular": "Vi devas ne aldoni pli ol unu bloko", - "error.blocks.min.plural": "Oni devas aldoni almenaŭ {min} blokojn", - "error.blocks.min.singular": "Oni devas aldoni almenaŭ unu blokon", - "error.blocks.validation": "There's an error on the \"{field}\" field in block {index} using the \"{fieldset}\" block type", - - "error.cache.type.invalid": "Invalid cache type \"{type}\"", - - "error.email.preset.notFound": "La retpoŝta antaŭagordo \"{name}\" ne estas trovebla", - - "error.field.converter.invalid": "Nevalida konvertilo \"{converter}\"", - "error.field.type.missing": "Field \"{ name }\": The field type \"{ type }\" does not exist", - - "error.file.changeName.empty": "La nomo ne rajtas esti malplena", - "error.file.changeName.permission": "Vi ne rajtas ŝanĝi la nomon de \"{filename}\"", - "error.file.changeTemplate.invalid": "The template for the file \"{id}\" cannot be changed to \"{template}\" (valid: \"{blueprints}\")", - "error.file.changeTemplate.permission": "You are not allowed to change the template for the file \"{id}\"", - - "error.file.duplicate": "Jam ekzistas dosiero nomita \"{filename}\"", - "error.file.extension.forbidden": "La dosiersufikso \"{extension}\" ne estas permesita", - "error.file.extension.invalid": "Nevalida dosiersufikso: {extension}", - "error.file.extension.missing": "Mankas la dosiersufiksoj por \"{filename}\"", - "error.file.maxheight": "La bildo ne povas esti pli ol {height} bilderojn alta ", - "error.file.maxsize": "La dosiero estas tro granda", - "error.file.maxwidth": "La bildo ne povas esti pli oll {width} bilderojn larĝa", - "error.file.mime.differs": "La alŝutata dosiero devas havi la saman MIME-tipon \"{mime}\"", - "error.file.mime.forbidden": "La MIME-tipo \"{mime}\" ne povas esti uzata ĉi tie", - "error.file.mime.invalid": "Nevalida MIME-tipo: {mime}", - "error.file.mime.missing": "La MIME-tipo for \"{filename}\" ne estas detektebla", - "error.file.minheight": "La bildo devas esti almenaŭ {height} bilderojn alta", - "error.file.minsize": "La dosiero estas tro malgranda", - "error.file.minwidth": "La bildo devas esti almenaŭ {width} bilderojn larĝa", - "error.file.name.unique": "The filename must be unique", - "error.file.name.missing": "La dosiernomo ne rajtas esti malplena", - "error.file.notFound": "La dosiero \"{filename}\" ne troveblas", - "error.file.orientation": "La orientiĝo de la bildo devas esti \"{orientation}\"", - "error.file.type.forbidden": "Vi ne rajtas alŝuti dosiertipon {type}", - "error.file.type.invalid": "Nevalida dosiertipo: {type}", - "error.file.undefined": "La dosiero ne troveblas", - - "error.form.incomplete": "Bonvolu korekti ĉiujn erarojn en formularo...", - "error.form.notSaved": "Ne eblis konservi la formularon", - - "error.language.code": "Bonvolu entajpi validan kodon por la lingvo", - "error.language.duplicate": "La lingvo jam ekzistas", - "error.language.name": "Bonvolu entajpi validan nomon por la lingvo", - "error.language.notFound": "La lingvo ne troveblas", - - "error.layout.validation.block": "There's an error on the \"{field}\" field in block {blockIndex} using the \"{fieldset}\" block type in layout {layoutIndex}", - "error.layout.validation.settings": "Estas eraro en la agordoj de blokaranĝo {index}", - - "error.license.domain": "The domain for the license is missing", - "error.license.email": "Bonvolu entajpi validan retpoŝtadreson", - "error.license.format": "Please enter a valid license code", - "error.license.verification": "Ne eblis kontroli la permisilon", - - "error.login.totp.confirm.invalid": "Nevalida kodo", - "error.login.totp.confirm.missing": "Please enter the current code", - - "error.object.validation": "There’s an error in the \"{label}\" field:\n{message}", - - "error.offline": "La panelo estas ĉi-momente nekonektita", - - "error.page.changeSlug.permission": "Vi ne rajtas ŝanĝi la URL-nomon de \"{slug}\"", - "error.page.changeSlug.reserved": "The path of top-level pages must not start with \"{path}\"", - "error.page.changeStatus.incomplete": "La paĝo havas erarojn, kaj tiel ne povas esti publikigita", - "error.page.changeStatus.permission": "La paĝstato ne estas ŝanĝebla", - "error.page.changeStatus.toDraft.invalid": "Ne eblas konverti la paĝon \"{slug}\" al malneto", - "error.page.changeTemplate.invalid": "Ne eblas ŝanĝi la ŝablonon de la paĝo \"{slug}\"", - "error.page.changeTemplate.permission": "Vi ne rajtas ŝanĝi la ŝablonon de \"{slug}\"", - "error.page.changeTitle.empty": "La titolo ne rajtas esti malplena", - "error.page.changeTitle.permission": "Vi ne rajtas ŝanĝi la titolon de \"{slug}\"", - "error.page.create.permission": "Vi ne rajtas krei \"{slug}\"", - "error.page.delete": "Ne eblas forigi la paĝon \"{slug}\"", - "error.page.delete.confirm": "Bonvolu entajpi la titolon de la paĝo for konfirmi", - "error.page.delete.hasChildren": "Ne eblas forigi la paĝon ĉar ĝi havas subpaĝojn", - "error.page.delete.permission": "Vi ne rajtas forigi \"{slug}\"", - "error.page.draft.duplicate": "Malneto uzanta la URL-nomon \"{slug}\" jam ekzistas", - "error.page.duplicate": "Paĝo uzanta la URL-nomon \"{slug}\" jam ekzistas", - "error.page.duplicate.permission": "Vi ne rajtas duobligi \"{slug}\"", - "error.page.move.ancestor": "The page cannot be moved into itself", - "error.page.move.directory": "The page directory cannot be moved", - "error.page.move.duplicate": "A sub page with the URL appendix \"{slug}\" already exists", - "error.page.move.notFound": "The moved page could not be found", - "error.page.move.permission": "You are not allowed to move \"{slug}\"", - "error.page.move.template": "The \"{template}\" template is not accepted as a subpage of \"{parent}\"", - "error.page.notFound": "La paĝo \"{slug}\" ne troveblas", - "error.page.num.invalid": "Bonvolu entajpi validan ord-numeron. Numeroj devas esti pozitivaj.", - "error.page.slug.invalid": "Bonvolu entajpi validan URL-nomon", - "error.page.slug.maxlength": "URL-nomo devas esti malpli ol \"{length}\" literojn longa", - "error.page.sort.permission": "Ne eblas ordigi la paĝon \"{slug}\" ", - "error.page.status.invalid": "Bonvolu elekti validan paĝstaton", - "error.page.undefined": "La paĝo ne estas trovebla", - "error.page.update.permission": "Vi ne rajtas ĝisdatigi \"{slug}\"", - - "error.section.files.max.plural": "Vi devas aldoni maksimume {max} dosierojn al sekcio \"{section}\"", - "error.section.files.max.singular": "Vi devas aldoni maksimume unu dosieron al sekcio \"{section}\"", - "error.section.files.min.plural": "La sekcio \"{section}\" bezonas almenaŭ {min} dosierojn", - "error.section.files.min.singular": "La sekcio \"{section}\" bezonas almenaŭ unu dosieron", - - "error.section.pages.max.plural": "Vi devas aldoni maksimume {max} paĝojn al sekcio \"{section}\"", - "error.section.pages.max.singular": "Vi devas aldoni maksimume unu paĝon al sekcio \"{section}\"", - "error.section.pages.min.plural": "La sekcio \"{section}\" bezonas almenaŭ {min} paĝojn", - "error.section.pages.min.singular": "La sekcio \"{section}\" bezonas almenaŭ unu paĝon", - - "error.section.notLoaded": "Ne eblis ŝarĝi la sekcion \"{section}\"", - "error.section.type.invalid": "La sekcia tipo \"{type}\" ne estas valida", - - "error.site.changeTitle.empty": "La titolo ne rajtas esti malplena", - "error.site.changeTitle.permission": "Vi ne rajtas ŝanĝi la titolon de la retejo", - "error.site.update.permission": "Vi ne rajtas ĝisdatigi la retejon", - - "error.structure.validation": "There's an error on the \"{field}\" field in row {index}", - - "error.template.default.notFound": "La defaŭlta ŝablono ne ekzistas", - - "error.unexpected": "An unexpected error occurred! Enable debug mode for more info: https://getkirby.com/docs/reference/system/options/debug", - - "error.user.changeEmail.permission": "Vi ne rajtas ŝanĝi la retpoŝtadreson de la uzanto \"{name}\"", - "error.user.changeLanguage.permission": "Vi ne rajtas ŝanĝi la lingvon de la uzanto \"{name}\"", - "error.user.changeName.permission": "Vi ne rajtas ŝanĝi la nomon de la uzanto \"{name}\"", - "error.user.changePassword.permission": "Vi ne rajtas ŝanĝi la pasvorton de la uzanto \"{name}\"", - "error.user.changeRole.lastAdmin": "Ne eblas ŝanĝi la rolon de la lasta administranto", - "error.user.changeRole.permission": "Vi ne rajtas ŝanĝi la rolon de la uzanto \"{name}\"", - "error.user.changeRole.toAdmin": "Vi ne rajtas promocii uzanton al rolo 'administranto'", - "error.user.create.permission": "Vi ne rajtas krei ĉi-tiun uzanton", - "error.user.delete": "Ne eblas forigi uzanton \"{name}\"", - "error.user.delete.lastAdmin": "Ne eblas forigi la lastan administranton", - "error.user.delete.lastUser": "Ne eblas forigi la lastan uzanton", - "error.user.delete.permission": "Vi ne rajtas forigi la uzanton \"{name}\"", - "error.user.duplicate": "Jam ekzistas uzanto kies retpoŝtadreso estas \"{email}\"", - "error.user.email.invalid": "Bonvolu entajpi validan retpoŝtadreson", - "error.user.language.invalid": "Bonvolu entajpi validan lingvon", - "error.user.notFound": "La uzanto \"{name}\" ne troveblas", - "error.user.password.excessive": "Please enter a valid password. Passwords must not be longer than 1000 characters.", - "error.user.password.invalid": "Bonvolu entajpi validan pasvorton. Pasvortoj devas esti almenaŭ 8 literojn longaj.", - "error.user.password.notSame": "La pasvortoj ne estas kongruantaj", - "error.user.password.undefined": "La uzanto ne havas pasvorton", - "error.user.password.wrong": "Malĝusta pasvorto", - "error.user.role.invalid": "Bonvolu entajpi validan rolon", - "error.user.undefined": "La uzanto ne troveblas", - "error.user.update.permission": "Vi ne rajtas ĝisdatigi la uzanton \"{name}\"", - - "error.validation.accepted": "Bonvolu konfirmi", - "error.validation.alpha": "Bonvolu entajpi nur literojn inter a-z", - "error.validation.alphanum": "Bonvolu entajpi nur aŭ literojn inter a-z aũ numerojn inter 0-9", - "error.validation.anchor": "Please enter a correct link anchor", - "error.validation.between": "Bonvolu entajpi valoron inter \"{min}\" kaj \"{max}\"", - "error.validation.boolean": "Bonvolu konfirmi aŭ malkonfirmi", - "error.validation.color": "Please enter a valid color in the {format} format", - "error.validation.contains": "Bonvolu entajpi valoron kiu enhavas \"{needle}\"", - "error.validation.date": "Bonvolu entajpi validan daton", - "error.validation.date.after": "Bonvolu entajpi daton post {date}", - "error.validation.date.before": "Bonvolu entajpi daton antaũ {date}", - "error.validation.date.between": "Bonvolu entajpi daton inter {min} kaj {max}", - "error.validation.denied": "Bonvolu malkonfirmi", - "error.validation.different": "La valoro ne rajtas esti \"{other}\"", - "error.validation.email": "Bonvolu entajpi validan retpoŝtadreson", - "error.validation.endswith": "La valoro devas finiĝi per \"{end}\"", - "error.validation.filename": "Bonvolu entajpi validan dosiernomon", - "error.validation.in": "Bonvolu entajpi unu el la sekvaj: ({in})", - "error.validation.integer": "Bonvolu entajpi validan entjeron", - "error.validation.ip": "Bonvolu entajpi validan IP-adreson", - "error.validation.less": "Bonvolu entajpi valoron malpli ol {max}", - "error.validation.linkType": "The link type is not allowed", - "error.validation.match": "La valoro ne kongruas al la atendata ŝablono", - "error.validation.max": "Bonvolu entajpi valoron egalan al aũ malpli ol {max}", - "error.validation.maxlength": "Bonvolu entajpi pli mallongan valoron (maksimume {max} literojn)", - "error.validation.maxwords": "Bonvolu entajpi maksimume {max} vorto(j)n", - "error.validation.min": "Bonvolu entajpi valoron egalan al aŭ pli granda ol {min}", - "error.validation.minlength": "Bonvolu entajpi pli longan valoron (minimume {min} literojn)", - "error.validation.minwords": "Bonvolu entajpi almenaŭ {min} vorto(j)n", - "error.validation.more": "Bonvolu entajpi valoron pli grandan ol {min}", - "error.validation.notcontains": "Bonvolu entajpi valoron kiu ne enhavas \"{needle}\"", - "error.validation.notin": "Bonvolu entajpi neniu ajn el la sekvaj: ({notin})", - "error.validation.option": "Bonvolu fari validan elekton", - "error.validation.num": "Bonvolu entajpi validan numeron", - "error.validation.required": "Bonvolu entajpi ion", - "error.validation.same": "Bonvolu entajpi \"{other}\"", - "error.validation.size": "La grando de la valoro devas esti \"{size}\"", - "error.validation.startswith": "La valoro devas komenciĝi per \"{start}\"", - "error.validation.tel": "Please enter an unformatted phone number", - "error.validation.time": "Bonvolu entajpi validan horaron", - "error.validation.time.after": "Bonvolu entajpi horaron post {time}", - "error.validation.time.before": "Bonvolu entajpi horaron antaŭ {time}", - "error.validation.time.between": "Bonvolu entajpi horaron inter {min} kaj {max}", - "error.validation.uuid": "Please enter a valid UUID", - "error.validation.url": "Bonvolu entajpi validan URL", - - "expand": "Etendi", - "expand.all": "Etendi ĉiujn", - - "field.invalid": "The field is invalid", - "field.required": "La kampo ne rajtas esti malplena", - "field.blocks.changeType": "Ŝanĝi tipon", - "field.blocks.code.name": "Kodo", - "field.blocks.code.language": "Lingvo", - "field.blocks.code.placeholder": "Via kodo ...", - "field.blocks.delete.confirm": "Ĉu vi certe volas forigi ĉi tiun blokon?", - "field.blocks.delete.confirm.all": "Ĉu vi certe volas forigi ĉiujn blokojn?", - "field.blocks.delete.confirm.selected": "Ĉu vi certe volas forigi la elektitajn blokojn?", - "field.blocks.empty": "Ankoraŭ neniu bloko", - "field.blocks.fieldsets.empty": "No fieldsets yet", - "field.blocks.fieldsets.label": "Bonvolu elekti tipon de bloko ...", - "field.blocks.fieldsets.paste": "Press {{ shortcut }} to import layouts/blocks from your clipboard Only those allowed in the current field will get inserted.", - "field.blocks.gallery.name": "Galerio", - "field.blocks.gallery.images.empty": "Ankoraŭ neniu bildo", - "field.blocks.gallery.images.label": "Bildoj", - "field.blocks.heading.level": "Nivelo", - "field.blocks.heading.name": "Titolo", - "field.blocks.heading.text": "Teksto", - "field.blocks.heading.placeholder": "Titolo ...", - "field.blocks.image.alt": "Alternativa titolo", - "field.blocks.image.caption": "Apudskribo", - "field.blocks.image.crop": "Stuci", - "field.blocks.image.link": "Ligilo", - "field.blocks.image.location": "Loko", - "field.blocks.image.location.internal": "This website", - "field.blocks.image.location.external": "External source", - "field.blocks.image.name": "Bildo", - "field.blocks.image.placeholder": "Elekti bildon", - "field.blocks.image.ratio": "Proporcio", - "field.blocks.image.url": "URL de la bildo", - "field.blocks.line.name": "Linio", - "field.blocks.list.name": "Listo", - "field.blocks.markdown.name": "Markdown", - "field.blocks.markdown.label": "Teksto", - "field.blocks.markdown.placeholder": "Markdown ...", - "field.blocks.quote.name": "Citaĵo", - "field.blocks.quote.text.label": "Teksto", - "field.blocks.quote.text.placeholder": "Citaĵo ...", - "field.blocks.quote.citation.label": "Citaĵo", - "field.blocks.quote.citation.placeholder": "de ...", - "field.blocks.text.name": "Teksto", - "field.blocks.text.placeholder": "Teksto ...", - "field.blocks.video.autoplay": "Autoplay", - "field.blocks.video.caption": "Apudskribo", - "field.blocks.video.controls": "Controls", - "field.blocks.video.location": "Loko", - "field.blocks.video.loop": "Loop", - "field.blocks.video.muted": "Muted", - "field.blocks.video.name": "Videâjo", - "field.blocks.video.placeholder": "Entajpi URL de videaĵo", - "field.blocks.video.poster": "Poster", - "field.blocks.video.preload": "Preload", - "field.blocks.video.url.label": "Video-URL", - "field.blocks.video.url.placeholder": "https://youtube.com/?v=", - - "field.files.empty": "Ankoraŭ neniu dosiero elektita", - - "field.layout.change": "Change layout", - "field.layout.delete": "Forigi blokaranĝo", - "field.layout.delete.confirm": "Ĉu vi certe volas forigi ĉi tiun blokaranĝon?", - "field.layout.delete.confirm.all": "Do you really want to delete all layouts?", - "field.layout.empty": "Ankoraŭ neniu vico", - "field.layout.select": "Elekti blokaranĝon", - - "field.object.empty": "No information yet", - - "field.pages.empty": "Ankoraŭ neniu paĝo elektita", - - "field.structure.delete.confirm": "Ĉu vi certe volas forigi ĉi tiun vicon?", - "field.structure.delete.confirm.all": "Do you really want to delete all entries?", - "field.structure.empty": "Ankoraŭ neniu enigo", - - "field.users.empty": "Ankoraŭ neniu uzanto elektita", - - "fields.empty": "No fields yet", - - "file": "Dosiero", - "file.blueprint": "Ĉi tiu dosiero ankoraŭ havas neniun planon. Vi povas difini planon ĉe /site/blueprints/files/{blueprint}.yml", - "file.changeTemplate": "Ŝanĝi ŝablonon", - "file.changeTemplate.notice": "Changing the file's template will remove content for fields that don't match in type. If the new template defines certain rules, e.g. image dimensions, those will also be applied irreversibly. Use with caution.", - "file.delete.confirm": "Ĉu vi certe vollas forigi
{filename}?", - "file.focus.placeholder": "Set focal point", - "file.focus.reset": "Remove focal point", - "file.focus.title": "Focus", - "file.sort": "Ŝanĝi ordon", - - "files": "Dosieroj", - "files.empty": "Ankoraŭ neniu dosiero", - - "filter": "Filter", - - "hide": "Kaŝi", - "hour": "Horo", - "hue": "Hue", - "import": "Importi", - "info": "Info", - "insert": "Enmeti", - "insert.after": "Enmeti post", - "insert.before": "Enmeti antaŭ", - "install": "Instali", - - "installation": "Instalado", - "installation.completed": "La panelo estas instalita", - "installation.disabled": "La instalilo de la panelo estas norme malebligita en publikaj serviloj. Bonvolu uzi la instalilon en via loka komputilo, aŭ ebligu ĝin per la opcio panel.install", - "installation.issues.accounts": "La dosierujo /site/accounts ne ekzistas, aŭ ne estas skribebla", - "installation.issues.content": "La dosierujo /content ne ekzistas, aŭ ne estas skribebla", - "installation.issues.curl": "La kromprogramo CURL estas deviga", - "installation.issues.headline": "Ne eblas instali la panelon", - "installation.issues.mbstring": "La kromprogramo MB String estas deviga", - "installation.issues.media": "La dosierujo /media ne ekzistas, aũ ne estas skribebla", - "installation.issues.php": "Nepre uzu PHP 8+", - "installation.issues.sessions": "La dosierujo /site/sessions ne ekzistas, aŭ ne estas skribebla", - - "language": "Lingvo", - "language.code": "Kodo", - "language.convert": "Farigi defaŭlton", - "language.convert.confirm": "

Ĉu vi certe volas konverti {name} al la defaŭlta lingvo? Ĉi tion vi ne povos malfari.

Se {name} havas netradukitan enhavon, tiuj tekstoj nun ne havos defaŭlton, kaj simple ne aperos en via retejo.

", - "language.create": "Aldoni novan lingvon", - "language.default": "Defaŭlta lingvo", - "language.delete.confirm": "Ĉu vi certe volas forigi la lingvon {name}, inkluzive de ĉiuj tradukoj? Vi ne povos malfari tion!", - "language.deleted": "La lingvo estas forigita", - "language.direction": "Direkto de leĝado", - "language.direction.ltr": "Dekstren", - "language.direction.rtl": "Maldesktren", - "language.locale": "Lokaĵaro de PHP", - "language.locale.warning": "Vi uzas tajloritan agordon de lokaĵaro. Bonvolu ŝanĝi viajn agordojn laŭmende en la lingva dosiero ĉe /site/languages", - "language.name": "Nomo", - "language.secondary": "Secondary language", - "language.settings": "Language settings", - "language.updated": "La lingvo estas ĝisdatigita", - "language.variables": "Language variables", - "language.variables.empty": "No translations yet", - - "language.variable.delete.confirm": "Do you really want to delete the variable for {key}?", - "language.variable.key": "Key", - "language.variable.notFound": "The variable could not be found", - "language.variable.value": "Value", - - "languages": "Lingvoj", - "languages.default": "Defaŭlta lingvo", - "languages.empty": "Ankoraũ estas neniu lingvo", - "languages.secondary": "Kromlingvoj", - "languages.secondary.empty": "Ankoraŭ estas neniu kromlingvoj", - - "license": "Permisilo", - "license.activate": "Activate it now", - "license.activate.label": "Please activate your license", - "license.activate.domain": "Your license will be activated for {host}.", - "license.activate.local": "You are about to activate your Kirby license for your local domain {host}. If this site will be deployed to a public domain, please activate it there instead. If {host} is the domain you want to use your license for, please continue.", - "license.activated": "Activated", - "license.buy": "Aĉeti permisilon", - "license.code": "Kodo", - "license.code.help": "You received your license code after the purchase via email. Please copy and paste it here.", - "license.code.label": "Bonvolu entajpi vian kodon de permisilo", - "license.status.active.info": "Includes new major versions until {date}", - "license.status.active.label": "Valid license", - "license.status.demo.info": "This is a demo installation", - "license.status.demo.label": "Demo", - "license.status.inactive.info": "Renew license to update to new major versions", - "license.status.inactive.label": "No new major versions", - "license.status.legacy.bubble": "Ready to renew your license?", - "license.status.legacy.info": "Your license does not cover this version", - "license.status.legacy.label": "Please renew your license", - "license.status.missing.bubble": "Ready to launch your site?", - "license.status.missing.info": "No valid license", - "license.status.missing.label": "Please activate your license", - "license.manage": "Manage your licenses", - "license.purchased": "Purchased", - "license.success": "Dankon pro subteni Kirby", - "license.unregistered.label": "Unregistered", - - "link": "Ligilo", - "link.text": "Ligila teksto", - - "loading": "Ŝargante", - - "lock.unsaved": "Nekonservitaj ŝanĝoj", - "lock.unsaved.empty": "Ĉiuj ŝanĝoj estas nun konservitaj", - "lock.isLocked": "Unsaved changes by {email}", - "lock.unlock": "Malŝlosi", - "lock.unlock.submit": "Unlock and overwrite unsaved changes by {email}", - "lock.isUnlocked": "Was unlocked by another user", - - "login": "Log in", - "login.code.label.login": "Ensaluta kodo", - "login.code.label.password-reset": "Kodo por restarigi pasvorton", - "login.code.placeholder.email": "000 000", - "login.code.placeholder.totp": "000000", - "login.code.text.email": "Se via retpoŝtadreso estas enregistrita, via kodo estis sendita retpoŝte", - "login.code.text.totp": "Please enter the one‑time code from your authenticator app.", - "login.email.login.body": "Saluton {user.nameOrEmail},\n\nVi petis ensalutan kodon por la panelo de la retejo {site}.\nLa sekvanta kodo validos dum {timeout} minutoj:\n\n{code}\n\nSe vi ne petis ensalutan kodon, bonvolu ignori ĉi tiun mesaĝon, aŭ kontaktu vian sistem-administranton se vi havas demandojn.\nPro sekureco, bonvolu NE plusendi ĉi tiun mesaĝon.", - "login.email.login.subject": "Via ensaluta kodo", - "login.email.password-reset.body": "Saluton {user.nameOrEmail},\n\nVi petis kodon por restarigi vian pasvorton por la panelo de la retejo {site}.\nLa sekvanta kodo validos dum {timeout} minutoj:\n\n{code}\n\nSe vi ne petis kodon por restarigi vian pasvorton, bonvolu ignori ĉi tiun mesaĝon, aŭ kontaktu vian sistem-administranton se vi havas demandojn.\nPro sekureco, bonvolu NE plusendi ĉi tiun mesaĝon.", - "login.email.password-reset.subject": "Kodo por restarigi pasvorton", - "login.remember": "Daŭre tenu min ensalutita", - "login.reset": "Restarigi pasvorton", - "login.toggleText.code.email": "Ensaluti retpoŝte", - "login.toggleText.code.email-password": "Ensaluti per pasvorto", - "login.toggleText.password-reset.email": "Ĉu vi forgesis vian pasvorton?", - "login.toggleText.password-reset.email-password": "← Reen al ensaluto", - "login.totp.enable.option": "Set up one‑time codes", - "login.totp.enable.intro": "Authenticator apps can generate one‑time codes that are used as a second factor when signing into your account.", - "login.totp.enable.qr.label": "1. Scan this QR code", - "login.totp.enable.qr.help": "Unable to scan? Add the setup key {secret} manually to your authenticator app.", - "login.totp.enable.confirm.headline": "2. Confirm with generated code", - "login.totp.enable.confirm.text": "Your app generates a new one‑time code every 30 seconds. Enter the current code to complete the setup:", - "login.totp.enable.confirm.label": "Current code", - "login.totp.enable.confirm.help": "After this setup, we will ask you for a one‑time code every time you log in.", - "login.totp.enable.success": "One‑time codes enabled", - "login.totp.disable.option": "Disable one‑time codes", - "login.totp.disable.label": "Enter your password to disable one‑time codes", - "login.totp.disable.help": "In the future, a different second factor like a login code sent via email will be requested when you log in. You can always set up one‑time codes again later.", - "login.totp.disable.admin": "

This will disable one‑time codes for {user}.

In the future, a different second factor like a login code sent via email will be requested when they log in. {user} can set up one‑time codes again after their next login.

", - "login.totp.disable.success": "One‑time codes disabled", - - "logout": "Elsaluti", - - "merge": "Merge", - "menu": "Menuo", - "meridiem": "atm/ptm", - "mime": "Tipo de aŭdvidaĵo", - "minutes": "Minutoj", - - "month": "Monato", - "months.april": "aprilo", - "months.august": "aŭgusto", - "months.december": "decembro", - "months.february": "februaro", - "months.january": "januaro", - "months.july": "julio", - "months.june": "junio", - "months.march": "marto", - "months.may": "majo", - "months.november": "novembro", - "months.october": "oktobro", - "months.september": "septembro", - - "more": "Pli", - "move": "Move", - "name": "Nomo", - "next": "Sekve", - "night": "Night", - "no": "ne", - "off": "ne", - "on": "jes", - "open": "Malfermi", - "open.newWindow": "Malfermi novan fenestron", - "option": "Option", - "options": "Opcioj", - "options.none": "Neniu opcio", - "options.all": "Show all {count} options", - - "orientation": "Orientiĝo", - "orientation.landscape": "Horizontala", - "orientation.portrait": "Vertikala", - "orientation.square": "Kvadrata", - - "page": "Paĝo", - "page.blueprint": "Ĉi tiu paĝo ankoraŭ ne havas planon. Vi povas difini planon ĉe /site/blueprints/pages/{blueprint}.yml", - "page.changeSlug": "Ŝanĝi URL", - "page.changeSlug.fromTitle": "Krei el titolo", - "page.changeStatus": "Ŝanĝi staton", - "page.changeStatus.position": "Bonvolu elekti ordon", - "page.changeStatus.select": "Elekti novan staton", - "page.changeTemplate": "Ŝanĝi ŝablonon", - "page.changeTemplate.notice": "Changing the page's template will remove content for fields that don't match in type. Use with caution.", - "page.create": "Create as {status}", - "page.delete.confirm": "Ĉu vi certe volas forigi {title}?", - "page.delete.confirm.subpages": "Ĉi tiu paĝo havas subpaĝojn.
Ĉiuj subpaĝoj estos ankaŭ forigitaj.", - "page.delete.confirm.title": "Entajpu la titolon de la paĝo por konfirmi", - "page.duplicate.appendix": "Kopii", - "page.duplicate.files": "Kopii dosierojn", - "page.duplicate.pages": "Kopii paĝojn", - "page.move": "Move page", - "page.sort": "Ŝanĝi ordon", - "page.status": "Stato", - "page.status.draft": "Malneto", - "page.status.draft.description": "La paĝo estas malneto, kaj nur atingebla de ensalutitaj redaktantoj, aŭ per sekreta ligilo", - "page.status.listed": "Publika", - "page.status.listed.description": "La paĝo estas publika por ĉiuj ajn", - "page.status.unlisted": "Nelistata", - "page.status.unlisted.description": "La paĝo estas atingebla nur per URL", - - "pages": "Paĝoj", - "pages.empty": "Ankoraŭ neniu paĝo", - "pages.status.draft": "Malnetoj", - "pages.status.listed": "Publikigita", - "pages.status.unlisted": "Nelistata", - - "pagination.page": "Paĝo", - - "password": "Pasvorto", - "paste": "Alglui", - "paste.after": "Alglui post", - "paste.success": "{count} pasted!", - "pixel": "Pikselo", - "plugin": "Plugin", - "plugins": "Kromprogramoj", - "prev": "Antaŭe", - "preview": "Antaŭrigardi", - "remove": "Forigi", - "rename": "Ŝanĝi nomon", - "renew": "Renew", - "replace": "Anstataŭi", - "replace.with": "Replace with", - "retry": "Provi denove", - "revert": "Malfari", - "revert.confirm": "Ĉu vi certe volas forigi ĉiujn nekonservitajn ŝanĝojn?", - - "role": "Rolo", - "role.admin.description": "La administranto havas ĉiujn rajtojn", - "role.admin.title": "Administranto", - "role.all": "Ĉiuj", - "role.empty": "Neniu uzanto havas ĉi tiun rolon", - "role.description.placeholder": "Neniu priskribo", - "role.nobody.description": "Ĉi tiu estas retrodefaŭlta rolo sen permesoj", - "role.nobody.title": "Neniu", - - "save": "Konservi", - "search": "Serĉi", - "search.min": "Entajpu {min} literojn por serĉi", - "search.all": "Show all {count} results", - "search.results.none": "Neniu rezulto", - - "section.invalid": "The section is invalid", - "section.required": "La sekcio estas deviga", - - "security": "Security", - "select": "Elekti", - "server": "Servilo", - "settings": "Agordoj", - "show": "Montri", - "site.blueprint": "La retejo ankoraŭ ne havas planon. Vi povas difini planon ĉe /site/blueprints/site.yml", - "size": "Grando", - "slug": "URL-nomo", - "sort": "Ordigi", - "sort.drag": "Drag to sort …", - "split": "Split", - - "stats.empty": "No reports", - "status": "Stato", - - "system.info.copy": "Copy info", - "system.info.copied": "System info copied", - "system.issues.content": "The content folder seems to be exposed", - "system.issues.eol.kirby": "Your installed Kirby version has reached end-of-life and will not receive further security updates", - "system.issues.eol.plugin": "Your installed version of the { plugin } plugin is has reached end-of-life and will not receive further security updates", - "system.issues.eol.php": "Your installed PHP release { release } has reached end-of-life and will not receive further security updates", - "system.issues.debug": "Debugging must be turned off in production", - "system.issues.git": "The .git folder seems to be exposed", - "system.issues.https": "We recommend HTTPS for all your sites", - "system.issues.kirby": "The kirby folder seems to be exposed", - "system.issues.site": "The site folder seems to be exposed", - "system.issues.vulnerability.kirby": "Your installation might be affected by the following vulnerability ({ severity } severity): { description }", - "system.issues.vulnerability.plugin": "Your installation might be affected by the following vulnerability in the { plugin } plugin ({ severity } severity): { description }", - "system.updateStatus": "Update status", - "system.updateStatus.error": "Could not check for updates", - "system.updateStatus.not-vulnerable": "No known vulnerabilities", - "system.updateStatus.security-update": "Free security update { version } available", - "system.updateStatus.security-upgrade": "Upgrade { version } with security fixes available", - "system.updateStatus.unreleased": "Unreleased version", - "system.updateStatus.up-to-date": "Up to date", - "system.updateStatus.update": "Free update { version } available", - "system.updateStatus.upgrade": "Upgrade { version } available", - - "tel": "Phone", - "tel.placeholder": "+49123456789", - "template": "Ŝablono", - "title": "Titolo", - "today": "Hodiaŭ", - - "toolbar.button.clear": "Clear formatting", - "toolbar.button.code": "Kodo", - "toolbar.button.bold": "Grasa", - "toolbar.button.email": "Retpoŝto", - "toolbar.button.headings": "Titoloj", - "toolbar.button.heading.1": "Titolo 1", - "toolbar.button.heading.2": "Titolo 2", - "toolbar.button.heading.3": "Titolo 3", - "toolbar.button.heading.4": "Titolo 4", - "toolbar.button.heading.5": "Titolo 5", - "toolbar.button.heading.6": "Titolo 6", - "toolbar.button.italic": "Kursiva", - "toolbar.button.file": "Dosiero", - "toolbar.button.file.select": "Elekti dosieron", - "toolbar.button.file.upload": "Alŝuti dosieron", - "toolbar.button.link": "Ligilo", - "toolbar.button.paragraph": "Paragrafo", - "toolbar.button.strike": "Trastrekita", - "toolbar.button.sub": "Subscript", - "toolbar.button.sup": "Superscript", - "toolbar.button.ol": "Numerita listo", - "toolbar.button.underline": "Substrekita", - "toolbar.button.ul": "Bula listo", - - "translation.author": "Teamo Kirby", - "translation.direction": "ltr", - "translation.name": "Esperanto", - "translation.locale": "eo", - - "type": "Type", - - "upload": "Alŝuti", - "upload.error.cantMove": "Ne eblis movi la alŝutita dosiero", - "upload.error.cantWrite": "Ne eblis registri la dosieron en la diskon", - "upload.error.default": "Ne eblis alŝuti la dosieron", - "upload.error.extension": "Alŝutado haltita pro la dosiersufikso", - "upload.error.formSize": "La alŝutita dosiero estas pli granda ol la direktivo MAX_FILE_SIZE indikata en la formularo", - "upload.error.iniPostSize": "La alŝutita dosiero estas pli granda ol la direktivo post_max_size de php.ini", - "upload.error.iniSize": "La alŝutita dosiero estas pli granda ol la direktivo upload_max_filesize de php.ini", - "upload.error.noFile": "Neniu dosiero alŝutita", - "upload.error.noFiles": "Neniuj dosieroj alŝutitaj", - "upload.error.partial": "La dosiero estis nur parte alŝutita", - "upload.error.tmpDir": "Mankas provizora dosierujo", - "upload.errors": "Eraro", - "upload.progress": "Alŝutante...", - - "url": "URL", - "url.placeholder": "https://ekzemplo.com", - - "user": "Uzanto", - "user.blueprint": "Vi povas difini pluajn sekciojn kaj kampojn de formularo por ĉi tiu rolo de uzanto ĉe /site/blueprints/users/{blueprint}.yml", - "user.changeEmail": "Ŝanĝi retpoŝtadreson", - "user.changeLanguage": "Ŝanĝi lingvon", - "user.changeName": "Ŝangi la nomon de la uzanto", - "user.changePassword": "Ŝanĝi pasvorton", - "user.changePassword.new": "Nova pasvorto", - "user.changePassword.new.confirm": "Konfirmi la novan pasvorton...", - "user.changeRole": "Ŝanĝi rolon", - "user.changeRole.select": "Elekti novan rolon", - "user.create": "Aldoni novan uzanton", - "user.delete": "Forigi ĉi tiun uzanton", - "user.delete.confirm": "Ĉu vi certe volas forigi
{email}?", - - "users": "Uzantoj", - - "version": "Versio", - "version.current": "Current version", - "version.latest": "Latest version", - "versionInformation": "Version information", - - "view.account": "Via konto", - "view.installation": "Instalado", - "view.languages": "Lingvoj", - "view.resetPassword": "Restarigi pasvorton", - "view.site": "Retejo", - "view.system": "Sistemo", - "view.users": "Uzantoj", - - "welcome": "Bonvenon", - "year": "Jaro", - "yes": "jes" + "account.changeName": "Ŝanĝi vian nomon", + "account.delete": "Forigi vian konton", + "account.delete.confirm": "Ĉu vi certe deziras forigi vian konton? Vi estos tuj elsalutita. Ne eblos malforigi vian konton.", + + "add": "Aldoni", + "author": "Aŭtoro", + "avatar": "Profilbildo", + "back": "Reen", + "cancel": "Nuligi", + "change": "Ŝanĝi", + "close": "Fermi", + "confirm": "Bone", + "collapse": "Fermi", + "collapse.all": "Fermi ĉiujn", + "copy": "Kopii", + "copy.all": "Kopii ĉiujn", + "create": "Krei", + + "date": "Dato", + "date.select": "Elekti daton", + + "day": "Tago", + "days.fri": "Ven", + "days.mon": "Lun", + "days.sat": "Sab", + "days.sun": "Dim", + "days.thu": "Ĵaŭ", + "days.tue": "Mar", + "days.wed": "Mer", + + "debugging": "Sencimigado", + + "delete": "Forigi", + "delete.all": "Forigi ĉiujn", + + "dialog.files.empty": "Neniu dosiero por elekti", + "dialog.pages.empty": "Neniu paĝo por elekti", + "dialog.users.empty": "Neniu uzanto por elekti", + + "dimensions": "Dimensioj", + "disabled": "Malebligita", + "discard": "Forĵeti", + "download": "Elŝuti", + "duplicate": "Duobligi", + + "edit": "Modifi", + + "email": "Retpoŝto", + "email.placeholder": "retpoŝto@ekzemplo.com", + + "entries": "Entries", + "entry": "Entry", + + "environment": "Medio", + + "error.access.code": "Nevalida kodo", + "error.access.login": "Nevalida ensaluto", + "error.access.panel": "Vi ne rajtas eniri la administran panelon", + "error.access.view": "Vi ne rajtas eniri ĉi tiun areon de la panelo", + + "error.avatar.create.fail": "La profilbildo ne povis esti alŝutita", + "error.avatar.delete.fail": "La profilbildo ne povis esti forigita", + "error.avatar.dimensions.invalid": "Bonvolu certigi ke la profilbildo ne estas pli ol 3000 bilderojn larĝa kaj alta", + "error.avatar.mime.forbidden": "La profilbildo devas esti dosiero en dosierformo aŭ JPEG aŭ PNG", + + "error.blueprint.notFound": "La plano \"{name}\" ne povis esti ŝargita", + + "error.blocks.max.plural": "Oni devas ne aldoni pli ol {max} blokoj", + "error.blocks.max.singular": "Vi devas ne aldoni pli ol unu bloko", + "error.blocks.min.plural": "Oni devas aldoni almenaŭ {min} blokojn", + "error.blocks.min.singular": "Oni devas aldoni almenaŭ unu blokon", + "error.blocks.validation": "Estas eraro en bloko {index}", + + "error.email.preset.notFound": "La retpoŝta antaŭagordo \"{name}\" ne estas trovebla", + + "error.field.converter.invalid": "Nevalida konvertilo \"{converter}\"", + + "error.file.changeName.empty": "La nomo ne rajtas esti malplena", + "error.file.changeName.permission": "Vi ne rajtas ŝanĝi la nomon de \"{filename}\"", + "error.file.duplicate": "Jam ekzistas dosiero nomita \"{filename}\"", + "error.file.extension.forbidden": "La dosiersufikso \"{extension}\" ne estas permesita", + "error.file.extension.invalid": "Nevalida dosiersufikso: {extension}", + "error.file.extension.missing": "Mankas la dosiersufiksoj por \"{filename}\"", + "error.file.maxheight": "La bildo ne povas esti pli ol {height} bilderojn alta ", + "error.file.maxsize": "La dosiero estas tro granda", + "error.file.maxwidth": "La bildo ne povas esti pli oll {width} bilderojn larĝa", + "error.file.mime.differs": "La alŝutata dosiero devas havi la saman MIME-tipon \"{mime}\"", + "error.file.mime.forbidden": "La MIME-tipo \"{mime}\" ne povas esti uzata ĉi tie", + "error.file.mime.invalid": "Nevalida MIME-tipo: {mime}", + "error.file.mime.missing": "La MIME-tipo for \"{filename}\" ne estas detektebla", + "error.file.minheight": "La bildo devas esti almenaŭ {height} bilderojn alta", + "error.file.minsize": "La dosiero estas tro malgranda", + "error.file.minwidth": "La bildo devas esti almenaŭ {width} bilderojn larĝa", + "error.file.name.missing": "La dosiernomo ne rajtas esti malplena", + "error.file.notFound": "La dosiero \"{filename}\" ne troveblas", + "error.file.orientation": "La orientiĝo de la bildo devas esti \"{orientation}\"", + "error.file.type.forbidden": "Vi ne rajtas alŝuti dosiertipon {type}", + "error.file.type.invalid": "Nevalida dosiertipo: {type}", + "error.file.undefined": "La dosiero ne troveblas", + + "error.form.incomplete": "Bonvolu korekti ĉiujn erarojn en formularo...", + "error.form.notSaved": "Ne eblis konservi la formularon", + + "error.language.code": "Bonvolu entajpi validan kodon por la lingvo", + "error.language.duplicate": "La lingvo jam ekzistas", + "error.language.name": "Bonvolu entajpi validan nomon por la lingvo", + "error.language.notFound": "La lingvo ne troveblas", + + "error.layout.validation.block": "Estas eraro en bloko {blockIndex}, en blokaranĝo {layoutIndex}", + "error.layout.validation.settings": "Estas eraro en la agordoj de blokaranĝo {index}", + + "error.license.format": "Bonvolu entajpi validan kodon de permisilo", + "error.license.email": "Bonvolu entajpi validan retpoŝtadreson", + "error.license.verification": "Ne eblis kontroli la permisilon", + + "error.offline": "La panelo estas ĉi-momente nekonektita", + + "error.page.changeSlug.permission": "Vi ne rajtas ŝanĝi la URL-nomon de \"{slug}\"", + "error.page.changeStatus.incomplete": "La paĝo havas erarojn, kaj tiel ne povas esti publikigita", + "error.page.changeStatus.permission": "La paĝstato ne estas ŝanĝebla", + "error.page.changeStatus.toDraft.invalid": "Ne eblas konverti la paĝon \"{slug}\" al malneto", + "error.page.changeTemplate.invalid": "Ne eblas ŝanĝi la ŝablonon de la paĝo \"{slug}\"", + "error.page.changeTemplate.permission": "Vi ne rajtas ŝanĝi la ŝablonon de \"{slug}\"", + "error.page.changeTitle.empty": "La titolo ne rajtas esti malplena", + "error.page.changeTitle.permission": "Vi ne rajtas ŝanĝi la titolon de \"{slug}\"", + "error.page.create.permission": "Vi ne rajtas krei \"{slug}\"", + "error.page.delete": "Ne eblas forigi la paĝon \"{slug}\"", + "error.page.delete.confirm": "Bonvolu entajpi la titolon de la paĝo for konfirmi", + "error.page.delete.hasChildren": "Ne eblas forigi la paĝon ĉar ĝi havas subpaĝojn", + "error.page.delete.permission": "Vi ne rajtas forigi \"{slug}\"", + "error.page.draft.duplicate": "Malneto uzanta la URL-nomon \"{slug}\" jam ekzistas", + "error.page.duplicate": "Paĝo uzanta la URL-nomon \"{slug}\" jam ekzistas", + "error.page.duplicate.permission": "Vi ne rajtas duobligi \"{slug}\"", + "error.page.notFound": "La paĝo \"{slug}\" ne troveblas", + "error.page.num.invalid": "Bonvolu entajpi validan ord-numeron. Numeroj devas esti pozitivaj.", + "error.page.slug.invalid": "Bonvolu entajpi validan URL-nomon", + "error.page.slug.maxlength": "URL-nomo devas esti malpli ol \"{length}\" literojn longa", + "error.page.sort.permission": "Ne eblas ordigi la paĝon \"{slug}\" ", + "error.page.status.invalid": "Bonvolu elekti validan paĝstaton", + "error.page.undefined": "La paĝo ne estas trovebla", + "error.page.update.permission": "Vi ne rajtas ĝisdatigi \"{slug}\"", + + "error.section.files.max.plural": "Vi devas aldoni maksimume {max} dosierojn al sekcio \"{section}\"", + "error.section.files.max.singular": "Vi devas aldoni maksimume unu dosieron al sekcio \"{section}\"", + "error.section.files.min.plural": "La sekcio \"{section}\" bezonas almenaŭ {min} dosierojn", + "error.section.files.min.singular": "La sekcio \"{section}\" bezonas almenaŭ unu dosieron", + + "error.section.pages.max.plural": "Vi devas aldoni maksimume {max} paĝojn al sekcio \"{section}\"", + "error.section.pages.max.singular": "Vi devas aldoni maksimume unu paĝon al sekcio \"{section}\"", + "error.section.pages.min.plural": "La sekcio \"{section}\" bezonas almenaŭ {min} paĝojn", + "error.section.pages.min.singular": "La sekcio \"{section}\" bezonas almenaŭ unu paĝon", + + "error.section.notLoaded": "Ne eblis ŝarĝi la sekcion \"{section}\"", + "error.section.type.invalid": "La sekcia tipo \"{type}\" ne estas valida", + + "error.site.changeTitle.empty": "La titolo ne rajtas esti malplena", + "error.site.changeTitle.permission": "Vi ne rajtas ŝanĝi la titolon de la retejo", + "error.site.update.permission": "Vi ne rajtas ĝisdatigi la retejon", + + "error.template.default.notFound": "La defaŭlta ŝablono ne ekzistas", + + "error.unexpected": "An unexpected error occurred! Enable debug mode for more info: https://getkirby.com/docs/reference/system/options/debug", + + "error.user.changeEmail.permission": "Vi ne rajtas ŝanĝi la retpoŝtadreson de la uzanto \"{name}\"", + "error.user.changeLanguage.permission": "Vi ne rajtas ŝanĝi la lingvon de la uzanto \"{name}\"", + "error.user.changeName.permission": "Vi ne rajtas ŝanĝi la nomon de la uzanto \"{name}\"", + "error.user.changePassword.permission": "Vi ne rajtas ŝanĝi la pasvorton de la uzanto \"{name}\"", + "error.user.changeRole.lastAdmin": "Ne eblas ŝanĝi la rolon de la lasta administranto", + "error.user.changeRole.permission": "Vi ne rajtas ŝanĝi la rolon de la uzanto \"{name}\"", + "error.user.changeRole.toAdmin": "Vi ne rajtas promocii uzanton al rolo 'administranto'", + "error.user.create.permission": "Vi ne rajtas krei ĉi-tiun uzanton", + "error.user.delete": "Ne eblas forigi uzanton \"{name}\"", + "error.user.delete.lastAdmin": "Ne eblas forigi la lastan administranton", + "error.user.delete.lastUser": "Ne eblas forigi la lastan uzanton", + "error.user.delete.permission": "Vi ne rajtas forigi la uzanton \"{name}\"", + "error.user.duplicate": "Jam ekzistas uzanto kies retpoŝtadreso estas \"{email}\"", + "error.user.email.invalid": "Bonvolu entajpi validan retpoŝtadreson", + "error.user.language.invalid": "Bonvolu entajpi validan lingvon", + "error.user.notFound": "La uzanto \"{name}\" ne troveblas", + "error.user.password.excessive": "Please enter a valid password. Passwords must not be longer than 1000 characters.", + "error.user.password.invalid": "Bonvolu entajpi validan pasvorton. Pasvortoj devas esti almenaŭ 8 literojn longaj.", + "error.user.password.notSame": "La pasvortoj ne estas kongruantaj", + "error.user.password.undefined": "La uzanto ne havas pasvorton", + "error.user.password.wrong": "Malĝusta pasvorto", + "error.user.role.invalid": "Bonvolu entajpi validan rolon", + "error.user.undefined": "La uzanto ne troveblas", + "error.user.update.permission": "Vi ne rajtas ĝisdatigi la uzanton \"{name}\"", + + "error.validation.accepted": "Bonvolu konfirmi", + "error.validation.alpha": "Bonvolu entajpi nur literojn inter a-z", + "error.validation.alphanum": "Bonvolu entajpi nur aŭ literojn inter a-z aũ numerojn inter 0-9", + "error.validation.between": "Bonvolu entajpi valoron inter \"{min}\" kaj \"{max}\"", + "error.validation.boolean": "Bonvolu konfirmi aŭ malkonfirmi", + "error.validation.contains": "Bonvolu entajpi valoron kiu enhavas \"{needle}\"", + "error.validation.date": "Bonvolu entajpi validan daton", + "error.validation.date.after": "Bonvolu entajpi daton post {date}", + "error.validation.date.before": "Bonvolu entajpi daton antaũ {date}", + "error.validation.date.between": "Bonvolu entajpi daton inter {min} kaj {max}", + "error.validation.denied": "Bonvolu malkonfirmi", + "error.validation.different": "La valoro ne rajtas esti \"{other}\"", + "error.validation.email": "Bonvolu entajpi validan retpoŝtadreson", + "error.validation.endswith": "La valoro devas finiĝi per \"{end}\"", + "error.validation.filename": "Bonvolu entajpi validan dosiernomon", + "error.validation.in": "Bonvolu entajpi unu el la sekvaj: ({in})", + "error.validation.integer": "Bonvolu entajpi validan entjeron", + "error.validation.ip": "Bonvolu entajpi validan IP-adreson", + "error.validation.less": "Bonvolu entajpi valoron malpli ol {max}", + "error.validation.match": "La valoro ne kongruas al la atendata ŝablono", + "error.validation.max": "Bonvolu entajpi valoron egalan al aũ malpli ol {max}", + "error.validation.maxlength": "Bonvolu entajpi pli mallongan valoron (maksimume {max} literojn)", + "error.validation.maxwords": "Bonvolu entajpi maksimume {max} vorto(j)n", + "error.validation.min": "Bonvolu entajpi valoron egalan al aŭ pli granda ol {min}", + "error.validation.minlength": "Bonvolu entajpi pli longan valoron (minimume {min} literojn)", + "error.validation.minwords": "Bonvolu entajpi almenaŭ {min} vorto(j)n", + "error.validation.more": "Bonvolu entajpi valoron pli grandan ol {min}", + "error.validation.notcontains": "Bonvolu entajpi valoron kiu ne enhavas \"{needle}\"", + "error.validation.notin": "Bonvolu entajpi neniu ajn el la sekvaj: ({notin})", + "error.validation.option": "Bonvolu fari validan elekton", + "error.validation.num": "Bonvolu entajpi validan numeron", + "error.validation.required": "Bonvolu entajpi ion", + "error.validation.same": "Bonvolu entajpi \"{other}\"", + "error.validation.size": "La grando de la valoro devas esti \"{size}\"", + "error.validation.startswith": "La valoro devas komenciĝi per \"{start}\"", + "error.validation.time": "Bonvolu entajpi validan horaron", + "error.validation.time.after": "Bonvolu entajpi horaron post {time}", + "error.validation.time.before": "Bonvolu entajpi horaron antaŭ {time}", + "error.validation.time.between": "Bonvolu entajpi horaron inter {min} kaj {max}", + "error.validation.url": "Bonvolu entajpi validan URL", + + "expand": "Etendi", + "expand.all": "Etendi ĉiujn", + + "field.required": "La kampo ne rajtas esti malplena", + "field.blocks.changeType": "Ŝanĝi tipon", + "field.blocks.code.name": "Kodo", + "field.blocks.code.language": "Lingvo", + "field.blocks.code.placeholder": "Via kodo ...", + "field.blocks.delete.confirm": "Ĉu vi certe volas forigi ĉi tiun blokon?", + "field.blocks.delete.confirm.all": "Ĉu vi certe volas forigi ĉiujn blokojn?", + "field.blocks.delete.confirm.selected": "Ĉu vi certe volas forigi la elektitajn blokojn?", + "field.blocks.empty": "Ankoraŭ neniu bloko", + "field.blocks.fieldsets.label": "Bonvolu elekti tipon de bloko ...", + "field.blocks.fieldsets.paste": "Premu {{ shortcut }}por alglui/importi blokojn el via tondujo", + "field.blocks.gallery.name": "Galerio", + "field.blocks.gallery.images.empty": "Ankoraŭ neniu bildo", + "field.blocks.gallery.images.label": "Bildoj", + "field.blocks.heading.level": "Nivelo", + "field.blocks.heading.name": "Titolo", + "field.blocks.heading.text": "Teksto", + "field.blocks.heading.placeholder": "Titolo ...", + "field.blocks.image.alt": "Alternativa titolo", + "field.blocks.image.caption": "Apudskribo", + "field.blocks.image.crop": "Stuci", + "field.blocks.image.link": "Ligilo", + "field.blocks.image.location": "Loko", + "field.blocks.image.name": "Bildo", + "field.blocks.image.placeholder": "Elekti bildon", + "field.blocks.image.ratio": "Proporcio", + "field.blocks.image.url": "URL de la bildo", + "field.blocks.line.name": "Linio", + "field.blocks.list.name": "Listo", + "field.blocks.markdown.name": "Markdown", + "field.blocks.markdown.label": "Teksto", + "field.blocks.markdown.placeholder": "Markdown ...", + "field.blocks.quote.name": "Citaĵo", + "field.blocks.quote.text.label": "Teksto", + "field.blocks.quote.text.placeholder": "Citaĵo ...", + "field.blocks.quote.citation.label": "Citaĵo", + "field.blocks.quote.citation.placeholder": "de ...", + "field.blocks.text.name": "Teksto", + "field.blocks.text.placeholder": "Teksto ...", + "field.blocks.video.caption": "Apudskribo", + "field.blocks.video.name": "Videâjo", + "field.blocks.video.placeholder": "Entajpi URL de videaĵo", + "field.blocks.video.url.label": "Video-URL", + "field.blocks.video.url.placeholder": "https://youtube.com/?v=", + + "field.files.empty": "Ankoraŭ neniu dosiero elektita", + + "field.layout.delete": "Forigi blokaranĝo", + "field.layout.delete.confirm": "Ĉu vi certe volas forigi ĉi tiun blokaranĝon?", + "field.layout.empty": "Ankoraŭ neniu vico", + "field.layout.select": "Elekti blokaranĝon", + + "field.pages.empty": "Ankoraŭ neniu paĝo elektita", + "field.structure.delete.confirm": "Ĉu vi certe volas forigi ĉi tiun vicon?", + "field.structure.empty": "Ankoraŭ neniu enigo", + "field.users.empty": "Ankoraŭ neniu uzanto elektita", + + "file.blueprint": "Ĉi tiu dosiero ankoraŭ havas neniun planon. Vi povas difini planon ĉe /site/blueprints/files/{blueprint}.yml", + "file.delete.confirm": "Ĉu vi certe vollas forigi
{filename}?", + "file.sort": "Ŝanĝi ordon", + + "files": "Dosieroj", + "files.empty": "Ankoraŭ neniu dosiero", + + "hide": "Kaŝi", + "hour": "Horo", + "import": "Importi", + "info": "Info", + "insert": "Enmeti", + "insert.after": "Enmeti post", + "insert.before": "Enmeti antaŭ", + "install": "Instali", + + "installation": "Instalado", + "installation.completed": "La panelo estas instalita", + "installation.disabled": "La instalilo de la panelo estas norme malebligita en publikaj serviloj. Bonvolu uzi la instalilon en via loka komputilo, aŭ ebligu ĝin per la opcio panel.install", + "installation.issues.accounts": "La dosierujo /site/accounts ne ekzistas, aŭ ne estas skribebla", + "installation.issues.content": "La dosierujo /content ne ekzistas, aŭ ne estas skribebla", + "installation.issues.curl": "La kromprogramo CURL estas deviga", + "installation.issues.headline": "Ne eblas instali la panelon", + "installation.issues.mbstring": "La kromprogramo MB String estas deviga", + "installation.issues.media": "La dosierujo /media ne ekzistas, aũ ne estas skribebla", + "installation.issues.php": "Nepre uzu PHP 7+", + "installation.issues.server": "Kirby bezonas Apache, NginxCaddy", + "installation.issues.sessions": "La dosierujo /site/sessions ne ekzistas, aŭ ne estas skribebla", + + "language": "Lingvo", + "language.code": "Kodo", + "language.convert": "Farigi defaŭlton", + "language.convert.confirm": "

Ĉu vi certe volas konverti {name} al la defaŭlta lingvo? Ĉi tion vi ne povos malfari.

Se {name} havas netradukitan enhavon, tiuj tekstoj nun ne havos defaŭlton, kaj simple ne aperos en via retejo.

", + "language.create": "Aldoni novan lingvon", + "language.delete.confirm": "Ĉu vi certe volas forigi la lingvon {name}, inkluzive de ĉiuj tradukoj? Vi ne povos malfari tion!", + "language.deleted": "La lingvo estas forigita", + "language.direction": "Direkto de leĝado", + "language.direction.ltr": "Dekstren", + "language.direction.rtl": "Maldesktren", + "language.locale": "Lokaĵaro de PHP", + "language.locale.warning": "Vi uzas tajloritan agordon de lokaĵaro. Bonvolu ŝanĝi viajn agordojn laŭmende en la lingva dosiero ĉe /site/languages", + "language.name": "Nomo", + "language.updated": "La lingvo estas ĝisdatigita", + + "languages": "Lingvoj", + "languages.default": "Defaŭlta lingvo", + "languages.empty": "Ankoraũ estas neniu lingvo", + "languages.secondary": "Kromlingvoj", + "languages.secondary.empty": "Ankoraŭ estas neniu kromlingvoj", + + "license": "Permisilo", + "license.buy": "Aĉeti permisilon", + "license.register": "Registriĝi", + "license.manage": "Manage your licenses", + "license.register.help": "Vi ricevis vian kodon de permisilo retpoŝte, post aĉeti ĝin. Bonvolu kopii kaj alglui ĝin por registriĝi.", + "license.register.label": "Bonvolu entajpi vian kodon de permisilo", + "license.register.success": "Dankon pro subteni Kirby", + "license.unregistered": "Ĉi tiu estas neregistrita kopio de Kirby", + "license.unregistered.label": "Unregistered", + + "link": "Ligilo", + "link.text": "Ligila teksto", + + "loading": "Ŝargante", + + "lock.unsaved": "Nekonservitaj ŝanĝoj", + "lock.unsaved.empty": "Ĉiuj ŝanĝoj estas nun konservitaj", + "lock.isLocked": "Nekonservitaj ŝanĝoj de {email}", + "lock.file.isLocked": "La dosiero estas ĉi-momente redaktata de {email}, kaj tial ne povas esti ŝanĝita", + "lock.page.isLocked": "La paĝo estas ĉi-momente redaktata de {email}, kaj tial ne povas esti ŝanĝita", + "lock.unlock": "Malŝlosi", + "lock.isUnlocked": "Viaj nekonservitaj ŝanĝoj estas ŝanĝitaj de alia uzanto. Vi povas elŝuti dosieron kun viaj ŝanĝoj por permane kunfandi ilin.", + + "login": "Ensaluti", + "login.code.label.login": "Ensaluta kodo", + "login.code.label.password-reset": "Kodo por restarigi pasvorton", + "login.code.placeholder.email": "000 000", + "login.code.text.email": "Se via retpoŝtadreso estas enregistrita, via kodo estis sendita retpoŝte", + "login.email.login.body": "Saluton {user.nameOrEmail},\n\nVi petis ensalutan kodon por la panelo de la retejo {site}.\nLa sekvanta kodo validos dum {timeout} minutoj:\n\n{code}\n\nSe vi ne petis ensalutan kodon, bonvolu ignori ĉi tiun mesaĝon, aŭ kontaktu vian sistem-administranton se vi havas demandojn.\nPro sekureco, bonvolu NE plusendi ĉi tiun mesaĝon.", + "login.email.login.subject": "Via ensaluta kodo", + "login.email.password-reset.body": "Saluton {user.nameOrEmail},\n\nVi petis kodon por restarigi vian pasvorton por la panelo de la retejo {site}.\nLa sekvanta kodo validos dum {timeout} minutoj:\n\n{code}\n\nSe vi ne petis kodon por restarigi vian pasvorton, bonvolu ignori ĉi tiun mesaĝon, aŭ kontaktu vian sistem-administranton se vi havas demandojn.\nPro sekureco, bonvolu NE plusendi ĉi tiun mesaĝon.", + "login.email.password-reset.subject": "Kodo por restarigi pasvorton", + "login.remember": "Daŭre tenu min ensalutita", + "login.reset": "Restarigi pasvorton", + "login.toggleText.code.email": "Ensaluti retpoŝte", + "login.toggleText.code.email-password": "Ensaluti per pasvorto", + "login.toggleText.password-reset.email": "Ĉu vi forgesis vian pasvorton?", + "login.toggleText.password-reset.email-password": "← Reen al ensaluto", + + "logout": "Elsaluti", + + "menu": "Menuo", + "meridiem": "atm/ptm", + "mime": "Tipo de aŭdvidaĵo", + "minutes": "Minutoj", + + "month": "Monato", + "months.april": "aprilo", + "months.august": "aŭgusto", + "months.december": "decembro", + "months.february": "februaro", + "months.january": "januaro", + "months.july": "julio", + "months.june": "junio", + "months.march": "marto", + "months.may": "majo", + "months.november": "novembro", + "months.october": "oktobro", + "months.september": "septembro", + + "more": "Pli", + "name": "Nomo", + "next": "Sekve", + "no": "ne", + "off": "ne", + "on": "jes", + "open": "Malfermi", + "open.newWindow": "Malfermi novan fenestron", + "options": "Opcioj", + "options.none": "Neniu opcio", + + "orientation": "Orientiĝo", + "orientation.landscape": "Horizontala", + "orientation.portrait": "Vertikala", + "orientation.square": "Kvadrata", + + "page.blueprint": "Ĉi tiu paĝo ankoraŭ ne havas planon. Vi povas difini planon ĉe /site/blueprints/pages/{blueprint}.yml", + "page.changeSlug": "Ŝanĝi URL", + "page.changeSlug.fromTitle": "Krei el titolo", + "page.changeStatus": "Ŝanĝi staton", + "page.changeStatus.position": "Bonvolu elekti ordon", + "page.changeStatus.select": "Elekti novan staton", + "page.changeTemplate": "Ŝanĝi ŝablonon", + "page.delete.confirm": "Ĉu vi certe volas forigi {title}?", + "page.delete.confirm.subpages": "Ĉi tiu paĝo havas subpaĝojn.
Ĉiuj subpaĝoj estos ankaŭ forigitaj.", + "page.delete.confirm.title": "Entajpu la titolon de la paĝo por konfirmi", + "page.draft.create": "Krei malneton", + "page.duplicate.appendix": "Kopii", + "page.duplicate.files": "Kopii dosierojn", + "page.duplicate.pages": "Kopii paĝojn", + "page.sort": "Ŝanĝi ordon", + "page.status": "Stato", + "page.status.draft": "Malneto", + "page.status.draft.description": "La paĝo estas malneto, kaj nur atingebla de ensalutitaj redaktantoj, aŭ per sekreta ligilo", + "page.status.listed": "Publika", + "page.status.listed.description": "La paĝo estas publika por ĉiuj ajn", + "page.status.unlisted": "Nelistata", + "page.status.unlisted.description": "La paĝo estas atingebla nur per URL", + + "pages": "Paĝoj", + "pages.empty": "Ankoraŭ neniu paĝo", + "pages.status.draft": "Malnetoj", + "pages.status.listed": "Publikigita", + "pages.status.unlisted": "Nelistata", + + "pagination.page": "Paĝo", + + "password": "Pasvorto", + "paste": "Alglui", + "paste.after": "Alglui post", + "pixel": "Pikselo", + "plugins": "Kromprogramoj", + "prev": "Antaŭe", + "preview": "Antaŭrigardi", + "remove": "Forigi", + "rename": "Ŝanĝi nomon", + "replace": "Anstataŭi", + "retry": "Provi denove", + "revert": "Malfari", + "revert.confirm": "Ĉu vi certe volas forigi ĉiujn nekonservitajn ŝanĝojn?", + + "role": "Rolo", + "role.admin.description": "La administranto havas ĉiujn rajtojn", + "role.admin.title": "Administranto", + "role.all": "Ĉiuj", + "role.empty": "Neniu uzanto havas ĉi tiun rolon", + "role.description.placeholder": "Neniu priskribo", + "role.nobody.description": "Ĉi tiu estas retrodefaŭlta rolo sen permesoj", + "role.nobody.title": "Neniu", + + "save": "Konservi", + "search": "Serĉi", + "search.min": "Entajpu {min} literojn por serĉi", + "search.all": "Montri ĉiujn", + "search.results.none": "Neniu rezulto", + + "section.required": "La sekcio estas deviga", + + "security": "Security", + "select": "Elekti", + "server": "Servilo", + "settings": "Agordoj", + "show": "Montri", + "site.blueprint": "La retejo ankoraŭ ne havas planon. Vi povas difini planon ĉe /site/blueprints/site.yml", + "size": "Grando", + "slug": "URL-nomo", + "sort": "Ordigi", + + "stats.empty": "No reports", + "system.issues.content": "The content folder seems to be exposed", + "system.issues.debug": "Debugging must be turned off in production", + "system.issues.git": "The .git folder seems to be exposed", + "system.issues.https": "We recommend HTTPS for all your sites", + "system.issues.kirby": "The kirby folder seems to be exposed", + "system.issues.site": "The site folder seems to be exposed", + + "title": "Titolo", + "template": "Ŝablono", + "today": "Hodiaŭ", + + "toolbar.button.code": "Kodo", + "toolbar.button.bold": "Grasa", + "toolbar.button.email": "Retpoŝto", + "toolbar.button.headings": "Titoloj", + "toolbar.button.heading.1": "Titolo 1", + "toolbar.button.heading.2": "Titolo 2", + "toolbar.button.heading.3": "Titolo 3", + "toolbar.button.heading.4": "Titolo 4", + "toolbar.button.heading.5": "Titolo 5", + "toolbar.button.heading.6": "Titolo 6", + "toolbar.button.italic": "Kursiva", + "toolbar.button.file": "Dosiero", + "toolbar.button.file.select": "Elekti dosieron", + "toolbar.button.file.upload": "Alŝuti dosieron", + "toolbar.button.link": "Ligilo", + "toolbar.button.paragraph": "Paragrafo", + "toolbar.button.strike": "Trastrekita", + "toolbar.button.ol": "Numerita listo", + "toolbar.button.underline": "Substrekita", + "toolbar.button.ul": "Bula listo", + + "translation.author": "Teamo Kirby", + "translation.direction": "ltr", + "translation.name": "Esperanto", + "translation.locale": "eo", + + "upload": "Alŝuti", + "upload.error.cantMove": "Ne eblis movi la alŝutita dosiero", + "upload.error.cantWrite": "Ne eblis registri la dosieron en la diskon", + "upload.error.default": "Ne eblis alŝuti la dosieron", + "upload.error.extension": "Alŝutado haltita pro la dosiersufikso", + "upload.error.formSize": "La alŝutita dosiero estas pli granda ol la direktivo MAX_FILE_SIZE indikata en la formularo", + "upload.error.iniPostSize": "La alŝutita dosiero estas pli granda ol la direktivo post_max_size de php.ini", + "upload.error.iniSize": "La alŝutita dosiero estas pli granda ol la direktivo upload_max_filesize de php.ini", + "upload.error.noFile": "Neniu dosiero alŝutita", + "upload.error.noFiles": "Neniuj dosieroj alŝutitaj", + "upload.error.partial": "La dosiero estis nur parte alŝutita", + "upload.error.tmpDir": "Mankas provizora dosierujo", + "upload.errors": "Eraro", + "upload.progress": "Alŝutante...", + + "url": "URL", + "url.placeholder": "https://ekzemplo.com", + + "user": "Uzanto", + "user.blueprint": "Vi povas difini pluajn sekciojn kaj kampojn de formularo por ĉi tiu rolo de uzanto ĉe /site/blueprints/users/{blueprint}.yml", + "user.changeEmail": "Ŝanĝi retpoŝtadreson", + "user.changeLanguage": "Ŝanĝi lingvon", + "user.changeName": "Ŝangi la nomon de la uzanto", + "user.changePassword": "Ŝanĝi pasvorton", + "user.changePassword.new": "Nova pasvorto", + "user.changePassword.new.confirm": "Konfirmi la novan pasvorton...", + "user.changeRole": "Ŝanĝi rolon", + "user.changeRole.select": "Elekti novan rolon", + "user.create": "Aldoni novan uzanton", + "user.delete": "Forigi ĉi tiun uzanton", + "user.delete.confirm": "Ĉu vi certe volas forigi
{email}?", + + "users": "Uzantoj", + + "version": "Versio", + + "view.account": "Via konto", + "view.installation": "Instalado", + "view.languages": "Lingvoj", + "view.resetPassword": "Restarigi pasvorton", + "view.site": "Retejo", + "view.system": "Sistemo", + "view.users": "Uzantoj", + + "welcome": "Bonvenon", + "year": "Jaro", + "yes": "jes" } diff --git a/kirby/i18n/translations/es_419.json b/kirby/i18n/translations/es_419.json index 8cc34c1..2bb1969 100644 --- a/kirby/i18n/translations/es_419.json +++ b/kirby/i18n/translations/es_419.json @@ -1,730 +1,574 @@ { - "account.changeName": "Cambiar nombre", - "account.delete": "Eliminar cuenta", - "account.delete.confirm": "¿Realmente quieres eliminar tu cuenta? Tu sesión se cerrará inmediatamente. Tu cuenta no podrá ser recuperada. ", - - "activate": "Activate", - "add": "Agregar", - "alpha": "Alpha", - "author": "Autor", - "avatar": "Foto de perfil", - "back": "Regresar", - "cancel": "Cancelar", - "change": "Cambiar", - "close": "Cerrar", - "changes": "Changes", - "confirm": "De acuerdo", - "collapse": "Colapsar", - "collapse.all": "Colapsar todos", - "color": "Color", - "coordinates": "Coordinates", - "copy": "Copiar", - "copy.all": "Copiar todo", - "copy.success": "{count} copied!", - "create": "Crear", - "custom": "Custom", - - "date": "Fecha", - "date.select": "Selecciona una fecha", - - "day": "Día", - "days.fri": "Vie", - "days.mon": "Lun", - "days.sat": "S\u00e1b", - "days.sun": "Dom", - "days.thu": "Jue", - "days.tue": "Mar", - "days.wed": "Mi\u00e9", - - "debugging": "Depuración", - - "delete": "Eliminar", - "delete.all": "Eliminar todos", - - "dialog.fields.empty": "This dialog has no fields", - "dialog.files.empty": "No has seleccionado ningún archivo", - "dialog.pages.empty": "No has seleccionado ninguna página", - "dialog.text.empty": "This dialog does not define any text", - "dialog.users.empty": "No has seleccionado ningún usuario", - - "dimensions": "Dimensiones", - "disable": "Disable", - "disabled": "Deshabilitado", - "discard": "Descartar", - - "drawer.fields.empty": "This drawer has no fields", - - "domain": "Domain", - "download": "Descargar", - "duplicate": "Duplicar", - - "edit": "Editar", - - "email": "Correo Electrónico", - "email.placeholder": "correo@ejemplo.com", - - "enter": "Enter", - "entries": "Entradas", - "entry": "Entrada", - - "environment": "Ambiente", - - "error": "Error", - "error.access.code": "Código inválido", - "error.access.login": "Ingreso inválido", - "error.access.panel": "No tienes permitido acceder al panel", - "error.access.view": "No tienes permiso para acceder a esta parte del panel", - - "error.avatar.create.fail": "No se pudo subir la foto de perfil", - "error.avatar.delete.fail": "No se pudo eliminar la foto de perfil", - "error.avatar.dimensions.invalid": "Por favor, mantén el ancho y la altura de la imagen de perfil por debajo de 3000 pixeles", - "error.avatar.mime.forbidden": "La foto de perfil debe de ser un archivo JPG o PNG", - - "error.blueprint.notFound": "El blueprint \"{name}\" no se pudo cargar.", - - "error.blocks.max.plural": "No debes añadir más de {max} bloques", - "error.blocks.max.singular": "No debes añadir más de un bloque", - "error.blocks.min.plural": "Debes añadir al menos {min} bloques ", - "error.blocks.min.singular": "Debes añadir al menos un bloque", - "error.blocks.validation": "Hay un error en el campo \"{field}\" del bloque {index} que utiliza el tipo de bloque \"{fieldset}\"", - - "error.cache.type.invalid": "Tipo de caché \"{tipo}\" no válido", - - "error.email.preset.notFound": "El preajuste de email \"{name}\" no se pudo encontrar.", - - "error.field.converter.invalid": "Convertidor inválido \"{converter}\"", - "error.field.type.missing": "Campo \"{ name }\": El tipo de campo \"{ type }\" no existe", - - "error.file.changeName.empty": "El nombre no debe estar vacío", - "error.file.changeName.permission": "No tienes permitido cambiar el nombre de \"{filename}\"", - "error.file.changeTemplate.invalid": "The template for the file \"{id}\" cannot be changed to \"{template}\" (valid: \"{blueprints}\")", - "error.file.changeTemplate.permission": "You are not allowed to change the template for the file \"{id}\"", - - "error.file.duplicate": "Ya existe un archivo con el nombre \"{filename}\".", - "error.file.extension.forbidden": "La extensión \"{extension}\" no está permitida.", - "error.file.extension.invalid": "Extensión inválida: {extension}", - "error.file.extension.missing": "Falta la extensión para \"{filename}\".", - "error.file.maxheight": "La altura de la imagen no debe exceder {height} pixeles", - "error.file.maxsize": "El archivo es muy grande", - "error.file.maxwidth": "El ancho de la imagen no debe exceder {width} pixeles", - "error.file.mime.differs": "El archivo cargado debe ser del mismo tipo mime \"{mime}\".", - "error.file.mime.forbidden": "El tipo de medios \"{mime}\" no está permitido.", - "error.file.mime.invalid": "Tipo invalido de mime: {mime}", - "error.file.mime.missing": "No se puede detectar el tipo de medio para \"{filename}\".", - "error.file.minheight": "La altura de la imagen debe ser de al menos {height} pixeles", - "error.file.minsize": "El archivo es muy pequeño", - "error.file.minwidth": "El ancho de la imagen debe ser de al menos {width} pixeles", - "error.file.name.unique": "The filename must be unique", - "error.file.name.missing": "El nombre del archivo no debe estar vacío.", - "error.file.notFound": "El archivo \"{filename}\" no pudo ser encontrado.", - "error.file.orientation": "La orientación de la imagen debe ser \"{orientation}\"", - "error.file.type.forbidden": "No está permitido subir archivos {type}.", - "error.file.type.invalid": "Tipo de archivo inválido: {type}", - "error.file.undefined": "El archivo no se puede encontrar", - - "error.form.incomplete": "Por favor, corrige todos los errores del formulario...", - "error.form.notSaved": "No se pudo guardar el formulario", - - "error.language.code": "Por favor introduce un código válido para el idioma", - "error.language.duplicate": "El idioma ya existe", - "error.language.name": "Por favor introduce un nombre válido para el idioma", - "error.language.notFound": "No se pudo encontrar el idioma", - - "error.layout.validation.block": "Hay un error en el campo \"{field}\" del bloque {blockIndex} que utiliza el tipo de bloque \"{fieldset}\" en el layout {layoutIndex}", - "error.layout.validation.settings": "Hay un error en los ajustes del layout {index}", - - "error.license.domain": "The domain for the license is missing", - "error.license.email": "Por favor ingresa un correo electrónico valido", - "error.license.format": "Please enter a valid license code", - "error.license.verification": "La licencia no pude ser verificada", - - "error.login.totp.confirm.invalid": "Código inválido", - "error.login.totp.confirm.missing": "Please enter the current code", - - "error.object.validation": "Hay un error en el campo \"{label}\":\n{message}", - - "error.offline": "El Panel se encuentra fuera de linea ", - - "error.page.changeSlug.permission": "No está permitido cambiar el apéndice de URL para \"{slug}\".", - "error.page.changeSlug.reserved": "The path of top-level pages must not start with \"{path}\"", - "error.page.changeStatus.incomplete": "La página tiene errores y no puede ser publicada.", - "error.page.changeStatus.permission": "El estado de esta página no se puede cambiar.", - "error.page.changeStatus.toDraft.invalid": "La página \"{slug}\" no se puede convertir en un borrador", - "error.page.changeTemplate.invalid": "La plantilla para la página \"{slug}\" no se puede cambiar", - "error.page.changeTemplate.permission": "No está permitido cambiar la plantilla para \"{slug}\"", - "error.page.changeTitle.empty": "El título no debe estar vacío.", - "error.page.changeTitle.permission": "No tienes permiso para cambiar el título de \"{slug}\"", - "error.page.create.permission": "No tienes permiso para crear \"{slug}\"", - "error.page.delete": "La página \"{slug}\" no se puede eliminar", - "error.page.delete.confirm": "Por favor, introduce el título de la página para confirmar", - "error.page.delete.hasChildren": "La página tiene subpáginas y no se puede eliminar", - "error.page.delete.permission": "No tienes permiso para borrar \"{slug}\"", - "error.page.draft.duplicate": "Ya existe un borrador de página con el apéndice de URL \"{slug}\"", - "error.page.duplicate": "Ya existe una página con el apéndice de URL \"{slug}\"", - "error.page.duplicate.permission": "No tienes permitido duplicar \"{slug}\"", - "error.page.move.ancestor": "The page cannot be moved into itself", - "error.page.move.directory": "The page directory cannot be moved", - "error.page.move.duplicate": "A sub page with the URL appendix \"{slug}\" already exists", - "error.page.move.notFound": "The moved page could not be found", - "error.page.move.permission": "You are not allowed to move \"{slug}\"", - "error.page.move.template": "The \"{template}\" template is not accepted as a subpage of \"{parent}\"", - "error.page.notFound": "La página \"{slug}\" no se encuentra", - "error.page.num.invalid": "Por favor, introduce un número de posición válido. Los números no deben ser negativos.", - "error.page.slug.invalid": "Por favor, introduce un apéndice de URL válido", - "error.page.slug.maxlength": "La longitud del slug debe ser inferior a \"{length}\" caracteres", - "error.page.sort.permission": "La página \"{slug}\" no se puede ordenar", - "error.page.status.invalid": "Por favor, establece una estado de página válido", - "error.page.undefined": "La p\u00e1gina no fue encontrada", - "error.page.update.permission": "No tienes permiso para actualizar \"{slug}\"", - - "error.section.files.max.plural": "No debes agregar más de {max} archivos a la sección \"{section}\"", - "error.section.files.max.singular": "No debes agregar más de un archivo a la sección \"{section}\"", - "error.section.files.min.plural": "La sección \"{section}\" requiere al menos {min} archivos", - "error.section.files.min.singular": "La sección \"{section}\" requiere al menos un archivo", - - "error.section.pages.max.plural": "No debes agregar más de {max} páginas a la sección \"{section}\"", - "error.section.pages.max.singular": "No debes agregar más de una página a la sección \"{section}\"", - "error.section.pages.min.plural": "La sección \"{section}\" requiere al menos {min} páginas", - "error.section.pages.min.singular": "La sección \"{section}\" requiere al menos una página", - - "error.section.notLoaded": "La sección \"{name}\" no se pudo cargar", - "error.section.type.invalid": "La sección \"{type}\" no es valida", - - "error.site.changeTitle.empty": "El título no debe estar vacío.", - "error.site.changeTitle.permission": "No tienes permiso para cambiar el título del sitio", - "error.site.update.permission": "No tienes permiso de actualizar el sitio", - - "error.structure.validation": "There's an error on the \"{field}\" field in row {index}", - - "error.template.default.notFound": "La plantilla predeterminada no existe", - - "error.unexpected": "¡Se ha producido un error inesperado! Activa el modo de depuración para obtener más información: https://getkirby.com/docs/reference/system/options/debug", - - "error.user.changeEmail.permission": "No tienes permiso para cambiar el email del usuario \"{name}\"", - "error.user.changeLanguage.permission": "No tienes permiso para cambiar el idioma del usuario \"{name}\"", - "error.user.changeName.permission": "No tienes permiso para cambiar el nombre del usuario \"{name}\"", - "error.user.changePassword.permission": "No tienes permiso para cambiar la contraseña del usuario \"{name}\"", - "error.user.changeRole.lastAdmin": "El rol del último administrador no puede ser cambiado", - "error.user.changeRole.permission": "No tienes permiso para cambiar el rol del usuario \"{name}\"", - "error.user.changeRole.toAdmin": "No tienes permitido promover a alguien al rol de admin", - "error.user.create.permission": "No tienes permiso de crear este usuario", - "error.user.delete": "El ususario no pudo ser eliminado", - "error.user.delete.lastAdmin": "Usted no puede borrar el \u00faltimo administrador", - "error.user.delete.lastUser": "El último usuario no puede ser borrado", - "error.user.delete.permission": "Usted no tiene permitido borrar este usuario", - "error.user.duplicate": "Ya existe un usuario con el email \"{email}\"", - "error.user.email.invalid": "Por favor ingresa un correo electrónico valido", - "error.user.language.invalid": "Por favor ingresa un idioma valido", - "error.user.notFound": "El usuario no pudo ser encontrado", - "error.user.password.excessive": "Please enter a valid password. Passwords must not be longer than 1000 characters.", - "error.user.password.invalid": "Por favor ingresa una contraseña valida. Las contraseñas deben tener al menos 8 caracteres de largo.", - "error.user.password.notSame": "Por favor confirma la contrase\u00f1a", - "error.user.password.undefined": "El usuario no tiene contraseña", - "error.user.password.wrong": "Contraseña incorrecta", - "error.user.role.invalid": "Por favor ingresa un rol valido", - "error.user.undefined": "El usuario no pudo ser encontrado", - "error.user.update.permission": "No tienes permiso para actualizar al usuario \"{name}\"", - - "error.validation.accepted": "Por favor, confirma", - "error.validation.alpha": "Por favor ingrese solo caracteres entre a-z", - "error.validation.alphanum": "Por favor ingrese solo caracteres entre a-z o números entre 0-9", - "error.validation.anchor": "Please enter a correct link anchor", - "error.validation.between": "Por favor ingrese valores entre \"{min}\" y \"{max}\"", - "error.validation.boolean": "Por favor confirme o niegue", - "error.validation.color": "Please enter a valid color in the {format} format", - "error.validation.contains": "Por favor ingrese valores que contengan \"{needle}\"", - "error.validation.date": "Por favor ingresa una fecha válida", - "error.validation.date.after": "Por favor introduce una fecha posterior a {date}", - "error.validation.date.before": "Por favor introduce una fecha anterior a {date}", - "error.validation.date.between": "Por favor introduce un número entre {min} y {max}", - "error.validation.denied": "Por favor niegue", - "error.validation.different": "EL valor no debe ser \"{other}\"", - "error.validation.email": "Por favor ingresa un correo electrónico valido", - "error.validation.endswith": "El valor no debe terminar con \"{end}\"", - "error.validation.filename": "Por favor ingresa un nombre de archivo válido", - "error.validation.in": "Por favor ingresa uno de los siguientes: ({in})", - "error.validation.integer": "Por favor ingresa un entero válido", - "error.validation.ip": "Por favor ingresa una dirección IP válida", - "error.validation.less": "Por favor ingresa un valor menor a {max}", - "error.validation.linkType": "The link type is not allowed", - "error.validation.match": "El valor no coincide con el patrón esperado", - "error.validation.max": "Por favor ingresa un valor menor o igual a {max}", - "error.validation.maxlength": "Por favor ingresa un valor mas corto. (max. {max} caracteres)", - "error.validation.maxwords": "Por favor ingresa no mas de {max} palabra(s)", - "error.validation.min": "Por favor ingresa un valor mayor o igual a {min}", - "error.validation.minlength": "Por favor ingresa un valor mas largo. (min. {min} caracteres)", - "error.validation.minwords": "Por favor ingresa al menos {min} palabra(s)", - "error.validation.more": "Por favor ingresa un valor mayor a {min}", - "error.validation.notcontains": "Por favor ingresa un valor que no contenga \"{needle}\"", - "error.validation.notin": "Por favor no ingreses ninguno de las siguientes: ({notIn})", - "error.validation.option": "Por favor selecciona una de las opciones válidas", - "error.validation.num": "Por favor ingresa un numero válido", - "error.validation.required": "Por favor ingresa algo", - "error.validation.same": "Por favor ingresa \"{other}\"", - "error.validation.size": "El tamaño del valor debe ser \"{size}\"", - "error.validation.startswith": "El valor debe comenzar con \"{start}\"", - "error.validation.tel": "Please enter an unformatted phone number", - "error.validation.time": "Por favor ingresa una hora válida", - "error.validation.time.after": "Por favor ingresa una fecha después de {time}", - "error.validation.time.before": "Por favor ingresa una fecha antes de {time}", - "error.validation.time.between": "Por favor ingresa un fecha entre {min} y {max}", - "error.validation.uuid": "Please enter a valid UUID", - "error.validation.url": "Por favor ingresa un URL válido", - - "expand": "Expandir", - "expand.all": "Expandir todo", - - "field.invalid": "The field is invalid", - "field.required": "Este campo es requerido", - "field.blocks.changeType": "Cambiar tipo", - "field.blocks.code.name": "Código", - "field.blocks.code.language": "Idioma", - "field.blocks.code.placeholder": "Tu código...", - "field.blocks.delete.confirm": "¿Seguro que quieres eliminar este bloque?", - "field.blocks.delete.confirm.all": "¿Seguro que quieres eliminar todos los bloques?", - "field.blocks.delete.confirm.selected": "¿Seguro que quieres eliminar los bloques seleccionados?", - "field.blocks.empty": "No hay bloques aún", - "field.blocks.fieldsets.empty": "No fieldsets yet", - "field.blocks.fieldsets.label": "Por favor selecciona un tipo de bloque...", - "field.blocks.fieldsets.paste": "Press {{ shortcut }} to import layouts/blocks from your clipboard Only those allowed in the current field will get inserted.", - "field.blocks.gallery.name": "Galería", - "field.blocks.gallery.images.empty": "No hay imágenes aún", - "field.blocks.gallery.images.label": "Imágenes", - "field.blocks.heading.level": "Nivel", - "field.blocks.heading.name": "Encabezado", - "field.blocks.heading.text": "Texto", - "field.blocks.heading.placeholder": "Encabezado...", - "field.blocks.image.alt": "Texto alternativo", - "field.blocks.image.caption": "Leyenda", - "field.blocks.image.crop": "Cortar", - "field.blocks.image.link": "Enlace", - "field.blocks.image.location": "Ubicación", - "field.blocks.image.location.internal": "This website", - "field.blocks.image.location.external": "External source", - "field.blocks.image.name": "Imágen", - "field.blocks.image.placeholder": "Selecciona una imagen", - "field.blocks.image.ratio": "Proporción", - "field.blocks.image.url": "URL de imágen", - "field.blocks.line.name": "Linea", - "field.blocks.list.name": "Lista", - "field.blocks.markdown.name": "Markdown", - "field.blocks.markdown.label": "Texto", - "field.blocks.markdown.placeholder": "Markdown...", - "field.blocks.quote.name": "Cita", - "field.blocks.quote.text.label": "Texto", - "field.blocks.quote.text.placeholder": "Cita...", - "field.blocks.quote.citation.label": "Cita", - "field.blocks.quote.citation.placeholder": "Por ...", - "field.blocks.text.name": "Texto", - "field.blocks.text.placeholder": "Texto ...", - "field.blocks.video.autoplay": "Autoplay", - "field.blocks.video.caption": "Leyenda", - "field.blocks.video.controls": "Controls", - "field.blocks.video.location": "Ubicación", - "field.blocks.video.loop": "Loop", - "field.blocks.video.muted": "Muted", - "field.blocks.video.name": "Video", - "field.blocks.video.placeholder": "Introduce la URL de un vídeo", - "field.blocks.video.poster": "Poster", - "field.blocks.video.preload": "Preload", - "field.blocks.video.url.label": "Vídeo-URL", - "field.blocks.video.url.placeholder": "https://youtube.com/?v=", - - "field.files.empty": "Aún no ha seleccionado ningún archivo", - - "field.layout.change": "Change layout", - "field.layout.delete": "Eliminar layout", - "field.layout.delete.confirm": "¿Realmente quieres eliminar este layout?", - "field.layout.delete.confirm.all": "Do you really want to delete all layouts?", - "field.layout.empty": "Aún no hay filas", - "field.layout.select": "Seleccionar layout", - - "field.object.empty": "Aún no hay información", - - "field.pages.empty": "Aún no ha seleccionado ningúna pagina", - - "field.structure.delete.confirm": "\u00bfEn realidad desea borrar esta entrada?", - "field.structure.delete.confirm.all": "¿Realmente quieres eliminar todas las entradas?", - "field.structure.empty": "A\u00fan no existen entradas.", - - "field.users.empty": "Aún no ha seleccionado ningún usuario", - - "fields.empty": "No fields yet", - - "file": "Archivo", - "file.blueprint": "Este archivo aún no tiene blueprint. Puedes definir la configuración en /site/blueprints/files/{blueprint}.yml", - "file.changeTemplate": "Cambiar plantilla", - "file.changeTemplate.notice": "Changing the file's template will remove content for fields that don't match in type. If the new template defines certain rules, e.g. image dimensions, those will also be applied irreversibly. Use with caution.", - "file.delete.confirm": "\u00bfEst\u00e1s seguro que deseas eliminar este archivo?", - "file.focus.placeholder": "Set focal point", - "file.focus.reset": "Remove focal point", - "file.focus.title": "Focus", - "file.sort": "Cambiar posición", - - "files": "Archivos", - "files.empty": "Aún no existen archivos", - - "filter": "Filter", - - "hide": "Ocultar", - "hour": "Hora", - "hue": "Hue", - "import": "Importar", - "info": "Info", - "insert": "Insertar", - "insert.after": "Insertar después", - "insert.before": "Insertar antes", - "install": "Instalar", - - "installation": "Instalación", - "installation.completed": "El panel ha sido instalado.", - "installation.disabled": "El instalador del panel está deshabilitado en servidores públicos por defecto. Ejecute el instalador en una máquina local o habilítelo con la opción panel.install.", - "installation.issues.accounts": "La carpeta /site/accounts no existe o no posee permisos de escritura.", - "installation.issues.content": "La carpeta /content no existe o no posee permisos de escritura.", - "installation.issues.curl": "Se requiere la extensión CURL.", - "installation.issues.headline": "El panel no puede ser instalado.", - "installation.issues.mbstring": "Se requiere la extensión MB String.", - "installation.issues.media": "La carpeta /media no existe o no posee permisos de escritura.", - "installation.issues.php": "Asegurese de estar usando PHP 8+", - "installation.issues.sessions": "La carpeta /site/sessions no existe o no posee permisos de escritura.", - - "language": "Idioma", - "language.code": "Código", - "language.convert": "Hacer por defecto", - "language.convert.confirm": "

Realmente deseas convertir {name} al idioma por defecto? Esta acción no se puede deshacer.

Si {name} tiene contenido sin traducir, no habrá vuelta atras y tu sitio puede quedar con partes sin contenido.

", - "language.create": "Añadir nuevo idioma", - "language.default": "Idioma por defecto", - "language.delete.confirm": "

", - "language.deleted": "El idioma ha sido borrado", - "language.direction": "Dirección de lectura", - "language.direction.ltr": "De Izquierda a derecha", - "language.direction.rtl": "De derecha a izquierda", - "language.locale": "Cadena de localización PHP", - "language.locale.warning": "Estas utilizando un configuración local. Por favor modifícalo en el archivo del lenguaje en /site/languages", - "language.name": "Nombre", - "language.secondary": "Secondary language", - "language.settings": "Language settings", - "language.updated": "El idioma a sido actualizado", - "language.variables": "Language variables", - "language.variables.empty": "No translations yet", - - "language.variable.delete.confirm": "Do you really want to delete the variable for {key}?", - "language.variable.key": "Key", - "language.variable.notFound": "The variable could not be found", - "language.variable.value": "Value", - - "languages": "Idiomas", - "languages.default": "Idioma por defecto", - "languages.empty": "Todavía no hay idiomas", - "languages.secondary": "Idiomas secundarios", - "languages.secondary.empty": "Todavía no hay idiomas secundarios", - - "license": "Licencia", - "license.activate": "Activate it now", - "license.activate.label": "Please activate your license", - "license.activate.domain": "Your license will be activated for {host}.", - "license.activate.local": "You are about to activate your Kirby license for your local domain {host}. If this site will be deployed to a public domain, please activate it there instead. If {host} is the domain you want to use your license for, please continue.", - "license.activated": "Activated", - "license.buy": "Comprar una licencia", - "license.code": "Código", - "license.code.help": "You received your license code after the purchase via email. Please copy and paste it here.", - "license.code.label": "Por favor, ingresa tu código de licencia", - "license.status.active.info": "Includes new major versions until {date}", - "license.status.active.label": "Valid license", - "license.status.demo.info": "This is a demo installation", - "license.status.demo.label": "Demo", - "license.status.inactive.info": "Renew license to update to new major versions", - "license.status.inactive.label": "No new major versions", - "license.status.legacy.bubble": "Ready to renew your license?", - "license.status.legacy.info": "Your license does not cover this version", - "license.status.legacy.label": "Please renew your license", - "license.status.missing.bubble": "Ready to launch your site?", - "license.status.missing.info": "No valid license", - "license.status.missing.label": "Please activate your license", - "license.manage": "Gestiona tus licencias", - "license.purchased": "Purchased", - "license.success": "Gracias por apoyar a Kirby", - "license.unregistered.label": "No registrado", - - "link": "Enlace", - "link.text": "Texto de Enlace", - - "loading": "Cargando", - - "lock.unsaved": "Cambios sin guardar", - "lock.unsaved.empty": "No hay más cambios sin guardar", - "lock.isLocked": "Unsaved changes by {email}", - "lock.unlock": "Desbloquear", - "lock.unlock.submit": "Unlock and overwrite unsaved changes by {email}", - "lock.isUnlocked": "Was unlocked by another user", - - "login": "Iniciar sesión", - "login.code.label.login": "Código de inicio de sesión", - "login.code.label.password-reset": "Código de restablecimiento de contraseña", - "login.code.placeholder.email": "000 000", - "login.code.placeholder.totp": "000000", - "login.code.text.email": "Si tu dirección de correo electrónico está registrada, el código solicitado fue enviado por correo electrónico.", - "login.code.text.totp": "Please enter the one‑time code from your authenticator app.", - "login.email.login.body": "Hola {user.nameOrEmail},\n\nHas pedido, recientemente, un código de restablecimiento de contraseña para el Panel del sitio {site}.\nEl siguiente código de restablecimiento de contraseña será válido por {timeout} minutos:\n\n{code}\n\nSi no pediste un código de restablecimiento de contraseña, por favor ignora este correo o contacta a tu administrador si tienes dudas.\nPor seguridad, por favor NO reenvíes este correo.", - "login.email.login.subject": "Tu código de inicio de sesión", - "login.email.password-reset.body": "Hola {user.nameOrEmail},\n\nHas pedido, recientemente, un código de restablecimiento de contraseña para el Panel del sitio {site}.\nEl siguiente código de restablecimiento de contraseña será válido por {timeout} minutos:\n\n{code}\n\nSi no pediste un código de restablecimiento de contraseña, por favor ignora este correo o contacta a tu administrador si tienes dudas.\nPor seguridad, por favor NO reenvíes este correo.", - "login.email.password-reset.subject": "Tu código de restablecimiento de contraseña", - "login.remember": "Mantener mi sesión iniciada", - "login.reset": "Restablecer contraseña", - "login.toggleText.code.email": "Iniciar sesión por correo electrónico", - "login.toggleText.code.email-password": "Iniciar sesión con contraseña", - "login.toggleText.password-reset.email": "¿Olvidaste tu contraseña?", - "login.toggleText.password-reset.email-password": "← Volver al inicio de sesión", - "login.totp.enable.option": "Set up one‑time codes", - "login.totp.enable.intro": "Authenticator apps can generate one‑time codes that are used as a second factor when signing into your account.", - "login.totp.enable.qr.label": "1. Scan this QR code", - "login.totp.enable.qr.help": "Unable to scan? Add the setup key {secret} manually to your authenticator app.", - "login.totp.enable.confirm.headline": "2. Confirm with generated code", - "login.totp.enable.confirm.text": "Your app generates a new one‑time code every 30 seconds. Enter the current code to complete the setup:", - "login.totp.enable.confirm.label": "Current code", - "login.totp.enable.confirm.help": "After this setup, we will ask you for a one‑time code every time you log in.", - "login.totp.enable.success": "One‑time codes enabled", - "login.totp.disable.option": "Disable one‑time codes", - "login.totp.disable.label": "Enter your password to disable one‑time codes", - "login.totp.disable.help": "In the future, a different second factor like a login code sent via email will be requested when you log in. You can always set up one‑time codes again later.", - "login.totp.disable.admin": "

This will disable one‑time codes for {user}.

In the future, a different second factor like a login code sent via email will be requested when they log in. {user} can set up one‑time codes again after their next login.

", - "login.totp.disable.success": "One‑time codes disabled", - - "logout": "Cerrar sesión", - - "merge": "Merge", - "menu": "Menù", - "meridiem": "AM/PM", - "mime": "Tipos de medios", - "minutes": "Minutos", - - "month": "Mes", - "months.april": "Abril", - "months.august": "Agosto", - "months.december": "Diciembre", - "months.february": "Febrero", - "months.january": "Enero", - "months.july": "Julio", - "months.june": "Junio", - "months.march": "Marzo", - "months.may": "Mayo", - "months.november": "Noviembre", - "months.october": "Octubre", - "months.september": "Septiembre", - - "more": "Màs", - "move": "Move", - "name": "Nombre", - "next": "Siguiente", - "night": "Night", - "no": "no", - "off": "Apagado", - "on": "Encendido", - "open": "Abrir", - "open.newWindow": "Abrir en una ventana nueva", - "option": "Option", - "options": "Opciones", - "options.none": "Sin opciones", - "options.all": "Show all {count} options", - - "orientation": "Orientación", - "orientation.landscape": "Paisaje", - "orientation.portrait": "Retrato", - "orientation.square": "Diapositiva", - - "page": "Página", - "page.blueprint": "Este archivo aún no tiene blueprint. Puedes definir la configuración en /site/blueprints/pages/{blueprint}.yml", - "page.changeSlug": "Cambiar URL", - "page.changeSlug.fromTitle": "Crear a partir del t\u00edtulo", - "page.changeStatus": "Cambiar estado", - "page.changeStatus.position": "Por favor selecciona una posición", - "page.changeStatus.select": "Selecciona un nuevo estado", - "page.changeTemplate": "Cambiar plantilla", - "page.changeTemplate.notice": "Changing the page's template will remove content for fields that don't match in type. Use with caution.", - "page.create": "Create as {status}", - "page.delete.confirm": "¿Estás seguro que deseas eliminar {title}?", - "page.delete.confirm.subpages": "Esta página tiene subpáginas.
Todas las súbpaginas serán eliminadas también.", - "page.delete.confirm.title": "Introduce el título de la página para confirmar", - "page.duplicate.appendix": "Copiar", - "page.duplicate.files": "Copiar archivos", - "page.duplicate.pages": "Copiar páginas", - "page.move": "Move page", - "page.sort": "Cambiar posición", - "page.status": "Estado", - "page.status.draft": "Borrador", - "page.status.draft.description": "La página está en modo borrador y solo es visible para editores conectados o mediante enlace secreto.", - "page.status.listed": "Pública", - "page.status.listed.description": "La página es pública para cualquiera", - "page.status.unlisted": "No publicada", - "page.status.unlisted.description": "La página sólo es accesible vía URL", - - "pages": "Páginas", - "pages.empty": "No hay páginas aún", - "pages.status.draft": "Borradores", - "pages.status.listed": "Publicado", - "pages.status.unlisted": "No publicado", - - "pagination.page": "Página", - - "password": "Contrase\u00f1a", - "paste": "Pegar", - "paste.after": "Pegar después", - "paste.success": "{count} pasted!", - "pixel": "Pixel", - "plugin": "Plugin", - "plugins": "Plugins", - "prev": "Anterior", - "preview": "Previsualizar", - "remove": "Eliminar", - "rename": "Renombrar", - "renew": "Renew", - "replace": "Reemplazar", - "replace.with": "Replace with", - "retry": "Reintentar", - "revert": "Revertir", - "revert.confirm": "¿Realmente quieres eliminar todos los cambios sin guardar?", - - "role": "Rol", - "role.admin.description": "El administrador tiene todos los derechos", - "role.admin.title": "Administrador", - "role.all": "Todos", - "role.empty": "No hay usuarios con este rol", - "role.description.placeholder": "Sin descripción", - "role.nobody.description": "Este es un rol alternativo sin permisos", - "role.nobody.title": "Nadie", - - "save": "Guardar", - "search": "Buscar", - "search.min": "Introduce {min} caracteres para buscar", - "search.all": "Show all {count} results", - "search.results.none": "Sin resultados", - - "section.invalid": "The section is invalid", - "section.required": "Esta sección es requerida", - - "security": "Seguridad", - "select": "Seleccionar", - "server": "Servidor", - "settings": "Ajustes", - "show": "Mostrar", - "site.blueprint": "Este archivo aún no tiene blueprint. Puedes definir la configuración en /site/blueprints/site.yml", - "size": "Tamaño", - "slug": "Apéndice URL", - "sort": "Ordenar", - "sort.drag": "Drag to sort …", - "split": "Split", - - "stats.empty": "Sin informes", - "status": "Estado", - - "system.info.copy": "Copy info", - "system.info.copied": "System info copied", - "system.issues.content": "La carpeta content parece estar expuesta", - "system.issues.eol.kirby": "La versión de Kirby que tienes instalada ha llegado al final de su vida útil y no recibirá más actualizaciones de seguridad.", - "system.issues.eol.plugin": "Tu versión instalada del plugin { plugin } ha llegado al final de su vida útil y no recibirá más actualizaciones de seguridad.", - "system.issues.eol.php": "Your installed PHP release { release } has reached end-of-life and will not receive further security updates", - "system.issues.debug": "La depuración debe estar desactivada en producción", - "system.issues.git": "La carpeta .git parece estar expuesta", - "system.issues.https": "Recomendamos HTTPS para todos tus sitios web", - "system.issues.kirby": "La carpeta kirby parece estar expuesta", - "system.issues.site": "La carpeta site parece estar expuesta", - "system.issues.vulnerability.kirby": "Tu instalación podría estar afectada por la siguiente vulnerabilidad ({ severity } gravedad): { description }", - "system.issues.vulnerability.plugin": "Tu instalación podría estar afectada por la siguiente vulnerabilidad en el plugin { plugin } ({ severity } gravedad): { description }", - "system.updateStatus": "Estado de actualización", - "system.updateStatus.error": "No se ha podido comprobar si hay actualizaciones", - "system.updateStatus.not-vulnerable": "No hay vulnerabilidades conocidas", - "system.updateStatus.security-update": "Actualización gratuita de seguridad { version } disponible", - "system.updateStatus.security-upgrade": "Actualización { versión } con correcciones de seguridad disponibles", - "system.updateStatus.unreleased": "Versión no publicada", - "system.updateStatus.up-to-date": "Actualizado", - "system.updateStatus.update": "Actualización gratuita {version} disponible", - "system.updateStatus.upgrade": "Actualización {versión} disponible", - - "tel": "Phone", - "tel.placeholder": "+49123456789", - "template": "Plantilla", - "title": "Título", - "today": "Hoy", - - "toolbar.button.clear": "Clear formatting", - "toolbar.button.code": "Código", - "toolbar.button.bold": "Negrita", - "toolbar.button.email": "Email", - "toolbar.button.headings": "Encabezados", - "toolbar.button.heading.1": "Encabezado 1", - "toolbar.button.heading.2": "Encabezado 2", - "toolbar.button.heading.3": "Encabezado 3", - "toolbar.button.heading.4": "Encabezado 4", - "toolbar.button.heading.5": "Encabezado 5", - "toolbar.button.heading.6": "Encabezado 6", - "toolbar.button.italic": "Texto en It\u00e1licas", - "toolbar.button.file": "Archivo", - "toolbar.button.file.select": "Selecciona un archivo", - "toolbar.button.file.upload": "Sube un archivo", - "toolbar.button.link": "Enlace", - "toolbar.button.paragraph": "Parágrafo", - "toolbar.button.strike": "Tachado", - "toolbar.button.sub": "Subscript", - "toolbar.button.sup": "Superscript", - "toolbar.button.ol": "Lista en orden", - "toolbar.button.underline": "Subrayado", - "toolbar.button.ul": "Lista de viñetas", - - "translation.author": "Equipo Kirby", - "translation.direction": "ltr", - "translation.name": "Español (América Latina)", - "translation.locale": "es_419", - - "type": "Type", - - "upload": "Subir", - "upload.error.cantMove": "El archivo subido no puede ser movido", - "upload.error.cantWrite": "Error al escribir el archivo en el disco", - "upload.error.default": "El archivo no pudo ser subido", - "upload.error.extension": "Subida de archivo detenida por la extensión", - "upload.error.formSize": "El archivo subido excede la directiva MAX_FILE_SIZE que fue especificada en el formulario", - "upload.error.iniPostSize": "El archivo subido excede la directiva post_max_size directive en php.ini", - "upload.error.iniSize": "El archivo subido excede la directiva upload_max_filesize en php.ini", - "upload.error.noFile": "Ningún archivo ha sido subido", - "upload.error.noFiles": "Ningún archivo ha sido subido", - "upload.error.partial": "El archivo ha sido subido solo parcialmente", - "upload.error.tmpDir": "No se encuentra la carpeta temporal", - "upload.errors": "Error", - "upload.progress": "Subiendo...", - - "url": "Url", - "url.placeholder": "https://ejemplo.com", - - "user": "Usuario", - "user.blueprint": "Puedes definir secciones y campos de formulario adicionales para este rol de usuario en /site/blueprints/users/{blueprint}.yml", - "user.changeEmail": "Cambiar correo electrónico", - "user.changeLanguage": "Cambiar idioma", - "user.changeName": "Renombrar este usuario", - "user.changePassword": "Cambiar la contraseña", - "user.changePassword.new": "Nueva contraseña", - "user.changePassword.new.confirm": "Confirma la nueva contraseña...", - "user.changeRole": "Cambiar rol", - "user.changeRole.select": "Selecciona un nuevo rol", - "user.create": "Agregar un nuevo usuario", - "user.delete": "Eliminar este usuario", - "user.delete.confirm": "¿Estás seguro que deseas eliminar
{email}?", - - "users": "Usuarios", - - "version": "Versión", - "version.current": "Versión actual", - "version.latest": "Última versión", - "versionInformation": "información sobre la versión", - - "view.account": "Tu cuenta", - "view.installation": "Instalaci\u00f3n", - "view.languages": "Idiomas", - "view.resetPassword": "Restablecer contraseña", - "view.site": "Sitio", - "view.system": "Sistema", - "view.users": "Usuarios", - - "welcome": "Bienvenido", - "year": "Año", - "yes": "Sí" + "account.changeName": "Cambiar nombre", + "account.delete": "Eliminar cuenta", + "account.delete.confirm": "¿Realmente quieres eliminar tu cuenta? Tu sesión se cerrará inmediatamente. Tu cuenta no podrá ser recuperada. ", + + "add": "Agregar", + "author": "Autor", + "avatar": "Foto de perfil", + "back": "Regresar", + "cancel": "Cancelar", + "change": "Cambiar", + "close": "Cerrar", + "confirm": "De acuerdo", + "collapse": "Colapsar", + "collapse.all": "Colapsar todos", + "copy": "Copiar", + "copy.all": "Copiar todo", + "create": "Crear", + + "date": "Fecha", + "date.select": "Selecciona una fecha", + + "day": "Día", + "days.fri": "Vie", + "days.mon": "Lun", + "days.sat": "S\u00e1b", + "days.sun": "Dom", + "days.thu": "Jue", + "days.tue": "Mar", + "days.wed": "Mi\u00e9", + + "debugging": "Debugging", + + "delete": "Eliminar", + "delete.all": "Eliminar todos", + + "dialog.files.empty": "No has seleccionado ningún archivo", + "dialog.pages.empty": "No has seleccionado ninguna página", + "dialog.users.empty": "No has seleccionado ningún usuario", + + "dimensions": "Dimensiones", + "disabled": "Deshabilitado", + "discard": "Descartar", + "download": "Descargar", + "duplicate": "Duplicar", + + "edit": "Editar", + + "email": "Correo Electrónico", + "email.placeholder": "correo@ejemplo.com", + + "entries": "Entries", + "entry": "Entry", + + "environment": "Ambiente", + + "error.access.code": "Código inválido", + "error.access.login": "Ingreso inválido", + "error.access.panel": "No tienes permitido acceder al panel", + "error.access.view": "No tienes permiso para acceder a esta parte del panel", + + "error.avatar.create.fail": "No se pudo subir la foto de perfil", + "error.avatar.delete.fail": "No se pudo eliminar la foto de perfil", + "error.avatar.dimensions.invalid": "Por favor, mantén el ancho y la altura de la imagen de perfil por debajo de 3000 pixeles", + "error.avatar.mime.forbidden": "La foto de perfil debe de ser un archivo JPG o PNG", + + "error.blueprint.notFound": "El blueprint \"{name}\" no se pudo cargar.", + + "error.blocks.max.plural": "No debes añadir más de {max} bloques", + "error.blocks.max.singular": "No debes añadir más de un bloque", + "error.blocks.min.plural": "Debes añadir al menos {min} bloques ", + "error.blocks.min.singular": "Debes añadir al menos un bloque", + "error.blocks.validation": "Hay un error en el bloque {index}", + + "error.email.preset.notFound": "El preajuste de email \"{name}\" no se pudo encontrar.", + + "error.field.converter.invalid": "Convertidor inválido \"{converter}\"", + + "error.file.changeName.empty": "El nombre no debe estar vacío", + "error.file.changeName.permission": "No tienes permitido cambiar el nombre de \"{filename}\"", + "error.file.duplicate": "Ya existe un archivo con el nombre \"{filename}\".", + "error.file.extension.forbidden": "La extensión \"{extension}\" no está permitida.", + "error.file.extension.invalid": "Extensión inválida: {extension}", + "error.file.extension.missing": "Falta la extensión para \"{filename}\".", + "error.file.maxheight": "La altura de la imagen no debe exceder {height} pixeles", + "error.file.maxsize": "El archivo es muy grande", + "error.file.maxwidth": "El ancho de la imagen no debe exceder {width} pixeles", + "error.file.mime.differs": "El archivo cargado debe ser del mismo tipo mime \"{mime}\".", + "error.file.mime.forbidden": "El tipo de medios \"{mime}\" no está permitido.", + "error.file.mime.invalid": "Tipo invalido de mime: {mime}", + "error.file.mime.missing": "No se puede detectar el tipo de medio para \"{filename}\".", + "error.file.minheight": "La altura de la imagen debe ser de al menos {height} pixeles", + "error.file.minsize": "El archivo es muy pequeño", + "error.file.minwidth": "El ancho de la imagen debe ser de al menos {width} pixeles", + "error.file.name.missing": "El nombre del archivo no debe estar vacío.", + "error.file.notFound": "El archivo \"{filename}\" no pudo ser encontrado.", + "error.file.orientation": "La orientación de la imagen debe ser \"{orientation}\"", + "error.file.type.forbidden": "No está permitido subir archivos {type}.", + "error.file.type.invalid": "Tipo de archivo inválido: {type}", + "error.file.undefined": "El archivo no se puede encontrar", + + "error.form.incomplete": "Por favor, corrige todos los errores del formulario...", + "error.form.notSaved": "No se pudo guardar el formulario", + + "error.language.code": "Por favor introduce un código válido para el idioma", + "error.language.duplicate": "El idioma ya existe", + "error.language.name": "Por favor introduce un nombre válido para el idioma", + "error.language.notFound": "No se pudo encontrar el idioma", + + "error.layout.validation.block": "There's an error in block {blockIndex} in layout {layoutIndex}", + "error.layout.validation.settings": "There's an error in layout {index} settings", + + "error.license.format": "Por favor introduce una llave de licencia válida", + "error.license.email": "Por favor ingresa un correo electrónico valido", + "error.license.verification": "La licencia no pude ser verificada", + + "error.offline": "El Panel se encuentra fuera de linea ", + + "error.page.changeSlug.permission": "No está permitido cambiar el apéndice de URL para \"{slug}\".", + "error.page.changeStatus.incomplete": "La página tiene errores y no puede ser publicada.", + "error.page.changeStatus.permission": "El estado de esta página no se puede cambiar.", + "error.page.changeStatus.toDraft.invalid": "La página \"{slug}\" no se puede convertir en un borrador", + "error.page.changeTemplate.invalid": "La plantilla para la página \"{slug}\" no se puede cambiar", + "error.page.changeTemplate.permission": "No está permitido cambiar la plantilla para \"{slug}\"", + "error.page.changeTitle.empty": "El título no debe estar vacío.", + "error.page.changeTitle.permission": "No tienes permiso para cambiar el título de \"{slug}\"", + "error.page.create.permission": "No tienes permiso para crear \"{slug}\"", + "error.page.delete": "La página \"{slug}\" no se puede eliminar", + "error.page.delete.confirm": "Por favor, introduce el título de la página para confirmar", + "error.page.delete.hasChildren": "La página tiene subpáginas y no se puede eliminar", + "error.page.delete.permission": "No tienes permiso para borrar \"{slug}\"", + "error.page.draft.duplicate": "Ya existe un borrador de página con el apéndice de URL \"{slug}\"", + "error.page.duplicate": "Ya existe una página con el apéndice de URL \"{slug}\"", + "error.page.duplicate.permission": "No tienes permitido duplicar \"{slug}\"", + "error.page.notFound": "La página \"{slug}\" no se encuentra", + "error.page.num.invalid": "Por favor, introduce un número de posición válido. Los números no deben ser negativos.", + "error.page.slug.invalid": "Please enter a valid URL appendix", + "error.page.slug.maxlength": "Slug length must be less than \"{length}\" characters", + "error.page.sort.permission": "La página \"{slug}\" no se puede ordenar", + "error.page.status.invalid": "Por favor, establece una estado de página válido", + "error.page.undefined": "La p\u00e1gina no fue encontrada", + "error.page.update.permission": "No tienes permiso para actualizar \"{slug}\"", + + "error.section.files.max.plural": "No debes agregar más de {max} archivos a la sección \"{section}\"", + "error.section.files.max.singular": "No debes agregar más de un archivo a la sección \"{section}\"", + "error.section.files.min.plural": "La sección \"{section}\" requiere al menos {min} archivos", + "error.section.files.min.singular": "La sección \"{section}\" requiere al menos un archivo", + + "error.section.pages.max.plural": "No debes agregar más de {max} páginas a la sección \"{section}\"", + "error.section.pages.max.singular": "No debes agregar más de una página a la sección \"{section}\"", + "error.section.pages.min.plural": "La sección \"{section}\" requiere al menos {min} páginas", + "error.section.pages.min.singular": "La sección \"{section}\" requiere al menos una página", + + "error.section.notLoaded": "La sección \"{name}\" no se pudo cargar", + "error.section.type.invalid": "La sección \"{type}\" no es valida", + + "error.site.changeTitle.empty": "El título no debe estar vacío.", + "error.site.changeTitle.permission": "No tienes permiso para cambiar el título del sitio", + "error.site.update.permission": "No tienes permiso de actualizar el sitio", + + "error.template.default.notFound": "La plantilla predeterminada no existe", + + "error.unexpected": "An unexpected error occurred! Enable debug mode for more info: https://getkirby.com/docs/reference/system/options/debug", + + "error.user.changeEmail.permission": "No tienes permiso para cambiar el email del usuario \"{name}\"", + "error.user.changeLanguage.permission": "No tienes permiso para cambiar el idioma del usuario \"{name}\"", + "error.user.changeName.permission": "No tienes permiso para cambiar el nombre del usuario \"{name}\"", + "error.user.changePassword.permission": "No tienes permiso para cambiar la contraseña del usuario \"{name}\"", + "error.user.changeRole.lastAdmin": "El rol del último administrador no puede ser cambiado", + "error.user.changeRole.permission": "No tienes permiso para cambiar el rol del usuario \"{name}\"", + "error.user.changeRole.toAdmin": "No tienes permitido promover a alguien al rol de admin", + "error.user.create.permission": "No tienes permiso de crear este usuario", + "error.user.delete": "El ususario no pudo ser eliminado", + "error.user.delete.lastAdmin": "Usted no puede borrar el \u00faltimo administrador", + "error.user.delete.lastUser": "El último usuario no puede ser borrado", + "error.user.delete.permission": "Usted no tiene permitido borrar este usuario", + "error.user.duplicate": "Ya existe un usuario con el email \"{email}\"", + "error.user.email.invalid": "Por favor ingresa un correo electrónico valido", + "error.user.language.invalid": "Por favor ingresa un idioma valido", + "error.user.notFound": "El usuario no pudo ser encontrado", + "error.user.password.excessive": "Please enter a valid password. Passwords must not be longer than 1000 characters.", + "error.user.password.invalid": "Por favor ingresa una contraseña valida. Las contraseñas deben tener al menos 8 caracteres de largo.", + "error.user.password.notSame": "Por favor confirma la contrase\u00f1a", + "error.user.password.undefined": "El usuario no tiene contraseña", + "error.user.password.wrong": "Contraseña incorrecta", + "error.user.role.invalid": "Por favor ingresa un rol valido", + "error.user.undefined": "El usuario no pudo ser encontrado", + "error.user.update.permission": "No tienes permiso para actualizar al usuario \"{name}\"", + + "error.validation.accepted": "Por favor, confirma", + "error.validation.alpha": "Por favor ingrese solo caracteres entre a-z", + "error.validation.alphanum": "Por favor ingrese solo caracteres entre a-z o números entre 0-9", + "error.validation.between": "Por favor ingrese valores entre \"{min}\" y \"{max}\"", + "error.validation.boolean": "Por favor confirme o niegue", + "error.validation.contains": "Por favor ingrese valores que contengan \"{needle}\"", + "error.validation.date": "Por favor ingresa una fecha válida", + "error.validation.date.after": "Por favor introduce una fecha posterior a {date}", + "error.validation.date.before": "Por favor introduce una fecha anterior a {date}", + "error.validation.date.between": "Por favor introduce un número entre {min} y {max}", + "error.validation.denied": "Por favor niegue", + "error.validation.different": "EL valor no debe ser \"{other}\"", + "error.validation.email": "Por favor ingresa un correo electrónico valido", + "error.validation.endswith": "El valor no debe terminar con \"{end}\"", + "error.validation.filename": "Por favor ingresa un nombre de archivo válido", + "error.validation.in": "Por favor ingresa uno de los siguientes: ({in})", + "error.validation.integer": "Por favor ingresa un entero válido", + "error.validation.ip": "Por favor ingresa una dirección IP válida", + "error.validation.less": "Por favor ingresa un valor menor a {max}", + "error.validation.match": "El valor no coincide con el patrón esperado", + "error.validation.max": "Por favor ingresa un valor menor o igual a {max}", + "error.validation.maxlength": "Por favor ingresa un valor mas corto. (max. {max} caracteres)", + "error.validation.maxwords": "Por favor ingresa no mas de {max} palabra(s)", + "error.validation.min": "Por favor ingresa un valor mayor o igual a {min}", + "error.validation.minlength": "Por favor ingresa un valor mas largo. (min. {min} caracteres)", + "error.validation.minwords": "Por favor ingresa al menos {min} palabra(s)", + "error.validation.more": "Por favor ingresa un valor mayor a {min}", + "error.validation.notcontains": "Por favor ingresa un valor que no contenga \"{needle}\"", + "error.validation.notin": "Por favor no ingreses ninguno de las siguientes: ({notIn})", + "error.validation.option": "Por favor selecciona una de las opciones válidas", + "error.validation.num": "Por favor ingresa un numero válido", + "error.validation.required": "Por favor ingresa algo", + "error.validation.same": "Por favor ingresa \"{other}\"", + "error.validation.size": "El tamaño del valor debe ser \"{size}\"", + "error.validation.startswith": "El valor debe comenzar con \"{start}\"", + "error.validation.time": "Por favor ingresa una hora válida", + "error.validation.time.after": "Por favor ingresa una fecha después de {time}", + "error.validation.time.before": "Por favor ingresa una fecha antes de {time}", + "error.validation.time.between": "Por favor ingresa un fecha entre {min} y {max}", + "error.validation.url": "Por favor ingresa un URL válido", + + "expand": "Expandir", + "expand.all": "Expandir todo", + + "field.required": "Este campo es requerido", + "field.blocks.changeType": "Cambiar tipo", + "field.blocks.code.name": "Código", + "field.blocks.code.language": "Idioma", + "field.blocks.code.placeholder": "Tu código...", + "field.blocks.delete.confirm": "¿Seguro que quieres eliminar este bloque?", + "field.blocks.delete.confirm.all": "¿Seguro que quieres eliminar todos los bloques?", + "field.blocks.delete.confirm.selected": "¿Seguro que quieres eliminar los bloques seleccionados?", + "field.blocks.empty": "No hay bloques aún", + "field.blocks.fieldsets.label": "Por favor selecciona un tipo de bloque...", + "field.blocks.fieldsets.paste": "Presiona {{ shortcut }}para pegar/importar bloques en tu portapapeles ", + "field.blocks.gallery.name": "Galería", + "field.blocks.gallery.images.empty": "No hay imágenes aún", + "field.blocks.gallery.images.label": "Imágenes", + "field.blocks.heading.level": "Nivel", + "field.blocks.heading.name": "Encabezado", + "field.blocks.heading.text": "Texto", + "field.blocks.heading.placeholder": "Encabezado...", + "field.blocks.image.alt": "Texto alternativo", + "field.blocks.image.caption": "Leyenda", + "field.blocks.image.crop": "Cortar", + "field.blocks.image.link": "Enlace", + "field.blocks.image.location": "Ubicación", + "field.blocks.image.name": "Imágen", + "field.blocks.image.placeholder": "Selecciona una imagen", + "field.blocks.image.ratio": "Proporción", + "field.blocks.image.url": "URL de imágen", + "field.blocks.line.name": "Linea", + "field.blocks.list.name": "Lista", + "field.blocks.markdown.name": "Markdown", + "field.blocks.markdown.label": "Texto", + "field.blocks.markdown.placeholder": "Markdown...", + "field.blocks.quote.name": "Cita", + "field.blocks.quote.text.label": "Texto", + "field.blocks.quote.text.placeholder": "Cita...", + "field.blocks.quote.citation.label": "Citation", + "field.blocks.quote.citation.placeholder": "Por ...", + "field.blocks.text.name": "Texto", + "field.blocks.text.placeholder": "Text …", + "field.blocks.video.caption": "Leyenda", + "field.blocks.video.name": "Video", + "field.blocks.video.placeholder": "Enter a video URL", + "field.blocks.video.url.label": "Video-URL", + "field.blocks.video.url.placeholder": "https://youtube.com/?v=", + + "field.files.empty": "Aún no ha seleccionado ningún archivo", + + "field.layout.delete": "Delete layout", + "field.layout.delete.confirm": "Do you really want to delete this layout?", + "field.layout.empty": "No rows yet", + "field.layout.select": "Select a layout", + + "field.pages.empty": "Aún no ha seleccionado ningúna pagina", + "field.structure.delete.confirm": "\u00bfEn realidad desea borrar esta entrada?", + "field.structure.empty": "A\u00fan no existen entradas.", + "field.users.empty": "Aún no ha seleccionado ningún usuario", + + "file.blueprint": "This file has no blueprint yet. You can define the setup in /site/blueprints/files/{blueprint}.yml", + "file.delete.confirm": "\u00bfEst\u00e1s seguro que deseas eliminar este archivo?", + "file.sort": "Change position", + + "files": "Archivos", + "files.empty": "Aún no existen archivos", + + "hide": "Hide", + "hour": "Hora", + "import": "Import", + "info": "Info", + "insert": "Insertar", + "insert.after": "Insert after", + "insert.before": "Insert before", + "install": "Instalar", + + "installation": "Instalación", + "installation.completed": "El panel ha sido instalado.", + "installation.disabled": "El instalador del panel está deshabilitado en servidores públicos por defecto. Ejecute el instalador en una máquina local o habilítelo con la opción panel.install.", + "installation.issues.accounts": "La carpeta /site/accounts no existe o no posee permisos de escritura.", + "installation.issues.content": "La carpeta /content no existe o no posee permisos de escritura.", + "installation.issues.curl": "Se requiere la extensión CURL.", + "installation.issues.headline": "El panel no puede ser instalado.", + "installation.issues.mbstring": "Se requiere la extensión MB String.", + "installation.issues.media": "La carpeta /media no existe o no posee permisos de escritura.", + "installation.issues.php": "Asegurese de estar usando PHP 7+", + "installation.issues.server": "Kirby requiere Apache, Nginx, Caddy", + "installation.issues.sessions": "La carpeta /site/sessions no existe o no posee permisos de escritura.", + + "language": "Idioma", + "language.code": "Código", + "language.convert": "Hacer por defecto", + "language.convert.confirm": "

Realmente deseas convertir {name} al idioma por defecto? Esta acción no se puede deshacer.

Si {name} tiene contenido sin traducir, no habrá vuelta atras y tu sitio puede quedar con partes sin contenido.

", + "language.create": "Añadir nuevo idioma", + "language.delete.confirm": "

", + "language.deleted": "El idioma ha sido borrado", + "language.direction": "Dirección de lectura", + "language.direction.ltr": "De Izquierda a derecha", + "language.direction.rtl": "De derecha a izquierda", + "language.locale": "Cadena de localización PHP", + "language.locale.warning": "Estas utilizando un configuración local. Por favor modifícalo en el archivo del lenguaje en /site/languages", + "language.name": "Nombre", + "language.updated": "El idioma a sido actualizado", + + "languages": "Idiomas", + "languages.default": "Idioma por defecto", + "languages.empty": "Todavía no hay idiomas", + "languages.secondary": "Idiomas secundarios", + "languages.secondary.empty": "Todavía no hay idiomas secundarios", + + "license": "Licencia", + "license.buy": "Comprar una licencia", + "license.register": "Registrar", + "license.manage": "Manage your licenses", + "license.register.help": "Recibió su código de licencia después de la compra por correo electrónico. Por favor copie y pegue para registrarse.", + "license.register.label": "Por favor, ingresa tu código de licencia", + "license.register.success": "Gracias por apoyar a Kirby", + "license.unregistered": "Este es un demo no registrado de Kirby", + "license.unregistered.label": "Unregistered", + + "link": "Enlace", + "link.text": "Texto de Enlace", + + "loading": "Cargando", + + "lock.unsaved": "Cambios sin guardar", + "lock.unsaved.empty": "No hay más cambios sin guardar", + "lock.isLocked": "Cambios sin guardar por {email}", + "lock.file.isLocked": "El archivo está siendo actualmente editado por {email} y no puede ser cambiado.", + "lock.page.isLocked": "La página está siendo actualmente editada por {email} y no puede ser cambiada.", + "lock.unlock": "Desbloquear", + "lock.isUnlocked": "Tus cambios sin guardar han sido sobrescritos por otro usuario. Puedes descargar los cambios y fusionarlos manualmente.", + + "login": "Iniciar sesión", + "login.code.label.login": "Login code", + "login.code.label.password-reset": "Password reset code", + "login.code.placeholder.email": "000 000", + "login.code.text.email": "If your email address is registered, the requested code was sent via email.", + "login.email.login.body": "Hi {user.nameOrEmail},\n\nYou recently requested a login code for the Panel of {site}.\nThe following login code will be valid for {timeout} minutes:\n\n{code}\n\nIf you did not request a login code, please ignore this email or contact your administrator if you have questions.\nFor security, please DO NOT forward this email.", + "login.email.login.subject": "Your login code", + "login.email.password-reset.body": "Hi {user.nameOrEmail},\n\nYou recently requested a password reset code for the Panel of {site}.\nThe following password reset code will be valid for {timeout} minutes:\n\n{code}\n\nIf you did not request a password reset code, please ignore this email or contact your administrator if you have questions.\nFor security, please DO NOT forward this email.", + "login.email.password-reset.subject": "Your password reset code", + "login.remember": "Mantener mi sesión iniciada", + "login.reset": "Reset password", + "login.toggleText.code.email": "Login via email", + "login.toggleText.code.email-password": "Login with password", + "login.toggleText.password-reset.email": "Forgot your password?", + "login.toggleText.password-reset.email-password": "← Back to login", + + "logout": "Cerrar sesi\u00f3n", + + "menu": "Menù", + "meridiem": "AM/PM", + "mime": "Tipos de medios", + "minutes": "Minutos", + + "month": "Mes", + "months.april": "Abril", + "months.august": "Agosto", + "months.december": "Diciembre", + "months.february": "Febrero", + "months.january": "Enero", + "months.july": "Julio", + "months.june": "Junio", + "months.march": "Marzo", + "months.may": "Mayo", + "months.november": "Noviembre", + "months.october": "Octubre", + "months.september": "Septiembre", + + "more": "Màs", + "name": "Nombre", + "next": "Siguiente", + "no": "no", + "off": "Apagado", + "on": "Encendido", + "open": "Abrir", + "open.newWindow": "Open in new window", + "options": "Opciones", + "options.none": "No options", + + "orientation": "Orientación", + "orientation.landscape": "Paisaje", + "orientation.portrait": "Retrato", + "orientation.square": "Diapositiva", + + "page.blueprint": "This page has no blueprint yet. You can define the setup in /site/blueprints/pages/{blueprint}.yml", + "page.changeSlug": "Cambiar URL", + "page.changeSlug.fromTitle": "Crear a partir del t\u00edtulo", + "page.changeStatus": "Cambiar estado", + "page.changeStatus.position": "Por favor selecciona una posición", + "page.changeStatus.select": "Selecciona un nuevo estado", + "page.changeTemplate": "Cambiar plantilla", + "page.delete.confirm": "¿Estás seguro que deseas eliminar {title}?", + "page.delete.confirm.subpages": "Esta página tiene subpáginas.
Todas las súbpaginas serán eliminadas también.", + "page.delete.confirm.title": "Introduce el título de la página para confirmar", + "page.draft.create": "Crear borrador", + "page.duplicate.appendix": "Copiar", + "page.duplicate.files": "Copiar archivos", + "page.duplicate.pages": "Copiar páginas", + "page.sort": "Change position", + "page.status": "Estado", + "page.status.draft": "Borrador", + "page.status.draft.description": "The page is in draft mode and only visible for logged in editors or via secret link", + "page.status.listed": "Pública", + "page.status.listed.description": "La página es pública para cualquiera", + "page.status.unlisted": "No publicada", + "page.status.unlisted.description": "La página sólo es accesible vía URL", + + "pages": "Páginas", + "pages.empty": "No hay páginas aún", + "pages.status.draft": "Borradores", + "pages.status.listed": "Publicado", + "pages.status.unlisted": "No publicado", + + "pagination.page": "Página", + + "password": "Contrase\u00f1a", + "paste": "Paste", + "paste.after": "Paste after", + "pixel": "Pixel", + "plugins": "Plugins", + "prev": "Anterior", + "preview": "Preview", + "remove": "Eliminar", + "rename": "Renombrar", + "replace": "Reemplazar", + "retry": "Reintentar", + "revert": "Revertir", + "revert.confirm": "Do you really want to delete all unsaved changes?", + + "role": "Rol", + "role.admin.description": "El administrador tiene todos los derechos", + "role.admin.title": "Administrador", + "role.all": "Todos", + "role.empty": "No hay usuarios con este rol", + "role.description.placeholder": "Sin descripción", + "role.nobody.description": "Este es un rol alternativo sin permisos", + "role.nobody.title": "Nadie", + + "save": "Guardar", + "search": "Buscar", + "search.min": "Enter {min} characters to search", + "search.all": "Show all", + "search.results.none": "No results", + + "section.required": "Esta sección es requerida", + + "security": "Security", + "select": "Seleccionar", + "server": "Server", + "settings": "Ajustes", + "show": "Show", + "site.blueprint": "The site has no blueprint yet. You can define the setup in /site/blueprints/site.yml", + "size": "Tamaño", + "slug": "Apéndice URL", + "sort": "Ordenar", + + "stats.empty": "No reports", + "system.issues.content": "The content folder seems to be exposed", + "system.issues.debug": "Debugging must be turned off in production", + "system.issues.git": "The .git folder seems to be exposed", + "system.issues.https": "We recommend HTTPS for all your sites", + "system.issues.kirby": "The kirby folder seems to be exposed", + "system.issues.site": "The site folder seems to be exposed", + + "title": "Título", + "template": "Plantilla", + "today": "Hoy", + + "toolbar.button.code": "Código", + "toolbar.button.bold": "Negrita", + "toolbar.button.email": "Email", + "toolbar.button.headings": "Encabezados", + "toolbar.button.heading.1": "Encabezado 1", + "toolbar.button.heading.2": "Encabezado 2", + "toolbar.button.heading.3": "Encabezado 3", + "toolbar.button.heading.4": "Encabezado 4", + "toolbar.button.heading.5": "Encabezado 5", + "toolbar.button.heading.6": "Encabezado 6", + "toolbar.button.italic": "Texto en It\u00e1licas", + "toolbar.button.file": "Archivo", + "toolbar.button.file.select": "Selecciona un archivo", + "toolbar.button.file.upload": "Sube un archivo", + "toolbar.button.link": "Enlace", + "toolbar.button.paragraph": "Paragraph", + "toolbar.button.strike": "Strike-through", + "toolbar.button.ol": "Lista en orden", + "toolbar.button.underline": "Underline", + "toolbar.button.ul": "Lista de viñetas", + + "translation.author": "Equipo Kirby", + "translation.direction": "ltr", + "translation.name": "Español (América Latina)", + "translation.locale": "es_419", + + "upload": "Subir", + "upload.error.cantMove": "El archivo subido no puede ser movido", + "upload.error.cantWrite": "Error al escribir el archivo en el disco", + "upload.error.default": "El archivo no pudo ser subido", + "upload.error.extension": "Subida de archivo detenida por la extensión", + "upload.error.formSize": "El archivo subido excede la directiva MAX_FILE_SIZE que fue especificada en el formulario", + "upload.error.iniPostSize": "El archivo subido excede la directiva post_max_size directive en php.ini", + "upload.error.iniSize": "El archivo subido excede la directiva upload_max_filesize en php.ini", + "upload.error.noFile": "Ningún archivo ha sido subido", + "upload.error.noFiles": "Ningún archivo ha sido subido", + "upload.error.partial": "El archivo ha sido subido solo parcialmente", + "upload.error.tmpDir": "No se encuentra la carpeta temporal", + "upload.errors": "Error", + "upload.progress": "Subiendo...", + + "url": "Url", + "url.placeholder": "https://ejemplo.com", + + "user": "Usuario", + "user.blueprint": "You can define additional sections and form fields for this user role in /site/blueprints/users/{blueprint}.yml", + "user.changeEmail": "Cambiar correo electrónico", + "user.changeLanguage": "Cambiar idioma", + "user.changeName": "Renombrar este usuario", + "user.changePassword": "Cambiar la contraseña", + "user.changePassword.new": "Nueva contraseña", + "user.changePassword.new.confirm": "Confirma la nueva contraseña...", + "user.changeRole": "Cambiar rol", + "user.changeRole.select": "Selecciona un nuevo rol", + "user.create": "Agregar un nuevo usuario", + "user.delete": "Eliminar este usuario", + "user.delete.confirm": "¿Estás seguro que deseas eliminar
{email}?", + + "users": "Usuarios", + + "version": "Versión", + + "view.account": "Tu cuenta", + "view.installation": "Instalaci\u00f3n", + "view.languages": "Idiomas", + "view.resetPassword": "Reset password", + "view.site": "Sitio", + "view.system": "System", + "view.users": "Usuarios", + + "welcome": "Bienvenido", + "year": "Año", + "yes": "yes" } diff --git a/kirby/i18n/translations/es_ES.json b/kirby/i18n/translations/es_ES.json index 0385355..48fa353 100644 --- a/kirby/i18n/translations/es_ES.json +++ b/kirby/i18n/translations/es_ES.json @@ -1,730 +1,574 @@ { - "account.changeName": "Cambiar nombre", - "account.delete": "Borrar cuenta", - "account.delete.confirm": "¿Realmente quieres eliminar tu cuenta? Tu sesión se cerrará inmediatamente. La cuenta no podrá ser recuperada.", - - "activate": "Activate", - "add": "Añadir", - "alpha": "Alpha", - "author": "Autor", - "avatar": "Foto de perfil", - "back": "Atrás", - "cancel": "Cancelar", - "change": "Cambiar", - "close": "Cerrar", - "changes": "Changes", - "confirm": "Confirmar", - "collapse": "Colapsar", - "collapse.all": "Colapsar todo", - "color": "Color", - "coordinates": "Coordinates", - "copy": "Copiar", - "copy.all": "Copiar todo", - "copy.success": "{count} copied!", - "create": "Crear", - "custom": "Custom", - - "date": "Fecha", - "date.select": "Selecciona una fecha", - - "day": "Día", - "days.fri": "Vi", - "days.mon": "Lu", - "days.sat": "Sá", - "days.sun": "Do", - "days.thu": "Ju", - "days.tue": "Ma", - "days.wed": "Mi", - - "debugging": "Depuración", - - "delete": "Eliminar", - "delete.all": "Eliminar todo", - - "dialog.fields.empty": "This dialog has no fields", - "dialog.files.empty": "No hay archivos para seleccionar", - "dialog.pages.empty": "No hay páginas para seleccionar", - "dialog.text.empty": "This dialog does not define any text", - "dialog.users.empty": "No hay usuarios para seleccionar", - - "dimensions": "Dimensiones", - "disable": "Disable", - "disabled": "Desabilitado", - "discard": "Descartar", - - "drawer.fields.empty": "This drawer has no fields", - - "domain": "Domain", - "download": "Descargar", - "duplicate": "Duplicar", - - "edit": "Editar", - - "email": "Correo electrónico", - "email.placeholder": "correo@ejemplo.com", - - "enter": "Enter", - "entries": "Entradas", - "entry": "Entrada", - - "environment": "Entorno", - - "error": "Error", - "error.access.code": "Código inválido", - "error.access.login": "Inicio de sesión inválido", - "error.access.panel": "No tienes permiso para acceder al panel", - "error.access.view": "No tienes permiso para acceder a esta parte del panel", - - "error.avatar.create.fail": "No se pudo subir la foto de perfil.", - "error.avatar.delete.fail": "No se pudo borrar la foto de perfil", - "error.avatar.dimensions.invalid": "Por favor, mantén el ancho y la altura de la imagen de perfil por debajo de 3000 píxeles", - "error.avatar.mime.forbidden": "La imagen del perfil debe ser JPEG o PNG.", - - "error.blueprint.notFound": "El blueprint \"{name}\" no pudo ser cargado", - - "error.blocks.max.plural": "No debes añadir más de {max} bloques", - "error.blocks.max.singular": "No debes añadir más de un bloque", - "error.blocks.min.plural": "Debes añadir al menos {min} bloques ", - "error.blocks.min.singular": "Debes añadir al menos un bloque", - "error.blocks.validation": "Hay un error en el campo \"{field}\" del bloque {index} que utiliza el tipo de bloque \"{fieldset}\"", - - "error.cache.type.invalid": "Tipo de caché inválido \"{tipo}\"", - - "error.email.preset.notFound": "El preset del correo \"{name}\" no puede ser encontrado", - - "error.field.converter.invalid": "Convertidor \"{converter}\" inválido", - "error.field.type.missing": "Campo \"{ name }\": El tipo de campo \"{ type }\" no existe", - - "error.file.changeName.empty": "El nombre no debe estar vacío", - "error.file.changeName.permission": "No tienes permiso para cambiar el nombre de \"{filename}\"", - "error.file.changeTemplate.invalid": "The template for the file \"{id}\" cannot be changed to \"{template}\" (valid: \"{blueprints}\")", - "error.file.changeTemplate.permission": "You are not allowed to change the template for the file \"{id}\"", - - "error.file.duplicate": "Ya existe un archivo con el nombre \"{filename}\"", - "error.file.extension.forbidden": "La extensión \"{extension}\" no está permitida", - "error.file.extension.invalid": "Extensión inválida: {extension}", - "error.file.extension.missing": "Falta la extensión para \"{filename}\"", - "error.file.maxheight": "La altura de la imagen no debe exceder {height} pixeles", - "error.file.maxsize": "El archivo es demasiado grande", - "error.file.maxwidth": "El ancho de la imagen no debe exceder {width} pixeles", - "error.file.mime.differs": "El archivo cargado debe ser del mismo tipo mime \"{mime}\"", - "error.file.mime.forbidden": "Los medios tipo \"{mime}\" no están permitidos", - "error.file.mime.invalid": "Tipo de mime inválido: {mime}", - "error.file.mime.missing": "El tipo de medio para \"{filename}\" no puede ser detectado", - "error.file.minheight": "La altura de la imagen debe ser de al menos {height} pixeles", - "error.file.minsize": "El archivo es demasiado pequeño", - "error.file.minwidth": "El ancho de la imagen debe ser de al menos {width} pixeles", - "error.file.name.unique": "The filename must be unique", - "error.file.name.missing": "El nombre de archivo no debe estar vacío", - "error.file.notFound": "El archivo \"{filename}\" no puede ser encontrado", - "error.file.orientation": "La orientación de la imagen debe ser \"{orientation}", - "error.file.type.forbidden": "No tienes permiso para subir archivos {type}", - "error.file.type.invalid": "Tipo de archivo inválido: {type}", - "error.file.undefined": "El archivo no puede ser encontrado", - - "error.form.incomplete": "Por favor, corrige todos los errores del formulario…", - "error.form.notSaved": "El formulario no pudo ser guardado", - - "error.language.code": "Por favor, introduce un código válido para el idioma", - "error.language.duplicate": "El idioma ya existe", - "error.language.name": "Por favor, introduce un nombre válido para el idioma", - "error.language.notFound": "No se pudo encontrar el idioma", - - "error.layout.validation.block": "Hay un error en el campo \"{field}\" del bloque {blockIndex} que utiliza el tipo de bloque \"{fieldset}\" en el layout {layoutIndex}", - "error.layout.validation.settings": "Hay un error en los ajustes del layout {index}", - - "error.license.domain": "The domain for the license is missing", - "error.license.email": "Por favor, introduce un correo electrónico válido", - "error.license.format": "Please enter a valid license code", - "error.license.verification": "La licencia no pudo ser verificada", - - "error.login.totp.confirm.invalid": "Código inválido", - "error.login.totp.confirm.missing": "Please enter the current code", - - "error.object.validation": "Hay un error en el campo \"{label}\":\n{message}", - - "error.offline": "El Panel se encuentra actualmente fuera de línea ", - - "error.page.changeSlug.permission": "No tienes permiso para cambiar el apéndice de URL para \"{slug}\"", - "error.page.changeSlug.reserved": "The path of top-level pages must not start with \"{path}\"", - "error.page.changeStatus.incomplete": "La página tiene errores y no puede ser publicada.", - "error.page.changeStatus.permission": "El estado de esta página no se puede cambiar", - "error.page.changeStatus.toDraft.invalid": "La página \"{slug}\" no se puede convertir a borrador", - "error.page.changeTemplate.invalid": "La plantilla para la página \"{slug}\" no se puede cambiar", - "error.page.changeTemplate.permission": "No tienes permiso para cambiar la plantilla para \"{slug}\"", - "error.page.changeTitle.empty": "El título no debe estar vacío.", - "error.page.changeTitle.permission": "No tienes permiso para cambiar el título por \"{slug}\"", - "error.page.create.permission": "No tienes permiso para crear \"{slug}\"", - "error.page.delete": "La página \"{slug}\" no se puede eliminar", - "error.page.delete.confirm": "Por favor, introduce el título de la página para confirmar", - "error.page.delete.hasChildren": "La página tiene subpáginas y no se puede eliminar", - "error.page.delete.permission": "No tienes permiso para eliminar \"{slug}\"", - "error.page.draft.duplicate": "Un borrador de página con el apéndice de URL \"{slug}\" ya existe", - "error.page.duplicate": "Una página con el apéndice de URL \"{slug}\" ya existe", - "error.page.duplicate.permission": "No tienes permiso para duplicar \"{slug}\"", - "error.page.move.ancestor": "The page cannot be moved into itself", - "error.page.move.directory": "The page directory cannot be moved", - "error.page.move.duplicate": "A sub page with the URL appendix \"{slug}\" already exists", - "error.page.move.notFound": "The moved page could not be found", - "error.page.move.permission": "You are not allowed to move \"{slug}\"", - "error.page.move.template": "The \"{template}\" template is not accepted as a subpage of \"{parent}\"", - "error.page.notFound": "No se puede encontrar la página \"{slug}\"", - "error.page.num.invalid": "Por favor, introduce un número de ordenación válido. Los números no deben ser negativos.", - "error.page.slug.invalid": "Por favor, introduce un apéndice de URL válido", - "error.page.slug.maxlength": "La longitud del slug debe ser inferior a \"{length}\" caracteres", - "error.page.sort.permission": "No se puede encontrar la página \"{slug}\"", - "error.page.status.invalid": "Por favor, establece un estado de página válido", - "error.page.undefined": "No se puede encontrar la página", - "error.page.update.permission": "No tienes permiso para actualizar \"{slug}\"", - - "error.section.files.max.plural": "No debes agregar más de {max} archivos a la sección \"{section}\"", - "error.section.files.max.singular": "No debes agregar más de 1 archivo a la sección \"{section}\"", - "error.section.files.min.plural": "La sección \"{section}\" requiere al menos {min} archivos", - "error.section.files.min.singular": "La sección \"{section}\" requiere al menos un archivo", - - "error.section.pages.max.plural": "No debes agregar más de {max} páginas a la sección \"{section}\"", - "error.section.pages.max.singular": "No debes agregar más de una página a la sección \"{section}\"", - "error.section.pages.min.plural": "La sección \"{section}\" requiere al menos {min} páginas", - "error.section.pages.min.singular": "La sección \"{section}\" requiere al menos una página", - - "error.section.notLoaded": "La sección \"{name}\" no pudo ser cargada", - "error.section.type.invalid": "El sección tipo \"{tipo}\" no es válido", - - "error.site.changeTitle.empty": "El título no debe estar vacío.", - "error.site.changeTitle.permission": "No tienes permiso para cambiar el título del sitio", - "error.site.update.permission": "No tienes permiso para actualizar el sitio", - - "error.structure.validation": "There's an error on the \"{field}\" field in row {index}", - - "error.template.default.notFound": "La plantilla por defecto no existe", - - "error.unexpected": "¡Se ha producido un error inesperado! Activa el modo de depuración para obtener más información: https://getkirby.com/docs/reference/system/options/debug", - - "error.user.changeEmail.permission": "No tienes permiso para cambiar el correo electrónico para el usuario \"{name}\"", - "error.user.changeLanguage.permission": "No tienes permiso para cambiar el idioma para el usuario \"{name}\"", - "error.user.changeName.permission": "No tienes permiso para cambiar el nombre del usuario \"{name}\"", - "error.user.changePassword.permission": "No tienes permiso para cambiar la contraseña del usuario \"{name}\"", - "error.user.changeRole.lastAdmin": "No se puede cambiar el rol del último administrador", - "error.user.changeRole.permission": "No tienes permiso para cambiar el rol del usuario \"{name}\"", - "error.user.changeRole.toAdmin": "No tienes permiso para promover a alguien al rol de admin", - "error.user.create.permission": "No tienes permiso para crear este usuario", - "error.user.delete": "No se puede eliminar el usuario \"{name}\"", - "error.user.delete.lastAdmin": "No se puede eliminar el último admin", - "error.user.delete.lastUser": "No se puede eliminar el último usuario ", - "error.user.delete.permission": "No tienes permiso para eliminar el usuario \"{name}\"", - "error.user.duplicate": "Un usuario con la dirección de correo electrónico \"{email}\" ya existe", - "error.user.email.invalid": "Por favor, introduce una dirección de correo electrónico válida", - "error.user.language.invalid": "Por favor, introduce un idioma válido", - "error.user.notFound": "No se puede encontrar el usuario \"{name}\"", - "error.user.password.excessive": "Please enter a valid password. Passwords must not be longer than 1000 characters.", - "error.user.password.invalid": "Por favor, introduce una contraseña válida. Las contraseñas deben tener al menos 8 caracteres de largo.", - "error.user.password.notSame": "Las contraseñas no coinciden", - "error.user.password.undefined": "El usuario no tiene contraseña", - "error.user.password.wrong": "Contraseña incorrecta", - "error.user.role.invalid": "Por favor, introduce un rol válido", - "error.user.undefined": "No se puede encontrar el usuario", - "error.user.update.permission": "No tienes permiso para actualizar el usuario \"{name}\"", - - "error.validation.accepted": "Por favor, confirma", - "error.validation.alpha": "Por favor, introduce solo caracteres entre a-z", - "error.validation.alphanum": "Por favor, introduce solo caracteres entre a-z o numerales 0-9", - "error.validation.anchor": "Please enter a correct link anchor", - "error.validation.between": "Por favor, introduce un valor entre \"{min}\" y \"{max}\"", - "error.validation.boolean": "Por favor, confirma o rechaza", - "error.validation.color": "Please enter a valid color in the {format} format", - "error.validation.contains": "Por favor, introduce un valor que contenga \"{needle}\"", - "error.validation.date": "Por favor, introduce una fecha válida", - "error.validation.date.after": "Por favor, introduce una fecha posterior a {date}", - "error.validation.date.before": "Por favor, introduce una fecha anterior a {date}", - "error.validation.date.between": "Por favor, introduce un número entre {min} y {max}", - "error.validation.denied": "Por favor, rechaza", - "error.validation.different": "El valor no debe ser \"{other}\"", - "error.validation.email": "Por favor, introduce un correo electrónico válido", - "error.validation.endswith": "El valor debe terminar con \"{end}\"", - "error.validation.filename": "Por favor, introduce un nombre de archivo válido", - "error.validation.in": "Por favor, introduce uno de los siguientes: ({in})", - "error.validation.integer": "Por favor, introduce un numero integro válido", - "error.validation.ip": "Por favor, introduce una dirección IP válida", - "error.validation.less": "Por favor, introduce un valor inferior a {max}", - "error.validation.linkType": "The link type is not allowed", - "error.validation.match": "El valor no coincide con el patrón esperado", - "error.validation.max": "Por favor, introduce un valor igual o inferior a {max}", - "error.validation.maxlength": "Por favor, introduce un valor más corto. (max. {max} caracteres)", - "error.validation.maxwords": "Por favor, introduce no más de {max} palabra(s)", - "error.validation.min": "Por favor, introduce un valor igual o mayor a {min}", - "error.validation.minlength": "Por favor, introduce un valor más largo. (min. {min} caracteres)", - "error.validation.minwords": "Por favor, introduce al menos {min} palabra(s)", - "error.validation.more": "Por favor, introduce un valor mayor a {min}", - "error.validation.notcontains": "Por favor, introduce un valor que no contenga \"{needle}\"", - "error.validation.notin": "Por favor, no introduzcas ninguno de los siguientes: ({notIn})", - "error.validation.option": "Por favor, selecciona una opción válida", - "error.validation.num": "Por favor, introduce un número valido", - "error.validation.required": "Por favor, introduce algo", - "error.validation.same": "Por favor, introduce \"{other}\"", - "error.validation.size": "El tamaño del valor debe ser \"{size}\"", - "error.validation.startswith": "El valor debe comenzar con \"{start}\"", - "error.validation.tel": "Please enter an unformatted phone number", - "error.validation.time": "Por favor, introduce una hora válida", - "error.validation.time.after": "Por favor, introduce una fecha después de {time}", - "error.validation.time.before": "Por favor, introduce una fecha antes de {time}", - "error.validation.time.between": "Por favor, introduce un fecha entre {min} y {max}", - "error.validation.uuid": "Please enter a valid UUID", - "error.validation.url": "Por favor, introduce un URL válido", - - "expand": "Expandir", - "expand.all": "Expandir todo", - - "field.invalid": "The field is invalid", - "field.required": "Este campo es obligatorio", - "field.blocks.changeType": "Cambiar tipo", - "field.blocks.code.name": "Código", - "field.blocks.code.language": "Idioma", - "field.blocks.code.placeholder": "Tu código...", - "field.blocks.delete.confirm": "¿Realmente quieres eliminar este bloque?", - "field.blocks.delete.confirm.all": "¿Realmente quieres eliminar todos los bloques?", - "field.blocks.delete.confirm.selected": "¿Realmente quieres eliminar los bloques seleccionados?", - "field.blocks.empty": "Aún no hay bloques", - "field.blocks.fieldsets.empty": "No fieldsets yet", - "field.blocks.fieldsets.label": "Por favor, selecciona un tipo de bloque...", - "field.blocks.fieldsets.paste": "Press {{ shortcut }} to import layouts/blocks from your clipboard Only those allowed in the current field will get inserted.", - "field.blocks.gallery.name": "Galería", - "field.blocks.gallery.images.empty": "Aún no hay imágenes", - "field.blocks.gallery.images.label": "Imágenes", - "field.blocks.heading.level": "Nivel", - "field.blocks.heading.name": "Encabezado", - "field.blocks.heading.text": "Texto", - "field.blocks.heading.placeholder": "Encabezado...", - "field.blocks.image.alt": "Texto alternativo", - "field.blocks.image.caption": "Leyenda", - "field.blocks.image.crop": "Cortar", - "field.blocks.image.link": "Enlace", - "field.blocks.image.location": "Ubicación", - "field.blocks.image.location.internal": "This website", - "field.blocks.image.location.external": "External source", - "field.blocks.image.name": "Imágen", - "field.blocks.image.placeholder": "Selecciona una imagen", - "field.blocks.image.ratio": "Proporción", - "field.blocks.image.url": "URL de imágen", - "field.blocks.line.name": "Linea", - "field.blocks.list.name": "Lista", - "field.blocks.markdown.name": "Markdown", - "field.blocks.markdown.label": "Texto", - "field.blocks.markdown.placeholder": "Markdown...", - "field.blocks.quote.name": "Cita", - "field.blocks.quote.text.label": "Texto", - "field.blocks.quote.text.placeholder": "Cita...", - "field.blocks.quote.citation.label": "Cita", - "field.blocks.quote.citation.placeholder": "Por ...", - "field.blocks.text.name": "Texto", - "field.blocks.text.placeholder": "Texto ...", - "field.blocks.video.autoplay": "Autoplay", - "field.blocks.video.caption": "Leyenda", - "field.blocks.video.controls": "Controls", - "field.blocks.video.location": "Ubicación", - "field.blocks.video.loop": "Loop", - "field.blocks.video.muted": "Muted", - "field.blocks.video.name": "Video", - "field.blocks.video.placeholder": "Introduce la URL de un vídeo", - "field.blocks.video.poster": "Poster", - "field.blocks.video.preload": "Preload", - "field.blocks.video.url.label": "Vídeo-URL", - "field.blocks.video.url.placeholder": "https://youtube.com/?v=", - - "field.files.empty": "Aún no hay archivos seleccionados", - - "field.layout.change": "Change layout", - "field.layout.delete": "Eliminar layout", - "field.layout.delete.confirm": "¿Realmente quieres eliminar este layout?", - "field.layout.delete.confirm.all": "Do you really want to delete all layouts?", - "field.layout.empty": "Aún no hay filas", - "field.layout.select": "Seleccionar layout", - - "field.object.empty": "Aún no hay información", - - "field.pages.empty": "Aún no hay páginas seleccionadas", - - "field.structure.delete.confirm": "¿Realmente quieres eliminar esta fila?", - "field.structure.delete.confirm.all": "¿Realmente quieres eliminar todas las entradas?", - "field.structure.empty": "Aún no hay entradas", - - "field.users.empty": "Aún no hay usuarios seleccionados", - - "fields.empty": "No fields yet", - - "file": "Archivo", - "file.blueprint": "Este archivo aún no tiene blueprint. Puedes definir la configuración en /site/blueprints/files/{blueprint}.yml", - "file.changeTemplate": "Cambiar plantilla", - "file.changeTemplate.notice": "Changing the file's template will remove content for fields that don't match in type. If the new template defines certain rules, e.g. image dimensions, those will also be applied irreversibly. Use with caution.", - "file.delete.confirm": "¿Realmente quieres eliminar
{filename}?", - "file.focus.placeholder": "Set focal point", - "file.focus.reset": "Remove focal point", - "file.focus.title": "Focus", - "file.sort": "Cambiar posición", - - "files": "Archivos", - "files.empty": "Aún no hay archivos", - - "filter": "Filter", - - "hide": "Ocultar", - "hour": "Hora", - "hue": "Hue", - "import": "Importar", - "info": "Info", - "insert": "Insertar", - "insert.after": "Insertar después", - "insert.before": "Insertar antes", - "install": "Instalar", - - "installation": "Instalación", - "installation.completed": "El panel ha sido instalado", - "installation.disabled": "El instalador del panel está deshabilitado en servidores públicos por defecto. Por favor, ejecuta el instalador en una máquina local o habilítalo con la opción panel.install.", - "installation.issues.accounts": "La carpeta /site/accounts no existe o no se puede escribir", - "installation.issues.content": "La carpeta /content no existe o no se puede escribir", - "installation.issues.curl": "La extensión CURL es requerida", - "installation.issues.headline": "No se puede instalar el panel", - "installation.issues.mbstring": "La extension MB String es requerida", - "installation.issues.media": "La carpeta /media no existe o no se puede escribir", - "installation.issues.php": "Asegurese de estar usando PHP 8+", - "installation.issues.sessions": "La carpeta /site/sessions no existe o no se puede escribir", - - "language": "Idioma", - "language.code": "Código", - "language.convert": "Hacer por defecto", - "language.convert.confirm": "

¿Realmente quieres convertir {name} al idioma por defecto? Esto no se puede deshacer.

Si {name} tiene contenido sin traducir, ya no habrá un respaldo válido y algunas partes de tu sitio podrían estar vacías.

", - "language.create": "Añadir un nuevo idioma", - "language.default": "Idioma predeterminado", - "language.delete.confirm": "¿Realmente quieres eliminar el idioma {name} incluyendo todas las traducciones? ¡Esto no se puede deshacer!", - "language.deleted": "El idioma ha sido eliminado", - "language.direction": "Leyendo dirección", - "language.direction.ltr": "De izquierda a derecha", - "language.direction.rtl": "De derecha a izquierda", - "language.locale": "PHP locale string", - "language.locale.warning": "Estás utilizando una configuración local. Por favor, modifícalo en el archivo del lenguaje en /site/languages", - "language.name": "Nombre", - "language.secondary": "Secondary language", - "language.settings": "Language settings", - "language.updated": "El idioma ha sido actualizado", - "language.variables": "Language variables", - "language.variables.empty": "No translations yet", - - "language.variable.delete.confirm": "Do you really want to delete the variable for {key}?", - "language.variable.key": "Key", - "language.variable.notFound": "The variable could not be found", - "language.variable.value": "Value", - - "languages": "Idiomas", - "languages.default": "Idioma predeterminado", - "languages.empty": "Aún no hay idiomas", - "languages.secondary": "Idiomas secundarios", - "languages.secondary.empty": "Aún no hay idiomas secundarios", - - "license": "Licencia", - "license.activate": "Activate it now", - "license.activate.label": "Please activate your license", - "license.activate.domain": "Your license will be activated for {host}.", - "license.activate.local": "You are about to activate your Kirby license for your local domain {host}. If this site will be deployed to a public domain, please activate it there instead. If {host} is the domain you want to use your license for, please continue.", - "license.activated": "Activated", - "license.buy": "Comprar una licencia", - "license.code": "Código", - "license.code.help": "You received your license code after the purchase via email. Please copy and paste it here.", - "license.code.label": "Por favor, introduce tu código de licencia", - "license.status.active.info": "Includes new major versions until {date}", - "license.status.active.label": "Valid license", - "license.status.demo.info": "This is a demo installation", - "license.status.demo.label": "Demo", - "license.status.inactive.info": "Renew license to update to new major versions", - "license.status.inactive.label": "No new major versions", - "license.status.legacy.bubble": "Ready to renew your license?", - "license.status.legacy.info": "Your license does not cover this version", - "license.status.legacy.label": "Please renew your license", - "license.status.missing.bubble": "Ready to launch your site?", - "license.status.missing.info": "No valid license", - "license.status.missing.label": "Please activate your license", - "license.manage": "Gestiona licencias", - "license.purchased": "Purchased", - "license.success": "Gracias por apoyar a Kirby", - "license.unregistered.label": "No registrado", - - "link": "Enlace", - "link.text": "Texto del enlace", - - "loading": "Cargando", - - "lock.unsaved": "Cambios sin guardar", - "lock.unsaved.empty": "No hay más cambios sin guardar", - "lock.isLocked": "Unsaved changes by {email}", - "lock.unlock": "Desbloquear", - "lock.unlock.submit": "Unlock and overwrite unsaved changes by {email}", - "lock.isUnlocked": "Was unlocked by another user", - - "login": "Iniciar sesión", - "login.code.label.login": "Código de inicio de sesión", - "login.code.label.password-reset": "Código de restablecimiento de contraseña", - "login.code.placeholder.email": "000 000", - "login.code.placeholder.totp": "000000", - "login.code.text.email": "Si tu dirección de correo electrónico está registrada, el código solicitado fue enviado por correo electrónico.", - "login.code.text.totp": "Please enter the one‑time code from your authenticator app.", - "login.email.login.body": "Hola {user.nameOrEmail},\n\nHas pedido, recientemente, un código de restablecimiento de contraseña para el Panel del sitio {site}.\nEl siguiente código de restablecimiento de contraseña será válido por {timeout} minutos:\n\n{code}\n\nSi no pediste un código de restablecimiento de contraseña, por favor ignora este correo o contacta a tu administrador si tienes dudas.\nPor seguridad, por favor NO reenvíes este correo.", - "login.email.login.subject": "Tu código de inicio de sesión", - "login.email.password-reset.body": "Hola {user.nameOrEmail},\n\nHas pedido, recientemente, un código de restablecimiento de contraseña para el Panel del sitio {site}.\nEl siguiente código de restablecimiento de contraseña será válido por {timeout} minutos:\n\n{code}\n\nSi no pediste un código de restablecimiento de contraseña, por favor ignora este correo o contacta a tu administrador si tienes dudas.\nPor seguridad, por favor NO reenvíes este correo.", - "login.email.password-reset.subject": "Tu código de restablecimiento de contraseña", - "login.remember": "Mantener sesión iniciada", - "login.reset": "Restablecer contraseña", - "login.toggleText.code.email": "Iniciar sesión por correo electrónico", - "login.toggleText.code.email-password": "Iniciar sesión con contraseña", - "login.toggleText.password-reset.email": "¿Olvidaste tu contraseña?", - "login.toggleText.password-reset.email-password": "← Volver al inicio de sesión", - "login.totp.enable.option": "Set up one‑time codes", - "login.totp.enable.intro": "Authenticator apps can generate one‑time codes that are used as a second factor when signing into your account.", - "login.totp.enable.qr.label": "1. Scan this QR code", - "login.totp.enable.qr.help": "Unable to scan? Add the setup key {secret} manually to your authenticator app.", - "login.totp.enable.confirm.headline": "2. Confirm with generated code", - "login.totp.enable.confirm.text": "Your app generates a new one‑time code every 30 seconds. Enter the current code to complete the setup:", - "login.totp.enable.confirm.label": "Current code", - "login.totp.enable.confirm.help": "After this setup, we will ask you for a one‑time code every time you log in.", - "login.totp.enable.success": "One‑time codes enabled", - "login.totp.disable.option": "Disable one‑time codes", - "login.totp.disable.label": "Enter your password to disable one‑time codes", - "login.totp.disable.help": "In the future, a different second factor like a login code sent via email will be requested when you log in. You can always set up one‑time codes again later.", - "login.totp.disable.admin": "

This will disable one‑time codes for {user}.

In the future, a different second factor like a login code sent via email will be requested when they log in. {user} can set up one‑time codes again after their next login.

", - "login.totp.disable.success": "One‑time codes disabled", - - "logout": "Cerrar sesión", - - "merge": "Merge", - "menu": "Menu", - "meridiem": "AM/PM", - "mime": "Tipos de medios", - "minutes": "Minutos", - - "month": "Mes", - "months.april": "Abril", - "months.august": "Agosto", - "months.december": "Diciembre", - "months.february": "Febrero", - "months.january": "Enero", - "months.july": "Julio", - "months.june": "Junio", - "months.march": "Marzo", - "months.may": "Mayo", - "months.november": "Noviembre", - "months.october": "Octubre", - "months.september": "Septiembre", - - "more": "Más", - "move": "Move", - "name": "Nombre", - "next": "Siguiente", - "night": "Night", - "no": "no", - "off": "Apagado", - "on": "Encendido", - "open": "Abrir", - "open.newWindow": "Abrir en una ventana nueva", - "option": "Option", - "options": "Opciones", - "options.none": "Sin opciones", - "options.all": "Show all {count} options", - - "orientation": "Orientación", - "orientation.landscape": "Paisaje", - "orientation.portrait": "Retrato", - "orientation.square": "Cuadrado", - - "page": "Página", - "page.blueprint": "Este archivo aún no tiene blueprint. Puedes definir la configuración en /site/blueprints/pages/{blueprint}.yml", - "page.changeSlug": "Cambiar URL", - "page.changeSlug.fromTitle": "Crear en base al título", - "page.changeStatus": "Cambiar estado", - "page.changeStatus.position": "Por favor, selecciona una posición", - "page.changeStatus.select": "Selecciona un nuevo estado", - "page.changeTemplate": "Cambiar plantilla", - "page.changeTemplate.notice": "Changing the page's template will remove content for fields that don't match in type. Use with caution.", - "page.create": "Create as {status}", - "page.delete.confirm": "¿Realmente quieres eliminar {title}?", - "page.delete.confirm.subpages": "Esta página tiene subpáginas.
Todas las subpáginas también serán eliminadas.", - "page.delete.confirm.title": "Introduce el título de la página para confirmar", - "page.duplicate.appendix": "Copiar", - "page.duplicate.files": "Copiar archivos", - "page.duplicate.pages": "Copiar páginas", - "page.move": "Move page", - "page.sort": "Cambiar posición", - "page.status": "Estado", - "page.status.draft": "Borrador", - "page.status.draft.description": "La página está en modo borrador y solo es visible para editores conectados o mediante enlace secreto.", - "page.status.listed": "Pública", - "page.status.listed.description": "La página es pública para cualquiera", - "page.status.unlisted": "Sin publicar", - "page.status.unlisted.description": "La página solo es accesible vía URL", - - "pages": "Paginas", - "pages.empty": "Aún no hay páginas", - "pages.status.draft": "Borradores", - "pages.status.listed": "Publicadas", - "pages.status.unlisted": "Sin publicar", - - "pagination.page": "Página", - - "password": "Contraseña", - "paste": "Pegar", - "paste.after": "Pegar después", - "paste.success": "{count} pasted!", - "pixel": "Pixel", - "plugin": "Plugin", - "plugins": "Plugins", - "prev": "Anterior", - "preview": "Previsualizar", - "remove": "Eliminar", - "rename": "Renombrar", - "renew": "Renew", - "replace": "Remplazar", - "replace.with": "Replace with", - "retry": "Inténtalo de nuevo", - "revert": "Revertir", - "revert.confirm": "¿Realmente quieres eliminar todos los cambios sin guardar?", - - "role": "Rol", - "role.admin.description": "El administrador tiene todos los derechos", - "role.admin.title": "Administrador", - "role.all": "Todo", - "role.empty": "No hay usuarios con este rol", - "role.description.placeholder": "Sin descripción", - "role.nobody.description": "Este es un rol alternativo sin permisos", - "role.nobody.title": "Nadie", - - "save": "Guardar", - "search": "Buscar", - "search.min": "Introduce {min} caracteres para buscar", - "search.all": "Show all {count} results", - "search.results.none": "Sin resultados", - - "section.invalid": "The section is invalid", - "section.required": "Esta sección es obligatoria", - - "security": "Seguridad", - "select": "Seleccionar", - "server": "Servidor", - "settings": "Ajustes", - "show": "Mostrar", - "site.blueprint": "Este archivo aún no tiene blueprint. Puedes definir la configuración en /site/blueprints/site.yml", - "size": "Tamaño", - "slug": "Apéndice de URL", - "sort": "Ordenar", - "sort.drag": "Drag to sort …", - "split": "Split", - - "stats.empty": "Sin informes", - "status": "Estado", - - "system.info.copy": "Copy info", - "system.info.copied": "System info copied", - "system.issues.content": "La carpeta content parece estar expuesta", - "system.issues.eol.kirby": "La versión de Kirby que tienes instalada ha llegado al final de su vida útil y no recibirá más actualizaciones de seguridad.", - "system.issues.eol.plugin": "La versión del plugin { plugin } que tienes instalada ha llegado al final de su vida útil y no recibirá más actualizaciones de seguridad.", - "system.issues.eol.php": "Your installed PHP release { release } has reached end-of-life and will not receive further security updates", - "system.issues.debug": "La depuración debe estar desactivada en producción", - "system.issues.git": "La carpeta .git parece estar expuesta", - "system.issues.https": "Recomendamos HTTPS para todos tus sitios web", - "system.issues.kirby": "La carpeta kirby parece estar expuesta", - "system.issues.site": "La carpeta site parece estar expuesta", - "system.issues.vulnerability.kirby": "Tu instalación podría estar afectada por la siguiente vulnerabilidad ({ severity } gravedad): { description }", - "system.issues.vulnerability.plugin": "Tu instalación podría estar afectada por la siguiente vulnerabilidad en el plugin { plugin } ({ severity } gravedad): { description }", - "system.updateStatus": "Estado de actualización", - "system.updateStatus.error": "No se pudo comprobar si hay actualizaciones", - "system.updateStatus.not-vulnerable": "Sin vulnerabilidades conocidas", - "system.updateStatus.security-update": "Actualización gratuita de seguridad { version } disponible", - "system.updateStatus.security-upgrade": "Actualización { versión } con correcciones de seguridad disponibles", - "system.updateStatus.unreleased": "Versión no publicada", - "system.updateStatus.up-to-date": "Actualizado", - "system.updateStatus.update": "Actualización gratuita {version} disponible", - "system.updateStatus.upgrade": "Actualización {versión} disponible", - - "tel": "Phone", - "tel.placeholder": "+49123456789", - "template": "Plantilla", - "title": "Título", - "today": "Hoy", - - "toolbar.button.clear": "Clear formatting", - "toolbar.button.code": "Código", - "toolbar.button.bold": "Negrita", - "toolbar.button.email": "Correo electrónico", - "toolbar.button.headings": "Encabezados", - "toolbar.button.heading.1": "Encabezado 1", - "toolbar.button.heading.2": "Encabezado 2", - "toolbar.button.heading.3": "Encabezado 3", - "toolbar.button.heading.4": "Encabezado 4", - "toolbar.button.heading.5": "Encabezado 5", - "toolbar.button.heading.6": "Encabezado 6", - "toolbar.button.italic": "Italica", - "toolbar.button.file": "Archivo", - "toolbar.button.file.select": "Seleccionar un archivo", - "toolbar.button.file.upload": "Subir un archivo", - "toolbar.button.link": "Enlace", - "toolbar.button.paragraph": "Parágrafo", - "toolbar.button.strike": "Tachado", - "toolbar.button.sub": "Subscript", - "toolbar.button.sup": "Superscript", - "toolbar.button.ol": "Lista ordenada", - "toolbar.button.underline": "Subrayado", - "toolbar.button.ul": "Lista de viñetas", - - "translation.author": "Turqueso", - "translation.direction": "ltr", - "translation.name": "Español", - "translation.locale": "es_ES", - - "type": "Type", - - "upload": "Subir", - "upload.error.cantMove": "El archivo subido no pudo ser movido", - "upload.error.cantWrite": "Error al escribir el archivo en el disco", - "upload.error.default": "El archivo no pudo ser subido", - "upload.error.extension": "Subida de archivo detenida por la extensión", - "upload.error.formSize": "El archivo subido excede la directiva MAX_FILE_SIZE que fue especificada en el formulario", - "upload.error.iniPostSize": "El archivo subido excede la directiva post_max_size directive en php.ini", - "upload.error.iniSize": "El archivo subido excede la directiva upload_max_filesize en php.ini", - "upload.error.noFile": "No se ha subido ningún archivo", - "upload.error.noFiles": "No se ha subido ningún archivo", - "upload.error.partial": "El archivo ha sido subido solo parcialmente", - "upload.error.tmpDir": "No se encuentra la carpeta temporal", - "upload.errors": "Error", - "upload.progress": "Cargando…", - - "url": "Url", - "url.placeholder": "https://ejemplo.com", - - "user": "Usuario", - "user.blueprint": "Puedes definir secciones y campos de formulario adicionales para este rol de usuario en /site/blueprints/users/{blueprint}.yml", - "user.changeEmail": "Cambiar correo electrónico", - "user.changeLanguage": "Cambiar idioma", - "user.changeName": "Renombrar a este usuario", - "user.changePassword": "Cambiar contraseña", - "user.changePassword.new": "Nueva contraseña", - "user.changePassword.new.confirm": "Confirmar nueva contraseña…", - "user.changeRole": "Cambiar rol", - "user.changeRole.select": "Seleccionar un nuevo rol", - "user.create": "Añadir un nuevo usuario", - "user.delete": "Eliminar este usuario", - "user.delete.confirm": "¿Realmente quieres eliminar
{email}?", - - "users": "Usuarios", - - "version": "Versión", - "version.current": "Versión actual", - "version.latest": "Última versión", - "versionInformation": "Información sobre la versión", - - "view.account": "Tu cuenta", - "view.installation": "Instalación", - "view.languages": "Idiomas", - "view.resetPassword": "Restablecer contraseña", - "view.site": "Sitio", - "view.system": "Sistema", - "view.users": "Usuarios", - - "welcome": "Bienvenido(a)", - "year": "Año", - "yes": "Sí" + "account.changeName": "Cambia tu nombre", + "account.delete": "Borrar tu cuenta", + "account.delete.confirm": "¿Realmente quieres eliminar tu cuenta? Tu sesión se cerrará inmediatamente. La cuenta no podrá ser recuperada.", + + "add": "Añadir", + "author": "Autor", + "avatar": "Foto de perfil", + "back": "Atrás", + "cancel": "Cancelar", + "change": "Cambiar", + "close": "Cerrar", + "confirm": "Confirmar", + "collapse": "Colapsar", + "collapse.all": "Colapsar todos", + "copy": "Copiar", + "copy.all": "Copiar todo", + "create": "Crear", + + "date": "Fecha", + "date.select": "Selecciona una fecha", + + "day": "Día", + "days.fri": "Vi", + "days.mon": "Lu", + "days.sat": "Sá", + "days.sun": "Do", + "days.thu": "Ju", + "days.tue": "Ma", + "days.wed": "Mi", + + "debugging": "Debugging", + + "delete": "Borrar", + "delete.all": "Eliminar todos", + + "dialog.files.empty": "No se ha seleccionado ningún archivo", + "dialog.pages.empty": "No se ha seleccionado ninguna página", + "dialog.users.empty": "No se ha seleccionado ningún usuario", + + "dimensions": "Dimensiones", + "disabled": "Desabilitado", + "discard": "Descartar", + "download": "Descargar", + "duplicate": "Duplicar", + + "edit": "Editar", + + "email": "Correo electrónico", + "email.placeholder": "correo@ejemplo.com", + + "entries": "Entries", + "entry": "Entry", + + "environment": "Ambiente", + + "error.access.code": "Código inválido", + "error.access.login": "Ingreso inválido", + "error.access.panel": "No estás autorizado para acceder al panel", + "error.access.view": "No tienes permiso para acceder a esta parte del panel", + + "error.avatar.create.fail": "No se pudo subir la foto de perfil.", + "error.avatar.delete.fail": "No se pudo borrar la foto de perfil", + "error.avatar.dimensions.invalid": "Por favor, mantenga el ancho y la altura de la imagen de perfil debajo de 3000 píxeles", + "error.avatar.mime.forbidden": "La imagen del perfil debe ser JPEG o PNG.", + + "error.blueprint.notFound": "El blueprint \"{name}\" no pudo ser cargado", + + "error.blocks.max.plural": "No debes añadir más de {max} bloques", + "error.blocks.max.singular": "No debes añadir más de un bloque", + "error.blocks.min.plural": "Debes añadir al menos {min} bloques ", + "error.blocks.min.singular": "Debes añadir al menos un bloque", + "error.blocks.validation": "Hay un error en el bloque {index}", + + "error.email.preset.notFound": "El preset del correo \"{name}\" no pudo ser encontrado", + + "error.field.converter.invalid": "Convertidor \"{converter}\" inválido", + + "error.file.changeName.empty": "El nombre no debe estar vacío", + "error.file.changeName.permission": "No tienes permitido cambiar el nombre de \"{filename}\"", + "error.file.duplicate": "Ya existe un archivo con el nombre \"{filename}\"", + "error.file.extension.forbidden": "La extensión \"{extension}\" no está permitida", + "error.file.extension.invalid": "Extensión inválida: {extension}", + "error.file.extension.missing": "Falta la extensión para \"{filename}\"", + "error.file.maxheight": "La altura de la imagen no debe exceder {height} pixeles", + "error.file.maxsize": "El archivo es muy grande", + "error.file.maxwidth": "El ancho de la imagen no debe exceder {width} pixeles", + "error.file.mime.differs": "El archivo cargado debe ser del mismo tipo mime \"{mime}\"", + "error.file.mime.forbidden": "Los medios tipo \"{mime}\" no están permitidos", + "error.file.mime.invalid": "Tipo invalido de mime: {mime}", + "error.file.mime.missing": "El tipo de medio para \"{filename}\" no pudo ser detectado", + "error.file.minheight": "La altura de la imagen debe ser de al menos {height} pixeles", + "error.file.minsize": "El archivo es muy pequeño", + "error.file.minwidth": "El ancho de la imagen debe ser de al menos {width} pixeles", + "error.file.name.missing": "El nombre de archivo no debe estar vacío", + "error.file.notFound": "El archivo \"{filename}\" no pudo ser encontrado", + "error.file.orientation": "The orientation of the image must be \"{orientation}\"", + "error.file.type.forbidden": "No está permitido subir archivos {type}", + "error.file.type.invalid": "Tipo de archivo inválido: {type}", + "error.file.undefined": "El archivo no pudo ser encontrado", + + "error.form.incomplete": "Por favor, corrija todos los errores del formulario…", + "error.form.notSaved": "El formulario no pudo ser guardado", + + "error.language.code": "Por favor introduce un código válido para el idioma", + "error.language.duplicate": "El idioma ya existe", + "error.language.name": "Por favor introduce un nombre válido para el idioma", + "error.language.notFound": "No se pudo encontrar el idioma", + + "error.layout.validation.block": "There's an error in block {blockIndex} in layout {layoutIndex}", + "error.layout.validation.settings": "There's an error in layout {index} settings", + + "error.license.format": "Por favor introduce una llave de licencia válida", + "error.license.email": "Por favor, introduce un correo electrónico válido", + "error.license.verification": "La licencia no pude ser verificada", + + "error.offline": "El Panel se encuentra fuera de linea ", + + "error.page.changeSlug.permission": "No está permitido cambiar el apéndice de URL para \"{slug}\"", + "error.page.changeStatus.incomplete": "La página tiene errores y no puede ser publicada.", + "error.page.changeStatus.permission": "El estado de esta página no se puede cambiar", + "error.page.changeStatus.toDraft.invalid": "La página \"{slug}\" no se puede convertir a borrador", + "error.page.changeTemplate.invalid": "La plantilla para la página \"{slug}\" no se puede cambiar", + "error.page.changeTemplate.permission": "No tienes permitido cambiar la plantilla para \"{slug}\"", + "error.page.changeTitle.empty": "El título no debe estar vacío.", + "error.page.changeTitle.permission": "No tienes permitido cambiar el título por \"{slug}\"", + "error.page.create.permission": "No tienes permitido crear \"{slug}\"", + "error.page.delete": "La página \"{slug}\" no puede ser eliminada", + "error.page.delete.confirm": "Por favor, introduzca el título de la página para confirmar", + "error.page.delete.hasChildren": "La página tiene subpáginas y no se puede eliminar", + "error.page.delete.permission": "No tienes permiso de eliminar \"{slug}\"", + "error.page.draft.duplicate": "Un borrador de página con el apéndice de URL \"{slug}\" ya existe", + "error.page.duplicate": "Una página con el apéndice de URL. \"{slug}\" ya existe", + "error.page.duplicate.permission": "You are not allowed to duplicate \"{slug}\"", + "error.page.notFound": "La página \"{slug}\" no puede ser encontrada", + "error.page.num.invalid": "Por favor, introduzca un número válido. Estos no deben ser negativos.", + "error.page.slug.invalid": "Please enter a valid URL appendix", + "error.page.slug.maxlength": "Slug length must be less than \"{length}\" characters", + "error.page.sort.permission": "La página \"{slug}\" no se puede ordenar", + "error.page.status.invalid": "Por favor, establezca un estado de página válido", + "error.page.undefined": "La página no se puede encontrar", + "error.page.update.permission": "No tienes permitido actualizar \"{slug}\"", + + "error.section.files.max.plural": "No debes agregar más de {max} archivos a la sección \"{section}\"", + "error.section.files.max.singular": "No debes agregar más de 1 archivo a la sección \"{section}\"", + "error.section.files.min.plural": "La sección \"{section}\" requiere al menos {min} archivos", + "error.section.files.min.singular": "La sección \"{section}\" requiere al menos un archivo", + + "error.section.pages.max.plural": "No debe agregar más de {max} páginas a la sección \"{section}\"", + "error.section.pages.max.singular": "No debe agregar más de una página a la sección \"{section}\"", + "error.section.pages.min.plural": "La sección \"{section}\" requiere al menos {min} páginas", + "error.section.pages.min.singular": "La sección \"{section}\" requiere al menos una página", + + "error.section.notLoaded": "La sección \"{name}\" no pudo ser cargada", + "error.section.type.invalid": "El sección tipo \"{tipo}\" no es válido", + + "error.site.changeTitle.empty": "El título no debe estar vacío.", + "error.site.changeTitle.permission": "No está permitido cambiar el título del sitio", + "error.site.update.permission": "No tienes permitido actualizar el sitio", + + "error.template.default.notFound": "La plantilla por defecto no existe", + + "error.unexpected": "An unexpected error occurred! Enable debug mode for more info: https://getkirby.com/docs/reference/system/options/debug", + + "error.user.changeEmail.permission": "No tienes permitido cambiar el correo electrónico para el usuario \"{name}\"", + "error.user.changeLanguage.permission": "No tienes permitido cambiar el idioma para el usuario \"{name}\"", + "error.user.changeName.permission": "No tienes permitido cambiar el nombre del usuario \"{name}\"", + "error.user.changePassword.permission": "No tienes permitido cambiar la contraseña del usuario \"{name}\"", + "error.user.changeRole.lastAdmin": "El rol para el último administrador no puede ser cambiado", + "error.user.changeRole.permission": "No tienes permitido cambiar el rol del usuario \"{name}\"", + "error.user.changeRole.toAdmin": "No tienes permitido promover a alguien al rol de admin", + "error.user.create.permission": "No tienes permiso para crear este usuario", + "error.user.delete": "El usuario \"{name}\" no puede ser eliminado", + "error.user.delete.lastAdmin": "El último administrador no puede ser eliminado", + "error.user.delete.lastUser": "El último usuario no puede ser eliminado", + "error.user.delete.permission": "No tienes permitido eliminar el usuario \"{name}\"", + "error.user.duplicate": "Un usuario con la dirección de correo electrónico \"{email}\" ya existe", + "error.user.email.invalid": "Por favor, introduce una dirección de correo electrónico válida", + "error.user.language.invalid": "Por favor ingrese un idioma válido", + "error.user.notFound": "El usuario \"{name}\" no pudo ser encontrado", + "error.user.password.excessive": "Please enter a valid password. Passwords must not be longer than 1000 characters.", + "error.user.password.invalid": "Por favor introduce una contraseña válida. Las contraseñas deben tener al menos 8 caracteres de largo.", + "error.user.password.notSame": "Las contraseñas no coinciden", + "error.user.password.undefined": "El usuario no tiene contraseña", + "error.user.password.wrong": "Contraseña incorrecta", + "error.user.role.invalid": "Por favor ingrese un rol válido", + "error.user.undefined": "El usuario no puede ser encontrado", + "error.user.update.permission": "No tienes permitido actualizar al usuario \"{name}\"", + + "error.validation.accepted": "Por favor, confirma", + "error.validation.alpha": "Por favor solo ingresa caracteres entre a-z", + "error.validation.alphanum": "Por favor solo ingrese caracteres entre a-z o numerales 0-9", + "error.validation.between": "Por favor, introduzca un valor entre \"{min}\" y \"{max}\"", + "error.validation.boolean": "Por favor confirme o rechace", + "error.validation.contains": "Por favor ingrese un valor que contenga \"{needle}\"", + "error.validation.date": "Por favor introduzca una fecha valida", + "error.validation.date.after": "Por favor introduce una fecha posterior a {date}", + "error.validation.date.before": "Por favor introduce una fecha anterior a {date}", + "error.validation.date.between": "Por favor introduce un número entre {min} y {max}", + "error.validation.denied": "Por favor, rechace", + "error.validation.different": "El valor no debe ser \"{other}\"", + "error.validation.email": "Por favor, introduce un correo electrónico válido", + "error.validation.endswith": "El valor debe terminar con \"{end}\"", + "error.validation.filename": "Por favor ingrese un nombre de archivo válido", + "error.validation.in": "Por favor ingrese uno de los siguientes: ({in})", + "error.validation.integer": "Por favor, introduce un numero integro válido", + "error.validation.ip": "Por favor ingrese una dirección IP válida", + "error.validation.less": "Por favor, introduzca un valor inferior a {max}", + "error.validation.match": "El valor no coincide con el patrón esperado", + "error.validation.max": "Por favor, introduzca un valor igual o inferior a {max}", + "error.validation.maxlength": "Por favor, introduzca un valor más corto. (max. {max} caracteres)", + "error.validation.maxwords": "Por favor ingrese no más de {max} palabra(s)", + "error.validation.min": "Por favor, introduzca un valor igual o mayor a {min}", + "error.validation.minlength": "Por favor, introduzca un valor más largo. (min. {min} caracteres)", + "error.validation.minwords": "Por favor ingrese al menos {min} palabra(s)", + "error.validation.more": "Por favor, introduzca un valor mayor a {min}", + "error.validation.notcontains": "Por favor ingrese un valor que no contenga \"{needle}\"", + "error.validation.notin": "Por favor, no ingrese ninguno de los siguientes: ({notIn})", + "error.validation.option": "Por favor seleccione una opción válida", + "error.validation.num": "Por favor ingrese un número valido", + "error.validation.required": "Por favor ingrese algo", + "error.validation.same": "Por favor escribe \"{other}\"", + "error.validation.size": "El tamaño del valor debe ser \"{size}\"", + "error.validation.startswith": "El valor debe comenzar con \"{start}\"", + "error.validation.time": "Por favor ingrese una hora válida", + "error.validation.time.after": "Por favor ingresa una fecha después de {time}", + "error.validation.time.before": "Por favor ingresa una fecha antes de {time}", + "error.validation.time.between": "Por favor ingresa un fecha entre {min} y {max}", + "error.validation.url": "Por favor introduzca un URL válido", + + "expand": "Expandir", + "expand.all": "Expandir todo", + + "field.required": "Este campo es requerido", + "field.blocks.changeType": "Cambiar tipo", + "field.blocks.code.name": "Código", + "field.blocks.code.language": "Idioma", + "field.blocks.code.placeholder": "Tu código...", + "field.blocks.delete.confirm": "¿Seguro que quieres eliminar este bloque?", + "field.blocks.delete.confirm.all": "¿Seguro que quieres eliminar todos los bloques?", + "field.blocks.delete.confirm.selected": "¿Seguro que quieres eliminar los bloques seleccionados?", + "field.blocks.empty": "No hay bloques aún", + "field.blocks.fieldsets.label": "Por favor selecciona un tipo de bloque...", + "field.blocks.fieldsets.paste": "Presiona {{ shortcut }}para pegar/importar bloques en tu portapapeles ", + "field.blocks.gallery.name": "Galería", + "field.blocks.gallery.images.empty": "No hay imágenes aún", + "field.blocks.gallery.images.label": "Imágenes", + "field.blocks.heading.level": "Nivel", + "field.blocks.heading.name": "Encabezado", + "field.blocks.heading.text": "Texto", + "field.blocks.heading.placeholder": "Encabezado...", + "field.blocks.image.alt": "Texto alternativo", + "field.blocks.image.caption": "Leyenda", + "field.blocks.image.crop": "Cortar", + "field.blocks.image.link": "Enlace", + "field.blocks.image.location": "Ubicación", + "field.blocks.image.name": "Imágen", + "field.blocks.image.placeholder": "Selecciona una imagen", + "field.blocks.image.ratio": "Proporción", + "field.blocks.image.url": "URL de imágen", + "field.blocks.line.name": "Linea", + "field.blocks.list.name": "Lista", + "field.blocks.markdown.name": "Markdown", + "field.blocks.markdown.label": "Texto", + "field.blocks.markdown.placeholder": "Markdown...", + "field.blocks.quote.name": "Cita", + "field.blocks.quote.text.label": "Texto", + "field.blocks.quote.text.placeholder": "Cita...", + "field.blocks.quote.citation.label": "Citation", + "field.blocks.quote.citation.placeholder": "Por ...", + "field.blocks.text.name": "Texto", + "field.blocks.text.placeholder": "Text …", + "field.blocks.video.caption": "Leyenda", + "field.blocks.video.name": "Video", + "field.blocks.video.placeholder": "Enter a video URL", + "field.blocks.video.url.label": "Video-URL", + "field.blocks.video.url.placeholder": "https://youtube.com/?v=", + + "field.files.empty": "Aún no hay archivos seleccionados", + + "field.layout.delete": "Delete layout", + "field.layout.delete.confirm": "Do you really want to delete this layout?", + "field.layout.empty": "No rows yet", + "field.layout.select": "Select a layout", + + "field.pages.empty": "Aún no hay páginas seleccionadas", + "field.structure.delete.confirm": "¿Realmente quieres eliminar esta fila?", + "field.structure.empty": "Aún no hay entradas", + "field.users.empty": "Aún no hay usuarios seleccionados", + + "file.blueprint": "This file has no blueprint yet. You can define the setup in /site/blueprints/files/{blueprint}.yml", + "file.delete.confirm": "¿Realmente quieres eliminar
{filename}?", + "file.sort": "Change position", + + "files": "Archivos", + "files.empty": "Aún no hay archivos", + + "hide": "Hide", + "hour": "Hora", + "import": "Import", + "info": "Info", + "insert": "Insertar", + "insert.after": "Insert after", + "insert.before": "Insert before", + "install": "Instalar", + + "installation": "Instalación", + "installation.completed": "El panel ha sido instalado", + "installation.disabled": "El instalador del panel está deshabilitado en servidores públicos por defecto. Ejecute el instalador en una máquina local o habilítelo con la opción panel.install.", + "installation.issues.accounts": "La carpeta /site/accounts no existe o no se puede escribir", + "installation.issues.content": "La carpeta /content no existe o no se puede escribir", + "installation.issues.curl": "La extensión CURL es requerida", + "installation.issues.headline": "No se pudo instalar el panel", + "installation.issues.mbstring": "La extension MB String es requerida", + "installation.issues.media": "La carpeta /media no existe o no se puede escribir", + "installation.issues.php": "Asegúrate de usar PHP 7+", + "installation.issues.server": "Kirby requiere Apache, Nginx o Caddy", + "installation.issues.sessions": "La carpeta /site/sessions no existe o no se puede escribir", + + "language": "Idioma", + "language.code": "Código", + "language.convert": "Hacer por defecto", + "language.convert.confirm": "{name} al idioma por defecto? Esto no se puede deshacer.

Si {name} tiene contenido sin traducir, ya no habrá un respaldo válido y algunas partes de su sitio podrían estar vacías.

", + "language.create": "Añadir un nuevo idioma", + "language.delete.confirm": "¿De verdad quieres eliminar el idioma {name} incluyendo todas las traducciones? ¡Esto no se puede deshacer!", + "language.deleted": "El idioma ha sido eliminado", + "language.direction": "Leyendo dirección", + "language.direction.ltr": "De izquierda a derecha", + "language.direction.rtl": "De derecha a izquierda", + "language.locale": "PHP locale string", + "language.locale.warning": "Estas utilizando un configuración local. Por favor modifícalo en el archivo del lenguaje en /site/languages", + "language.name": "Nombre", + "language.updated": "El idioma ha sido actualizado", + + "languages": "Idiomas", + "languages.default": "Idioma predeterminado", + "languages.empty": "Todavía no hay idiomas", + "languages.secondary": "Idiomas secundarios", + "languages.secondary.empty": "Todavía no hay idiomas secundarios", + + "license": "Licencia", + "license.buy": "Comprar una licencia", + "license.register": "Registro", + "license.manage": "Manage your licenses", + "license.register.help": "Recibió su código de licencia después de la compra por correo electrónico. Por favor copie y pegue para registrarse.", + "license.register.label": "Por favor ingrese su código de licencia", + "license.register.success": "Gracias por apoyar a Kirby", + "license.unregistered": "Esta es una demo no registrada de Kirby", + "license.unregistered.label": "Unregistered", + + "link": "Enlace", + "link.text": "Texto del enlace", + + "loading": "Cargando", + + "lock.unsaved": "Cambios sin guardar", + "lock.unsaved.empty": "No hay más cambios sin guardar", + "lock.isLocked": "Cambios sin guardar por {email}", + "lock.file.isLocked": "El archivo está siendo actualmente editado por {email} y no puede ser cambiado.", + "lock.page.isLocked": "La página está siendo actualmente editada por {email} y no puede ser cambiada.", + "lock.unlock": "Desbloquear", + "lock.isUnlocked": "Tus cambios sin guardar han sido sobrescritos por otro usuario. Puedes descargar los cambios y fusionarlos manualmente.", + + "login": "Iniciar sesión", + "login.code.label.login": "Login code", + "login.code.label.password-reset": "Password reset code", + "login.code.placeholder.email": "000 000", + "login.code.text.email": "If your email address is registered, the requested code was sent via email.", + "login.email.login.body": "Hi {user.nameOrEmail},\n\nYou recently requested a login code for the Panel of {site}.\nThe following login code will be valid for {timeout} minutes:\n\n{code}\n\nIf you did not request a login code, please ignore this email or contact your administrator if you have questions.\nFor security, please DO NOT forward this email.", + "login.email.login.subject": "Your login code", + "login.email.password-reset.body": "Hi {user.nameOrEmail},\n\nYou recently requested a password reset code for the Panel of {site}.\nThe following password reset code will be valid for {timeout} minutes:\n\n{code}\n\nIf you did not request a password reset code, please ignore this email or contact your administrator if you have questions.\nFor security, please DO NOT forward this email.", + "login.email.password-reset.subject": "Your password reset code", + "login.remember": "Mantener sesión iniciada", + "login.reset": "Reset password", + "login.toggleText.code.email": "Login via email", + "login.toggleText.code.email-password": "Login with password", + "login.toggleText.password-reset.email": "Forgot your password?", + "login.toggleText.password-reset.email-password": "← Back to login", + + "logout": "Cerrar sesión", + + "menu": "Menu", + "meridiem": "AM/PM", + "mime": "Tipos de medios", + "minutes": "Minutos", + + "month": "Mes", + "months.april": "Abril", + "months.august": "Agosto", + "months.december": "Diciembre", + "months.february": "Febrero", + "months.january": "Enero", + "months.july": "Julio", + "months.june": "Junio", + "months.march": "Marzo", + "months.may": "Mayo", + "months.november": "Noviembre", + "months.october": "Octubre", + "months.september": "Septiembre", + + "more": "Más", + "name": "Nombre", + "next": "Siguiente", + "no": "no", + "off": "Apagado", + "on": "Encendido", + "open": "Abrir", + "open.newWindow": "Open in new window", + "options": "Opciones", + "options.none": "No options", + + "orientation": "Orientación", + "orientation.landscape": "Paisaje", + "orientation.portrait": "Retrato", + "orientation.square": "Cuadrado", + + "page.blueprint": "This page has no blueprint yet. You can define the setup in /site/blueprints/pages/{blueprint}.yml", + "page.changeSlug": "Cambiar URL", + "page.changeSlug.fromTitle": "Crear en base al título", + "page.changeStatus": "Cambiar estado", + "page.changeStatus.position": "Por favor seleccione una posición", + "page.changeStatus.select": "Seleccione un nuevo estado", + "page.changeTemplate": "Cambiar plantilla", + "page.delete.confirm": "¿Realmente quieres eliminar {title}?", + "page.delete.confirm.subpages": "Esta página tiene subpáginas.
Todas las subpáginas también serán eliminadas.", + "page.delete.confirm.title": "Introduzca el título de la página para confirmar", + "page.draft.create": "Crear borrador", + "page.duplicate.appendix": "Copiar", + "page.duplicate.files": "Copiar archivos", + "page.duplicate.pages": "Copiar páginas", + "page.sort": "Change position", + "page.status": "Estado", + "page.status.draft": "Borrador", + "page.status.draft.description": "The page is in draft mode and only visible for logged in editors or via secret link", + "page.status.listed": "Publica", + "page.status.listed.description": "La página es pública para cualquiera", + "page.status.unlisted": "Sin publicar", + "page.status.unlisted.description": "La página solo es accesible vía URL", + + "pages": "Paginas", + "pages.empty": "Aún no hay páginas", + "pages.status.draft": "Borradores", + "pages.status.listed": "Publicadas", + "pages.status.unlisted": "Sin publicar", + + "pagination.page": "Página", + + "password": "Contraseña", + "paste": "Paste", + "paste.after": "Paste after", + "pixel": "Pixel", + "plugins": "Plugins", + "prev": "Anterior", + "preview": "Preview", + "remove": "Eliminar", + "rename": "Renombrar", + "replace": "Remplazar", + "retry": "Inténtalo de nuevo", + "revert": "Revertir", + "revert.confirm": "Do you really want to delete all unsaved changes?", + + "role": "Rol", + "role.admin.description": "El administrador tiene todos los derechos", + "role.admin.title": "Administrador", + "role.all": "Todos", + "role.empty": "No hay usuarios con este rol", + "role.description.placeholder": "Sin descripción", + "role.nobody.description": "Este es un rol alternativo sin permisos", + "role.nobody.title": "Nadie", + + "save": "Guardar", + "search": "Buscar", + "search.min": "Enter {min} characters to search", + "search.all": "Show all", + "search.results.none": "No results", + + "section.required": "Esta sección es requerida", + + "security": "Security", + "select": "Seleccionar", + "server": "Server", + "settings": "Ajustes", + "show": "Show", + "site.blueprint": "The site has no blueprint yet. You can define the setup in /site/blueprints/site.yml", + "size": "Tamaño", + "slug": "Apéndice URL", + "sort": "Ordenar", + + "stats.empty": "No reports", + "system.issues.content": "The content folder seems to be exposed", + "system.issues.debug": "Debugging must be turned off in production", + "system.issues.git": "The .git folder seems to be exposed", + "system.issues.https": "We recommend HTTPS for all your sites", + "system.issues.kirby": "The kirby folder seems to be exposed", + "system.issues.site": "The site folder seems to be exposed", + + "title": "Titulo", + "template": "Plantilla", + "today": "Hoy", + + "toolbar.button.code": "Código", + "toolbar.button.bold": "Negritas", + "toolbar.button.email": "Correo electrónico", + "toolbar.button.headings": "Encabezados", + "toolbar.button.heading.1": "Encabezado 1", + "toolbar.button.heading.2": "Encabezado 2", + "toolbar.button.heading.3": "Encabezado 3", + "toolbar.button.heading.4": "Encabezado 4", + "toolbar.button.heading.5": "Encabezado 5", + "toolbar.button.heading.6": "Encabezado 6", + "toolbar.button.italic": "Italica", + "toolbar.button.file": "Archivo", + "toolbar.button.file.select": "Seleccione un archivo", + "toolbar.button.file.upload": "Sube un archivo", + "toolbar.button.link": "Enlace", + "toolbar.button.paragraph": "Paragraph", + "toolbar.button.strike": "Strike-through", + "toolbar.button.ol": "Lista ordenada", + "toolbar.button.underline": "Underline", + "toolbar.button.ul": "Lista de viñetas", + + "translation.author": "Turqueso", + "translation.direction": "ltr", + "translation.name": "Español", + "translation.locale": "es_ES", + + "upload": "Subir", + "upload.error.cantMove": "El archivo subido no puede ser movido", + "upload.error.cantWrite": "Error al escribir el archivo en el disco", + "upload.error.default": "El archivo no pudo ser subido", + "upload.error.extension": "Subida de archivo detenida por la extensión", + "upload.error.formSize": "El archivo subido excede la directiva MAX_FILE_SIZE que fue especificada en el formulario", + "upload.error.iniPostSize": "El archivo subido excede la directiva post_max_size directive en php.ini", + "upload.error.iniSize": "El archivo subido excede la directiva upload_max_filesize en php.ini", + "upload.error.noFile": "Ningún archivo ha sido subido", + "upload.error.noFiles": "Ningún archivo ha sido subido", + "upload.error.partial": "El archivo ha sido subido solo parcialmente", + "upload.error.tmpDir": "No se encuentra la carpeta temporal", + "upload.errors": "Error", + "upload.progress": "Cargando…", + + "url": "Url", + "url.placeholder": "https://ejemplo.com", + + "user": "Usuario", + "user.blueprint": "You can define additional sections and form fields for this user role in /site/blueprints/users/{blueprint}.yml", + "user.changeEmail": "Cambiar correo electrónico", + "user.changeLanguage": "Cambiar idioma", + "user.changeName": "Renombrar a este usuario", + "user.changePassword": "Cambia contraseña", + "user.changePassword.new": "Nueva contraseña", + "user.changePassword.new.confirm": "Confirmar nueva contraseña…", + "user.changeRole": "Cambiar rol", + "user.changeRole.select": "Seleccione un nuevo rol", + "user.create": "Añadir un nuevo usuario", + "user.delete": "Eliminar este usuario", + "user.delete.confirm": "¿Realmente quieres eliminar
{email}?", + + "users": "Usuarios", + + "version": "Versión", + + "view.account": "Su cuenta", + "view.installation": "Instalación", + "view.languages": "Idiomas", + "view.resetPassword": "Reset password", + "view.site": "Sitio", + "view.system": "System", + "view.users": "Usuarios", + + "welcome": "Bienvenido(a)", + "year": "Año", + "yes": "yes" } diff --git a/kirby/i18n/translations/fa.json b/kirby/i18n/translations/fa.json index 6b648b8..7a3e151 100644 --- a/kirby/i18n/translations/fa.json +++ b/kirby/i18n/translations/fa.json @@ -1,730 +1,574 @@ { - "account.changeName": "Change your name", - "account.delete": "Delete your account", - "account.delete.confirm": "Do you really want to delete your account? You will be logged out immediately. Your account cannot be recovered.", - - "activate": "Activate", - "add": "\u0627\u0641\u0632\u0648\u062f\u0646", - "alpha": "Alpha", - "author": "Author", - "avatar": "\u062a\u0635\u0648\u06cc\u0631 \u067e\u0631\u0648\u0641\u0627\u06cc\u0644", - "back": "بازگشت", - "cancel": "\u0627\u0646\u0635\u0631\u0627\u0641", - "change": "\u0627\u0635\u0644\u0627\u062d", - "close": "\u0628\u0633\u062a\u0646", - "changes": "Changes", - "confirm": "تایید", - "collapse": "Collapse", - "collapse.all": "Collapse All", - "color": "Color", - "coordinates": "Coordinates", - "copy": "کپی", - "copy.all": "Copy all", - "copy.success": "{count} copied!", - "create": "ایجاد", - "custom": "Custom", - - "date": "تاریخ", - "date.select": "یک تاریخ را انتخاب کنید", - - "day": "روز", - "days.fri": "\u062c\u0645\u0639\u0647", - "days.mon": "\u062f\u0648\u0634\u0646\u0628\u0647", - "days.sat": "\u0634\u0646\u0628\u0647", - "days.sun": "\u06cc\u06a9\u0634\u0646\u0628\u0647", - "days.thu": "\u067e\u0646\u062c\u0634\u0646\u0628\u0647", - "days.tue": "\u0633\u0647 \u0634\u0646\u0628\u0647", - "days.wed": "\u0686\u0647\u0627\u0631\u0634\u0646\u0628\u0647", - - "debugging": "Debugging", - - "delete": "\u062d\u0630\u0641", - "delete.all": "Delete all", - - "dialog.fields.empty": "This dialog has no fields", - "dialog.files.empty": "No files to select", - "dialog.pages.empty": "No pages to select", - "dialog.text.empty": "This dialog does not define any text", - "dialog.users.empty": "No users to select", - - "dimensions": "ابعاد", - "disable": "Disable", - "disabled": "Disabled", - "discard": "\u0627\u0646\u0635\u0631\u0627\u0641", - - "drawer.fields.empty": "This drawer has no fields", - - "domain": "Domain", - "download": "Download", - "duplicate": "Duplicate", - - "edit": "\u0648\u06cc\u0631\u0627\u06cc\u0634", - - "email": "\u067e\u0633\u062a \u0627\u0644\u06a9\u062a\u0631\u0648\u0646\u06cc\u06a9", - "email.placeholder": "mail@example.com", - - "enter": "Enter", - "entries": "Entries", - "entry": "Entry", - - "environment": "Environment", - - "error": "Error", - "error.access.code": "Invalid code", - "error.access.login": "اطلاعات ورودی نامعتبر است", - "error.access.panel": "شما اجازه دسترسی به پانل را ندارید", - "error.access.view": "You are not allowed to access this part of the panel", - - "error.avatar.create.fail": "بارگزاری تصویر پروفایل موفق نبود", - "error.avatar.delete.fail": "\u062a\u0635\u0648\u06cc\u0631 \u067e\u0631\u0648\u0641\u0627\u06cc\u0644 \u0631\u0627 \u0646\u0645\u06cc\u062a\u0648\u0627\u0646 \u062d\u0630\u0641 \u06a9\u0631\u062f", - "error.avatar.dimensions.invalid": "لطفا طول و عرض تصویر پروفایل را زیر 3000 پیکسل انتخاب کنید", - "error.avatar.mime.forbidden": "تصویر پروفایل باید از نوع JPEG یا PNG باشد", - - "error.blueprint.notFound": "بلوپرینت با نام «{name}» قابل بارگذاری نیست", - - "error.blocks.max.plural": "You must not add more than {max} blocks", - "error.blocks.max.singular": "You must not add more than one block", - "error.blocks.min.plural": "You must add at least {min} blocks", - "error.blocks.min.singular": "You must add at least one block", - "error.blocks.validation": "There's an error on the \"{field}\" field in block {index} using the \"{fieldset}\" block type", - - "error.cache.type.invalid": "Invalid cache type \"{type}\"", - - "error.email.preset.notFound": "قالب ایمیل «{name}» پیدا نشد", - - "error.field.converter.invalid": "مبدل «{converter}» نامعتبر است", - "error.field.type.missing": "Field \"{ name }\": The field type \"{ type }\" does not exist", - - "error.file.changeName.empty": "The name must not be empty", - "error.file.changeName.permission": "شما اجازه تنغییر نام فایل «{filename}» را ندارید", - "error.file.changeTemplate.invalid": "The template for the file \"{id}\" cannot be changed to \"{template}\" (valid: \"{blueprints}\")", - "error.file.changeTemplate.permission": "You are not allowed to change the template for the file \"{id}\"", - - "error.file.duplicate": "فایلی هم نام با «{filename}» هم اکنون موجود است", - "error.file.extension.forbidden": "پسوند فایل «{extension}» غیرمجاز است", - "error.file.extension.invalid": "Invalid extension: {extension}", - "error.file.extension.missing": "\u0634\u0645\u0627 \u0646\u0645\u06cc\u200c\u062a\u0648\u0627\u0646\u06cc\u062f \u0641\u0627\u06cc\u0644\u200c\u0647\u0627\u06cc \u0628\u062f\u0648\u0646 \u067e\u0633\u0648\u0646\u062f \u0631\u0627 \u0622\u067e\u0644\u0648\u062f \u06a9\u0646\u06cc\u062f", - "error.file.maxheight": "The height of the image must not exceed {height} pixels", - "error.file.maxsize": "The file is too large", - "error.file.maxwidth": "The width of the image must not exceed {width} pixels", - "error.file.mime.differs": "فایل آپلود شده باید از همان نوع باشد «{mime}»", - "error.file.mime.forbidden": "فرمت فایل «{mime}» غیرمجاز است", - "error.file.mime.invalid": "Invalid mime type: {mime}", - "error.file.mime.missing": "فرمت فایل «{filename}» قابل شناسایی نیست", - "error.file.minheight": "The height of the image must be at least {height} pixels", - "error.file.minsize": "The file is too small", - "error.file.minwidth": "The width of the image must be at least {width} pixels", - "error.file.name.unique": "The filename must be unique", - "error.file.name.missing": "نام فایل اجباری است", - "error.file.notFound": "فایل «{filename}» پیدا نشد.", - "error.file.orientation": "The orientation of the image must be \"{orientation}\"", - "error.file.type.forbidden": "شما اجازه بارگذاری فایلهای «{type}» را ندارید", - "error.file.type.invalid": "Invalid file type: {type}", - "error.file.undefined": "\u0641\u0627\u06cc\u0644 \u0645\u0648\u0631\u062f \u0646\u0638\u0631 \u067e\u06cc\u062f\u0627 \u0646\u0634\u062f.", - - "error.form.incomplete": "لطفا کلیه خطاهای فرم را برطرف کنید", - "error.form.notSaved": "امکان دخیره فرم وجود ندارد", - - "error.language.code": "Please enter a valid code for the language", - "error.language.duplicate": "The language already exists", - "error.language.name": "Please enter a valid name for the language", - "error.language.notFound": "The language could not be found", - - "error.layout.validation.block": "There's an error on the \"{field}\" field in block {blockIndex} using the \"{fieldset}\" block type in layout {layoutIndex}", - "error.layout.validation.settings": "There's an error in layout {index} settings", - - "error.license.domain": "The domain for the license is missing", - "error.license.email": "لطفا ایمیل صحیحی وارد کنید", - "error.license.format": "Please enter a valid license code", - "error.license.verification": "The license could not be verified", - - "error.login.totp.confirm.invalid": "Invalid code", - "error.login.totp.confirm.missing": "Please enter the current code", - - "error.object.validation": "There’s an error in the \"{label}\" field:\n{message}", - - "error.offline": "The Panel is currently offline", - - "error.page.changeSlug.permission": "شما امکان تغییر پسوند Url صفحه «{slug}» را ندارید", - "error.page.changeSlug.reserved": "The path of top-level pages must not start with \"{path}\"", - "error.page.changeStatus.incomplete": "صفحه حاوی خطا است و قابل انتشار نیست", - "error.page.changeStatus.permission": "وضعیت صفحه جاری قابل تغییر نیست", - "error.page.changeStatus.toDraft.invalid": "صفحه «{slug}» قابل تبدیل به پیش نویس نیست", - "error.page.changeTemplate.invalid": "قالب صفحه «{slug}» قابل تغییر نیست", - "error.page.changeTemplate.permission": "شما اجازه تغییر قالب «{slug}» را ندارید", - "error.page.changeTitle.empty": "عنوان اجباری است", - "error.page.changeTitle.permission": "شما اجازه تغییر عنوان «{slug}» را ندارید", - "error.page.create.permission": "شما اجازه ایجاد «{slug}» را ندارید", - "error.page.delete": "حذف صفحه «{slug}» ممکن نیست", - "error.page.delete.confirm": "جهت ادامه عنوان صفحه را وارد کنید", - "error.page.delete.hasChildren": "این صفحه جاوی زیرصفحه است و نمی تواند حذف شود", - "error.page.delete.permission": "شما اجازه حذف «{slug}» را ندارید", - "error.page.draft.duplicate": "صفحه پیش‌نویسی با پسوند Url مشابه «{slug}» هم اکنون موجود است", - "error.page.duplicate": "صفحه‌ای با آدرس Url مشابه «{slug}» هم اکنون موجود است", - "error.page.duplicate.permission": "You are not allowed to duplicate \"{slug}\"", - "error.page.move.ancestor": "The page cannot be moved into itself", - "error.page.move.directory": "The page directory cannot be moved", - "error.page.move.duplicate": "A sub page with the URL appendix \"{slug}\" already exists", - "error.page.move.notFound": "The moved page could not be found", - "error.page.move.permission": "You are not allowed to move \"{slug}\"", - "error.page.move.template": "The \"{template}\" template is not accepted as a subpage of \"{parent}\"", - "error.page.notFound": "صفحه مورد نظر با آدرس «{slug}» پیدا نشد.", - "error.page.num.invalid": "لطفا شماره ترتیب را بدرستی وارد نمایید. اعداد نباید منفی باشند.", - "error.page.slug.invalid": "Please enter a valid URL appendix", - "error.page.slug.maxlength": "Slug length must be less than \"{length}\" characters", - "error.page.sort.permission": "امکان مرتب‌سازی «{slug}» نیست", - "error.page.status.invalid": "لطفا وضعیت صحیحی برای صفحه انتخاب کنید", - "error.page.undefined": "صفحه مورد نظر پیدا نشد", - "error.page.update.permission": "شما اجازه بروزرسانی «{slug}» را ندارید", - - "error.section.files.max.plural": "نباید بیش از {max} فایل به بخش «{section}» اضافه کنید", - "error.section.files.max.singular": "نباید بیش از یک فایل به بخش «{section}» اضافه کنید", - "error.section.files.min.plural": "The \"{section}\" section requires at least {min} files", - "error.section.files.min.singular": "The \"{section}\" section requires at least one file", - - "error.section.pages.max.plural": "نباید بیش از {max} صفحه به بخش «{section}» اضافه کنید", - "error.section.pages.max.singular": "نباید بیش از یک صفحه به بخش «{section}» اضافه کنید", - "error.section.pages.min.plural": "The \"{section}\" section requires at least {min} pages", - "error.section.pages.min.singular": "The \"{section}\" section requires at least one page", - - "error.section.notLoaded": "بخش «{name}» قابل بارکذاری نیست", - "error.section.type.invalid": "نوع بخش «{type}» غیرمجاز است", - - "error.site.changeTitle.empty": "عنوان اجباری است", - "error.site.changeTitle.permission": "شما اجازه تغییر عنوان سایت را ندارید", - "error.site.update.permission": "شما اجازه بروزرسانی سایت را ندارید", - - "error.structure.validation": "There's an error on the \"{field}\" field in row {index}", - - "error.template.default.notFound": "قالب پیش فرض موجود نیست", - - "error.unexpected": "An unexpected error occurred! Enable debug mode for more info: https://getkirby.com/docs/reference/system/options/debug", - - "error.user.changeEmail.permission": "شما اجازه تغییر ایمیل کاربر «{name}» را ندارید", - "error.user.changeLanguage.permission": "شما اجازه تغییر زبان برای کاربر «{name}» را ندارید", - "error.user.changeName.permission": "شما اجازه تنغییر نام کاربر «{name}» را ندارید", - "error.user.changePassword.permission": "شما اجازه تغییر رمز عبور کاربر «{name}» را ندارید", - "error.user.changeRole.lastAdmin": "نقش آخرین مدیر سیستم قابل تغییر نیست", - "error.user.changeRole.permission": "شما اجازه تغییر نقش کاربر «{name}» را ندارید", - "error.user.changeRole.toAdmin": "You are not allowed to promote someone to the admin role", - "error.user.create.permission": "شما اجازه ایجاد این کاربر را ندارید", - "error.user.delete": "کاربر «{name}» نمی تواند حذف شود", - "error.user.delete.lastAdmin": "\u062d\u0630\u0641 \u0622\u062e\u0631\u06cc\u0646 \u0645\u062f\u06cc\u0631 \u0633\u06cc\u0633\u062a\u0645 \u0645\u0645\u06a9\u0646 \u0646\u06cc\u0633\u062a", - "error.user.delete.lastUser": "حذف آخرین کاربر ممکن نیست", - "error.user.delete.permission": "شما اجازه حذف کاربر «{name}» را ندارید", - "error.user.duplicate": "کاربری با ایمیل «{email}» هم اکنون موجود است", - "error.user.email.invalid": "لطفا یک ایمیل معتبر وارد کنید", - "error.user.language.invalid": "لطفا زبان معتبری انتخاب کنید", - "error.user.notFound": "کاربر «{name}» پیدا نشد", - "error.user.password.excessive": "Please enter a valid password. Passwords must not be longer than 1000 characters.", - "error.user.password.invalid": "لطفا گذرواژه صحیحی با حداقل طول 8 حرف وارد کنید. ", - "error.user.password.notSame": "\u0644\u0637\u0641\u0627 \u062a\u06a9\u0631\u0627\u0631 \u06af\u0630\u0631\u0648\u0627\u0698\u0647 \u0631\u0627 \u0648\u0627\u0631\u062f \u0646\u0645\u0627\u06cc\u06cc\u062f", - "error.user.password.undefined": "کاربر فاقد گذرواژه است", - "error.user.password.wrong": "Wrong password", - "error.user.role.invalid": "لطفا نقش صحیحی وارد نمایید", - "error.user.undefined": "کاربر مورد نظر پیدا نشد", - "error.user.update.permission": "شما اجازه بروزرسانی کاربر «{name}» را ندارید", - - "error.validation.accepted": "لطفا تایید کنید", - "error.validation.alpha": "لطفا تنها از بین حروف a-z انتخاب کنید", - "error.validation.alphanum": "لطفا تنها از بین حروف a-z و اعداد 0-9 انتخاب کنید", - "error.validation.anchor": "Please enter a correct link anchor", - "error.validation.between": "لطفا مقداری مابین «{min}» و «{max}» وارد کنید", - "error.validation.boolean": "لطفا تایید یا رد کنید", - "error.validation.color": "Please enter a valid color in the {format} format", - "error.validation.contains": "لطفا مقداری شامل «{needle}» وارد کنید", - "error.validation.date": "لطفا تاریخ معتبری وارد کنید", - "error.validation.date.after": "Please enter a date after {date}", - "error.validation.date.before": "Please enter a date before {date}", - "error.validation.date.between": "Please enter a date between {min} and {max}", - "error.validation.denied": "لطفا رد کنید", - "error.validation.different": "مقدار نباید مساوی «{other}» باشد", - "error.validation.email": "لطفا ایمیل صحیحی وارد کنید", - "error.validation.endswith": "مقدار باید با «{end}» ختم شود", - "error.validation.filename": "لطفا نام فایل صحیحی وارد کنید", - "error.validation.in": "لطفا یکی از مقادیر روبرو را وارد کنید: ({in})", - "error.validation.integer": "لطفا عدد صحیحی وارد کنید", - "error.validation.ip": "لطفا IP آدرس صحیحی وارد کنید", - "error.validation.less": "لطفا مقداری کمتر از {max} وارد کنید", - "error.validation.linkType": "The link type is not allowed", - "error.validation.match": "مقدار وارد شده با الگوی مورد نظر همخوانی ندارد", - "error.validation.max": "لطفا مقداری کوچکتر یا مساوی {min} وارد کنید", - "error.validation.maxlength": "لطفا عبارت کوتاه‌تری وارد کنید. (حداکثر {max} حرف)", - "error.validation.maxwords": "لطفا بیش از {max} کلمه وارد نکنید", - "error.validation.min": "لطفا مقداری بزرگتر یا مساوی با {min} وارد کنید", - "error.validation.minlength": "لطفا عبارتی طولانی‌تری وارد کنید. (حداقل {min} حرف)", - "error.validation.minwords": "لطفا حداقل {min} کلمه وارد کنید", - "error.validation.more": "لطفا مقداری بیش از {min} وارد کنید", - "error.validation.notcontains": "لطفا مقداری فاقد «{needle}» وارد کنید", - "error.validation.notin": "لطفا از مقادیر روبرو استفاده نکنید: ({notin})", - "error.validation.option": "لطفا گزینه معتبری انتخاب کنید", - "error.validation.num": "لطفا عدد صحیحی وارد کنید", - "error.validation.required": "لطفا مقداری وارد کنید", - "error.validation.same": "لطفا مقدار «{other}» را وارد کنید", - "error.validation.size": "اندازه ورودی باید معادل «{size}» باشد", - "error.validation.startswith": "مقدار باید با «{start}» شروع شود", - "error.validation.tel": "Please enter an unformatted phone number", - "error.validation.time": "لطفا زمان معتبری وارد کنید", - "error.validation.time.after": "Please enter a time after {time}", - "error.validation.time.before": "Please enter a time before {time}", - "error.validation.time.between": "Please enter a time between {min} and {max}", - "error.validation.uuid": "Please enter a valid UUID", - "error.validation.url": "لطفا آدرس URL صحیح وارد کنید", - - "expand": "Expand", - "expand.all": "Expand All", - - "field.invalid": "The field is invalid", - "field.required": "The field is required", - "field.blocks.changeType": "Change type", - "field.blocks.code.name": "کد", - "field.blocks.code.language": "زبان", - "field.blocks.code.placeholder": "Your code …", - "field.blocks.delete.confirm": "Do you really want to delete this block?", - "field.blocks.delete.confirm.all": "Do you really want to delete all blocks?", - "field.blocks.delete.confirm.selected": "Do you really want to delete the selected blocks?", - "field.blocks.empty": "No blocks yet", - "field.blocks.fieldsets.empty": "No fieldsets yet", - "field.blocks.fieldsets.label": "Please select a block type …", - "field.blocks.fieldsets.paste": "Press {{ shortcut }} to import layouts/blocks from your clipboard Only those allowed in the current field will get inserted.", - "field.blocks.gallery.name": "Gallery", - "field.blocks.gallery.images.empty": "No images yet", - "field.blocks.gallery.images.label": "Images", - "field.blocks.heading.level": "Level", - "field.blocks.heading.name": "Heading", - "field.blocks.heading.text": "Text", - "field.blocks.heading.placeholder": "Heading …", - "field.blocks.image.alt": "Alternative text", - "field.blocks.image.caption": "Caption", - "field.blocks.image.crop": "Crop", - "field.blocks.image.link": "پیوند", - "field.blocks.image.location": "Location", - "field.blocks.image.location.internal": "This website", - "field.blocks.image.location.external": "External source", - "field.blocks.image.name": "تصویر", - "field.blocks.image.placeholder": "Select an image", - "field.blocks.image.ratio": "Ratio", - "field.blocks.image.url": "Image URL", - "field.blocks.line.name": "Line", - "field.blocks.list.name": "List", - "field.blocks.markdown.name": "Markdown", - "field.blocks.markdown.label": "Text", - "field.blocks.markdown.placeholder": "Markdown …", - "field.blocks.quote.name": "Quote", - "field.blocks.quote.text.label": "Text", - "field.blocks.quote.text.placeholder": "Quote …", - "field.blocks.quote.citation.label": "Citation", - "field.blocks.quote.citation.placeholder": "by …", - "field.blocks.text.name": "Text", - "field.blocks.text.placeholder": "Text …", - "field.blocks.video.autoplay": "Autoplay", - "field.blocks.video.caption": "Caption", - "field.blocks.video.controls": "Controls", - "field.blocks.video.location": "Location", - "field.blocks.video.loop": "Loop", - "field.blocks.video.muted": "Muted", - "field.blocks.video.name": "Video", - "field.blocks.video.placeholder": "Enter a video URL", - "field.blocks.video.poster": "Poster", - "field.blocks.video.preload": "Preload", - "field.blocks.video.url.label": "Video-URL", - "field.blocks.video.url.placeholder": "https://youtube.com/?v=", - - "field.files.empty": "فایلی انتخاب نشده است", - - "field.layout.change": "Change layout", - "field.layout.delete": "Delete layout", - "field.layout.delete.confirm": "Do you really want to delete this layout?", - "field.layout.delete.confirm.all": "Do you really want to delete all layouts?", - "field.layout.empty": "No rows yet", - "field.layout.select": "Select a layout", - - "field.object.empty": "No information yet", - - "field.pages.empty": "صفحه‌ای انتخاب نشده است", - - "field.structure.delete.confirm": "\u0645\u062f\u062e\u0644 \u062c\u0627\u0631\u06cc \u062d\u0630\u0641 \u0634\u0648\u062f\u061f", - "field.structure.delete.confirm.all": "Do you really want to delete all entries?", - "field.structure.empty": "\u0645\u0648\u0631\u062f\u06cc \u0648\u062c\u0648\u062f \u0646\u062f\u0627\u0631\u062f.", - - "field.users.empty": "کاربری انتخاب نشده است", - - "fields.empty": "No fields yet", - - "file": "File", - "file.blueprint": "This file has no blueprint yet. You can define the setup in /site/blueprints/files/{blueprint}.yml", - "file.changeTemplate": "تغییر قالب", - "file.changeTemplate.notice": "Changing the file's template will remove content for fields that don't match in type. If the new template defines certain rules, e.g. image dimensions, those will also be applied irreversibly. Use with caution.", - "file.delete.confirm": "آیا واقعا می خواهید این فایل را حذف کنید؟
{filename}", - "file.focus.placeholder": "Set focal point", - "file.focus.reset": "Remove focal point", - "file.focus.title": "Focus", - "file.sort": "Change position", - - "files": "فایل‌ها", - "files.empty": "فایلی موجود نیست", - - "filter": "Filter", - - "hide": "Hide", - "hour": "ساعت", - "hue": "Hue", - "import": "Import", - "info": "Info", - "insert": "\u062f\u0631\u062c", - "insert.after": "Insert after", - "insert.before": "Insert before", - "install": "نصب", - - "installation": "نصب و راه اندازی", - "installation.completed": "پنل کاربری نصب شد", - "installation.disabled": "نصب کننده پانل کاربری بصورت پیش‌فرض در سرورهای عمومی غیرفعال است. لطفا نصب را روی یک ماشین محلی اجرا کنید یا آن را با استفاده از panel.install فعال کنید.", - "installation.issues.accounts": "پوشه /site/accounts موجود نیست یا قابل نوشتن نیست.", - "installation.issues.content": "پوشه /content موجود نیست یا قابل نوشتن نیست", - "installation.issues.curl": "افزونه CURL مورد نیاز است", - "installation.issues.headline": "نصب پانل کاربری ممکن نیست", - "installation.issues.mbstring": "افزونه MB String مورد نیاز است", - "installation.issues.media": "پوشه /media موجود نیست یا قابل نوشتن نیست", - "installation.issues.php": "لطفا از پی‌اچ‌پی 8 یا بالاتر استفاده کنید", - "installation.issues.sessions": "پوشه /site/sessions وجود ندارد یا قابل نوشتن نیست", - - "language": "\u0632\u0628\u0627\u0646", - "language.code": "کد", - "language.convert": "پیش‌فرض شود", - "language.convert.confirm": "

آیا واقعا میخواهید {name} را به زبان پیشفرض تبدیل کنید؟ این عمل برگشت ناپذیر است.

اگر {name} دارای محتوای غیر ترجمه شده باشد، جایگزین معتبر دیگری نخواهد بود و ممکن است بخش‌هایی از سایت شما خالی باشد.

", - "language.create": "افزودن زبان جدید", - "language.default": "زبان پیش‌فرض", - "language.delete.confirm": "آیا واقعا میخواهید زبان {name} را به همراه تمام ترجمه‌ها حذف کنید؟ این عمل قابل بازگشت نخواهد بود!", - "language.deleted": "زبان مورد نظر حذف شد", - "language.direction": "rtl", - "language.direction.ltr": "چپ به راست", - "language.direction.rtl": "راست به چپ", - "language.locale": "PHP locale string", - "language.locale.warning": "You are using a custom locale set up. Please modify it in the language file in /site/languages", - "language.name": "پارسی", - "language.secondary": "Secondary language", - "language.settings": "Language settings", - "language.updated": "زبان به روز شد", - "language.variables": "Language variables", - "language.variables.empty": "No translations yet", - - "language.variable.delete.confirm": "Do you really want to delete the variable for {key}?", - "language.variable.key": "Key", - "language.variable.notFound": "The variable could not be found", - "language.variable.value": "Value", - - "languages": "زبان‌ها", - "languages.default": "زبان پیش‌فرض", - "languages.empty": "هنوز هیچ زبانی موجود نیست", - "languages.secondary": "زبان‌های ثانویه", - "languages.secondary.empty": "هنوز هیچ زبان ثانویه‌ای موجود نیست", - - "license": "\u0645\u062c\u0648\u0632", - "license.activate": "Activate it now", - "license.activate.label": "Please activate your license", - "license.activate.domain": "Your license will be activated for {host}.", - "license.activate.local": "You are about to activate your Kirby license for your local domain {host}. If this site will be deployed to a public domain, please activate it there instead. If {host} is the domain you want to use your license for, please continue.", - "license.activated": "Activated", - "license.buy": "خرید مجوز", - "license.code": "کد", - "license.code.help": "You received your license code after the purchase via email. Please copy and paste it here.", - "license.code.label": "لطفا کد مجوز خود را وارد کنید", - "license.status.active.info": "Includes new major versions until {date}", - "license.status.active.label": "Valid license", - "license.status.demo.info": "This is a demo installation", - "license.status.demo.label": "Demo", - "license.status.inactive.info": "Renew license to update to new major versions", - "license.status.inactive.label": "No new major versions", - "license.status.legacy.bubble": "Ready to renew your license?", - "license.status.legacy.info": "Your license does not cover this version", - "license.status.legacy.label": "Please renew your license", - "license.status.missing.bubble": "Ready to launch your site?", - "license.status.missing.info": "No valid license", - "license.status.missing.label": "Please activate your license", - "license.manage": "Manage your licenses", - "license.purchased": "Purchased", - "license.success": "با تشکر از شما برای حمایت از کربی", - "license.unregistered.label": "Unregistered", - - "link": "\u067e\u06cc\u0648\u0646\u062f", - "link.text": "\u0645\u062a\u0646 \u067e\u06cc\u0648\u0646\u062f", - - "loading": "بارگزاری", - - "lock.unsaved": "Unsaved changes", - "lock.unsaved.empty": "There are no more unsaved changes", - "lock.isLocked": "Unsaved changes by {email}", - "lock.unlock": "Unlock", - "lock.unlock.submit": "Unlock and overwrite unsaved changes by {email}", - "lock.isUnlocked": "Was unlocked by another user", - - "login": "ورود", - "login.code.label.login": "Login code", - "login.code.label.password-reset": "Password reset code", - "login.code.placeholder.email": "000 000", - "login.code.placeholder.totp": "000000", - "login.code.text.email": "If your email address is registered, the requested code was sent via email.", - "login.code.text.totp": "Please enter the one‑time code from your authenticator app.", - "login.email.login.body": "Hi {user.nameOrEmail},\n\nYou recently requested a login code for the Panel of {site}.\nThe following login code will be valid for {timeout} minutes:\n\n{code}\n\nIf you did not request a login code, please ignore this email or contact your administrator if you have questions.\nFor security, please DO NOT forward this email.", - "login.email.login.subject": "Your login code", - "login.email.password-reset.body": "Hi {user.nameOrEmail},\n\nYou recently requested a password reset code for the Panel of {site}.\nThe following password reset code will be valid for {timeout} minutes:\n\n{code}\n\nIf you did not request a password reset code, please ignore this email or contact your administrator if you have questions.\nFor security, please DO NOT forward this email.", - "login.email.password-reset.subject": "Your password reset code", - "login.remember": "مرا به خاطر بسپار", - "login.reset": "Reset password", - "login.toggleText.code.email": "Login via email", - "login.toggleText.code.email-password": "Login with password", - "login.toggleText.password-reset.email": "Forgot your password?", - "login.toggleText.password-reset.email-password": "← Back to login", - "login.totp.enable.option": "Set up one‑time codes", - "login.totp.enable.intro": "Authenticator apps can generate one‑time codes that are used as a second factor when signing into your account.", - "login.totp.enable.qr.label": "1. Scan this QR code", - "login.totp.enable.qr.help": "Unable to scan? Add the setup key {secret} manually to your authenticator app.", - "login.totp.enable.confirm.headline": "2. Confirm with generated code", - "login.totp.enable.confirm.text": "Your app generates a new one‑time code every 30 seconds. Enter the current code to complete the setup:", - "login.totp.enable.confirm.label": "Current code", - "login.totp.enable.confirm.help": "After this setup, we will ask you for a one‑time code every time you log in.", - "login.totp.enable.success": "One‑time codes enabled", - "login.totp.disable.option": "Disable one‑time codes", - "login.totp.disable.label": "Enter your password to disable one‑time codes", - "login.totp.disable.help": "In the future, a different second factor like a login code sent via email will be requested when you log in. You can always set up one‑time codes again later.", - "login.totp.disable.admin": "

This will disable one‑time codes for {user}.

In the future, a different second factor like a login code sent via email will be requested when they log in. {user} can set up one‑time codes again after their next login.

", - "login.totp.disable.success": "One‑time codes disabled", - - "logout": "خروج", - - "merge": "Merge", - "menu": "منو", - "meridiem": "ق.ظ/ب.ظ", - "mime": "نوع رسانه", - "minutes": "دقیقه", - - "month": "ماه", - "months.april": "\u0622\u0648\u0631\u06cc\u0644", - "months.august": "\u0627\u0648\u062a", - "months.december": "\u062f\u0633\u0627\u0645\u0628\u0631", - "months.february": "فوریه", - "months.january": "\u0698\u0627\u0646\u0648\u06cc\u0647", - "months.july": "\u0698\u0648\u0626\u06cc\u0647", - "months.june": "\u0698\u0648\u0626\u0646", - "months.march": "\u0645\u0627\u0631\u0633", - "months.may": "\u0645\u06cc", - "months.november": "\u0646\u0648\u0627\u0645\u0628\u0631", - "months.october": "\u0627\u06a9\u062a\u0628\u0631", - "months.september": "\u0633\u067e\u062a\u0627\u0645\u0628\u0631", - - "more": "بیشتر", - "move": "Move", - "name": "نام", - "next": "بعدی", - "night": "Night", - "no": "no", - "off": "off", - "on": "on", - "open": "بازکردن", - "open.newWindow": "Open in new window", - "option": "Option", - "options": "گزینه‌ها", - "options.none": "No options", - "options.all": "Show all {count} options", - - "orientation": "جهت", - "orientation.landscape": "افقی", - "orientation.portrait": "عمودی", - "orientation.square": "مربع", - - "page": "صفحه", - "page.blueprint": "This page has no blueprint yet. You can define the setup in /site/blueprints/pages/{blueprint}.yml", - "page.changeSlug": "تغییر Url صفحه", - "page.changeSlug.fromTitle": "\u0627\u06cc\u062c\u0627\u062f \u0627\u0632 \u0631\u0648\u06cc \u0639\u0646\u0648\u0627\u0646", - "page.changeStatus": "تغییر وضعیت", - "page.changeStatus.position": "لطفا یک موقعیت را انتخاب کنید", - "page.changeStatus.select": "یک وضعیت جدید را انتخاب کنید", - "page.changeTemplate": "تغییر قالب", - "page.changeTemplate.notice": "Changing the page's template will remove content for fields that don't match in type. Use with caution.", - "page.create": "Create as {status}", - "page.delete.confirm": "صفحه {title} حذف شود؟", - "page.delete.confirm.subpages": "این صفحه دارای زیرصفحه است.
تمام زیر صفحات نیز حذف خواهد شد.", - "page.delete.confirm.title": "جهت ادامه عنوان صفحه را وارد کنید", - "page.duplicate.appendix": "کپی", - "page.duplicate.files": "Copy files", - "page.duplicate.pages": "Copy pages", - "page.move": "Move page", - "page.sort": "Change position", - "page.status": "وضعیت", - "page.status.draft": "پیش‌نویس", - "page.status.draft.description": "The page is in draft mode and only visible for logged in editors or via secret link", - "page.status.listed": "عمومی", - "page.status.listed.description": "این صفحه برای عموم قابل مشاهده است", - "page.status.unlisted": "فهرست نشده", - "page.status.unlisted.description": "این صفحه فقط از طریق URL قابل دسترسی است", - - "pages": "صفحات", - "pages.empty": "هنوز هیچ صفحه‌ای موجود نیست", - "pages.status.draft": "پیش‌نویس‌ها", - "pages.status.listed": "منتشر شده", - "pages.status.unlisted": "فهرست نشده", - - "pagination.page": "صفحه", - - "password": "\u06af\u0630\u0631\u0648\u0627\u0698\u0647", - "paste": "Paste", - "paste.after": "Paste after", - "paste.success": "{count} pasted!", - "pixel": "پیکسل", - "plugin": "Plugin", - "plugins": "Plugins", - "prev": "قبلی", - "preview": "Preview", - "remove": "حذف", - "rename": "تغییر نام", - "renew": "Renew", - "replace": "\u062c\u0627\u06cc\u06af\u0632\u06cc\u0646\u06cc", - "replace.with": "Replace with", - "retry": "\u062a\u0644\u0627\u0634 \u0645\u062c\u062f\u062f", - "revert": "بازگرداندن تغییرات", - "revert.confirm": "Do you really want to delete all unsaved changes?", - - "role": "\u0646\u0642\u0634", - "role.admin.description": "The admin has all rights", - "role.admin.title": "Admin", - "role.all": "همه", - "role.empty": "هیچ کاربری با این نقش وجود ندارد", - "role.description.placeholder": "فاقد شرح", - "role.nobody.description": "This is a fallback role without any permissions", - "role.nobody.title": "Nobody", - - "save": "\u0630\u062e\u06cc\u0631\u0647", - "search": "جستجو", - "search.min": "Enter {min} characters to search", - "search.all": "Show all {count} results", - "search.results.none": "No results", - - "section.invalid": "The section is invalid", - "section.required": "The section is required", - - "security": "Security", - "select": "انتخاب", - "server": "Server", - "settings": "تنظیمات", - "show": "Show", - "site.blueprint": "The site has no blueprint yet. You can define the setup in /site/blueprints/site.yml", - "size": "اندازه", - "slug": "پسوند Url", - "sort": "ترتیب", - "sort.drag": "Drag to sort …", - "split": "Split", - - "stats.empty": "No reports", - "status": "وضعیت", - - "system.info.copy": "Copy info", - "system.info.copied": "System info copied", - "system.issues.content": "The content folder seems to be exposed", - "system.issues.eol.kirby": "Your installed Kirby version has reached end-of-life and will not receive further security updates", - "system.issues.eol.plugin": "Your installed version of the { plugin } plugin is has reached end-of-life and will not receive further security updates", - "system.issues.eol.php": "Your installed PHP release { release } has reached end-of-life and will not receive further security updates", - "system.issues.debug": "Debugging must be turned off in production", - "system.issues.git": "The .git folder seems to be exposed", - "system.issues.https": "We recommend HTTPS for all your sites", - "system.issues.kirby": "The kirby folder seems to be exposed", - "system.issues.site": "The site folder seems to be exposed", - "system.issues.vulnerability.kirby": "Your installation might be affected by the following vulnerability ({ severity } severity): { description }", - "system.issues.vulnerability.plugin": "Your installation might be affected by the following vulnerability in the { plugin } plugin ({ severity } severity): { description }", - "system.updateStatus": "Update status", - "system.updateStatus.error": "Could not check for updates", - "system.updateStatus.not-vulnerable": "No known vulnerabilities", - "system.updateStatus.security-update": "Free security update { version } available", - "system.updateStatus.security-upgrade": "Upgrade { version } with security fixes available", - "system.updateStatus.unreleased": "Unreleased version", - "system.updateStatus.up-to-date": "Up to date", - "system.updateStatus.update": "Free update { version } available", - "system.updateStatus.upgrade": "Upgrade { version } available", - - "tel": "Phone", - "tel.placeholder": "+49123456789", - "template": "\u0642\u0627\u0644\u0628 \u0635\u0641\u062d\u0647", - "title": "عنوان", - "today": "امروز", - - "toolbar.button.clear": "Clear formatting", - "toolbar.button.code": "کد", - "toolbar.button.bold": "\u0645\u062a\u0646 \u0628\u0627 \u062d\u0631\u0648\u0641 \u062f\u0631\u0634\u062a", - "toolbar.button.email": "\u067e\u0633\u062a \u0627\u0644\u06a9\u062a\u0631\u0648\u0646\u06cc\u06a9", - "toolbar.button.headings": "عنوان‌ها", - "toolbar.button.heading.1": "عنوان 1", - "toolbar.button.heading.2": "عنوان 2", - "toolbar.button.heading.3": "عنوان 3", - "toolbar.button.heading.4": "Heading 4", - "toolbar.button.heading.5": "Heading 5", - "toolbar.button.heading.6": "Heading 6", - "toolbar.button.italic": "\u0645\u062a\u0646 \u0627\u0631\u06cc\u0628", - "toolbar.button.file": "فایل", - "toolbar.button.file.select": "Select a file", - "toolbar.button.file.upload": "Upload a file", - "toolbar.button.link": "\u067e\u06cc\u0648\u0646\u062f", - "toolbar.button.paragraph": "Paragraph", - "toolbar.button.strike": "Strike-through", - "toolbar.button.sub": "Subscript", - "toolbar.button.sup": "Superscript", - "toolbar.button.ol": "لیست مرتب", - "toolbar.button.underline": "Underline", - "toolbar.button.ul": "لیست معمولی", - - "translation.author": "تیم کربی", - "translation.direction": "rtl", - "translation.name": "انگلیسی", - "translation.locale": "fa_IR", - - "type": "Type", - - "upload": "بارگذاری", - "upload.error.cantMove": "The uploaded file could not be moved", - "upload.error.cantWrite": "Failed to write file to disk", - "upload.error.default": "The file could not be uploaded", - "upload.error.extension": "File upload stopped by extension", - "upload.error.formSize": "The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the form", - "upload.error.iniPostSize": "The uploaded file exceeds the post_max_size directive in php.ini", - "upload.error.iniSize": "The uploaded file exceeds the upload_max_filesize directive in php.ini", - "upload.error.noFile": "No file was uploaded", - "upload.error.noFiles": "No files were uploaded", - "upload.error.partial": "The uploaded file was only partially uploaded", - "upload.error.tmpDir": "Missing a temporary folder", - "upload.errors": "خطا", - "upload.progress": "در حال بارگذاری...", - - "url": "Url", - "url.placeholder": "https://example.com", - - "user": "کاربر", - "user.blueprint": "You can define additional sections and form fields for this user role in /site/blueprints/users/{blueprint}.yml", - "user.changeEmail": "تغییر ایمیل", - "user.changeLanguage": "تغییر زبان", - "user.changeName": "تغییر نام این کاربر", - "user.changePassword": "تغییر گذرواژه", - "user.changePassword.new": "گذرواژه جدید", - "user.changePassword.new.confirm": "تایید گذرواژه جدید...", - "user.changeRole": "تغییر نقش", - "user.changeRole.select": "یک نقش جدید را انتخاب کنید", - "user.create": "افزودن کاربر جدید", - "user.delete": "حذف کاربر جاری", - "user.delete.confirm": "آیا واقعا میخواهید {email} را حذف کنید؟", - - "users": "کاربران", - - "version": "\u0646\u0633\u062e\u0647 \u0646\u0631\u0645 \u0627\u0641\u0632\u0627\u0631", - "version.current": "Current version", - "version.latest": "Latest version", - "versionInformation": "Version information", - - "view.account": "حساب کاربری شما", - "view.installation": "\u0646\u0635\u0628 \u0648 \u0631\u0627\u0647 \u0627\u0646\u062f\u0627\u0632\u06cc", - "view.languages": "زبان‌ها", - "view.resetPassword": "Reset password", - "view.site": "سایت", - "view.system": "System", - "view.users": "\u06a9\u0627\u0631\u0628\u0631\u0627\u0646", - - "welcome": "خوش آمدید", - "year": "سال", - "yes": "yes" + "account.changeName": "Change your name", + "account.delete": "Delete your account", + "account.delete.confirm": "Do you really want to delete your account? You will be logged out immediately. Your account cannot be recovered.", + + "add": "\u0627\u0641\u0632\u0648\u062f\u0646", + "author": "Author", + "avatar": "\u062a\u0635\u0648\u06cc\u0631 \u067e\u0631\u0648\u0641\u0627\u06cc\u0644", + "back": "بازگشت", + "cancel": "\u0627\u0646\u0635\u0631\u0627\u0641", + "change": "\u0627\u0635\u0644\u0627\u062d", + "close": "\u0628\u0633\u062a\u0646", + "confirm": "تایید", + "collapse": "Collapse", + "collapse.all": "Collapse All", + "copy": "کپی", + "copy.all": "Copy all", + "create": "ایجاد", + + "date": "تاریخ", + "date.select": "یک تاریخ را انتخاب کنید", + + "day": "روز", + "days.fri": "\u062c\u0645\u0639\u0647", + "days.mon": "\u062f\u0648\u0634\u0646\u0628\u0647", + "days.sat": "\u0634\u0646\u0628\u0647", + "days.sun": "\u06cc\u06a9\u0634\u0646\u0628\u0647", + "days.thu": "\u067e\u0646\u062c\u0634\u0646\u0628\u0647", + "days.tue": "\u0633\u0647 \u0634\u0646\u0628\u0647", + "days.wed": "\u0686\u0647\u0627\u0631\u0634\u0646\u0628\u0647", + + "debugging": "Debugging", + + "delete": "\u062d\u0630\u0641", + "delete.all": "Delete all", + + "dialog.files.empty": "No files to select", + "dialog.pages.empty": "No pages to select", + "dialog.users.empty": "No users to select", + + "dimensions": "ابعاد", + "disabled": "Disabled", + "discard": "\u0627\u0646\u0635\u0631\u0627\u0641", + "download": "Download", + "duplicate": "Duplicate", + + "edit": "\u0648\u06cc\u0631\u0627\u06cc\u0634", + + "email": "\u067e\u0633\u062a \u0627\u0644\u06a9\u062a\u0631\u0648\u0646\u06cc\u06a9", + "email.placeholder": "mail@example.com", + + "entries": "Entries", + "entry": "Entry", + + "environment": "Environment", + + "error.access.code": "Invalid code", + "error.access.login": "اطلاعات ورودی نامعتبر است", + "error.access.panel": "شما اجازه دسترسی به پانل را ندارید", + "error.access.view": "You are not allowed to access this part of the panel", + + "error.avatar.create.fail": "بارگزاری تصویر پروفایل موفق نبود", + "error.avatar.delete.fail": "\u062a\u0635\u0648\u06cc\u0631 \u067e\u0631\u0648\u0641\u0627\u06cc\u0644 \u0631\u0627 \u0646\u0645\u06cc\u062a\u0648\u0627\u0646 \u062d\u0630\u0641 \u06a9\u0631\u062f", + "error.avatar.dimensions.invalid": "لطفا طول و عرض تصویر پروفایل را زیر 3000 پیکسل انتخاب کنید", + "error.avatar.mime.forbidden": "تصویر پروفایل باید از نوع JPEG یا PNG باشد", + + "error.blueprint.notFound": "بلوپرینت با نام «{name}» قابل بارگذاری نیست", + + "error.blocks.max.plural": "You must not add more than {max} blocks", + "error.blocks.max.singular": "You must not add more than one block", + "error.blocks.min.plural": "You must add at least {min} blocks", + "error.blocks.min.singular": "You must add at least one block", + "error.blocks.validation": "There's an error in block {index}", + + "error.email.preset.notFound": "قالب ایمیل «{name}» پیدا نشد", + + "error.field.converter.invalid": "مبدل «{converter}» نامعتبر است", + + "error.file.changeName.empty": "The name must not be empty", + "error.file.changeName.permission": "شما اجازه تنغییر نام فایل «{filename}» را ندارید", + "error.file.duplicate": "فایلی هم نام با «{filename}» هم اکنون موجود است", + "error.file.extension.forbidden": "پسوند فایل «{extension}» غیرمجاز است", + "error.file.extension.invalid": "Invalid extension: {extension}", + "error.file.extension.missing": "\u0634\u0645\u0627 \u0646\u0645\u06cc\u200c\u062a\u0648\u0627\u0646\u06cc\u062f \u0641\u0627\u06cc\u0644\u200c\u0647\u0627\u06cc \u0628\u062f\u0648\u0646 \u067e\u0633\u0648\u0646\u062f \u0631\u0627 \u0622\u067e\u0644\u0648\u062f \u06a9\u0646\u06cc\u062f", + "error.file.maxheight": "The height of the image must not exceed {height} pixels", + "error.file.maxsize": "The file is too large", + "error.file.maxwidth": "The width of the image must not exceed {width} pixels", + "error.file.mime.differs": "فایل آپلود شده باید از همان نوع باشد «{mime}»", + "error.file.mime.forbidden": "فرمت فایل «{mime}» غیرمجاز است", + "error.file.mime.invalid": "Invalid mime type: {mime}", + "error.file.mime.missing": "فرمت فایل «{filename}» قابل شناسایی نیست", + "error.file.minheight": "The height of the image must be at least {height} pixels", + "error.file.minsize": "The file is too small", + "error.file.minwidth": "The width of the image must be at least {width} pixels", + "error.file.name.missing": "نام فایل اجباری است", + "error.file.notFound": "فایل «{filename}» پیدا نشد.", + "error.file.orientation": "The orientation of the image must be \"{orientation}\"", + "error.file.type.forbidden": "شما اجازه بارگذاری فایلهای «{type}» را ندارید", + "error.file.type.invalid": "Invalid file type: {type}", + "error.file.undefined": "\u0641\u0627\u06cc\u0644 \u0645\u0648\u0631\u062f \u0646\u0638\u0631 \u067e\u06cc\u062f\u0627 \u0646\u0634\u062f.", + + "error.form.incomplete": "لطفا کلیه خطاهای فرم را برطرف کنید", + "error.form.notSaved": "امکان دخیره فرم وجود ندارد", + + "error.language.code": "Please enter a valid code for the language", + "error.language.duplicate": "The language already exists", + "error.language.name": "Please enter a valid name for the language", + "error.language.notFound": "The language could not be found", + + "error.layout.validation.block": "There's an error in block {blockIndex} in layout {layoutIndex}", + "error.layout.validation.settings": "There's an error in layout {index} settings", + + "error.license.format": "Please enter a valid license key", + "error.license.email": "لطفا ایمیل صحیحی وارد کنید", + "error.license.verification": "The license could not be verified", + + "error.offline": "The Panel is currently offline", + + "error.page.changeSlug.permission": "شما امکان تغییر پسوند Url صفحه «{slug}» را ندارید", + "error.page.changeStatus.incomplete": "صفحه حاوی خطا است و قابل انتشار نیست", + "error.page.changeStatus.permission": "وضعیت صفحه جاری قابل تغییر نیست", + "error.page.changeStatus.toDraft.invalid": "صفحه «{slug}» قابل تبدیل به پیش نویس نیست", + "error.page.changeTemplate.invalid": "قالب صفحه «{slug}» قابل تغییر نیست", + "error.page.changeTemplate.permission": "شما اجازه تغییر قالب «{slug}» را ندارید", + "error.page.changeTitle.empty": "عنوان اجباری است", + "error.page.changeTitle.permission": "شما اجازه تغییر عنوان «{slug}» را ندارید", + "error.page.create.permission": "شما اجازه ایجاد «{slug}» را ندارید", + "error.page.delete": "حذف صفحه «{slug}» ممکن نیست", + "error.page.delete.confirm": "جهت ادامه عنوان صفحه را وارد کنید", + "error.page.delete.hasChildren": "این صفحه جاوی زیرصفحه است و نمی تواند حذف شود", + "error.page.delete.permission": "شما اجازه حذف «{slug}» را ندارید", + "error.page.draft.duplicate": "صفحه پیش‌نویسی با پسوند Url مشابه «{slug}» هم اکنون موجود است", + "error.page.duplicate": "صفحه‌ای با آدرس Url مشابه «{slug}» هم اکنون موجود است", + "error.page.duplicate.permission": "You are not allowed to duplicate \"{slug}\"", + "error.page.notFound": "صفحه مورد نظر با آدرس «{slug}» پیدا نشد.", + "error.page.num.invalid": "لطفا شماره ترتیب را بدرستی وارد نمایید. اعداد نباید منفی باشند.", + "error.page.slug.invalid": "Please enter a valid URL appendix", + "error.page.slug.maxlength": "Slug length must be less than \"{length}\" characters", + "error.page.sort.permission": "امکان مرتب‌سازی «{slug}» نیست", + "error.page.status.invalid": "لطفا وضعیت صحیحی برای صفحه انتخاب کنید", + "error.page.undefined": "صفحه مورد نظر پیدا نشد", + "error.page.update.permission": "شما اجازه بروزرسانی «{slug}» را ندارید", + + "error.section.files.max.plural": "نباید بیش از {max} فایل به بخش «{section}» اضافه کنید", + "error.section.files.max.singular": "نباید بیش از یک فایل به بخش «{section}» اضافه کنید", + "error.section.files.min.plural": "The \"{section}\" section requires at least {min} files", + "error.section.files.min.singular": "The \"{section}\" section requires at least one file", + + "error.section.pages.max.plural": "نباید بیش از {max} صفحه به بخش «{section}» اضافه کنید", + "error.section.pages.max.singular": "نباید بیش از یک صفحه به بخش «{section}» اضافه کنید", + "error.section.pages.min.plural": "The \"{section}\" section requires at least {min} pages", + "error.section.pages.min.singular": "The \"{section}\" section requires at least one page", + + "error.section.notLoaded": "بخش «{name}» قابل بارکذاری نیست", + "error.section.type.invalid": "نوع بخش «{type}» غیرمجاز است", + + "error.site.changeTitle.empty": "عنوان اجباری است", + "error.site.changeTitle.permission": "شما اجازه تغییر عنوان سایت را ندارید", + "error.site.update.permission": "شما اجازه بروزرسانی سایت را ندارید", + + "error.template.default.notFound": "قالب پیش فرض موجود نیست", + + "error.unexpected": "An unexpected error occurred! Enable debug mode for more info: https://getkirby.com/docs/reference/system/options/debug", + + "error.user.changeEmail.permission": "شما اجازه تغییر ایمیل کاربر «{name}» را ندارید", + "error.user.changeLanguage.permission": "شما اجازه تغییر زبان برای کاربر «{name}» را ندارید", + "error.user.changeName.permission": "شما اجازه تنغییر نام کاربر «{name}» را ندارید", + "error.user.changePassword.permission": "شما اجازه تغییر رمز عبور کاربر «{name}» را ندارید", + "error.user.changeRole.lastAdmin": "نقش آخرین مدیر سیستم قابل تغییر نیست", + "error.user.changeRole.permission": "شما اجازه تغییر نقش کاربر «{name}» را ندارید", + "error.user.changeRole.toAdmin": "You are not allowed to promote someone to the admin role", + "error.user.create.permission": "شما اجازه ایجاد این کاربر را ندارید", + "error.user.delete": "کاربر «{name}» نمی تواند حذف شود", + "error.user.delete.lastAdmin": "\u062d\u0630\u0641 \u0622\u062e\u0631\u06cc\u0646 \u0645\u062f\u06cc\u0631 \u0633\u06cc\u0633\u062a\u0645 \u0645\u0645\u06a9\u0646 \u0646\u06cc\u0633\u062a", + "error.user.delete.lastUser": "حذف آخرین کاربر ممکن نیست", + "error.user.delete.permission": "شما اجازه حذف کاربر «{name}» را ندارید", + "error.user.duplicate": "کاربری با ایمیل «{email}» هم اکنون موجود است", + "error.user.email.invalid": "لطفا یک ایمیل معتبر وارد کنید", + "error.user.language.invalid": "لطفا زبان معتبری انتخاب کنید", + "error.user.notFound": "کاربر «{name}» پیدا نشد", + "error.user.password.excessive": "Please enter a valid password. Passwords must not be longer than 1000 characters.", + "error.user.password.invalid": "لطفا گذرواژه صحیحی با حداقل طول 8 حرف وارد کنید. ", + "error.user.password.notSame": "\u0644\u0637\u0641\u0627 \u062a\u06a9\u0631\u0627\u0631 \u06af\u0630\u0631\u0648\u0627\u0698\u0647 \u0631\u0627 \u0648\u0627\u0631\u062f \u0646\u0645\u0627\u06cc\u06cc\u062f", + "error.user.password.undefined": "کاربر فاقد گذرواژه است", + "error.user.password.wrong": "Wrong password", + "error.user.role.invalid": "لطفا نقش صحیحی وارد نمایید", + "error.user.undefined": "کاربر مورد نظر پیدا نشد", + "error.user.update.permission": "شما اجازه بروزرسانی کاربر «{name}» را ندارید", + + "error.validation.accepted": "لطفا تایید کنید", + "error.validation.alpha": "لطفا تنها از بین حروف a-z انتخاب کنید", + "error.validation.alphanum": "لطفا تنها از بین حروف a-z و اعداد 0-9 انتخاب کنید", + "error.validation.between": "لطفا مقداری مابین «{min}» و «{max}» وارد کنید", + "error.validation.boolean": "لطفا تایید یا رد کنید", + "error.validation.contains": "لطفا مقداری شامل «{needle}» وارد کنید", + "error.validation.date": "لطفا تاریخ معتبری وارد کنید", + "error.validation.date.after": "Please enter a date after {date}", + "error.validation.date.before": "Please enter a date before {date}", + "error.validation.date.between": "Please enter a date between {min} and {max}", + "error.validation.denied": "لطفا رد کنید", + "error.validation.different": "مقدار نباید مساوی «{other}» باشد", + "error.validation.email": "لطفا ایمیل صحیحی وارد کنید", + "error.validation.endswith": "مقدار باید با «{end}» ختم شود", + "error.validation.filename": "لطفا نام فایل صحیحی وارد کنید", + "error.validation.in": "لطفا یکی از مقادیر روبرو را وارد کنید: ({in})", + "error.validation.integer": "لطفا عدد صحیحی وارد کنید", + "error.validation.ip": "لطفا IP آدرس صحیحی وارد کنید", + "error.validation.less": "لطفا مقداری کمتر از {max} وارد کنید", + "error.validation.match": "مقدار وارد شده با الگوی مورد نظر همخوانی ندارد", + "error.validation.max": "لطفا مقداری کوچکتر یا مساوی {min} وارد کنید", + "error.validation.maxlength": "لطفا عبارت کوتاه‌تری وارد کنید. (حداکثر {max} حرف)", + "error.validation.maxwords": "لطفا بیش از {max} کلمه وارد نکنید", + "error.validation.min": "لطفا مقداری بزرگتر یا مساوی با {min} وارد کنید", + "error.validation.minlength": "لطفا عبارتی طولانی‌تری وارد کنید. (حداقل {min} حرف)", + "error.validation.minwords": "لطفا حداقل {min} کلمه وارد کنید", + "error.validation.more": "لطفا مقداری بیش از {min} وارد کنید", + "error.validation.notcontains": "لطفا مقداری فاقد «{needle}» وارد کنید", + "error.validation.notin": "لطفا از مقادیر روبرو استفاده نکنید: ({notin})", + "error.validation.option": "لطفا گزینه معتبری انتخاب کنید", + "error.validation.num": "لطفا عدد صحیحی وارد کنید", + "error.validation.required": "لطفا مقداری وارد کنید", + "error.validation.same": "لطفا مقدار «{other}» را وارد کنید", + "error.validation.size": "اندازه ورودی باید معادل «{size}» باشد", + "error.validation.startswith": "مقدار باید با «{start}» شروع شود", + "error.validation.time": "لطفا زمان معتبری وارد کنید", + "error.validation.time.after": "Please enter a time after {time}", + "error.validation.time.before": "Please enter a time before {time}", + "error.validation.time.between": "Please enter a time between {min} and {max}", + "error.validation.url": "لطفا آدرس URL صحیح وارد کنید", + + "expand": "Expand", + "expand.all": "Expand All", + + "field.required": "The field is required", + "field.blocks.changeType": "Change type", + "field.blocks.code.name": "کد", + "field.blocks.code.language": "زبان", + "field.blocks.code.placeholder": "Your code …", + "field.blocks.delete.confirm": "Do you really want to delete this block?", + "field.blocks.delete.confirm.all": "Do you really want to delete all blocks?", + "field.blocks.delete.confirm.selected": "Do you really want to delete the selected blocks?", + "field.blocks.empty": "No blocks yet", + "field.blocks.fieldsets.label": "Please select a block type …", + "field.blocks.fieldsets.paste": "Press {{ shortcut }} to paste/import blocks from your clipboard", + "field.blocks.gallery.name": "Gallery", + "field.blocks.gallery.images.empty": "No images yet", + "field.blocks.gallery.images.label": "Images", + "field.blocks.heading.level": "Level", + "field.blocks.heading.name": "Heading", + "field.blocks.heading.text": "Text", + "field.blocks.heading.placeholder": "Heading …", + "field.blocks.image.alt": "Alternative text", + "field.blocks.image.caption": "Caption", + "field.blocks.image.crop": "Crop", + "field.blocks.image.link": "پیوند", + "field.blocks.image.location": "Location", + "field.blocks.image.name": "تصویر", + "field.blocks.image.placeholder": "Select an image", + "field.blocks.image.ratio": "Ratio", + "field.blocks.image.url": "Image URL", + "field.blocks.line.name": "Line", + "field.blocks.list.name": "List", + "field.blocks.markdown.name": "Markdown", + "field.blocks.markdown.label": "Text", + "field.blocks.markdown.placeholder": "Markdown …", + "field.blocks.quote.name": "Quote", + "field.blocks.quote.text.label": "Text", + "field.blocks.quote.text.placeholder": "Quote …", + "field.blocks.quote.citation.label": "Citation", + "field.blocks.quote.citation.placeholder": "by …", + "field.blocks.text.name": "Text", + "field.blocks.text.placeholder": "Text …", + "field.blocks.video.caption": "Caption", + "field.blocks.video.name": "Video", + "field.blocks.video.placeholder": "Enter a video URL", + "field.blocks.video.url.label": "Video-URL", + "field.blocks.video.url.placeholder": "https://youtube.com/?v=", + + "field.files.empty": "فایلی انتخاب نشده است", + + "field.layout.delete": "Delete layout", + "field.layout.delete.confirm": "Do you really want to delete this layout?", + "field.layout.empty": "No rows yet", + "field.layout.select": "Select a layout", + + "field.pages.empty": "صفحه‌ای انتخاب نشده است", + "field.structure.delete.confirm": "\u0645\u062f\u062e\u0644 \u062c\u0627\u0631\u06cc \u062d\u0630\u0641 \u0634\u0648\u062f\u061f", + "field.structure.empty": "\u0645\u0648\u0631\u062f\u06cc \u0648\u062c\u0648\u062f \u0646\u062f\u0627\u0631\u062f.", + "field.users.empty": "کاربری انتخاب نشده است", + + "file.blueprint": "This file has no blueprint yet. You can define the setup in /site/blueprints/files/{blueprint}.yml", + "file.delete.confirm": "آیا واقعا می خواهید این فایل را حذف کنید؟
{filename}", + "file.sort": "Change position", + + "files": "فایل‌ها", + "files.empty": "فایلی موجود نیست", + + "hide": "Hide", + "hour": "ساعت", + "import": "Import", + "info": "Info", + "insert": "\u062f\u0631\u062c", + "insert.after": "Insert after", + "insert.before": "Insert before", + "install": "نصب", + + "installation": "نصب و راه اندازی", + "installation.completed": "پنل کاربری نصب شد", + "installation.disabled": "نصب کننده پانل کاربری بصورت پیش‌فرض در سرورهای عمومی غیرفعال است. لطفا نصب را روی یک ماشین محلی اجرا کنید یا آن را با استفاده از panel.install فعال کنید.", + "installation.issues.accounts": "پوشه /site/accounts موجود نیست یا قابل نوشتن نیست.", + "installation.issues.content": "پوشه /content موجود نیست یا قابل نوشتن نیست", + "installation.issues.curl": "افزونه CURL مورد نیاز است", + "installation.issues.headline": "نصب پانل کاربری ممکن نیست", + "installation.issues.mbstring": "افزونه MB String مورد نیاز است", + "installation.issues.media": "پوشه /media موجود نیست یا قابل نوشتن نیست", + "installation.issues.php": "لطفا از پی‌اچ‌پی 7 یا بالاتر استفاده کنید", + "installation.issues.server": "کربی نیاز به Apache، Nginx یا Caddy دارد", + "installation.issues.sessions": "پوشه /site/sessions وجود ندارد یا قابل نوشتن نیست", + + "language": "\u0632\u0628\u0627\u0646", + "language.code": "کد", + "language.convert": "پیش‌فرض شود", + "language.convert.confirm": "

آیا واقعا میخواهید {name} را به زبان پیشفرض تبدیل کنید؟ این عمل برگشت ناپذیر است.

اگر {name} دارای محتوای غیر ترجمه شده باشد، جایگزین معتبر دیگری نخواهد بود و ممکن است بخش‌هایی از سایت شما خالی باشد.

", + "language.create": "افزودن زبان جدید", + "language.delete.confirm": "آیا واقعا میخواهید زبان {name} را به همراه تمام ترجمه‌ها حذف کنید؟ این عمل قابل بازگشت نخواهد بود!", + "language.deleted": "زبان مورد نظر حذف شد", + "language.direction": "rtl", + "language.direction.ltr": "چپ به راست", + "language.direction.rtl": "راست به چپ", + "language.locale": "PHP locale string", + "language.locale.warning": "You are using a custom locale set up. Please modify it in the language file in /site/languages", + "language.name": "پارسی", + "language.updated": "زبان به روز شد", + + "languages": "زبان‌ها", + "languages.default": "زبان پیش‌فرض", + "languages.empty": "هنوز هیچ زبانی موجود نیست", + "languages.secondary": "زبان‌های ثانویه", + "languages.secondary.empty": "هنوز هیچ زبان ثانویه‌ای موجود نیست", + + "license": "\u0645\u062c\u0648\u0632", + "license.buy": "خرید مجوز", + "license.register": "ثبت", + "license.manage": "Manage your licenses", + "license.register.help": "پس از خرید از طریق ایمیل، کد مجوز خود را دریافت کردید. لطفا برای ثبت‌نام آن را کپی و اینجا پیست کنید.", + "license.register.label": "لطفا کد مجوز خود را وارد کنید", + "license.register.success": "با تشکر از شما برای حمایت از کربی", + "license.unregistered": "این یک نسخه آزمایشی ثبت نشده از کربی است", + "license.unregistered.label": "Unregistered", + + "link": "\u067e\u06cc\u0648\u0646\u062f", + "link.text": "\u0645\u062a\u0646 \u067e\u06cc\u0648\u0646\u062f", + + "loading": "بارگزاری", + + "lock.unsaved": "Unsaved changes", + "lock.unsaved.empty": "There are no more unsaved changes", + "lock.isLocked": "Unsaved changes by {email}", + "lock.file.isLocked": "The file is currently being edited by {email} and cannot be changed.", + "lock.page.isLocked": "The page is currently being edited by {email} and cannot be changed.", + "lock.unlock": "Unlock", + "lock.isUnlocked": "Your unsaved changes have been overwritten by another user. You can download your changes to merge them manually.", + + "login": "ورود", + "login.code.label.login": "Login code", + "login.code.label.password-reset": "Password reset code", + "login.code.placeholder.email": "000 000", + "login.code.text.email": "If your email address is registered, the requested code was sent via email.", + "login.email.login.body": "Hi {user.nameOrEmail},\n\nYou recently requested a login code for the Panel of {site}.\nThe following login code will be valid for {timeout} minutes:\n\n{code}\n\nIf you did not request a login code, please ignore this email or contact your administrator if you have questions.\nFor security, please DO NOT forward this email.", + "login.email.login.subject": "Your login code", + "login.email.password-reset.body": "Hi {user.nameOrEmail},\n\nYou recently requested a password reset code for the Panel of {site}.\nThe following password reset code will be valid for {timeout} minutes:\n\n{code}\n\nIf you did not request a password reset code, please ignore this email or contact your administrator if you have questions.\nFor security, please DO NOT forward this email.", + "login.email.password-reset.subject": "Your password reset code", + "login.remember": "مرا به خاطر بسپار", + "login.reset": "Reset password", + "login.toggleText.code.email": "Login via email", + "login.toggleText.code.email-password": "Login with password", + "login.toggleText.password-reset.email": "Forgot your password?", + "login.toggleText.password-reset.email-password": "← Back to login", + + "logout": "خروج", + + "menu": "منو", + "meridiem": "ق.ظ/ب.ظ", + "mime": "نوع رسانه", + "minutes": "دقیقه", + + "month": "ماه", + "months.april": "\u0622\u0648\u0631\u06cc\u0644", + "months.august": "\u0627\u0648\u062a", + "months.december": "\u062f\u0633\u0627\u0645\u0628\u0631", + "months.february": "فوریه", + "months.january": "\u0698\u0627\u0646\u0648\u06cc\u0647", + "months.july": "\u0698\u0648\u0626\u06cc\u0647", + "months.june": "\u0698\u0648\u0626\u0646", + "months.march": "\u0645\u0627\u0631\u0633", + "months.may": "\u0645\u06cc", + "months.november": "\u0646\u0648\u0627\u0645\u0628\u0631", + "months.october": "\u0627\u06a9\u062a\u0628\u0631", + "months.september": "\u0633\u067e\u062a\u0627\u0645\u0628\u0631", + + "more": "بیشتر", + "name": "نام", + "next": "بعدی", + "no": "no", + "off": "off", + "on": "on", + "open": "بازکردن", + "open.newWindow": "Open in new window", + "options": "گزینه‌ها", + "options.none": "No options", + + "orientation": "جهت", + "orientation.landscape": "افقی", + "orientation.portrait": "عمودی", + "orientation.square": "مربع", + + "page.blueprint": "This page has no blueprint yet. You can define the setup in /site/blueprints/pages/{blueprint}.yml", + "page.changeSlug": "تغییر Url صفحه", + "page.changeSlug.fromTitle": "\u0627\u06cc\u062c\u0627\u062f \u0627\u0632 \u0631\u0648\u06cc \u0639\u0646\u0648\u0627\u0646", + "page.changeStatus": "تغییر وضعیت", + "page.changeStatus.position": "لطفا یک موقعیت را انتخاب کنید", + "page.changeStatus.select": "یک وضعیت جدید را انتخاب کنید", + "page.changeTemplate": "تغییر قالب", + "page.delete.confirm": "صفحه {title} حذف شود؟", + "page.delete.confirm.subpages": "این صفحه دارای زیرصفحه است.
تمام زیر صفحات نیز حذف خواهد شد.", + "page.delete.confirm.title": "جهت ادامه عنوان صفحه را وارد کنید", + "page.draft.create": "ایجاد پیش‌نویس", + "page.duplicate.appendix": "کپی", + "page.duplicate.files": "Copy files", + "page.duplicate.pages": "Copy pages", + "page.sort": "Change position", + "page.status": "وضعیت", + "page.status.draft": "پیش‌نویس", + "page.status.draft.description": "The page is in draft mode and only visible for logged in editors or via secret link", + "page.status.listed": "عمومی", + "page.status.listed.description": "این صفحه برای عموم قابل مشاهده است", + "page.status.unlisted": "فهرست نشده", + "page.status.unlisted.description": "این صفحه فقط از طریق URL قابل دسترسی است", + + "pages": "صفحات", + "pages.empty": "هنوز هیچ صفحه‌ای موجود نیست", + "pages.status.draft": "پیش‌نویس‌ها", + "pages.status.listed": "منتشر شده", + "pages.status.unlisted": "فهرست نشده", + + "pagination.page": "صفحه", + + "password": "\u06af\u0630\u0631\u0648\u0627\u0698\u0647", + "paste": "Paste", + "paste.after": "Paste after", + "pixel": "پیکسل", + "plugins": "Plugins", + "prev": "قبلی", + "preview": "Preview", + "remove": "حذف", + "rename": "تغییر نام", + "replace": "\u062c\u0627\u06cc\u06af\u0632\u06cc\u0646\u06cc", + "retry": "\u062a\u0644\u0627\u0634 \u0645\u062c\u062f\u062f", + "revert": "بازگرداندن تغییرات", + "revert.confirm": "Do you really want to delete all unsaved changes?", + + "role": "\u0646\u0642\u0634", + "role.admin.description": "The admin has all rights", + "role.admin.title": "Admin", + "role.all": "همه", + "role.empty": "هیچ کاربری با این نقش وجود ندارد", + "role.description.placeholder": "فاقد شرح", + "role.nobody.description": "This is a fallback role without any permissions", + "role.nobody.title": "Nobody", + + "save": "\u0630\u062e\u06cc\u0631\u0647", + "search": "جستجو", + "search.min": "Enter {min} characters to search", + "search.all": "Show all", + "search.results.none": "No results", + + "section.required": "The section is required", + + "security": "Security", + "select": "انتخاب", + "server": "Server", + "settings": "تنظیمات", + "show": "Show", + "site.blueprint": "The site has no blueprint yet. You can define the setup in /site/blueprints/site.yml", + "size": "اندازه", + "slug": "پسوند Url", + "sort": "ترتیب", + + "stats.empty": "No reports", + "system.issues.content": "The content folder seems to be exposed", + "system.issues.debug": "Debugging must be turned off in production", + "system.issues.git": "The .git folder seems to be exposed", + "system.issues.https": "We recommend HTTPS for all your sites", + "system.issues.kirby": "The kirby folder seems to be exposed", + "system.issues.site": "The site folder seems to be exposed", + + "title": "عنوان", + "template": "\u0642\u0627\u0644\u0628 \u0635\u0641\u062d\u0647", + "today": "امروز", + + "toolbar.button.code": "کد", + "toolbar.button.bold": "\u0645\u062a\u0646 \u0628\u0627 \u062d\u0631\u0648\u0641 \u062f\u0631\u0634\u062a", + "toolbar.button.email": "\u067e\u0633\u062a \u0627\u0644\u06a9\u062a\u0631\u0648\u0646\u06cc\u06a9", + "toolbar.button.headings": "عنوان‌ها", + "toolbar.button.heading.1": "عنوان 1", + "toolbar.button.heading.2": "عنوان 2", + "toolbar.button.heading.3": "عنوان 3", + "toolbar.button.heading.4": "Heading 4", + "toolbar.button.heading.5": "Heading 5", + "toolbar.button.heading.6": "Heading 6", + "toolbar.button.italic": "\u0645\u062a\u0646 \u0627\u0631\u06cc\u0628", + "toolbar.button.file": "فایل", + "toolbar.button.file.select": "Select a file", + "toolbar.button.file.upload": "Upload a file", + "toolbar.button.link": "\u067e\u06cc\u0648\u0646\u062f", + "toolbar.button.paragraph": "Paragraph", + "toolbar.button.strike": "Strike-through", + "toolbar.button.ol": "لیست مرتب", + "toolbar.button.underline": "Underline", + "toolbar.button.ul": "لیست معمولی", + + "translation.author": "تیم کربی", + "translation.direction": "rtl", + "translation.name": "انگلیسی", + "translation.locale": "fa_IR", + + "upload": "بارگذاری", + "upload.error.cantMove": "The uploaded file could not be moved", + "upload.error.cantWrite": "Failed to write file to disk", + "upload.error.default": "The file could not be uploaded", + "upload.error.extension": "File upload stopped by extension", + "upload.error.formSize": "The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the form", + "upload.error.iniPostSize": "The uploaded file exceeds the post_max_size directive in php.ini", + "upload.error.iniSize": "The uploaded file exceeds the upload_max_filesize directive in php.ini", + "upload.error.noFile": "No file was uploaded", + "upload.error.noFiles": "No files were uploaded", + "upload.error.partial": "The uploaded file was only partially uploaded", + "upload.error.tmpDir": "Missing a temporary folder", + "upload.errors": "خطا", + "upload.progress": "در حال بارگذاری...", + + "url": "Url", + "url.placeholder": "https://example.com", + + "user": "کاربر", + "user.blueprint": "You can define additional sections and form fields for this user role in /site/blueprints/users/{blueprint}.yml", + "user.changeEmail": "تغییر ایمیل", + "user.changeLanguage": "تغییر زبان", + "user.changeName": "تغییر نام این کاربر", + "user.changePassword": "تغییر گذرواژه", + "user.changePassword.new": "گذرواژه جدید", + "user.changePassword.new.confirm": "تایید گذرواژه جدید...", + "user.changeRole": "تغییر نقش", + "user.changeRole.select": "یک نقش جدید را انتخاب کنید", + "user.create": "افزودن کاربر جدید", + "user.delete": "حذف کاربر جاری", + "user.delete.confirm": "آیا واقعا میخواهید {email} را حذف کنید؟", + + "users": "کاربران", + + "version": "\u0646\u0633\u062e\u0647 \u0646\u0631\u0645 \u0627\u0641\u0632\u0627\u0631", + + "view.account": "حساب کاربری شما", + "view.installation": "\u0646\u0635\u0628 \u0648 \u0631\u0627\u0647 \u0627\u0646\u062f\u0627\u0632\u06cc", + "view.languages": "زبان‌ها", + "view.resetPassword": "Reset password", + "view.site": "سایت", + "view.system": "System", + "view.users": "\u06a9\u0627\u0631\u0628\u0631\u0627\u0646", + + "welcome": "خوش آمدید", + "year": "سال", + "yes": "yes" } diff --git a/kirby/i18n/translations/fi.json b/kirby/i18n/translations/fi.json index 13c1c39..2bb1e1e 100644 --- a/kirby/i18n/translations/fi.json +++ b/kirby/i18n/translations/fi.json @@ -1,730 +1,574 @@ { - "account.changeName": "Muuta nimesi", - "account.delete": "Poista tilisi", - "account.delete.confirm": "Haluatko varmasti poistaa tilisi? Sinut kirjataan ulos välittömästi, eikä tiliäsi voi palauttaa.", - - "activate": "Activate", - "add": "Lis\u00e4\u00e4", - "alpha": "Alpha", - "author": "Tekijä", - "avatar": "Profiilikuva", - "back": "Takaisin", - "cancel": "Peruuta", - "change": "Muuta", - "close": "Sulje", - "changes": "Changes", - "confirm": "Ok", - "collapse": "Pienennä", - "collapse.all": "Pienennä kaikki", - "color": "Color", - "coordinates": "Coordinates", - "copy": "Kopioi", - "copy.all": "Kopioi kaikki", - "copy.success": "{count} copied!", - "create": "Luo", - "custom": "Custom", - - "date": "Päivämäärä", - "date.select": "Valitse päivämäärä", - - "day": "Päivä", - "days.fri": "Pe", - "days.mon": "Ma", - "days.sat": "La", - "days.sun": "Su", - "days.thu": "To", - "days.tue": "Ti", - "days.wed": "Ke", - - "debugging": "Virheenkäsittelytila", - - "delete": "Poista", - "delete.all": "Poista kaikki", - - "dialog.fields.empty": "This dialog has no fields", - "dialog.files.empty": "Ei valittavissa olevia tiedostoja", - "dialog.pages.empty": "Ei valittavissa olevia sivuja", - "dialog.text.empty": "This dialog does not define any text", - "dialog.users.empty": "Ei valittavissa olevia käyttäjiä", - - "dimensions": "Mitat", - "disable": "Disable", - "disabled": "Pois käytöstä", - "discard": "Hylkää", - - "drawer.fields.empty": "This drawer has no fields", - - "domain": "Domain", - "download": "Lataa", - "duplicate": "Kahdenna", - - "edit": "Muokkaa", - - "email": "S\u00e4hk\u00f6posti", - "email.placeholder": "nimi@osoite.fi", - - "enter": "Enter", - "entries": "Entries", - "entry": "Entry", - - "environment": "Ympäristö", - - "error": "Error", - "error.access.code": "Väärä koodi", - "error.access.login": "Kirjautumistiedot eivät kelpaa", - "error.access.panel": "Sinulla ei ole oikeutta käyttää paneelia", - "error.access.view": "Sinulla ei ole oikeutta käyttää tätä osaa paneelista", - - "error.avatar.create.fail": "Profiilikuvaa ei voitu lähettää", - "error.avatar.delete.fail": "Profiilikuvaa ei voitu poistaa", - "error.avatar.dimensions.invalid": "Profiilikuvan leveys ja korkeus voivat olla enintään 3000 pikseliä", - "error.avatar.mime.forbidden": "Profiilikuvan täytyy olla joko JPEG- tai PNG-formaatissa", - - "error.blueprint.notFound": "Suunnitelmaa \"{name}\" ei voitu ladata", - - "error.blocks.max.plural": "Voit lisätä enintään {max} lohkoa", - "error.blocks.max.singular": "Voit lisätä enintään yhden lohkon", - "error.blocks.min.plural": "Lisää vähintään {min} lohkoa", - "error.blocks.min.singular": "Lisää vähintään yksi lohko", - "error.blocks.validation": "There's an error on the \"{field}\" field in block {index} using the \"{fieldset}\" block type", - - "error.cache.type.invalid": "Invalid cache type \"{type}\"", - - "error.email.preset.notFound": "Nimellä \"{name}\" ja kyseisellä verkkotunnuksella ei löydy sähköpostiosoitetta", - - "error.field.converter.invalid": "Muunnin \"{converter}\" ei kelpaa", - "error.field.type.missing": "Field \"{ name }\": The field type \"{ type }\" does not exist", - - "error.file.changeName.empty": "Nimi ei voi olla tyhjä", - "error.file.changeName.permission": "Sinulla ei ole oikeutta muuttaa tiedoston \"{filename}\" nimeä", - "error.file.changeTemplate.invalid": "The template for the file \"{id}\" cannot be changed to \"{template}\" (valid: \"{blueprints}\")", - "error.file.changeTemplate.permission": "You are not allowed to change the template for the file \"{id}\"", - - "error.file.duplicate": "Tiedosto nimeltä \"{filename}\" on jo olemassa", - "error.file.extension.forbidden": "Tiedostopääte \"{extension}\" ei ole sallittu", - "error.file.extension.invalid": "Pääte {extension} ei kelpaa", - "error.file.extension.missing": "Tiedoston \"{filename}\" tiedostopääte puuttuu", - "error.file.maxheight": "Kuvan korkeus ei voi ylittää {height} pikseliä", - "error.file.maxsize": "Tiedosto on liian suuri", - "error.file.maxwidth": "Kuvan leveys ei voi ylittää {width} pikseliä", - "error.file.mime.differs": "Lähetetyllä tiedostolla täytyy olla sama mime-tyyppi \"{mime}\"", - "error.file.mime.forbidden": "Median tyyppi \"{mime}\" ei ole sallittu", - "error.file.mime.invalid": "Mime-tyyppi {mime} ei kelpaa", - "error.file.mime.missing": "Tiedoston \"{filename}\" mediatyyppiä ei voida tunnistaa", - "error.file.minheight": "Kuvan korkeus täytyy olla vähintään {height} pikseliä", - "error.file.minsize": "Tiedosto on liian pieni", - "error.file.minwidth": "Kuvan leveys täytyy olla vähintään {width} pikseliä", - "error.file.name.unique": "The filename must be unique", - "error.file.name.missing": "Tiedostonimi ei voi olla tyhjä", - "error.file.notFound": "Tiedostoa \"{filename}\" ei löytynyt", - "error.file.orientation": "Kuvan suuntaus täytyy olla \"{orientation}\"", - "error.file.type.forbidden": "Sinulla ei ole oikeutta lähettää tiedostoja joiden tyyppi on {type}", - "error.file.type.invalid": "Tiedostotyyppi {type} ei kelpaa", - "error.file.undefined": "Tiedostoa ei l\u00f6ytynyt", - - "error.form.incomplete": "Korjaa kaikki lomakkeen virheet…", - "error.form.notSaved": "Lomaketta ei voitu tallentaa", - - "error.language.code": "Anna kielen lyhenne", - "error.language.duplicate": "Kieli on jo olemassa", - "error.language.name": "Anna kielen nimi", - "error.language.notFound": "Kieltä ei löytynyt", - - "error.layout.validation.block": "There's an error on the \"{field}\" field in block {blockIndex} using the \"{fieldset}\" block type in layout {layoutIndex}", - "error.layout.validation.settings": "Virhe asetelman {index} asetuksissa", - - "error.license.domain": "The domain for the license is missing", - "error.license.email": "Anna sähköpostiosoite", - "error.license.format": "Please enter a valid license code", - "error.license.verification": "Lisenssiä ei voitu vahvistaa", - - "error.login.totp.confirm.invalid": "Väärä koodi", - "error.login.totp.confirm.missing": "Please enter the current code", - - "error.object.validation": "There’s an error in the \"{label}\" field:\n{message}", - - "error.offline": "Paneeli on offline-tilassa", - - "error.page.changeSlug.permission": "Sinulla ei ole oikeutta muuttaa URL-liitettä sivulle \"{slug}\"", - "error.page.changeSlug.reserved": "The path of top-level pages must not start with \"{path}\"", - "error.page.changeStatus.incomplete": "Sivulla on virheitä eikä sitä voitu julkaista", - "error.page.changeStatus.permission": "Tämän sivun tilaa ei voi muuttaa", - "error.page.changeStatus.toDraft.invalid": "Sivua \"{slug}\" ei voi muuttaa luonnokseksi", - "error.page.changeTemplate.invalid": "Sivun \"{slug}\" pohjaa ei voi muuttaa", - "error.page.changeTemplate.permission": "Sinulla ei ole oikeutta muuttaa sivun \"{slug}\" sivupohjaa", - "error.page.changeTitle.empty": "Nimi ei voi olla tyhjä", - "error.page.changeTitle.permission": "Sinulla ei ole oikeutta muuttaa sivun \"{slug}\" nimeä", - "error.page.create.permission": "Sinulla ei ole oikeutta luoda sivua \"{slug}\"", - "error.page.delete": "Sivua \"{slug}\" ei voi poistaa", - "error.page.delete.confirm": "Anna vahvistuksena sivun nimi", - "error.page.delete.hasChildren": "Sivu sisältää alasivuja eikä sitä voida poistaa", - "error.page.delete.permission": "Sinulla ei ole oikeutta poistaa sivua \"{slug}\"", - "error.page.draft.duplicate": "Sivuluonnos URL-liitteellä \"{slug}\" on jo olemassa", - "error.page.duplicate": "Sivu URL-liitteellä \"{slug}\" on jo olemassa", - "error.page.duplicate.permission": "Sinulla ei ole oikeutta kahdentaa sivua \"{slug}\"", - "error.page.move.ancestor": "The page cannot be moved into itself", - "error.page.move.directory": "The page directory cannot be moved", - "error.page.move.duplicate": "A sub page with the URL appendix \"{slug}\" already exists", - "error.page.move.notFound": "The moved page could not be found", - "error.page.move.permission": "You are not allowed to move \"{slug}\"", - "error.page.move.template": "The \"{template}\" template is not accepted as a subpage of \"{parent}\"", - "error.page.notFound": "Sivua \"{slug}\" ei löytynyt", - "error.page.num.invalid": "Anna kelpaava järjestysnumero. Numero ei voi olla negatiivinen.", - "error.page.slug.invalid": "Anna kelpaava URL-liite", - "error.page.slug.maxlength": "URL-liite täytyy olla vähemmän kuin \"{length}\" merkkiä pitkä", - "error.page.sort.permission": "Sivua \"{slug}\" ei voi järjestellä", - "error.page.status.invalid": "Aseta kelvollinen sivun tila", - "error.page.undefined": "Sivua ei l\u00f6ytynyt", - "error.page.update.permission": "Sinulla ei ole oikeutta päivittää sivua \"{slug}\"", - - "error.section.files.max.plural": "Et voi lisätä enemmän kuin {max} tiedostoa osioon \"{section}\"", - "error.section.files.max.singular": "Et voi lisätä enempää kuin yhden tiedoston osioon \"{section}\"", - "error.section.files.min.plural": "Osio \"{section}\" vaatii ainakin {min} tiedostoa", - "error.section.files.min.singular": "Osio \"{section}\" vaatii ainakin yhden sivun", - - "error.section.pages.max.plural": "Et voi lisätä enemmän kuin {max} sivua osioon \"{section}\"", - "error.section.pages.max.singular": "Et voi lisätä enempää kuin yhden sivun osioon \"{section}\"", - "error.section.pages.min.plural": "Osio \"{section}\" vaatii ainakin {min} sivua", - "error.section.pages.min.singular": "Osio \"{section}\" vaatii ainakin yhden sivun", - - "error.section.notLoaded": "Osiota \"{name}\" ei voitu ladata", - "error.section.type.invalid": "Osion tyyppi \"{type}\" ei ole kelvollinen", - - "error.site.changeTitle.empty": "Nimi ei voi olla tyhjä", - "error.site.changeTitle.permission": "Sinulla ei ole oikeutta päivittää sivuston nimeä", - "error.site.update.permission": "Sinulla ei ole oikeutta päivittää sivuston tietoja", - - "error.structure.validation": "There's an error on the \"{field}\" field in row {index}", - - "error.template.default.notFound": "Oletussivupohjaa ei ole määritetty", - - "error.unexpected": "Pahus, määrittelemätön virhe! Laita virheenkäsittelytila päälle saadaksesi lisätietoja: https://getkirby.com/docs/reference/system/options/debug", - - "error.user.changeEmail.permission": "Sinulla ei ole oikeutta vaihtaa käyttäjän \"{name}\" sähköpostiosoitetta", - "error.user.changeLanguage.permission": "Sinulla ei ole oikeutta vaihtaa käyttäjän \"{name}\" kieltä", - "error.user.changeName.permission": "Sinulla ei ole oikeutta vaihtaa käyttäjän \"{name}\" nimeä", - "error.user.changePassword.permission": "Sinulla ei ole oikeutta vaihtaa käyttäjän \"{name}\" salasanaa", - "error.user.changeRole.lastAdmin": "Ainoan pääkäyttäjän roolia ei voi muuttaa", - "error.user.changeRole.permission": "Sinulla ei ole oikeutta vaihtaa käyttäjän \"{name}\" käyttäjätasoa", - "error.user.changeRole.toAdmin": "Sinulla ei ole oikeutta vaihtaa käyttäjätasoa pääkäyttäjäksi", - "error.user.create.permission": "Sinulla ei ole oikeutta luoda tätä käyttäjää", - "error.user.delete": "Käyttäjää \"{name}\" ei voi poistaa", - "error.user.delete.lastAdmin": "Ainoaa pääkäyttäjää ei voi poistaa", - "error.user.delete.lastUser": "Ainoaa käyttäjää ei voi poistaa", - "error.user.delete.permission": "Sinulla ei ole oikeutta poistaa käyttäjää \"{name}\"", - "error.user.duplicate": "Käyttäjä, jonka sähköpostiosoite on \"{name}\", on jo olemassa", - "error.user.email.invalid": "Anna kelpaava sähköpostiosoite", - "error.user.language.invalid": "Anna kelpaava kieli", - "error.user.notFound": "K\u00e4ytt\u00e4j\u00e4\u00e4 ei l\u00f6ytynyt", - "error.user.password.excessive": "Please enter a valid password. Passwords must not be longer than 1000 characters.", - "error.user.password.invalid": "Anna kelpaava salasana. Salasanan täytyy olla ainakin 8 merkkiä pitkä.", - "error.user.password.notSame": "Salasanat eivät täsmää", - "error.user.password.undefined": "Käyttäjällä ei ole salasanaa", - "error.user.password.wrong": "Väärä salasana", - "error.user.role.invalid": "Anna kelpaava käyttäjätaso", - "error.user.undefined": "Käyttäjää ei löytynyt", - "error.user.update.permission": "Sinulla ei ole oikeutta päivittää käyttäjää \"{name}\"", - - "error.validation.accepted": "Ole hyvä ja vahvista", - "error.validation.alpha": "Anna vain merkkejä väliltä a-z", - "error.validation.alphanum": "Anna vain merkkejä väliltä a-z tai/ja numeroita väliltä 0-9", - "error.validation.anchor": "Please enter a correct link anchor", - "error.validation.between": "Anna arvo väliltä \"{min}\" ja \"{max}\"", - "error.validation.boolean": "Vahvista tai peruuta", - "error.validation.color": "Please enter a valid color in the {format} format", - "error.validation.contains": "Anna arvo joka sisältää \"{needle}\"", - "error.validation.date": "Anna kelpaava päivämäärä", - "error.validation.date.after": "Anna päivämäärä {date} jälkeen", - "error.validation.date.before": "Anna päivämäärä ennen {date}", - "error.validation.date.between": "Anna päivämäärä väliltä {min} ja {max}", - "error.validation.denied": "Ole hyvä ja peruuta", - "error.validation.different": "Arvo ei voi olla \"{other}\"", - "error.validation.email": "Anna kelpaava sähköpostiosoite", - "error.validation.endswith": "Arvon loppuosa täytyy olla \"{end}\"", - "error.validation.filename": "Anna kelpaava tiedostonimi", - "error.validation.in": "Anna joku seuraavista: ({in})", - "error.validation.integer": "Anna kelpaava kokonaisluku", - "error.validation.ip": "Anna kelpaava IP-osoite", - "error.validation.less": "Anna arvo joka on pienempi kuin {max}", - "error.validation.linkType": "The link type is not allowed", - "error.validation.match": "Arvo ei vastaa vaadittua kaavaa", - "error.validation.max": "Anna arvo joka on enintään {max}", - "error.validation.maxlength": "Anna lyhyempi arvo. (enintään {max} merkkiä)", - "error.validation.maxwords": "Anna korkeintaan {max} sana(a)", - "error.validation.min": "Anna arvo joka on vähintään {min}", - "error.validation.minlength": "Anna pidempi arvo. (vähintään {min} merkkiä)", - "error.validation.minwords": "Anna vähintään {min} sana(a)", - "error.validation.more": "Anna suurempi arvo kuin {min}", - "error.validation.notcontains": "Anna arvo joka ei sisällä \"{needle}\"", - "error.validation.notin": "Arvo ei voi sisältää mitään seuraavista: ({notIn})", - "error.validation.option": "Valitse kelpaava vaihtoehto", - "error.validation.num": "Anna kelpaava numero", - "error.validation.required": "Arvo ei voi olla tyhjä", - "error.validation.same": "Anna \"{other}\"", - "error.validation.size": "Arvon koko täytyy olla \"{size}\"", - "error.validation.startswith": "Arvon alkuosa täytyy olla \"{start}\"", - "error.validation.tel": "Please enter an unformatted phone number", - "error.validation.time": "Anna kelpaava aika", - "error.validation.time.after": "Anna myöhempi aika kuin {time}", - "error.validation.time.before": "Anna aiempi aika kuin {time}", - "error.validation.time.between": "Anna aika väliltä {min} ja {max}", - "error.validation.uuid": "Please enter a valid UUID", - "error.validation.url": "Anna kelpaava URL", - - "expand": "Laajenna", - "expand.all": "Laajenna kaikki", - - "field.invalid": "The field is invalid", - "field.required": "Kenttä on pakollinen", - "field.blocks.changeType": "Vaihda tyyppiä", - "field.blocks.code.name": "Koodi", - "field.blocks.code.language": "Kieli", - "field.blocks.code.placeholder": "Koodisi …", - "field.blocks.delete.confirm": "Haluatko varmasti poistaa tämän lohkon?", - "field.blocks.delete.confirm.all": "Haluatko varmasti poistaa kaikki lohkot?", - "field.blocks.delete.confirm.selected": "Haluatko varmasti poistaa valitut lohkot?", - "field.blocks.empty": "Ei lohkoja", - "field.blocks.fieldsets.empty": "No fieldsets yet", - "field.blocks.fieldsets.label": "Valitse lohkon tyyppi …", - "field.blocks.fieldsets.paste": "Press {{ shortcut }} to import layouts/blocks from your clipboard Only those allowed in the current field will get inserted.", - "field.blocks.gallery.name": "Galleria", - "field.blocks.gallery.images.empty": "Ei kuvia", - "field.blocks.gallery.images.label": "Kuvat", - "field.blocks.heading.level": "Taso", - "field.blocks.heading.name": "Otsikko", - "field.blocks.heading.text": "Teksti", - "field.blocks.heading.placeholder": "Otsikko …", - "field.blocks.image.alt": "Vaihtoehtoinen teksti", - "field.blocks.image.caption": "Kuvateksti", - "field.blocks.image.crop": "Rajaa", - "field.blocks.image.link": "Linkki", - "field.blocks.image.location": "Sijainti", - "field.blocks.image.location.internal": "This website", - "field.blocks.image.location.external": "External source", - "field.blocks.image.name": "Kuva", - "field.blocks.image.placeholder": "Valitse kuva", - "field.blocks.image.ratio": "Kuvasuhde", - "field.blocks.image.url": "Kuvan URL", - "field.blocks.line.name": "Rivi", - "field.blocks.list.name": "Lista", - "field.blocks.markdown.name": "Markdown", - "field.blocks.markdown.label": "Teksti", - "field.blocks.markdown.placeholder": "Markdown …", - "field.blocks.quote.name": "Lainaus", - "field.blocks.quote.text.label": "Teksti", - "field.blocks.quote.text.placeholder": "Lainaus …", - "field.blocks.quote.citation.label": "Sitaatti", - "field.blocks.quote.citation.placeholder": "Lähde …", - "field.blocks.text.name": "Teksti", - "field.blocks.text.placeholder": "Teksti …", - "field.blocks.video.autoplay": "Autoplay", - "field.blocks.video.caption": "Videon teksti", - "field.blocks.video.controls": "Controls", - "field.blocks.video.location": "Sijainti", - "field.blocks.video.loop": "Loop", - "field.blocks.video.muted": "Muted", - "field.blocks.video.name": "Video", - "field.blocks.video.placeholder": "Anna videon URL", - "field.blocks.video.poster": "Poster", - "field.blocks.video.preload": "Preload", - "field.blocks.video.url.label": "Videon URL", - "field.blocks.video.url.placeholder": "https://youtube.com/?v=", - - "field.files.empty": "Tiedostoja ei ole vielä valittu", - - "field.layout.change": "Change layout", - "field.layout.delete": "Poista asettelu", - "field.layout.delete.confirm": "Halutako varmasti poistaa tämän asettelun?", - "field.layout.delete.confirm.all": "Do you really want to delete all layouts?", - "field.layout.empty": "Ei rivejä", - "field.layout.select": "Valitse asettelu", - - "field.object.empty": "Ei vielä tietoja", - - "field.pages.empty": " Sivuja ei ole vielä valittu", - - "field.structure.delete.confirm": "Haluatko varmasti poistaa tämän rivin?", - "field.structure.delete.confirm.all": "Do you really want to delete all entries?", - "field.structure.empty": "Rivejä ei ole vielä lisätty", - - "field.users.empty": "Käyttäjiä ei ole vielä valittu", - - "fields.empty": "No fields yet", - - "file": "File", - "file.blueprint": "Tällä tiedostolla ei ole vielä suunnitelmaa. Voit määrittää suunnitelman tiedostoon /site/blueprints/files/{blueprint}.yml", - "file.changeTemplate": "Vaihda sivupohja", - "file.changeTemplate.notice": "Changing the file's template will remove content for fields that don't match in type. If the new template defines certain rules, e.g. image dimensions, those will also be applied irreversibly. Use with caution.", - "file.delete.confirm": "Haluatko varmasti poistaa tiedoston
{filename}?", - "file.focus.placeholder": "Set focal point", - "file.focus.reset": "Remove focal point", - "file.focus.title": "Focus", - "file.sort": "Muuta järjestyspaikkaa", - - "files": "Tiedostot", - "files.empty": "Tiedostoja ei ole vielä lisätty", - - "filter": "Filter", - - "hide": "Piilota", - "hour": "Tunti", - "hue": "Hue", - "import": "Tuo", - "info": "Tietoja", - "insert": "Lis\u00e4\u00e4", - "insert.after": "Lisää eteen", - "insert.before": "Lisää jälkeen", - "install": "Asenna", - - "installation": "Asennus", - "installation.completed": "Paneeli on asennettu", - "installation.disabled": "Paneelin asennus on oletuksena poissa käytöstä julkisilla palvelimilla. Aja asennus paikallisella koneella, tai ota paneeli käyttöön panel.install-optiolla.", - "installation.issues.accounts": "/site/accounts -kansio ei ole olemassa tai siihen ei voi kirjoittaa", - "installation.issues.content": "/content -kansio ei ole olemassa tai siihen ei voi kirjoittaa", - "installation.issues.curl": "CURL-laajennos on pakollinen", - "installation.issues.headline": "Paneelia ei voida asentaa", - "installation.issues.mbstring": "MB String-laajennos on pakollinen", - "installation.issues.media": "/media -kansio ei ole olemassa tai siihen ei voi kirjoittaa", - "installation.issues.php": "Varmista että PHP 8+ on käytössä", - "installation.issues.sessions": "/site/sessions -kansio ei ole olemassa tai siihen ei voi kirjoittaa", - - "language": "Kieli", - "language.code": "Tunniste", - "language.convert": "Muuta oletukseksi", - "language.convert.confirm": "

Haluatko varmasti muuttaa kielen {name} oletuskieleksi? Tätä muutosta ei voi peruuttaa.

Jos{name} sisältää kääntämättömiä kohtia, varakäännöstä ei enää ole näille kohdille ja sivustosi saattaa olla osittain tyhjä.

", - "language.create": "Lisää uusi kieli", - "language.default": "Oletuskieli", - "language.delete.confirm": "Haluatko varmasti poistaa kielen {name}, mukaanlukien kaikki käännökset? Tätä toimintoa ei voi peruuttaa!", - "language.deleted": "Kieli on poistettu", - "language.direction": "Lukusuunta", - "language.direction.ltr": "Vasemmalta oikealle", - "language.direction.rtl": "Oikealta vasemmalle", - "language.locale": "PHP-aluemäärityksen tunniste", - "language.locale.warning": "Käytät mukautettua aluemääritystä. Muokkaa sitä kielitiedostossa /site/languages", - "language.name": "Nimi", - "language.secondary": "Secondary language", - "language.settings": "Language settings", - "language.updated": "Kieli on päivitetty", - "language.variables": "Language variables", - "language.variables.empty": "No translations yet", - - "language.variable.delete.confirm": "Do you really want to delete the variable for {key}?", - "language.variable.key": "Key", - "language.variable.notFound": "The variable could not be found", - "language.variable.value": "Value", - - "languages": "Kielet", - "languages.default": "Oletuskieli", - "languages.empty": "Kieliä ei ole vielä määritetty", - "languages.secondary": "Toissijaiset kielet", - "languages.secondary.empty": "Toissijaisia kieliä ei ole vielä määritetty", - - "license": "Lisenssi", - "license.activate": "Activate it now", - "license.activate.label": "Please activate your license", - "license.activate.domain": "Your license will be activated for {host}.", - "license.activate.local": "You are about to activate your Kirby license for your local domain {host}. If this site will be deployed to a public domain, please activate it there instead. If {host} is the domain you want to use your license for, please continue.", - "license.activated": "Activated", - "license.buy": "Osta lisenssi", - "license.code": "Tunniste", - "license.code.help": "You received your license code after the purchase via email. Please copy and paste it here.", - "license.code.label": "Anna lisenssiavain", - "license.status.active.info": "Includes new major versions until {date}", - "license.status.active.label": "Valid license", - "license.status.demo.info": "This is a demo installation", - "license.status.demo.label": "Demo", - "license.status.inactive.info": "Renew license to update to new major versions", - "license.status.inactive.label": "No new major versions", - "license.status.legacy.bubble": "Ready to renew your license?", - "license.status.legacy.info": "Your license does not cover this version", - "license.status.legacy.label": "Please renew your license", - "license.status.missing.bubble": "Ready to launch your site?", - "license.status.missing.info": "No valid license", - "license.status.missing.label": "Please activate your license", - "license.manage": "Hallinnoi lisenssejäsi", - "license.purchased": "Purchased", - "license.success": "Kiitos kun tuet Kirbyä", - "license.unregistered.label": "Rekisteröimätön", - - "link": "Linkki", - "link.text": "Linkin teksti", - - "loading": "Ladataan", - - "lock.unsaved": "Tallentamattomia muutoksia", - "lock.unsaved.empty": "Ei enempää tallentamattomia muutoksia ", - "lock.isLocked": "Unsaved changes by {email}", - "lock.unlock": "Vapauta", - "lock.unlock.submit": "Unlock and overwrite unsaved changes by {email}", - "lock.isUnlocked": "Was unlocked by another user", - - "login": "Kirjaudu", - "login.code.label.login": "Kirjautumiskoodi", - "login.code.label.password-reset": "Salasanan asetuskoodi", - "login.code.placeholder.email": "000 000", - "login.code.placeholder.totp": "000000", - "login.code.text.email": "Jos sähköpostiosoitteesi on rekisteröity, tilaamasi koodi lähetetään tähän osoitteeseen.", - "login.code.text.totp": "Please enter the one‑time code from your authenticator app.", - "login.email.login.body": "Hi {user.nameOrEmail},\n\nYou recently requested a login code for the Panel of {site}.\nThe following login code will be valid for {timeout} minutes:\n\n{code}\n\nIf you did not request a login code, please ignore this email or contact your administrator if you have questions.\nFor security, please DO NOT forward this email.", - "login.email.login.subject": "Kirjautumiskoodisi", - "login.email.password-reset.body": "Hi {user.nameOrEmail},\n\nYou recently requested a password reset code for the Panel of {site}.\nThe following password reset code will be valid for {timeout} minutes:\n\n{code}\n\nIf you did not request a password reset code, please ignore this email or contact your administrator if you have questions.\nFor security, please DO NOT forward this email.", - "login.email.password-reset.subject": "Salasanan asetuskoodisi", - "login.remember": "Pidä minut kirjautuneena", - "login.reset": "Aseta salasana", - "login.toggleText.code.email": "Kirjaudu sähköpostiosoitteella", - "login.toggleText.code.email-password": "Kirjaudu salasanalla", - "login.toggleText.password-reset.email": "Unohditko salasanasi?", - "login.toggleText.password-reset.email-password": "← Takaisin kirjautumiseen", - "login.totp.enable.option": "Set up one‑time codes", - "login.totp.enable.intro": "Authenticator apps can generate one‑time codes that are used as a second factor when signing into your account.", - "login.totp.enable.qr.label": "1. Scan this QR code", - "login.totp.enable.qr.help": "Unable to scan? Add the setup key {secret} manually to your authenticator app.", - "login.totp.enable.confirm.headline": "2. Confirm with generated code", - "login.totp.enable.confirm.text": "Your app generates a new one‑time code every 30 seconds. Enter the current code to complete the setup:", - "login.totp.enable.confirm.label": "Current code", - "login.totp.enable.confirm.help": "After this setup, we will ask you for a one‑time code every time you log in.", - "login.totp.enable.success": "One‑time codes enabled", - "login.totp.disable.option": "Disable one‑time codes", - "login.totp.disable.label": "Enter your password to disable one‑time codes", - "login.totp.disable.help": "In the future, a different second factor like a login code sent via email will be requested when you log in. You can always set up one‑time codes again later.", - "login.totp.disable.admin": "

This will disable one‑time codes for {user}.

In the future, a different second factor like a login code sent via email will be requested when they log in. {user} can set up one‑time codes again after their next login.

", - "login.totp.disable.success": "One‑time codes disabled", - - "logout": "Kirjaudu ulos", - - "merge": "Merge", - "menu": "Valikko", - "meridiem": "am/pm", - "mime": "Median tyyppi", - "minutes": "Minuutit", - - "month": "Kuukausi", - "months.april": "Huhtikuu", - "months.august": "Elokuu", - "months.december": "Joulukuu", - "months.february": "Helmikuu", - "months.january": "Tammikuu", - "months.july": "Hein\u00e4kuu", - "months.june": "Kes\u00e4kuu", - "months.march": "Maaliskuu", - "months.may": "Toukokuu", - "months.november": "Marraskuu", - "months.october": "Lokakuu", - "months.september": "Syyskuu", - - "more": "Lisää", - "move": "Move", - "name": "Nimi", - "next": "Seuraava", - "night": "Night", - "no": "ei", - "off": "Pois käytöstä", - "on": "Käytössä", - "open": "Avaa", - "open.newWindow": "Avaa uudessa ikkunassa", - "option": "Option", - "options": "Asetukset", - "options.none": "Ei valintoja", - "options.all": "Show all {count} options", - - "orientation": "Suunta", - "orientation.landscape": "Vaakasuuntainen", - "orientation.portrait": "Pystysuuntainen", - "orientation.square": "Neliskulmainen", - - "page": "Page", - "page.blueprint": "Tällä sivulla ei ole vielä suunnitelmaa. Voit määrittää suunnitelman tiedostoon /site/blueprints/pages/{blueprint}.yml", - "page.changeSlug": "Vaihda URL-osoite", - "page.changeSlug.fromTitle": "Luo nimen perusteella", - "page.changeStatus": "Muuta tilaa", - "page.changeStatus.position": "Valitse järjestyspaikka", - "page.changeStatus.select": "Valitse uusi tila", - "page.changeTemplate": "Vaihda sivupohja", - "page.changeTemplate.notice": "Changing the page's template will remove content for fields that don't match in type. Use with caution.", - "page.create": "Create as {status}", - "page.delete.confirm": "Haluatko varmasti poistaa sivun {title}?", - "page.delete.confirm.subpages": "Tällä sivulla on alasivuja.
Myös kaikki alasivut poistetaan.", - "page.delete.confirm.title": "Anna vahvistuksena sivun nimi", - "page.duplicate.appendix": "Kopioi", - "page.duplicate.files": "Kopioi tiedostot", - "page.duplicate.pages": "Kopioi sivut", - "page.move": "Move page", - "page.sort": "Muuta järjestyspaikkaa", - "page.status": "Tila", - "page.status.draft": "Luonnos", - "page.status.draft.description": "Sivu on luonnostilassa ja näkyvissä vain kirjautuneille editoijille tai yksityisen linkin kautta", - "page.status.listed": "Julkinen", - "page.status.listed.description": "Sivu on julkinen kaikille", - "page.status.unlisted": "Listaamaton", - "page.status.unlisted.description": "Sivulle pääsee vain URL:n kautta", - - "pages": "Sivut", - "pages.empty": "Sivuja ei ole vielä lisätty", - "pages.status.draft": "Luonnokset", - "pages.status.listed": "Julkaistut", - "pages.status.unlisted": "Listaamaton", - - "pagination.page": "Sivu", - - "password": "Salasana", - "paste": "Liitä", - "paste.after": "Liitä jälkeen", - "paste.success": "{count} pasted!", - "pixel": "Pikseli", - "plugin": "Liitännäinen", - "plugins": "Liitännäiset", - "prev": "Edellinen", - "preview": "Esikatselu", - "remove": "Poista", - "rename": "Nimeä uudelleen", - "renew": "Renew", - "replace": "Korvaa", - "replace.with": "Replace with", - "retry": "Yrit\u00e4 uudelleen", - "revert": "Palauta", - "revert.confirm": "Haluatko varmasti poistaa kaikki tallentamattomat muutokset?", - - "role": "K\u00e4ytt\u00e4j\u00e4taso", - "role.admin.description": "Pääkäyttäjällä on kaikki oikeudet", - "role.admin.title": "Pääkäyttäjä", - "role.all": "Kaikki", - "role.empty": "Tällä käyttäjätasolla ei ole yhtään käyttäjää", - "role.description.placeholder": "Ei kuvausta", - "role.nobody.description": "Tämä on vararooli, jolla ei ole mitään oikeuksia", - "role.nobody.title": "Tuntematon", - - "save": "Tallenna", - "search": "Haku", - "search.min": "Anna vähintään {min} merkkiä hakua varten", - "search.all": "Show all {count} results", - "search.results.none": "Ei tuloksia", - - "section.invalid": "The section is invalid", - "section.required": "Osio on pakollinen", - - "security": "Tietoturva", - "select": "Valitse", - "server": "Palvelin", - "settings": "Asetukset", - "show": "Näytä", - "site.blueprint": "Tällä sivustolla ei ole vielä suunnitelmaa. Voit määrittää suunnitelman tiedostoon /site/blueprints/site.yml", - "size": "Koko", - "slug": "URL-tunniste", - "sort": "Järjestele", - "sort.drag": "Drag to sort …", - "split": "Split", - - "stats.empty": "Ei raportteja", - "status": "Tila", - - "system.info.copy": "Copy info", - "system.info.copied": "System info copied", - "system.issues.content": "Content-kansio näyttäisi olevan julkinen", - "system.issues.eol.kirby": "Your installed Kirby version has reached end-of-life and will not receive further security updates", - "system.issues.eol.plugin": "Your installed version of the { plugin } plugin is has reached end-of-life and will not receive further security updates", - "system.issues.eol.php": "Your installed PHP release { release } has reached end-of-life and will not receive further security updates", - "system.issues.debug": "Virheenkäsittelytila pitää poistaa käytöstä tuotantoympäristössä", - "system.issues.git": ".git-kansio näyttäisi olevan julkinen", - "system.issues.https": "Suosittelemme HTTPS:n käyttöä kaikilla sivustoillasi", - "system.issues.kirby": "Kirby-kansio näyttäisi olevan julkinen", - "system.issues.site": "Site-kansio näyttäisi olevan julkinen", - "system.issues.vulnerability.kirby": "Asennuksesi voi olla altis seuraaville haavoittuvuuksille ({ severity } vakavuus): { description }", - "system.issues.vulnerability.plugin": "Asennuksesi käyttämä liitännäinen { plugin } voi olla altis haavoittuvuudelle ({ severity } vakavuus): { description }", - "system.updateStatus": "Päivitysten tilanne", - "system.updateStatus.error": "Päivityksiä ei voitu tarkistaa", - "system.updateStatus.not-vulnerable": "Ei tunnettuja haavoittuvuuksia", - "system.updateStatus.security-update": "Ilmainen tietoturvapäivitys { version } saatavilla", - "system.updateStatus.security-upgrade": "Tietoturvakorjauksia sisältävä päivitys { version } saatavilla", - "system.updateStatus.unreleased": "Julkaisematon versio", - "system.updateStatus.up-to-date": "Ajan tasalla", - "system.updateStatus.update": "Ilmainen päivitys { version } saatavilla", - "system.updateStatus.upgrade": "Päivitys { version } saatavilla", - - "tel": "Phone", - "tel.placeholder": "+49123456789", - "template": "Sivupohja", - "title": "Nimi", - "today": "Tänään", - - "toolbar.button.clear": "Clear formatting", - "toolbar.button.code": "Koodi", - "toolbar.button.bold": "Lihavointi", - "toolbar.button.email": "S\u00e4hk\u00f6posti", - "toolbar.button.headings": "Otsikot", - "toolbar.button.heading.1": "Otsikko 1", - "toolbar.button.heading.2": "Otsikko 2", - "toolbar.button.heading.3": "Otsikko 3", - "toolbar.button.heading.4": "Otsikko 4", - "toolbar.button.heading.5": "Otsikko 5", - "toolbar.button.heading.6": "Otsikko 6", - "toolbar.button.italic": "Kursivointi", - "toolbar.button.file": "Tiedosto", - "toolbar.button.file.select": "Valitse tiedosto", - "toolbar.button.file.upload": "Lähetä tiedosto", - "toolbar.button.link": "Linkki", - "toolbar.button.paragraph": "Kappale", - "toolbar.button.strike": "Yliviivaus", - "toolbar.button.sub": "Subscript", - "toolbar.button.sup": "Superscript", - "toolbar.button.ol": "Järjestetty lista", - "toolbar.button.underline": "Alaviiva", - "toolbar.button.ul": "Järjestämätön lista", - - "translation.author": "Kirby-tiimi", - "translation.direction": "ltr", - "translation.name": "Suomi", - "translation.locale": "fi_FI", - - "type": "Type", - - "upload": "Lähetä", - "upload.error.cantMove": "Lähetettyä tiedostoa ei voitu siirtää", - "upload.error.cantWrite": "Tiedoston kirjoitus levylle epäonnistui", - "upload.error.default": "Tiedostoa ei voitu lähettää", - "upload.error.extension": "Tiedostoa ei lähetetty tiedostopäätteen takia", - "upload.error.formSize": "Lähetetyn tiedoston koko ylittää lomakkeen sallitun ylärajan MAX_FILE_SIZE", - "upload.error.iniPostSize": "Lähetetyn tiedoston koko ylittää sallitun ylärajan post_max_size asetustiedostossa php.ini", - "upload.error.iniSize": "Lähetetyn tiedoston koko ylittää sallitun ylärajan upload_max_filesize asetustiedostossa php.ini", - "upload.error.noFile": "Tiedostoa ei lähetetty", - "upload.error.noFiles": "Tiedostoja ei lähetetty", - "upload.error.partial": "Tiedoston lähetys onnistui vain osittain", - "upload.error.tmpDir": "Väliaikainen hakemisto puuttuu", - "upload.errors": "Virhe", - "upload.progress": "Lähetetään...", - - "url": "Url", - "url.placeholder": "https://esimerkki.fi", - - "user": "Käyttäjä", - "user.blueprint": "Voit määrittää lisää osioita ja lomakekenttiä tälle käyttäjälle suunnitelmassa /site/blueprints/users/{blueprint}.yml", - "user.changeEmail": "Muuta sähköpostiosoite", - "user.changeLanguage": "Vaihda kieli", - "user.changeName": "Nimeä uudelleen", - "user.changePassword": "Vaihda salasana", - "user.changePassword.new": "Uusi salasana", - "user.changePassword.new.confirm": "Vahvista uusi salasana...", - "user.changeRole": "Muuta käyttäjätasoa", - "user.changeRole.select": "Valitse uusi käyttäjätaso", - "user.create": "Lisää uusi käyttäjä", - "user.delete": "Poista tämä käyttäjä", - "user.delete.confirm": "Haluatko varmsti poistaa käyttäjän
{email}?", - - "users": "Käyttäjät", - - "version": "Versio", - "version.current": "Nykyinen versio ", - "version.latest": "Uusin versio ", - "versionInformation": "Version tiedot", - - "view.account": "Oma käyttäjätili", - "view.installation": "Asennus", - "view.languages": "Kielet", - "view.resetPassword": "Aseta salasana", - "view.site": "Sivusto", - "view.system": "Järjestelmä", - "view.users": "K\u00e4ytt\u00e4j\u00e4t", - - "welcome": "Tervetuloa", - "year": "Vuosi", - "yes": "kyllä" + "account.changeName": "Muuta nimesi", + "account.delete": "Poista tilisi", + "account.delete.confirm": "Haluatko varmasti poistaa tilisi? Sinut kirjataan ulos välittömästi, eikä tiliäsi voi palauttaa.", + + "add": "Lis\u00e4\u00e4", + "author": "Tekijä", + "avatar": "Profiilikuva", + "back": "Takaisin", + "cancel": "Peruuta", + "change": "Muuta", + "close": "Sulje", + "confirm": "Ok", + "collapse": "Pienennä", + "collapse.all": "Pienennä kaikki", + "copy": "Kopioi", + "copy.all": "Kopioi kaikki", + "create": "Luo", + + "date": "Päivämäärä", + "date.select": "Valitse päivämäärä", + + "day": "Päivä", + "days.fri": "Pe", + "days.mon": "Ma", + "days.sat": "La", + "days.sun": "Su", + "days.thu": "To", + "days.tue": "Ti", + "days.wed": "Ke", + + "debugging": "Debugging", + + "delete": "Poista", + "delete.all": "Poista kaikki", + + "dialog.files.empty": "Ei valittavissa olevia tiedostoja", + "dialog.pages.empty": "Ei valittavissa olevia sivuja", + "dialog.users.empty": "Ei valittavissa olevia käyttäjiä", + + "dimensions": "Mitat", + "disabled": "Pois käytöstä", + "discard": "Hylkää", + "download": "Lataa", + "duplicate": "Kahdenna", + + "edit": "Muokkaa", + + "email": "S\u00e4hk\u00f6posti", + "email.placeholder": "nimi@osoite.fi", + + "entries": "Entries", + "entry": "Entry", + + "environment": "Ympäristö", + + "error.access.code": "Väärä koodi", + "error.access.login": "Kirjautumistiedot eivät kelpaa", + "error.access.panel": "Sinulla ei ole oikeutta käyttää paneelia", + "error.access.view": "Sinulla ei ole oikeutta käyttää tätä osaa paneelista", + + "error.avatar.create.fail": "Profiilikuvaa ei voitu lähettää", + "error.avatar.delete.fail": "Profiilikuvaa ei voitu poistaa", + "error.avatar.dimensions.invalid": "Profiilikuvan leveys ja korkeus voivat olla enintään 3000 pikseliä", + "error.avatar.mime.forbidden": "Profiilikuvan täytyy olla joko JPEG- tai PNG-formaatissa", + + "error.blueprint.notFound": "Suunnitelmaa \"{name}\" ei voitu ladata", + + "error.blocks.max.plural": "Voit lisätä enintään {max} lohkoa", + "error.blocks.max.singular": "Voit lisätä enintään yhden lohkon", + "error.blocks.min.plural": "Lisää vähintään {min} lohkoa", + "error.blocks.min.singular": "Lisää vähintään yksi lohko", + "error.blocks.validation": "Virhe lohkossa {index}", + + "error.email.preset.notFound": "Nimellä \"{name}\" ja kyseisellä verkkotunnuksella ei löydy sähköpostiosoitetta", + + "error.field.converter.invalid": "Muunnin \"{converter}\" ei kelpaa", + + "error.file.changeName.empty": "Nimi ei voi olla tyhjä", + "error.file.changeName.permission": "Sinulla ei ole oikeutta muuttaa tiedoston \"{filename}\" nimeä", + "error.file.duplicate": "Tiedosto nimeltä \"{filename}\" on jo olemassa", + "error.file.extension.forbidden": "Tiedostopääte \"{extension}\" ei ole sallittu", + "error.file.extension.invalid": "Pääte {extension} ei kelpaa", + "error.file.extension.missing": "Tiedoston \"{filename}\" tiedostopääte puuttuu", + "error.file.maxheight": "Kuvan korkeus ei voi ylittää {height} pikseliä", + "error.file.maxsize": "Tiedosto on liian suuri", + "error.file.maxwidth": "Kuvan leveys ei voi ylittää {width} pikseliä", + "error.file.mime.differs": "Lähetetyllä tiedostolla täytyy olla sama mime-tyyppi \"{mime}\"", + "error.file.mime.forbidden": "Median tyyppi \"{mime}\" ei ole sallittu", + "error.file.mime.invalid": "Mime-tyyppi {mime} ei kelpaa", + "error.file.mime.missing": "Tiedoston \"{filename}\" mediatyyppiä ei voida tunnistaa", + "error.file.minheight": "Kuvan korkeus täytyy olla vähintään {height} pikseliä", + "error.file.minsize": "Tiedosto on liian pieni", + "error.file.minwidth": "Kuvan leveys täytyy olla vähintään {width} pikseliä", + "error.file.name.missing": "Tiedostonimi ei voi olla tyhjä", + "error.file.notFound": "Tiedostoa \"{filename}\" ei löytynyt", + "error.file.orientation": "Kuvan suuntaus täytyy olla \"{orientation}\"", + "error.file.type.forbidden": "Sinulla ei ole oikeutta lähettää tiedostoja joiden tyyppi on {type}", + "error.file.type.invalid": "Tiedostotyyppi {type} ei kelpaa", + "error.file.undefined": "Tiedostoa ei l\u00f6ytynyt", + + "error.form.incomplete": "Korjaa kaikki lomakkeen virheet…", + "error.form.notSaved": "Lomaketta ei voitu tallentaa", + + "error.language.code": "Anna kielen lyhenne", + "error.language.duplicate": "Kieli on jo olemassa", + "error.language.name": "Anna kielen nimi", + "error.language.notFound": "Kieltä ei löytynyt", + + "error.layout.validation.block": "Lohkon {blockIndex} asetelmassa {layoutIndex} tapahtui virhe", + "error.layout.validation.settings": "Virhe asetelman {index} asetuksissa", + + "error.license.format": "Anna lisenssiavain", + "error.license.email": "Anna sähköpostiosoite", + "error.license.verification": "Lisenssiä ei voitu vahvistaa", + + "error.offline": "Paneeli on offline-tilassa", + + "error.page.changeSlug.permission": "Sinulla ei ole oikeutta muuttaa URL-liitettä sivulle \"{slug}\"", + "error.page.changeStatus.incomplete": "Sivulla on virheitä eikä sitä voitu julkaista", + "error.page.changeStatus.permission": "Tämän sivun tilaa ei voi muuttaa", + "error.page.changeStatus.toDraft.invalid": "Sivua \"{slug}\" ei voi muuttaa luonnokseksi", + "error.page.changeTemplate.invalid": "Sivun \"{slug}\" pohjaa ei voi muuttaa", + "error.page.changeTemplate.permission": "Sinulla ei ole oikeutta muuttaa sivun \"{slug}\" sivupohjaa", + "error.page.changeTitle.empty": "Nimi ei voi olla tyhjä", + "error.page.changeTitle.permission": "Sinulla ei ole oikeutta muuttaa sivun \"{slug}\" nimeä", + "error.page.create.permission": "Sinulla ei ole oikeutta luoda sivua \"{slug}\"", + "error.page.delete": "Sivua \"{slug}\" ei voi poistaa", + "error.page.delete.confirm": "Anna vahvistuksena sivun nimi", + "error.page.delete.hasChildren": "Sivu sisältää alasivuja eikä sitä voida poistaa", + "error.page.delete.permission": "Sinulla ei ole oikeutta poistaa sivua \"{slug}\"", + "error.page.draft.duplicate": "Sivuluonnos URL-liitteellä \"{slug}\" on jo olemassa", + "error.page.duplicate": "Sivu URL-liitteellä \"{slug}\" on jo olemassa", + "error.page.duplicate.permission": "Sinulla ei ole oikeutta kahdentaa sivua \"{slug}\"", + "error.page.notFound": "Sivua \"{slug}\" ei löytynyt", + "error.page.num.invalid": "Anna kelpaava järjestysnumero. Numero ei voi olla negatiivinen.", + "error.page.slug.invalid": "Anna kelpaava URL-liite", + "error.page.slug.maxlength": "URL-liite täytyy olla vähemmän kuin \"{length}\" merkkiä pitkä", + "error.page.sort.permission": "Sivua \"{slug}\" ei voi järjestellä", + "error.page.status.invalid": "Aseta kelvollinen sivun tila", + "error.page.undefined": "Sivua ei l\u00f6ytynyt", + "error.page.update.permission": "Sinulla ei ole oikeutta päivittää sivua \"{slug}\"", + + "error.section.files.max.plural": "Et voi lisätä enemmän kuin {max} tiedostoa osioon \"{section}\"", + "error.section.files.max.singular": "Et voi lisätä enempää kuin yhden tiedoston osioon \"{section}\"", + "error.section.files.min.plural": "Osio \"{section}\" vaatii ainakin {min} tiedostoa", + "error.section.files.min.singular": "Osio \"{section}\" vaatii ainakin yhden sivun", + + "error.section.pages.max.plural": "Et voi lisätä enemmän kuin {max} sivua osioon \"{section}\"", + "error.section.pages.max.singular": "Et voi lisätä enempää kuin yhden sivun osioon \"{section}\"", + "error.section.pages.min.plural": "Osio \"{section}\" vaatii ainakin {min} sivua", + "error.section.pages.min.singular": "Osio \"{section}\" vaatii ainakin yhden sivun", + + "error.section.notLoaded": "Osiota \"{name}\" ei voitu ladata", + "error.section.type.invalid": "Osion tyyppi \"{type}\" ei ole kelvollinen", + + "error.site.changeTitle.empty": "Nimi ei voi olla tyhjä", + "error.site.changeTitle.permission": "Sinulla ei ole oikeutta päivittää sivuston nimeä", + "error.site.update.permission": "Sinulla ei ole oikeutta päivittää sivuston tietoja", + + "error.template.default.notFound": "Oletussivupohjaa ei ole määritetty", + + "error.unexpected": "An unexpected error occurred! Enable debug mode for more info: https://getkirby.com/docs/reference/system/options/debug", + + "error.user.changeEmail.permission": "Sinulla ei ole oikeutta vaihtaa käyttäjän \"{name}\" sähköpostiosoitetta", + "error.user.changeLanguage.permission": "Sinulla ei ole oikeutta vaihtaa käyttäjän \"{name}\" kieltä", + "error.user.changeName.permission": "Sinulla ei ole oikeutta vaihtaa käyttäjän \"{name}\" nimeä", + "error.user.changePassword.permission": "Sinulla ei ole oikeutta vaihtaa käyttäjän \"{name}\" salasanaa", + "error.user.changeRole.lastAdmin": "Ainoan pääkäyttäjän roolia ei voi muuttaa", + "error.user.changeRole.permission": "Sinulla ei ole oikeutta vaihtaa käyttäjän \"{name}\" käyttäjätasoa", + "error.user.changeRole.toAdmin": "Sinulla ei ole oikeutta vaihtaa käyttäjätasoa pääkäyttäjäksi", + "error.user.create.permission": "Sinulla ei ole oikeutta luoda tätä käyttäjää", + "error.user.delete": "Käyttäjää \"{name}\" ei voi poistaa", + "error.user.delete.lastAdmin": "Ainoaa pääkäyttäjää ei voi poistaa", + "error.user.delete.lastUser": "Ainoaa käyttäjää ei voi poistaa", + "error.user.delete.permission": "Sinulla ei ole oikeutta poistaa käyttäjää \"{name}\"", + "error.user.duplicate": "Käyttäjä, jonka sähköpostiosoite on \"{name}\", on jo olemassa", + "error.user.email.invalid": "Anna kelpaava sähköpostiosoite", + "error.user.language.invalid": "Anna kelpaava kieli", + "error.user.notFound": "K\u00e4ytt\u00e4j\u00e4\u00e4 ei l\u00f6ytynyt", + "error.user.password.excessive": "Please enter a valid password. Passwords must not be longer than 1000 characters.", + "error.user.password.invalid": "Anna kelpaava salasana. Salasanan täytyy olla ainakin 8 merkkiä pitkä.", + "error.user.password.notSame": "Salasanat eivät täsmää", + "error.user.password.undefined": "Käyttäjällä ei ole salasanaa", + "error.user.password.wrong": "Väärä salasana", + "error.user.role.invalid": "Anna kelpaava käyttäjätaso", + "error.user.undefined": "Käyttäjää ei löytynyt", + "error.user.update.permission": "Sinulla ei ole oikeutta päivittää käyttäjää \"{name}\"", + + "error.validation.accepted": "Ole hyvä ja vahvista", + "error.validation.alpha": "Anna vain merkkejä väliltä a-z", + "error.validation.alphanum": "Anna vain merkkejä väliltä a-z tai/ja numeroita väliltä 0-9", + "error.validation.between": "Anna arvo väliltä \"{min}\" ja \"{max}\"", + "error.validation.boolean": "Vahvista tai peruuta", + "error.validation.contains": "Anna arvo joka sisältää \"{needle}\"", + "error.validation.date": "Anna kelpaava päivämäärä", + "error.validation.date.after": "Anna päivämäärä {date} jälkeen", + "error.validation.date.before": "Anna päivämäärä ennen {date}", + "error.validation.date.between": "Anna päivämäärä väliltä {min} ja {max}", + "error.validation.denied": "Ole hyvä ja peruuta", + "error.validation.different": "Arvo ei voi olla \"{other}\"", + "error.validation.email": "Anna kelpaava sähköpostiosoite", + "error.validation.endswith": "Arvon loppuosa täytyy olla \"{end}\"", + "error.validation.filename": "Anna kelpaava tiedostonimi", + "error.validation.in": "Anna joku seuraavista: ({in})", + "error.validation.integer": "Anna kelpaava kokonaisluku", + "error.validation.ip": "Anna kelpaava IP-osoite", + "error.validation.less": "Anna arvo joka on pienempi kuin {max}", + "error.validation.match": "Arvo ei vastaa vaadittua kaavaa", + "error.validation.max": "Anna arvo joka on enintään {max}", + "error.validation.maxlength": "Anna lyhyempi arvo. (enintään {max} merkkiä)", + "error.validation.maxwords": "Anna korkeintaan {max} sana(a)", + "error.validation.min": "Anna arvo joka on vähintään {min}", + "error.validation.minlength": "Anna pidempi arvo. (vähintään {min} merkkiä)", + "error.validation.minwords": "Anna vähintään {min} sana(a)", + "error.validation.more": "Anna suurempi arvo kuin {min}", + "error.validation.notcontains": "Anna arvo joka ei sisällä \"{needle}\"", + "error.validation.notin": "Arvo ei voi sisältää mitään seuraavista: ({notIn})", + "error.validation.option": "Valitse kelpaava vaihtoehto", + "error.validation.num": "Anna kelpaava numero", + "error.validation.required": "Arvo ei voi olla tyhjä", + "error.validation.same": "Anna \"{other}\"", + "error.validation.size": "Arvon koko täytyy olla \"{size}\"", + "error.validation.startswith": "Arvon alkuosa täytyy olla \"{start}\"", + "error.validation.time": "Anna kelpaava aika", + "error.validation.time.after": "Anna myöhempi aika kuin {time}", + "error.validation.time.before": "Anna aiempi aika kuin {time}", + "error.validation.time.between": "Anna aika väliltä {min} ja {max}", + "error.validation.url": "Anna kelpaava URL", + + "expand": "Laajenna", + "expand.all": "Laajenna kaikki", + + "field.required": "Kenttä on pakollinen", + "field.blocks.changeType": "Vaihda tyyppiä", + "field.blocks.code.name": "Koodi", + "field.blocks.code.language": "Kieli", + "field.blocks.code.placeholder": "Koodisi …", + "field.blocks.delete.confirm": "Haluatko varmasti poistaa tämän lohkon?", + "field.blocks.delete.confirm.all": "Haluatko varmasti poistaa kaikki lohkot?", + "field.blocks.delete.confirm.selected": "Haluatko varmasti poistaa valitut lohkot?", + "field.blocks.empty": "Ei lohkoja", + "field.blocks.fieldsets.label": "Valitse lohkon tyyppi …", + "field.blocks.fieldsets.paste": "Paina {{ shortcut }} liittääksesi tai tuodaksesi lohkoja leikepöydältä", + "field.blocks.gallery.name": "Galleria", + "field.blocks.gallery.images.empty": "Ei kuvia", + "field.blocks.gallery.images.label": "Kuvat", + "field.blocks.heading.level": "Taso", + "field.blocks.heading.name": "Otsikko", + "field.blocks.heading.text": "Teksti", + "field.blocks.heading.placeholder": "Otsikko …", + "field.blocks.image.alt": "Vaihtoehtoinen teksti", + "field.blocks.image.caption": "Kuvateksti", + "field.blocks.image.crop": "Rajaa", + "field.blocks.image.link": "Linkki", + "field.blocks.image.location": "Sijainti", + "field.blocks.image.name": "Kuva", + "field.blocks.image.placeholder": "Valitse kuva", + "field.blocks.image.ratio": "Kuvasuhde", + "field.blocks.image.url": "Kuvan URL", + "field.blocks.line.name": "Line", + "field.blocks.list.name": "Lista", + "field.blocks.markdown.name": "Markdown", + "field.blocks.markdown.label": "Teksti", + "field.blocks.markdown.placeholder": "Markdown …", + "field.blocks.quote.name": "Lainaus", + "field.blocks.quote.text.label": "Teksti", + "field.blocks.quote.text.placeholder": "Lainaus …", + "field.blocks.quote.citation.label": "Sitaatti", + "field.blocks.quote.citation.placeholder": "Lähde …", + "field.blocks.text.name": "Teksti", + "field.blocks.text.placeholder": "Teksti …", + "field.blocks.video.caption": "Videon teksti", + "field.blocks.video.name": "Video", + "field.blocks.video.placeholder": "Anna videon URL", + "field.blocks.video.url.label": "Videon URL", + "field.blocks.video.url.placeholder": "https://youtube.com/?v=", + + "field.files.empty": "Tiedostoja ei ole vielä valittu", + + "field.layout.delete": "Poista asettelu", + "field.layout.delete.confirm": "Halutako varmasti poistaa tämän asettelun?", + "field.layout.empty": "Ei rivejä", + "field.layout.select": "Valitse asettelu", + + "field.pages.empty": " Sivuja ei ole vielä valittu", + "field.structure.delete.confirm": "Haluatko varmasti poistaa tämän rivin?", + "field.structure.empty": "Rivejä ei ole vielä lisätty", + "field.users.empty": "Käyttäjiä ei ole vielä valittu", + + "file.blueprint": "Tällä tiedostolla ei ole vielä suunnitelmaa. Voit määrittää suunnitelman tiedostoon /site/blueprints/files/{blueprint}.yml", + "file.delete.confirm": "Haluatko varmasti poistaa tiedoston
{filename}?", + "file.sort": "Muuta järjestyspaikkaa", + + "files": "Tiedostot", + "files.empty": "Tiedostoja ei ole vielä lisätty", + + "hide": "Piilota", + "hour": "Tunti", + "import": "Tuo", + "info": "Info", + "insert": "Lis\u00e4\u00e4", + "insert.after": "Lisää eteen", + "insert.before": "Lisää jälkeen", + "install": "Asenna", + + "installation": "Asennus", + "installation.completed": "Paneeli on asennettu", + "installation.disabled": "Paneelin asennus on oletuksena poissa käytöstä julkisilla palvelimilla. Aja asennus paikallisella koneella, tai ota paneeli käyttöön panel.install-optiolla.", + "installation.issues.accounts": "/site/accounts -kansio ei ole olemassa tai siihen ei voi kirjoittaa", + "installation.issues.content": "/content -kansio ei ole olemassa tai siihen ei voi kirjoittaa", + "installation.issues.curl": "CURL-laajennos on pakollinen", + "installation.issues.headline": "Paneelia ei voida asentaa", + "installation.issues.mbstring": "MB String-laajennos on pakollinen", + "installation.issues.media": "/media -kansio ei ole olemassa tai siihen ei voi kirjoittaa", + "installation.issues.php": "Varmista että PHP 7+ on käytössä", + "installation.issues.server": "Kirby tarvitsee jonkun seuraavista: Apache, Nginx tai Caddy", + "installation.issues.sessions": "/site/sessions -kansio ei ole olemassa tai siihen ei voi kirjoittaa", + + "language": "Kieli", + "language.code": "Tunniste", + "language.convert": "Muuta oletukseksi", + "language.convert.confirm": "

Haluatko varmasti muuttaa kielen {name} oletuskieleksi? Tätä muutosta ei voi peruuttaa.

Jos{name} sisältää kääntämättömiä kohtia, varakäännöstä ei enää ole näille kohdille ja sivustosi saattaa olla osittain tyhjä.

", + "language.create": "Lisää uusi kieli", + "language.delete.confirm": "Haluatko varmasti poistaa kielen {name}, mukaanlukien kaikki käännökset? Tätä toimintoa ei voi peruuttaa!", + "language.deleted": "Kieli on poistettu", + "language.direction": "Lukusuunta", + "language.direction.ltr": "Vasemmalta oikealle", + "language.direction.rtl": "Oikealta vasemmalle", + "language.locale": "PHP-aluemäärityksen tunniste", + "language.locale.warning": "Käytät mukautettua aluemääritystä. Muokkaa sitä kielitiedostossa /site/languages", + "language.name": "Nimi", + "language.updated": "Kieli on päivitetty", + + "languages": "Kielet", + "languages.default": "Oletuskieli", + "languages.empty": "Kieliä ei ole vielä määritetty", + "languages.secondary": "Toissijaiset kielet", + "languages.secondary.empty": "Toissijaisia kieliä ei ole vielä määritetty", + + "license": "Lisenssi", + "license.buy": "Osta lisenssi", + "license.register": "Rekisteröi", + "license.manage": "Manage your licenses", + "license.register.help": "Lisenssiavain on lähetetty oston jälkeen sähköpostiisi. Kopioi ja liitä avain tähän.", + "license.register.label": "Anna lisenssiavain", + "license.register.success": "Kiitos kun tuet Kirbyä", + "license.unregistered": "Tämä on rekisteröimätön demo Kirbystä", + "license.unregistered.label": "Unregistered", + + "link": "Linkki", + "link.text": "Linkin teksti", + + "loading": "Ladataan", + + "lock.unsaved": "Tallentamattomia muutoksia", + "lock.unsaved.empty": "Ei enempää tallentamattomia muutoksia ", + "lock.isLocked": "Käyttäjällä {email} on tallentamattomia muutoksia", + "lock.file.isLocked": "Tiedostoa ei voi muokata juuri nyt, sillä {email} on muokkaamassa tiedostoa.", + "lock.page.isLocked": "Sivua ei voi muokata juuri nyt, sillä {email} on muokkaamassa sivua.", + "lock.unlock": "Vapauta", + "lock.isUnlocked": "Toinen käyttäjä ylikirjoitti tallentamattomat muutoksesi. Voit ladata tekemäsi muutokset ja lisätä ne käsin.", + + "login": "Kirjaudu", + "login.code.label.login": "Kirjautumiskoodi", + "login.code.label.password-reset": "Salasanan asetuskoodi", + "login.code.placeholder.email": "000 000", + "login.code.text.email": "Jos sähköpostiosoitteesi on rekisteröity, tilaamasi koodi lähetetään tähän osoitteeseen.", + "login.email.login.body": "Hi {user.nameOrEmail},\n\nYou recently requested a login code for the Panel of {site}.\nThe following login code will be valid for {timeout} minutes:\n\n{code}\n\nIf you did not request a login code, please ignore this email or contact your administrator if you have questions.\nFor security, please DO NOT forward this email.", + "login.email.login.subject": "Kirjautumiskoodisi", + "login.email.password-reset.body": "Hi {user.nameOrEmail},\n\nYou recently requested a password reset code for the Panel of {site}.\nThe following password reset code will be valid for {timeout} minutes:\n\n{code}\n\nIf you did not request a password reset code, please ignore this email or contact your administrator if you have questions.\nFor security, please DO NOT forward this email.", + "login.email.password-reset.subject": "Salasanan asetuskoodisi", + "login.remember": "Pidä minut kirjautuneena", + "login.reset": "Aseta salasana", + "login.toggleText.code.email": "Kirjaudu sähköpostiosoitteella", + "login.toggleText.code.email-password": "Kirjaudu salasanalla", + "login.toggleText.password-reset.email": "Unohditko salasanasi?", + "login.toggleText.password-reset.email-password": "← Takaisin kirjautumiseen", + + "logout": "Kirjaudu ulos", + + "menu": "Valikko", + "meridiem": "am/pm", + "mime": "Median tyyppi", + "minutes": "Minuutit", + + "month": "Kuukausi", + "months.april": "Huhtikuu", + "months.august": "Elokuu", + "months.december": "Joulukuu", + "months.february": "Helmikuu", + "months.january": "Tammikuu", + "months.july": "Hein\u00e4kuu", + "months.june": "Kes\u00e4kuu", + "months.march": "Maaliskuu", + "months.may": "Toukokuu", + "months.november": "Marraskuu", + "months.october": "Lokakuu", + "months.september": "Syyskuu", + + "more": "Lisää", + "name": "Nimi", + "next": "Seuraava", + "no": "ei", + "off": "Pois käytöstä", + "on": "Käytössä", + "open": "Avaa", + "open.newWindow": "Avaa uudessa ikkunassa", + "options": "Asetukset", + "options.none": "Ei valintoja", + + "orientation": "Suunta", + "orientation.landscape": "Vaakasuuntainen", + "orientation.portrait": "Pystysuuntainen", + "orientation.square": "Neliskulmainen", + + "page.blueprint": "Tällä sivulla ei ole vielä suunnitelmaa. Voit määrittää suunnitelman tiedostoon /site/blueprints/pages/{blueprint}.yml", + "page.changeSlug": "Vaihda URL-osoite", + "page.changeSlug.fromTitle": "Luo nimen perusteella", + "page.changeStatus": "Muuta tilaa", + "page.changeStatus.position": "Valitse järjestyspaikka", + "page.changeStatus.select": "Valitse uusi tila", + "page.changeTemplate": "Vaihda sivupohja", + "page.delete.confirm": "Haluatko varmasti poistaa sivun {title}?", + "page.delete.confirm.subpages": "Tällä sivulla on alasivuja.
Myös kaikki alasivut poistetaan.", + "page.delete.confirm.title": "Anna vahvistuksena sivun nimi", + "page.draft.create": "Uusi luonnos", + "page.duplicate.appendix": "Kopioi", + "page.duplicate.files": "Kopioi tiedostot", + "page.duplicate.pages": "Kopioi sivut", + "page.sort": "Muuta järjestyspaikkaa", + "page.status": "Tila", + "page.status.draft": "Luonnos", + "page.status.draft.description": "Sivu on luonnostilassa ja näkyvissä vain kirjautuneille editoijille tai yksityisen linkin kautta", + "page.status.listed": "Julkinen", + "page.status.listed.description": "Sivu on julkinen kaikille", + "page.status.unlisted": "Listaamaton", + "page.status.unlisted.description": "Sivulle pääsee vain URL:n kautta", + + "pages": "Sivut", + "pages.empty": "Sivuja ei ole vielä lisätty", + "pages.status.draft": "Luonnokset", + "pages.status.listed": "Julkaistut", + "pages.status.unlisted": "Listaamaton", + + "pagination.page": "Sivu", + + "password": "Salasana", + "paste": "Liitä", + "paste.after": "Liitä jälkeen", + "pixel": "Pikseli", + "plugins": "Liitännäiset", + "prev": "Edellinen", + "preview": "Esikatselu", + "remove": "Poista", + "rename": "Nimeä uudelleen", + "replace": "Korvaa", + "retry": "Yrit\u00e4 uudelleen", + "revert": "Palauta", + "revert.confirm": "Haluatko varmasti poistaa kaikki tallentamattomat muutokset?", + + "role": "K\u00e4ytt\u00e4j\u00e4taso", + "role.admin.description": "Pääkäyttäjällä on kaikki oikeudet", + "role.admin.title": "Pääkäyttäjä", + "role.all": "Kaikki", + "role.empty": "Tällä käyttäjätasolla ei ole yhtään käyttäjää", + "role.description.placeholder": "Ei kuvausta", + "role.nobody.description": "Tämä on vararooli, jolla ei ole mitään oikeuksia", + "role.nobody.title": "Tuntematon", + + "save": "Tallenna", + "search": "Haku", + "search.min": "Anna vähintään {min} merkkiä hakua varten", + "search.all": "Näytä kaikki", + "search.results.none": "Ei tuloksia", + + "section.required": "Osio on pakollinen", + + "security": "Security", + "select": "Valitse", + "server": "Palvelin", + "settings": "Asetukset", + "show": "Näytä", + "site.blueprint": "Tällä sivustolla ei ole vielä suunnitelmaa. Voit määrittää suunnitelman tiedostoon /site/blueprints/site.yml", + "size": "Koko", + "slug": "URL-tunniste", + "sort": "Järjestele", + + "stats.empty": "No reports", + "system.issues.content": "The content folder seems to be exposed", + "system.issues.debug": "Debugging must be turned off in production", + "system.issues.git": "The .git folder seems to be exposed", + "system.issues.https": "We recommend HTTPS for all your sites", + "system.issues.kirby": "The kirby folder seems to be exposed", + "system.issues.site": "The site folder seems to be exposed", + + "title": "Nimi", + "template": "Sivupohja", + "today": "Tänään", + + "toolbar.button.code": "Koodi", + "toolbar.button.bold": "Lihavointi", + "toolbar.button.email": "S\u00e4hk\u00f6posti", + "toolbar.button.headings": "Otsikot", + "toolbar.button.heading.1": "Otsikko 1", + "toolbar.button.heading.2": "Otsikko 2", + "toolbar.button.heading.3": "Otsikko 3", + "toolbar.button.heading.4": "Otsikko 4", + "toolbar.button.heading.5": "Otsikko 5", + "toolbar.button.heading.6": "Otsikko 6", + "toolbar.button.italic": "Kursivointi", + "toolbar.button.file": "Tiedosto", + "toolbar.button.file.select": "Valitse tiedosto", + "toolbar.button.file.upload": "Lähetä tiedosto", + "toolbar.button.link": "Linkki", + "toolbar.button.paragraph": "Kappale", + "toolbar.button.strike": "Yliviivaus", + "toolbar.button.ol": "Järjestetty lista", + "toolbar.button.underline": "Alaviiva", + "toolbar.button.ul": "Järjestämätön lista", + + "translation.author": "Kirby-tiimi", + "translation.direction": "ltr", + "translation.name": "Suomi", + "translation.locale": "fi_FI", + + "upload": "Lähetä", + "upload.error.cantMove": "Lähetettyä tiedostoa ei voitu siirtää", + "upload.error.cantWrite": "Tiedoston kirjoitus levylle epäonnistui", + "upload.error.default": "Tiedostoa ei voitu lähettää", + "upload.error.extension": "Tiedostoa ei lähetetty tiedostopäätteen takia", + "upload.error.formSize": "Lähetetyn tiedoston koko ylittää lomakkeen sallitun ylärajan MAX_FILE_SIZE", + "upload.error.iniPostSize": "Lähetetyn tiedoston koko ylittää sallitun ylärajan post_max_size asetustiedostossa php.ini", + "upload.error.iniSize": "Lähetetyn tiedoston koko ylittää sallitun ylärajan upload_max_filesize asetustiedostossa php.ini", + "upload.error.noFile": "Tiedostoa ei lähetetty", + "upload.error.noFiles": "Tiedostoja ei lähetetty", + "upload.error.partial": "Tiedoston lähetys onnistui vain osittain", + "upload.error.tmpDir": "Väliaikainen hakemisto puuttuu", + "upload.errors": "Virhe", + "upload.progress": "Lähetetään...", + + "url": "Url", + "url.placeholder": "https://esimerkki.fi", + + "user": "Käyttäjä", + "user.blueprint": "Voit määrittää lisää osioita ja lomakekenttiä tälle käyttäjälle suunnitelmassa /site/blueprints/users/{blueprint}.yml", + "user.changeEmail": "Muuta sähköpostiosoite", + "user.changeLanguage": "Vaihda kieli", + "user.changeName": "Nimeä uudelleen", + "user.changePassword": "Vaihda salasana", + "user.changePassword.new": "Uusi salasana", + "user.changePassword.new.confirm": "Vahvista uusi salasana...", + "user.changeRole": "Muuta käyttäjätasoa", + "user.changeRole.select": "Valitse uusi käyttäjätaso", + "user.create": "Lisää uusi käyttäjä", + "user.delete": "Poista tämä käyttäjä", + "user.delete.confirm": "Haluatko varmsti poistaa käyttäjän
{email}?", + + "users": "Käyttäjät", + + "version": "Versio", + + "view.account": "Oma käyttäjätili", + "view.installation": "Asennus", + "view.languages": "Kielet", + "view.resetPassword": "Aseta salasana", + "view.site": "Sivusto", + "view.system": "Järjestelmä", + "view.users": "K\u00e4ytt\u00e4j\u00e4t", + + "welcome": "Tervetuloa", + "year": "Vuosi", + "yes": "kyllä" } diff --git a/kirby/i18n/translations/fr.json b/kirby/i18n/translations/fr.json index 358ff06..40c5b6f 100644 --- a/kirby/i18n/translations/fr.json +++ b/kirby/i18n/translations/fr.json @@ -1,730 +1,574 @@ { - "account.changeName": "Modifier votre nom", - "account.delete": "Supprimer votre compte", - "account.delete.confirm": "Voulez-vous vraiment supprimer votre compte ? Vous serez déconnecté immédiatement. Votre compte ne pourra pas être récupéré.", - - "activate": "Activer", - "add": "Ajouter", - "alpha": "Alpha", - "author": "Auteur", - "avatar": "Image de profil", - "back": "Retour", - "cancel": "Annuler", - "change": "Changer", - "close": "Fermer", - "changes": "Modifications", - "confirm": "Ok", - "collapse": "Replier", - "collapse.all": "Tout replier", - "color": "Couleur", - "coordinates": "Coordonnées", - "copy": "Copier", - "copy.all": "Tout copier", - "copy.success": "Copié : {count}", - "create": "Créer", - "custom": "Personnalisé", - - "date": "Date", - "date.select": "Choisir une date", - - "day": "Jour", - "days.fri": "Ven", - "days.mon": "Lun", - "days.sat": "Sam", - "days.sun": "Dim", - "days.thu": "Jeu", - "days.tue": "Mar", - "days.wed": "Mer", - - "debugging": "Débogage", - - "delete": "Supprimer", - "delete.all": "Tout supprimer", - - "dialog.fields.empty": "Ce dialogue ne comporte aucun champ", - "dialog.files.empty": "Aucun fichier à sélectionner", - "dialog.pages.empty": "Aucune page à sélectionner", - "dialog.text.empty": "Ce dialogue ne définit aucun texte", - "dialog.users.empty": "Aucun utilisateur à sélectionner", - - "dimensions": "Dimensions", - "disable": "Désactiver", - "disabled": "Désactivé", - "discard": "Supprimer", - - "drawer.fields.empty": "Ce tiroir ne comporte aucun champ", - - "domain": "Domaine", - "download": "Télécharger", - "duplicate": "Dupliquer", - - "edit": "Éditer", - - "email": "Courriel", - "email.placeholder": "mail@example.com", - - "enter": "Entrer", - "entries": "Entrées", - "entry": "Entrée", - - "environment": "Environnement", - - "error": "Erreur", - "error.access.code": "Code incorrect", - "error.access.login": "Identifiant incorrect", - "error.access.panel": "Vous n’êtes pas autorisé à accéder au Panel", - "error.access.view": "Vous n’êtes pas autorisé à accéder à cette section du Panel", - - "error.avatar.create.fail": "L’image du profil n’a pu être transférée", - "error.avatar.delete.fail": "L’image du profil n’a pu être supprimée", - "error.avatar.dimensions.invalid": "Veuillez choisir une image de profil de largeur et hauteur inférieures à 3000 pixels", - "error.avatar.mime.forbidden": "L'image du profil utilisateur doit être un fichier JPEG ou PNG", - - "error.blueprint.notFound": "Le blueprint « {name} » n’a pu être chargé", - - "error.blocks.max.plural": "Vous ne devez pas ajouter plus de {max} blocs", - "error.blocks.max.singular": "Vous ne devez pas ajouter plus d'un bloc", - "error.blocks.min.plural": "Vous devez ajouter au moins {min} blocs", - "error.blocks.min.singular": "Vous devez ajouter au moins un bloc", - "error.blocks.validation": "Il y a une erreur sur le champ « {field} » du bloc {index} utilisant le type de bloc « {fieldset} »", - - "error.cache.type.invalid": "Type de cache invalide « {type} »", - - "error.email.preset.notFound": "La configuration de courriel « {name} » n’a pu être trouvé ", - - "error.field.converter.invalid": "Convertisseur « {converter} » invalide", - "error.field.type.missing": "Champ « { name } » : Le type de champ « { type } » n’existe pas", - - "error.file.changeName.empty": "Le nom ne peut être vide", - "error.file.changeName.permission": "Vous n’êtes pas autorisé à modifier le nom de « {filename} »", - "error.file.changeTemplate.invalid": "Le modèle du fichier « {id} » ne peut être modifié en « {template} » (valide : « {blueprints} »)", - "error.file.changeTemplate.permission": "Vous n’êtes pas autorisé à changer le modèle du fichier « {id} »", - - "error.file.duplicate": "Un fichier nommé « {filename} » existe déjà", - "error.file.extension.forbidden": "L’extension « {extension} » n’est pas autorisée", - "error.file.extension.invalid": "Extension incorrecte : {extension}", - "error.file.extension.missing": "L’extension pour « {filename} » est manquante", - "error.file.maxheight": "La hauteur de l'image ne doit pas excéder {height} pixels", - "error.file.maxsize": "Le fichier est trop volumineux", - "error.file.maxwidth": "La largeur de l’image ne doit pas excéder {width} pixels", - "error.file.mime.differs": "Le fichier transféré doit être du même type de média « {mime} »", - "error.file.mime.forbidden": "Le type de média « {mime} » n’est pas autorisé", - "error.file.mime.invalid": "Type de média invalide : {mime}", - "error.file.mime.missing": "Le type de média de « {filename} » n’a pu être détecté", - "error.file.minheight": "La hauteur de l’image doit être au moins {height} pixels", - "error.file.minsize": "Le fichier n’est pas assez volumineux", - "error.file.minwidth": "La largeur de l’image doit être au moins {width} pixels", - "error.file.name.unique": "Le nom de fichier doit être unique", - "error.file.name.missing": "Veuillez entrer un titre", - "error.file.notFound": "Le fichier « {filename} » n’a pu être trouvé", - "error.file.orientation": "L’orientation de l'image doit être « {orientation} »", - "error.file.type.forbidden": "Vous n’êtes pas autorisé à transférer des fichiers {type}", - "error.file.type.invalid": "Type de fichier invalide : {type}", - "error.file.undefined": "Le fichier n’a pu être trouvé", - - "error.form.incomplete": "Veuillez corriger toutes les erreurs du formulaire…", - "error.form.notSaved": "Le formulaire n’a pu être enregistré", - - "error.language.code": "Veuillez saisir un code correct pour cette langue", - "error.language.duplicate": "Cette langue existe déjà", - "error.language.name": "Veuillez saisir un nom correct pour cette langue", - "error.language.notFound": "La langue n’a pu être trouvée", - - "error.layout.validation.block": "Il y a une erreur sur le champ « {field} » du bloc {blockIndex} utilisant le type de bloc « {fieldset} » dans le layout {layoutIndex}.", - "error.layout.validation.settings": "Il y a une erreur dans les paramètres de la disposition {index}", - - "error.license.domain": "Le domaine de la licence est manquant", - "error.license.email": "Veuillez saisir un courriel correct", - "error.license.format": "Veuillez saisir un numéro de licence valide", - "error.license.verification": "La licence n’a pu être vérifiée", - - "error.login.totp.confirm.invalid": "Code invalide", - "error.login.totp.confirm.missing": "Veuillez saisir le code actuel", - - "error.object.validation": "Il y a une erreur dans le champ « {label} » :\n{message}", - - "error.offline": "Le Panel est actuellement hors ligne", - - "error.page.changeSlug.permission": "Vous n’êtes pas autorisé à modifier l’identifiant d’URL pour « {slug} »", - "error.page.changeSlug.reserved": "Le chemin des pages de premier niveau ne doit pas commencer par « {path} »", - "error.page.changeStatus.incomplete": "La page comporte des erreurs et ne peut pas être publiée", - "error.page.changeStatus.permission": "Le statut de cette page ne peut être modifié", - "error.page.changeStatus.toDraft.invalid": "La page « {slug} » ne peut être convertie en brouillon", - "error.page.changeTemplate.invalid": "Le modèle de la page « {slug} » ne peut être changé", - "error.page.changeTemplate.permission": "Vous n’êtes pas autorisé à changer le modèle de « {slug} »", - "error.page.changeTitle.empty": "Le titre ne peut être vide", - "error.page.changeTitle.permission": "Vous n’êtes pas autorisé à modifier le titre de « {slug} »", - "error.page.create.permission": "Vous n’êtes pas autorisé à créer « {slug} »", - "error.page.delete": "La page « {slug} » ne peut être supprimée", - "error.page.delete.confirm": "Veuillez saisir le titre de la page pour confirmer", - "error.page.delete.hasChildren": "La page comporte des sous-pages et ne peut pas être supprimée", - "error.page.delete.permission": "Vous n’êtes pas autorisé à supprimer « {slug} »", - "error.page.draft.duplicate": "Un brouillon avec l’identifiant d’URL « {slug} » existe déjà", - "error.page.duplicate": "Une page avec l’identifiant d’URL « {slug} » existe déjà", - "error.page.duplicate.permission": "Vous n’êtes pas autorisé à dupliquer « {slug} »", - "error.page.move.ancestor": "La page ne peut être déplacée à l’intérieur d’elle-même", - "error.page.move.directory": "Le répertoire de la page ne peut être déplacé", - "error.page.move.duplicate": "Une sous-page possédant l’identifiant d’URL « {slug} » existe déjà", - "error.page.move.notFound": "La page déplacée n’a pu être trouvée", - "error.page.move.permission": "Vous n’êtes pas autorisé à déplacer « {slug} » ", - "error.page.move.template": "Le modèle « {template} » n’est pas accepté en tant que sous-page de « {parent} »", - "error.page.notFound": "La page « {slug} » n’a pu être trouvée", - "error.page.num.invalid": "Veuillez saisir un numéro de position correct. Les numéros ne doivent pas être négatifs.", - "error.page.slug.invalid": "Veuillez entrer un identifiant d’URL correct", - "error.page.slug.maxlength": "L’identifiant d’URL doit faire moins de « {length} » caractères", - "error.page.sort.permission": "La page « {slug} » ne peut être réordonnée", - "error.page.status.invalid": "Veuillez choisir un statut de page correct", - "error.page.undefined": "La page n’a pu être trouvée", - "error.page.update.permission": "Vous n’êtes pas autorisé à modifier « {slug} »", - - "error.section.files.max.plural": "Vous ne pouvez ajouter plus de {max} fichier(s) à la section « {section} »", - "error.section.files.max.singular": "Vous ne pouvez ajouter plus d’un fichier à la section « {section} »", - "error.section.files.min.plural": "La section « {section} » requiert au moins {min} fichiers", - "error.section.files.min.singular": "La section « {section} » requiert au moins un fichier", - - "error.section.pages.max.plural": "Vous ne pouvez ajouter plus de {max} pages à la section « {section} »", - "error.section.pages.max.singular": "Vous ne pouvez ajouter plus d’une page à la section « {section} »", - "error.section.pages.min.plural": "La section « {section} » requiert au moins {min} pages", - "error.section.pages.min.singular": "La section « {section} » requiert au moins une page", - - "error.section.notLoaded": "La section « {name} » n’a pu être chargée", - "error.section.type.invalid": "Le type de section « {type} » est incorrect", - - "error.site.changeTitle.empty": "Le titre ne peut être vide", - "error.site.changeTitle.permission": "Vous n’êtes pas autorisé à modifier le titre du site", - "error.site.update.permission": "Vous n’êtes pas autorisé à modifier le contenu global du site", - - "error.structure.validation": "Il y a une erreur dans le champ « {field} » de la rangée {index}", - - "error.template.default.notFound": "Le modèle par défaut n’existe pas", - - "error.unexpected": "Une erreur inattendue est survenue ! Activez le mode de débogage pour plus d’informations : https://getkirby.com/docs/reference/system/options/debug", - - "error.user.changeEmail.permission": "Vous n’êtes pas autorisé à modifier le courriel de l’utilisateur « {name} »", - "error.user.changeLanguage.permission": "Vous n’êtes pas autorisé à changer la langue de l’utilisateur « {name} »", - "error.user.changeName.permission": "Vous n’êtes pas autorisé à modifier le nom de l’utilisateur « {name} »", - "error.user.changePassword.permission": "Vous n’êtes pas autorisé à changer le mot de passe de l’utilisateur « {name} »", - "error.user.changeRole.lastAdmin": "Le rôle du dernier administrateur ne peut être modifié", - "error.user.changeRole.permission": "Vous n’êtes pas autorisé à changer le rôle de l’utilisateur « {name} »", - "error.user.changeRole.toAdmin": "Vous n’êtes pas autorisé à attribuer le rôle d’administrateur aux utilisateurs", - "error.user.create.permission": "Vous n’êtes pas autorisé à créer cet utilisateur", - "error.user.delete": "L’utilisateur « {name} » ne peut être supprimé", - "error.user.delete.lastAdmin": "Le dernier administrateur ne peut être supprimé", - "error.user.delete.lastUser": "Le dernier utilisateur ne peut être supprimé", - "error.user.delete.permission": "Vous n’êtes pas autorisé à supprimer l’utilisateur « {name} »", - "error.user.duplicate": "Un utilisateur avec le courriel « {email} » existe déjà", - "error.user.email.invalid": "Veuillez saisir un courriel correct", - "error.user.language.invalid": "Veuillez saisir une langue correcte", - "error.user.notFound": "L’utilisateur « {name} » n’a pu être trouvé", - "error.user.password.excessive": "Veuillez entrer un mot de passe valide. Les mots de passe ne doivent pas dépasser 1000 caractères de long.", - "error.user.password.invalid": "Veuillez saisir un mot de passe valide. Les mots de passe doivent comporter au moins 8 caractères.", - "error.user.password.notSame": "Les mots de passe ne sont pas identiques", - "error.user.password.undefined": "Cet utilisateur n’a pas de mot de passe", - "error.user.password.wrong": "Mot de passe incorrect", - "error.user.role.invalid": "Veuillez saisir un rôle correct", - "error.user.undefined": "L’utilisateur n’a pu être trouvé", - "error.user.update.permission": "Vous n’êtes pas autorisé à modifier l’utilisateur « {name} »", - - "error.validation.accepted": "Veuillez confirmer", - "error.validation.alpha": "Veuillez saisir uniquement des caractères alphabétiques minuscules", - "error.validation.alphanum": "Veuillez ne saisir que des minuscules de a à z et des chiffres de 0 à 9", - "error.validation.anchor": "Veuillez entrer un lien ancré correct", - "error.validation.between": "Veuillez saisir une valeur entre « {min} » et « {max} »", - "error.validation.boolean": "Veuillez confirmer ou refuser", - "error.validation.color": "Veuillez entrer une couleur valide dans le format {format}", - "error.validation.contains": "Veuillez saisir une valeur contenant « {needle} »", - "error.validation.date": "Veuillez saisir une date correcte", - "error.validation.date.after": "Veuillez saisir une date après {date}", - "error.validation.date.before": "Veuillez saisir une date avant {date}", - "error.validation.date.between": "Veuillez saisir une date entre {min} et {max}", - "error.validation.denied": "Veuillez refuser", - "error.validation.different": "La valeur ne doit pas être « {other} »", - "error.validation.email": "Veuillez saisir un courriel correct", - "error.validation.endswith": "La valeur doit se terminer par « {end} »", - "error.validation.filename": "Veuillez saisir un nom de fichier correct", - "error.validation.in": "Veuillez saisir l’un des éléments suivants: ({in})", - "error.validation.integer": "Veuillez saisir un entier correct", - "error.validation.ip": "Veuillez saisir une adresse IP correcte", - "error.validation.less": "Veuillez saisir une valeur inférieure à {max}", - "error.validation.linkType": "Le type de lien n’est pas autorisé", - "error.validation.match": "La valeur ne correspond pas au modèle attendu", - "error.validation.max": "Veuillez saisir une valeur inférieure ou égale à {max}", - "error.validation.maxlength": "Veuillez saisir une valeur plus courte (max. {max} caractères)", - "error.validation.maxwords": "Veuillez ne pas saisir plus de {max} mot(s)", - "error.validation.min": "Veuillez saisir une valeur supérieure ou égale à {min}", - "error.validation.minlength": "Veuillez saisir une valeur plus longue (min. {min} caractères)", - "error.validation.minwords": "Veuillez saisir au moins {min} mot(s)", - "error.validation.more": "Veuillez saisir une valeur supérieure à {min}", - "error.validation.notcontains": "Veuillez saisir une valeur ne contenant pas « {needle} »", - "error.validation.notin": "Veuillez ne saisir aucun des éléments suivants: ({notIn})", - "error.validation.option": "Veuillez sélectionner une option correcte", - "error.validation.num": "Veuillez saisir un nombre correct", - "error.validation.required": "Veuillez saisir quelque chose", - "error.validation.same": "Veuillez saisir « {other} »", - "error.validation.size": "La grandeur de la valeur doit être « {size} »", - "error.validation.startswith": "La valeur doit commencer par « {start} »", - "error.validation.tel": "Veuillez saisir un numéro de téléphone non formaté", - "error.validation.time": "Veuillez saisir une heure correcte", - "error.validation.time.after": "Veuillez saisir une heure après {time}", - "error.validation.time.before": "Veuillez saisir une heure avant {time}", - "error.validation.time.between": "Veuillez saisir une heure entre {min} et {max}", - "error.validation.uuid": "Veuillez saisir un UUID valide", - "error.validation.url": "Veuillez saisir une URL correcte", - - "expand": "Déplier", - "expand.all": "Tout déplier", - - "field.invalid": "Le champ est invalide", - "field.required": "Le champ est obligatoire", - "field.blocks.changeType": "Changer le type", - "field.blocks.code.name": "Code", - "field.blocks.code.language": "Langue", - "field.blocks.code.placeholder": "Votre code…", - "field.blocks.delete.confirm": "Voulez-vous vraiment supprimer ce bloc ?", - "field.blocks.delete.confirm.all": "Voulez-vous vraiment supprimer tous les blocs ?", - "field.blocks.delete.confirm.selected": "Voulez-vous vraiment supprimer les blocs sélectionnés ?", - "field.blocks.empty": "Pas encore de blocs", - "field.blocks.fieldsets.empty": "Pas encore d‘ensembles de champs", - "field.blocks.fieldsets.label": "Veuillez sélectionner un type de bloc…", - "field.blocks.fieldsets.paste": "Pressez {{ shortcut }} pour importer des dispositions ou blocs depuis votre presse-papier Seuls ceux autorisés dans le champ actuel seront insérés.", - "field.blocks.gallery.name": "Galerie", - "field.blocks.gallery.images.empty": "Pas encore d’images", - "field.blocks.gallery.images.label": "Images", - "field.blocks.heading.level": "Niveau", - "field.blocks.heading.name": "Titre", - "field.blocks.heading.text": "Texte", - "field.blocks.heading.placeholder": "Titre…", - "field.blocks.image.alt": "Texte alternatif", - "field.blocks.image.caption": "Légende", - "field.blocks.image.crop": "Recadrer", - "field.blocks.image.link": "Lien", - "field.blocks.image.location": "Emplacement", - "field.blocks.image.location.internal": "Ce site web", - "field.blocks.image.location.external": "Source externe", - "field.blocks.image.name": "Image", - "field.blocks.image.placeholder": "Sélectionnez une image", - "field.blocks.image.ratio": "Proportions", - "field.blocks.image.url": "URL de l’image", - "field.blocks.line.name": "Ligne", - "field.blocks.list.name": "Liste", - "field.blocks.markdown.name": "Markdown", - "field.blocks.markdown.label": "Texte", - "field.blocks.markdown.placeholder": "Markdown…", - "field.blocks.quote.name": "Citation", - "field.blocks.quote.text.label": "Texte", - "field.blocks.quote.text.placeholder": "Citation…", - "field.blocks.quote.citation.label": "Citation", - "field.blocks.quote.citation.placeholder": "par…", - "field.blocks.text.name": "Texte", - "field.blocks.text.placeholder": "Texte…", - "field.blocks.video.autoplay": "Lecture automatique", - "field.blocks.video.caption": "Légende", - "field.blocks.video.controls": "Contrôles", - "field.blocks.video.location": "Emplacement", - "field.blocks.video.loop": "Boucle", - "field.blocks.video.muted": "Muet", - "field.blocks.video.name": "Vidéo", - "field.blocks.video.placeholder": "Saisissez l’URL d’une vidéo", - "field.blocks.video.poster": "Vignette", - "field.blocks.video.preload": "Préchargement", - "field.blocks.video.url.label": "URL de la vidéo", - "field.blocks.video.url.placeholder": "https://youtube.com/?v=", - - "field.files.empty": "Pas encore de fichier sélectionné", - - "field.layout.change": "Changer de disposition", - "field.layout.delete": "Supprimer cette disposition", - "field.layout.delete.confirm": "Voulez-vous vraiment supprimer cette disposition ?", - "field.layout.delete.confirm.all": "Voulez-vous vraiment supprimer toutes les dispositions ?", - "field.layout.empty": "Pas encore de rangées", - "field.layout.select": "Choisir une disposition", - - "field.object.empty": "Pas encore d‘information", - - "field.pages.empty": "Pas encore de page sélectionnée", - - "field.structure.delete.confirm": "Voulez-vous vraiment supprimer cette ligne ?", - "field.structure.delete.confirm.all": "Voulez-vous vraiment supprimer toutes les entrées ?", - "field.structure.empty": "Pas encore d’entrée", - - "field.users.empty": "Pas encore d’utilisateur sélectionné", - - "fields.empty": "Pas encore de champs", - - "file": "Fichier", - "file.blueprint": "Ce fichier n’a pas encore de blueprint. Vous pouvez en définir les paramètres dans /site/blueprints/files/{blueprint}.yml", - "file.changeTemplate": "Changer de modèle", - "file.changeTemplate.notice": "Modifier le modèle du fichier supprimera le contenu des champs dont le type ne correspond pas. Si le nouveau modèle définit certaines règles, par exemple les dimensions des images, celles-ci seront également appliquées de manière irréversible. Utilisez avec précaution.", - "file.delete.confirm": "Voulez-vous vraiment supprimer
{filename} ?", - "file.focus.placeholder": "Définir le point focal", - "file.focus.reset": "Supprimer le point focal", - "file.focus.title": "Point focal", - "file.sort": "Modifier la position", - - "files": "Fichiers", - "files.empty": "Pas encore de fichier", - - "filter": "Filtrer", - - "hide": "Masquer", - "hour": "Heure", - "hue": "Teinte", - "import": "Importer", - "info": "Info", - "insert": "Insérer", - "insert.after": "Insérer après", - "insert.before": "Insérer avant", - "install": "Installer", - - "installation": "Installation", - "installation.completed": "Le Panel a été installé", - "installation.disabled": "L’installation du Panel est désactivée par défaut sur les serveurs publics. Veuillez lancer l’installation sur un serveur local, ou activez-la avec l’option panel.install.", - "installation.issues.accounts": "Le dossier /site/accounts n’existe pas ou n’est pas accessible en écriture", - "installation.issues.content": "Le dossier /content n’existe pas ou n’est pas accessible en écriture", - "installation.issues.curl": "L’extension CURL est requise", - "installation.issues.headline": "Le Panel ne peut être installé", - "installation.issues.mbstring": "L’extension MB String est requise", - "installation.issues.media": "Le dossier /media n’existe pas ou n’est pas accessible en écriture", - "installation.issues.php": "Veuillez utiliser PHP 8+", - "installation.issues.sessions": "Le dossier /site/sessions n’existe pas ou n’est pas accessible en écriture", - - "language": "Langue", - "language.code": "Code", - "language.convert": "Choisir comme langue par défaut", - "language.convert.confirm": "

Souhaitez-vous vraiment convertir {name} vers la langue par défaut ? Cette action ne peut pas être annulée.

Si {name} a un contenu non traduit, il n’y aura plus de solution de secours possible et certaines parties de votre site pourraient être vides.

", - "language.create": "Ajouter une nouvelle langue", - "language.default": "Langue par défaut", - "language.delete.confirm": "Voulez-vous vraiment supprimer la langue {name}, ainsi que toutes ses traductions ? Cette action ne peut être annulée !", - "language.deleted": "La langue a été supprimée", - "language.direction": "Sens de lecture", - "language.direction.ltr": "De gauche à droite", - "language.direction.rtl": "De droite à gauche", - "language.locale": "Locales PHP", - "language.locale.warning": "Vous utilisez une Locale PHP personnalisée. Veuillez la modifier dans le fichier de langue situé dans /site/languages", - "language.name": "Nom", - "language.secondary": "Langue secondaire", - "language.settings": "Préférences de langue", - "language.updated": "La langue a été mise à jour", - "language.variables": "Variables de langue", - "language.variables.empty": "Pas encore de traductions", - - "language.variable.delete.confirm": "Voulez-vous vraiment supprimer la variable pour {key} ?", - "language.variable.key": "Clé", - "language.variable.notFound": "La variable n’a pu être trouvée", - "language.variable.value": "Valeur", - - "languages": "Langages", - "languages.default": "Langue par défaut", - "languages.empty": "Il n’y a pas encore de langues", - "languages.secondary": "Langues secondaires", - "languages.secondary.empty": "Il n’y a pas encore de langues secondaires", - - "license": "Licence", - "license.activate": "Activer maintenant", - "license.activate.label": "Veuillez activer votre licence", - "license.activate.domain": "Votre licence sera activée pour {host}.", - "license.activate.local": "Vous êtes sur le point d‘activer votre licence de Kirby pour votre domaine local {host}. Si ce site doit être activé sur un domaine publique, veuillez plutôt l‘activer là-bas. Si {host} est bien le domaine pour lequel vous voulez activer votre licence, veuillez continuer.", - "license.activated": "Activée", - "license.buy": "Acheter une licence", - "license.code": "Code", - "license.code.help": "Vous avez reçu votre code de licence par courriel après l‘achat. Veuillez le copier et le coller ici.", - "license.code.label": "Veuillez saisir votre numéro de licence", - "license.status.active.info": "Inclut les nouvelles versions majeures jusqu’au {date}", - "license.status.active.label": "Licence valide", - "license.status.demo.info": "Ceci est une installation de démonstration", - "license.status.demo.label": "Démonstration", - "license.status.inactive.info": "Renouveler la licence pour mettre à jour vers les nouvelles versions majeures", - "license.status.inactive.label": "Pas de nouvelles versions majeures", - "license.status.legacy.bubble": "Prêt à renouveler votre licence ?", - "license.status.legacy.info": "Votre licence ne couvre pas cette version", - "license.status.legacy.label": "Veuillez renouveler votre licence", - "license.status.missing.bubble": "Prêt à lancer votre site ?", - "license.status.missing.info": "Pas de licence valide", - "license.status.missing.label": "Veuillez activer votre licence", - "license.manage": "Gérer vos licences", - "license.purchased": "Achetée", - "license.success": "Merci pour votre soutien à Kirby", - "license.unregistered.label": "Non enregistré", - - "link": "Lien", - "link.text": "Texte du lien", - - "loading": "Chargement", - - "lock.unsaved": "Modifications non enregistrées", - "lock.unsaved.empty": "Il n’y a plus de modifications non enregistrées", - "lock.isLocked": "Modifications non enregistrées par {email}", - "lock.unlock": "Déverrouiller", - "lock.unlock.submit": "Déverrouiller et écraser les modifications non enregistrées par {email}", - "lock.isUnlocked": "A été déverrouillé par un autre utilisateur", - - "login": "Connexion", - "login.code.label.login": "Code de connexion", - "login.code.label.password-reset": "Code de réinitialisation du mot de passe", - "login.code.placeholder.email": "000 000", - "login.code.placeholder.totp": "000000", - "login.code.text.email": "Si votre adresse de courriel est enregistrée, le code demandé vous sera envoyé par courriel.", - "login.code.text.totp": "Veuillez saisir le code à usage unique de votre application d‘authentification", - "login.email.login.body": "Bonjour {user.nameOrEmail},\n\nVous avez récemment demandé un code de connexion pour le Panel de {site}.\nLe code de connexion suivant sera valable pendant {timeout} minutes :\n\n{code}\n\nSi vous n’avez pas demandé de code de connexion, veuillez ignorer cet email ou contacter votre administrateur si vous avez des questions.\nPar sécurité, merci de ne PAS faire suivre cet email.", - "login.email.login.subject": "Votre code de connexion", - "login.email.password-reset.body": "Bonjour {user.nameOrEmail},\n\nVous avez récemment demandé un code de réinitialisation de mot de passe pour le Panel de {site}.\nLe code de réinitialisation de mot de passe suivant sera valable pendant {timeout} minutes :\n\n{code}\n\nSi vous n’avez pas demandé de code de réinitialisation de mot de passe, veuillez ignorer cet email ou contacter votre administrateur si vous avez des questions.\nPar sécurité, merci de ne PAS faire suivre ce courriel.", - "login.email.password-reset.subject": "Votre code de réinitialisation du mot de passe", - "login.remember": "Rester connecté", - "login.reset": "Réinitialiser le mot de passe", - "login.toggleText.code.email": "Se connecter par courriel", - "login.toggleText.code.email-password": "Se connecter avec un mot de passe", - "login.toggleText.password-reset.email": "Mot de passe oublié ?", - "login.toggleText.password-reset.email-password": "← Retour à la connexion", - "login.totp.enable.option": "Configurer les codes à usage unique", - "login.totp.enable.intro": "Les applications d’authentification peuvent générer des codes à usage unique qui sont utilisés comme second facteur lors de la connexion à votre compte.", - "login.totp.enable.qr.label": "1. Scannez ce QR code", - "login.totp.enable.qr.help": "Impossible de scanner ? Ajoutez la clé de configuration {secret} manuellement à votre application d’authentification..", - "login.totp.enable.confirm.headline": "2. Confirmez avec le code généré", - "login.totp.enable.confirm.text": "Votre application génère un nouveau code à usage unique toutes les 30 secondes. Saisissez le code actuel pour terminer la configuration :", - "login.totp.enable.confirm.label": "Code actuel", - "login.totp.enable.confirm.help": "Après cette configuration, nous vous demanderons un code à usage unique à chaque connexion.", - "login.totp.enable.success": "Codes à usage unique activés", - "login.totp.disable.option": "Désactiver les codes à usage unique", - "login.totp.disable.label": "Saisissez votre mot de passe pour désactiver les codes à usage unique.", - "login.totp.disable.help": "Un second facteur différent, par exemple un code de connexion envoyé par courriel, vous sera demandé à la connexion. Vous pourrez à nouveau configurer les codes à usage unique ultérieurement.", - "login.totp.disable.admin": "

Cela désactivera les codes à usage unique pour {user}.

Un second facteur différent, par exemple un code de connexion envoyé par courriel lui sera demandé à la connexion. {user} pourra à nouveau configurer les codes à usage unique ultérieurement.

", - "login.totp.disable.success": "Codes à usage unique désactivés", - - "logout": "Déconnexion", - - "merge": "Fusionner", - "menu": "Menu", - "meridiem": "AM/PM", - "mime": "Type de médias", - "minutes": "Minutes", - - "month": "Mois", - "months.april": "Avril", - "months.august": "Août", - "months.december": "Décembre", - "months.february": "Février", - "months.january": "Janvier", - "months.july": "Juillet", - "months.june": "Juin", - "months.march": "Mars", - "months.may": "Mai", - "months.november": "Novembre", - "months.october": "Octobre", - "months.september": "Septembre", - - "more": "Plus", - "move": "Déplacer", - "name": "Nom", - "next": "Suivant", - "night": "Nuit", - "no": "non", - "off": "off", - "on": "on", - "open": "Ouvrir", - "open.newWindow": "Ouvrir dans une nouvelle fenêtre", - "option": "Option", - "options": "Options", - "options.none": "Pas d’options", - "options.all": "Afficher toutes les options de {count}", - - "orientation": "Orientation", - "orientation.landscape": "Paysage", - "orientation.portrait": "Portrait", - "orientation.square": "Carré", - - "page": "Page", - "page.blueprint": "Cette page n’a pas encore de blueprint. Vous pouvez en définir les paramètres dans /site/blueprints/pages/{blueprint}.yml", - "page.changeSlug": "Modifier l’URL", - "page.changeSlug.fromTitle": "Créer à partir du titre", - "page.changeStatus": "Changer le statut", - "page.changeStatus.position": "Veuillez sélectionner une position", - "page.changeStatus.select": "Sélectionner un nouveau statut", - "page.changeTemplate": "Changer de modèle", - "page.changeTemplate.notice": "Modifier le modèle de la page supprimera le contenu des champs dont le type ne correspond pas. Utilisez avec précaution.", - "page.create": "Créer en tant que {status}", - "page.delete.confirm": "Voulez-vous vraiment supprimer {title} ?", - "page.delete.confirm.subpages": "Cette page contient des sous-pages.
Toutes les sous-pages seront également supprimées.", - "page.delete.confirm.title": "Veuillez saisir le titre de la page pour confirmer", - "page.duplicate.appendix": "Copier", - "page.duplicate.files": "Copier les fichiers", - "page.duplicate.pages": "Copier les pages", - "page.move": "Déplacer la page", - "page.sort": "Modifier la position", - "page.status": "Statut", - "page.status.draft": "Brouillon", - "page.status.draft.description": "La page est accessible uniquement pour les éditeurs connectés ou via un lien secret", - "page.status.listed": "Public", - "page.status.listed.description": "La page est accessible par tout le monde", - "page.status.unlisted": "Non listé", - "page.status.unlisted.description": "La page est accessible uniquement par son URL", - - "pages": "Pages", - "pages.empty": "Pas encore de pages", - "pages.status.draft": "Brouillons", - "pages.status.listed": "Publié", - "pages.status.unlisted": "Non listé", - - "pagination.page": "Page", - - "password": "Mot de passe", - "paste": "Coller", - "paste.after": "Coller après", - "paste.success": "Copié : {count}", - "pixel": "Pixel", - "plugin": "Plugin", - "plugins": "Plugins", - "prev": "Précédent", - "preview": "Prévisualiser", - "remove": "Supprimer", - "rename": "Renommer", - "renew": "Renouveler", - "replace": "Remplacer", - "replace.with": "Remplacer par", - "retry": "Essayer à nouveau", - "revert": "Revenir", - "revert.confirm": "Voulez-vous vraiment supprimer toutes les modifications non enregistrées ?", - - "role": "Rôle", - "role.admin.description": "L’administrateur dispose de tous les droits", - "role.admin.title": "Administrateur", - "role.all": "Tous", - "role.empty": "Il n’y a aucun utilisateur avec ce rôle", - "role.description.placeholder": "Pas de description", - "role.nobody.description": "Ceci est un rôle de secours sans aucune permission.", - "role.nobody.title": "Personne", - - "save": "Enregistrer", - "search": "Rechercher", - "search.min": "Saisissez {min} caractères pour rechercher", - "search.all": "Afficher tous les résultats de {count}", - "search.results.none": "Pas de résultats", - - "section.invalid": "La section est invalide", - "section.required": "Cette section est obligatoire", - - "security": "Sécurité", - "select": "Sélectionner", - "server": "Serveur", - "settings": "Paramètres", - "show": "Afficher", - "site.blueprint": "Ce site n’a pas encore de blueprint. Vous pouvez en définir les paramètres dans /site/blueprints/site.yml", - "size": "Poids", - "slug": "Identifiant de l’URL", - "sort": "Trier", - "sort.drag": "Déplacer pour réordonner…", - "split": "Diviser", - - "stats.empty": "Aucun rapport", - "status": "Statut", - - "system.info.copy": "Copy info", - "system.info.copied": "System info copied", - "system.issues.content": "Le dossier content semble exposé", - "system.issues.eol.kirby": "La version de Kirby installée a atteint la fin de son cycle de vie et ne recevra plus de mises à jour de sécurité", - "system.issues.eol.plugin": "La version du plugin { plugin } installée a atteint la fin de son cycle de vie et ne recevra plus de mises à jour de sécurité", - "system.issues.eol.php": "Votre version de PHP installée { release } a atteint la fin de son cycle de vie et ne recevra plus de mises à jour de sécurité", - "system.issues.debug": "Le débogage doit être désactivé en production", - "system.issues.git": "Le dossier .git semble exposé", - "system.issues.https": "Nous recommandons HTTPS pour tous vos sites", - "system.issues.kirby": "Le dossier kirby semble exposé", - "system.issues.site": "Le dossier site semble exposé", - "system.issues.vulnerability.kirby": "Votre installation pourrait être affectée par la vulnérabilité suivante ({ severity } gravité) : { description }", - "system.issues.vulnerability.plugin": "Votre installation pourrait être affectée par la vulnérabilité suivante du plugin { plugin } ({ severity } gravité) : { description }", - "system.updateStatus": "Statut des mises à jour", - "system.updateStatus.error": "Les mises à jour n’ont pu être vérifiées", - "system.updateStatus.not-vulnerable": "Aucune vulnérabilité connue", - "system.updateStatus.security-update": "Mise à jour gratuite { version } disponible", - "system.updateStatus.security-upgrade": "Mise à jour { version } avec correctifs de sécurité disponible", - "system.updateStatus.unreleased": "Version non diffusée", - "system.updateStatus.up-to-date": "À jour", - "system.updateStatus.update": "Mise à jour gratuite { version } disponible", - "system.updateStatus.upgrade": "Mise à jour { version } disponible", - - "tel": "Téléphone", - "tel.placeholder": "+33123456789", - "template": "Modèle", - "title": "Titre", - "today": "Aujourd’hui", - - "toolbar.button.clear": "Supprimer la mise en forme", - "toolbar.button.code": "Code", - "toolbar.button.bold": "Gras", - "toolbar.button.email": "Courriel", - "toolbar.button.headings": "Titres", - "toolbar.button.heading.1": "Titre 1", - "toolbar.button.heading.2": "Titre 2", - "toolbar.button.heading.3": "Titre 3", - "toolbar.button.heading.4": "Titre 4", - "toolbar.button.heading.5": "Titre 5", - "toolbar.button.heading.6": "Titre 6", - "toolbar.button.italic": "Italique", - "toolbar.button.file": "Fichier", - "toolbar.button.file.select": "Sélectionner un fichier", - "toolbar.button.file.upload": "Transférer un fichier", - "toolbar.button.link": "Lien", - "toolbar.button.paragraph": "Paragraphe", - "toolbar.button.strike": "Barré", - "toolbar.button.sub": "Indice", - "toolbar.button.sup": "Exposant", - "toolbar.button.ol": "Liste ordonnée", - "toolbar.button.underline": "Souligné", - "toolbar.button.ul": "Liste non-ordonnée", - - "translation.author": "Kirby Team", - "translation.direction": "ltr", - "translation.name": "Français", - "translation.locale": "fr_FR", - - "type": "Type", - - "upload": "Transférer", - "upload.error.cantMove": "Le fichier transféré n’a pu être déplacé", - "upload.error.cantWrite": "Le fichier n’a pu être écrit sur le disque", - "upload.error.default": "Le fichier n’a pu être transféré", - "upload.error.extension": "Le transfert de fichier a été stoppé par une extension", - "upload.error.formSize": "Le fichier transféré excède la directive MAX_FILE_SIZE spécifiée dans le formulaire", - "upload.error.iniPostSize": "Le fichier transféré excède la directive post_max_size spécifiée dans php.ini", - "upload.error.iniSize": "Le fichier transféré excède la directive upload_max_filesize spécifiée dans php.ini", - "upload.error.noFile": "Aucun fichier n’a été transféré", - "upload.error.noFiles": "Aucun fichier n’a été transféré", - "upload.error.partial": "Le fichier n’a été que partiellement transféré", - "upload.error.tmpDir": "Un dossier temporaire est manquant", - "upload.errors": "Erreur", - "upload.progress": "Transfert en cours…", - - "url": "Url", - "url.placeholder": "https://example.com", - - "user": "Utilisateur", - "user.blueprint": "Vous pouvez définir de nouvelles sections et champs de formulaires pour ce rôle d’utilisateur dans /site/blueprints/users/{blueprint}.yml", - "user.changeEmail": "Modifier le courriel", - "user.changeLanguage": "Modifier la langue", - "user.changeName": "Renommer cet utilisateur", - "user.changePassword": "Modifier le mot de passe", - "user.changePassword.new": "Nouveau mot de passe", - "user.changePassword.new.confirm": "Confirmer le nouveau mot de passe…", - "user.changeRole": "Modifier le rôle", - "user.changeRole.select": "Sélectionner un nouveau rôle", - "user.create": "Ajouter un nouvel utilisateur", - "user.delete": "Supprimer cet utilisateur", - "user.delete.confirm": "Voulez-vous vraiment supprimer
{email} ?", - - "users": "Utilisateurs", - - "version": "Version", - "version.current": "Version actuelle", - "version.latest": "Dernière version", - "versionInformation": "Informations de version", - - "view.account": "Votre compte", - "view.installation": "Installation", - "view.languages": "Langues", - "view.resetPassword": "Réinitialiser le mot de passe", - "view.site": "Site", - "view.system": "Système", - "view.users": "Utilisateurs", - - "welcome": "Bienvenue", - "year": "Année", - "yes": "oui" + "account.changeName": "Modifier votre nom", + "account.delete": "Supprimer votre compte", + "account.delete.confirm": "Voulez-vous vraiment supprimer votre compte ? Vous serez déconnecté immédiatement. Votre compte ne pourra pas être récupéré.", + + "add": "Ajouter", + "author": "Auteur", + "avatar": "Image du profil", + "back": "Retour", + "cancel": "Annuler", + "change": "Changer", + "close": "Fermer", + "confirm": "Ok", + "collapse": "Replier", + "collapse.all": "Tout replier", + "copy": "Copier", + "copy.all": "Tout copier", + "create": "Créer", + + "date": "Date", + "date.select": "Choisir une date", + + "day": "Jour", + "days.fri": "Ven", + "days.mon": "Lun", + "days.sat": "Sam", + "days.sun": "Dim", + "days.thu": "Jeu", + "days.tue": "Mar", + "days.wed": "Mer", + + "debugging": "Débogage", + + "delete": "Supprimer", + "delete.all": "Tout supprimer", + + "dialog.files.empty": "Aucun fichier à sélectionner", + "dialog.pages.empty": "Aucune page à sélectionner", + "dialog.users.empty": "Aucun utilisateur à sélectionner", + + "dimensions": "Dimensions", + "disabled": "Désactivé", + "discard": "Supprimer", + "download": "Télécharger", + "duplicate": "Dupliquer", + + "edit": "Éditer", + + "email": "Courriel", + "email.placeholder": "mail@example.com", + + "entries": "Entrées", + "entry": "Entrée", + + "environment": "Environnement", + + "error.access.code": "Code incorrect", + "error.access.login": "Identifiant incorrect", + "error.access.panel": "Vous n’êtes pas autorisé à accéder au Panel", + "error.access.view": "Vous n’êtes pas autorisé à accéder à cette section du Panel", + + "error.avatar.create.fail": "L’image du profil n’a pu être transférée", + "error.avatar.delete.fail": "L’image du profil n’a pu être supprimée", + "error.avatar.dimensions.invalid": "Veuillez choisir une image de profil de largeur et hauteur inférieures à 3000 pixels", + "error.avatar.mime.forbidden": "L'image du profil utilisateur doit être un fichier JPEG ou PNG", + + "error.blueprint.notFound": "Le blueprint « {name} » n’a pu être chargé", + + "error.blocks.max.plural": "Vous ne devez pas ajouter plus de {max} blocs", + "error.blocks.max.singular": "Vous ne devez pas ajouter plus d'un bloc", + "error.blocks.min.plural": "Vous devez ajouter au moins {min} blocs", + "error.blocks.min.singular": "Vous devez ajouter au moins un bloc", + "error.blocks.validation": "Il y a une erreur dans le bloc {index}", + + "error.email.preset.notFound": "La configuration de courriel « {name} » n’a pu être trouvé ", + + "error.field.converter.invalid": "Convertisseur « {converter} » incorrect", + + "error.file.changeName.empty": "Le nom ne peut être vide", + "error.file.changeName.permission": "Vous n’êtes pas autorisé à modifier le nom de « {filename} »", + "error.file.duplicate": "Un fichier nommé « {filename} » existe déjà", + "error.file.extension.forbidden": "L’extension « {extension} » n’est pas autorisée", + "error.file.extension.invalid": "Extension non valide : {extension}", + "error.file.extension.missing": "L’extension pour « {filename} » est manquante", + "error.file.maxheight": "La hauteur de l'image ne doit pas excéder {height} pixels", + "error.file.maxsize": "Le fichier est trop volumineux", + "error.file.maxwidth": "La largeur de l'image ne doit pas excéder {width} pixels", + "error.file.mime.differs": "Le fichier transféré doit être du même type de média « {mime} »", + "error.file.mime.forbidden": "Le type de média « {mime} » n’est pas autorisé", + "error.file.mime.invalid": "Type de média non valide : {mime}", + "error.file.mime.missing": "Le type de média de « {filename} » n’a pu être détecté", + "error.file.minheight": "La hauteur de l'image doit être au moins {height} pixels", + "error.file.minsize": "Le fichier n'est pas assez volumineux", + "error.file.minwidth": "La largeur de l'image doit être au moins {width} pixels", + "error.file.name.missing": "Veuillez entrer un titre", + "error.file.notFound": "Le fichier « {filename} » n’a pu être trouvé", + "error.file.orientation": "L'orientation de l'image doit être « {orientation} »", + "error.file.type.forbidden": "Vous n’êtes pas autorisé à transférer des fichiers {type}", + "error.file.type.invalid": "Type de fichier non valide : {type}", + "error.file.undefined": "Le fichier n’a pu être trouvé", + + "error.form.incomplete": "Veuillez corriger toutes les erreurs du formulaire…", + "error.form.notSaved": "Le formulaire n’a pu être enregistré", + + "error.language.code": "Veuillez saisir un code valide pour cette langue", + "error.language.duplicate": "Cette langue existe déjà", + "error.language.name": "Veuillez saisir un nom valide pour cette langue", + "error.language.notFound": "La langue n’a pu être trouvée", + + "error.layout.validation.block": "Il y a une erreur dans le block {blockIndex} de la disposition {layoutIndex}", + "error.layout.validation.settings": "Il y a une erreur dans les paramètres de la disposition {index}", + + "error.license.format": "Veuillez saisir un numéro de licence valide", + "error.license.email": "Veuillez saisir un courriel valide", + "error.license.verification": "La licence n’a pu être vérifiée", + + "error.offline": "Le Panel est actuellement hors ligne", + + "error.page.changeSlug.permission": "Vous n’êtes pas autorisé à modifier l’identifiant d’URL pour « {slug} »", + "error.page.changeStatus.incomplete": "La page comporte des erreurs et ne peut pas être publiée", + "error.page.changeStatus.permission": "Le statut de cette page ne peut être modifié", + "error.page.changeStatus.toDraft.invalid": "La page « {slug} » ne peut être convertie en brouillon", + "error.page.changeTemplate.invalid": "Le modèle de la page « {slug} » ne peut être changé", + "error.page.changeTemplate.permission": "Vous n’êtes pas autorisé à changer le modèle de « {slug} »", + "error.page.changeTitle.empty": "Le titre ne peut être vide", + "error.page.changeTitle.permission": "Vous n’êtes pas autorisé à modifier le titre de « {slug} »", + "error.page.create.permission": "Vous n’êtes pas autorisé à créer « {slug} »", + "error.page.delete": "La page « {slug} » ne peut être supprimée", + "error.page.delete.confirm": "Veuillez saisir le titre de la page pour confirmer", + "error.page.delete.hasChildren": "La page comporte des sous-pages et ne peut pas être supprimée", + "error.page.delete.permission": "Vous n’êtes pas autorisé à supprimer « {slug} »", + "error.page.draft.duplicate": "Un brouillon avec l’identifiant d’URL « {slug} » existe déjà", + "error.page.duplicate": "Une page avec l’identifiant d’URL « {slug} » existe déjà", + "error.page.duplicate.permission": "Vous n'êtes pas autorisé à dupliquer « {slug} »", + "error.page.notFound": "La page « {slug} » n’a pu être trouvée", + "error.page.num.invalid": "Veuillez saisir un numéro de position valide. Les numéros ne doivent pas être négatifs.", + "error.page.slug.invalid": "Veuillez entrer un identifiant d’URL valide", + "error.page.slug.maxlength": "L’identifiant d’URL doit faire moins de « {length} » caractères", + "error.page.sort.permission": "La page « {slug} » ne peut être réordonnée", + "error.page.status.invalid": "Veuillez choisir un statut de page valide", + "error.page.undefined": "La page n’a pu être trouvée", + "error.page.update.permission": "Vous n’êtes pas autorisé à modifier « {slug} »", + + "error.section.files.max.plural": "Vous ne pouvez ajouter plus de {max} fichier(s) à la section « {section} »", + "error.section.files.max.singular": "Vous ne pouvez ajouter plus d’un fichier à la section « {section} »", + "error.section.files.min.plural": "La section « {section} » requiert au moins {min} fichiers", + "error.section.files.min.singular": "La section « {section} » requiert au moins un fichier", + + "error.section.pages.max.plural": "Vous ne pouvez ajouter plus de {max} pages à la section « {section} »", + "error.section.pages.max.singular": "Vous ne pouvez ajouter plus d’une page à la section « {section} »", + "error.section.pages.min.plural": "La section « {section} » requiert au moins {min} pages", + "error.section.pages.min.singular": "La section « {section} » requiert au moins une page", + + "error.section.notLoaded": "La section « {name} » n’a pu être chargée", + "error.section.type.invalid": "Le type de section « {type} » est incorrect", + + "error.site.changeTitle.empty": "Le titre ne peut être vide", + "error.site.changeTitle.permission": "Vous n’êtes pas autorisé à modifier le titre du site", + "error.site.update.permission": "Vous n’êtes pas autorisé à modifier le contenu global du site", + + "error.template.default.notFound": "Le modèle par défaut n’existe pas", + + "error.unexpected": "Une erreur inattendue est survenue ! Activez le mode de débogage pour plus d'informations : https://getkirby.com/docs/reference/system/options/debug", + + "error.user.changeEmail.permission": "Vous n’êtes pas autorisé à modifier le courriel de l’utilisateur « {name} »", + "error.user.changeLanguage.permission": "Vous n’êtes pas autorisé à changer la langue de l’utilisateur « {name} »", + "error.user.changeName.permission": "Vous n’êtes pas autorisé à modifier le nom de l’utilisateur « {name} »", + "error.user.changePassword.permission": "Vous n’êtes pas autorisé à changer le mot de passe de l’utilisateur « {name} »", + "error.user.changeRole.lastAdmin": "Le rôle du dernier administrateur ne peut être modifié", + "error.user.changeRole.permission": "Vous n’êtes pas autorisé à changer le rôle de l’utilisateur « {name} »", + "error.user.changeRole.toAdmin": "Vous n’êtes pas autorisé à attribuer le rôle d’administrateur aux utilisateurs", + "error.user.create.permission": "Vous n’êtes pas autorisé à créer cet utilisateur", + "error.user.delete": "L’utilisateur « {name} » ne peut être supprimé", + "error.user.delete.lastAdmin": "Le dernier administrateur ne peut être supprimé", + "error.user.delete.lastUser": "Le dernier utilisateur ne peut être supprimé", + "error.user.delete.permission": "Vous n’êtes pas autorisé à supprimer l’utilisateur « {name} »", + "error.user.duplicate": "Un utilisateur avec le courriel « {email} » existe déjà", + "error.user.email.invalid": "Veuillez saisir un courriel valide", + "error.user.language.invalid": "Veuillez saisir une langue valide", + "error.user.notFound": "L’utilisateur « {name} » n’a pu être trouvé", + "error.user.password.excessive": "Please enter a valid password. Passwords must not be longer than 1000 characters.", + "error.user.password.invalid": "Veuillez saisir un mot de passe valide. Les mots de passe doivent comporter au moins 8 caractères.", + "error.user.password.notSame": "Les mots de passe ne sont pas identiques", + "error.user.password.undefined": "Cet utilisateur n’a pas de mot de passe", + "error.user.password.wrong": "Mot de passe incorrect", + "error.user.role.invalid": "Veuillez saisir un rôle valide", + "error.user.undefined": "L’utilisateur n’a pu être trouvé", + "error.user.update.permission": "Vous n’êtes pas autorisé à modifier l’utilisateur « {name} »", + + "error.validation.accepted": "Veuillez confirmer", + "error.validation.alpha": "Veuillez saisir uniquement des caractères alphabétiques minuscules", + "error.validation.alphanum": "Veuillez ne saisir que des minuscules de a à z et des chiffres de 0 à 9", + "error.validation.between": "Veuillez saisir une valeur entre « {min} » et « {max} »", + "error.validation.boolean": "Veuillez confirmer ou refuser", + "error.validation.contains": "Veuillez saisir une valeur contenant « {needle} »", + "error.validation.date": "Veuillez saisir une date valide", + "error.validation.date.after": "Veuillez saisir une date après {date}", + "error.validation.date.before": "Veuillez saisir une date avant {date}", + "error.validation.date.between": "Veuillez saisir une date entre {min} et {max}", + "error.validation.denied": "Veuillez refuser", + "error.validation.different": "La valeur ne doit pas être « {other} »", + "error.validation.email": "Veuillez saisir un courriel valide", + "error.validation.endswith": "La valeur doit se terminer par « {end} »", + "error.validation.filename": "Veuillez saisir un nom de fichier valide", + "error.validation.in": "Veuillez saisir l’un des éléments suivants: ({in})", + "error.validation.integer": "Veuillez saisir un entier valide", + "error.validation.ip": "Veuillez saisir une adresse IP valide", + "error.validation.less": "Veuillez saisir une valeur inférieure à {max}", + "error.validation.match": "La valeur ne correspond pas au modèle attendu", + "error.validation.max": "Veuillez saisir une valeur inférieure ou égale à {max}", + "error.validation.maxlength": "Veuillez saisir une valeur plus courte (max. {max} caractères)", + "error.validation.maxwords": "Veuillez ne pas saisir plus de {max} mot(s)", + "error.validation.min": "Veuillez saisir une valeur supérieure ou égale à {min}", + "error.validation.minlength": "Veuillez saisir une valeur plus longue (min. {min} caractères)", + "error.validation.minwords": "Veuillez saisir au moins {min} mot(s)", + "error.validation.more": "Veuillez saisir une valeur supérieure à {min}", + "error.validation.notcontains": "Veuillez saisir une valeur ne contenant pas « {needle} »", + "error.validation.notin": "Veuillez ne saisir aucun des éléments suivants: ({notIn})", + "error.validation.option": "Veuillez sélectionner une option valide", + "error.validation.num": "Veuillez saisir un nombre valide", + "error.validation.required": "Veuillez saisir quelque chose", + "error.validation.same": "Veuillez saisir « {other} »", + "error.validation.size": "La grandeur de la valeur doit être « {size} »", + "error.validation.startswith": "La valeur doit commencer par « {start} »", + "error.validation.time": "Veuillez saisir une heure valide", + "error.validation.time.after": "Veuillez entrer une heure après {time}", + "error.validation.time.before": "Veuillez entrer une heure avant {time}", + "error.validation.time.between": "Veuillez entrer une heure entre {min} et {max}", + "error.validation.url": "Veuillez saisir une URL valide", + + "expand": "Déplier", + "expand.all": "Tout déplier", + + "field.required": "Le champ est obligatoire", + "field.blocks.changeType": "Changer le type", + "field.blocks.code.name": "Code", + "field.blocks.code.language": "Langue", + "field.blocks.code.placeholder": "Votre code…", + "field.blocks.delete.confirm": "Voulez-vous vraiment supprimer ce bloc ?", + "field.blocks.delete.confirm.all": "Voulez-vous vraiment supprimer tous les blocs ?", + "field.blocks.delete.confirm.selected": "Voulez-vous vraiment supprimer les blocs sélectionnés ?", + "field.blocks.empty": "Pas encore de blocs", + "field.blocks.fieldsets.label": "Veuillez sélectionner un type de bloc…", + "field.blocks.fieldsets.paste": "Presser {{ shortcut }} pour coller/importer des blocks depuis votre presse-papier", + "field.blocks.gallery.name": "Galerie", + "field.blocks.gallery.images.empty": "Pas encore d’images", + "field.blocks.gallery.images.label": "Images", + "field.blocks.heading.level": "Niveau", + "field.blocks.heading.name": "Titre", + "field.blocks.heading.text": "Texte", + "field.blocks.heading.placeholder": "Titre…", + "field.blocks.image.alt": "Texte alternatif", + "field.blocks.image.caption": "Légende", + "field.blocks.image.crop": "Recadrer", + "field.blocks.image.link": "Lien", + "field.blocks.image.location": "Emplacement", + "field.blocks.image.name": "Image", + "field.blocks.image.placeholder": "Sélectionnez une image", + "field.blocks.image.ratio": "Proportions", + "field.blocks.image.url": "URL de l'image", + "field.blocks.line.name": "Ligne", + "field.blocks.list.name": "Liste", + "field.blocks.markdown.name": "Markdown", + "field.blocks.markdown.label": "Texte", + "field.blocks.markdown.placeholder": "Markdown…", + "field.blocks.quote.name": "Citation", + "field.blocks.quote.text.label": "Texte", + "field.blocks.quote.text.placeholder": "Citation…", + "field.blocks.quote.citation.label": "Citation", + "field.blocks.quote.citation.placeholder": "par…", + "field.blocks.text.name": "Texte", + "field.blocks.text.placeholder": "Texte…", + "field.blocks.video.caption": "Légende", + "field.blocks.video.name": "Vidéo", + "field.blocks.video.placeholder": "Entrez l’URL d’une vidéo", + "field.blocks.video.url.label": "URL de la vidéo", + "field.blocks.video.url.placeholder": "https://youtube.com/?v=", + + "field.files.empty": "Pas encore de fichier sélectionné", + + "field.layout.delete": "Supprimer cette disposition", + "field.layout.delete.confirm": "Voulez-vous vraiment supprimer cette disposition ?", + "field.layout.empty": "Pas encore de rangées", + "field.layout.select": "Choisir une disposition", + + "field.pages.empty": "Pas encore de page sélectionnée", + "field.structure.delete.confirm": "Voulez-vous vraiment supprimer cette ligne ?", + "field.structure.empty": "Pas encore d’entrée", + "field.users.empty": "Pas encore d’utilisateur sélectionné", + + "file.blueprint": "Ce fichier n’a pas encore de blueprint. Vous pouvez en définir les paramètres dans /site/blueprints/files/{blueprint}.yml", + "file.delete.confirm": "Voulez-vous vraiment supprimer
{filename} ?", + "file.sort": "Modifier la position", + + "files": "Fichiers", + "files.empty": "Pas encore de fichier", + + "hide": "Masquer", + "hour": "Heure", + "import": "Importer", + "info": "Info", + "insert": "Insérer", + "insert.after": "Insérer après", + "insert.before": "Insérer avant", + "install": "Installer", + + "installation": "Installation", + "installation.completed": "Le Panel a été installé", + "installation.disabled": "L'installation du Panel est désactivée par défaut sur les serveurs publics. Veuillez lancer l'installation sur un serveur local, ou activez-la avec l'option panel.install.", + "installation.issues.accounts": "Le dossier /site/accounts n’existe pas ou n’est pas accessible en écriture", + "installation.issues.content": "Le dossier /content n’existe pas ou n’est pas accessible en écriture", + "installation.issues.curl": "L’extension CURL est requise", + "installation.issues.headline": "Le Panel ne peut être installé", + "installation.issues.mbstring": "L’extension MB String est requise", + "installation.issues.media": "Le dossier /media n’existe pas ou n’est pas accessible en écriture", + "installation.issues.php": "Veuillez utiliser PHP 7+", + "installation.issues.server": "Kirby requiert Apache, Nginx ou Caddy", + "installation.issues.sessions": "Le dossier /site/sessions n’existe pas ou n’est pas accessible en écriture", + + "language": "Langue", + "language.code": "Code", + "language.convert": "Choisir comme langue par défaut", + "language.convert.confirm": "

Souhaitez-vous vraiment convertir {name} vers la langue par défaut ? Cette action ne peut pas être annulée.

Si {name} a un contenu non traduit, il n’y aura plus de solution de secours possible et certaines parties de votre site pourraient être vides.

", + "language.create": "Ajouter une nouvelle langue", + "language.delete.confirm": "Voulez-vous vraiment supprimer la langue {name}, ainsi que toutes ses traductions ? Cette action ne peut être annulée !", + "language.deleted": "La langue a été supprimée", + "language.direction": "Sens de lecture", + "language.direction.ltr": "De gauche à droite", + "language.direction.rtl": "De droite à gauche", + "language.locale": "Locales PHP", + "language.locale.warning": "Vous utilisez une Locale PHP personnalisée. Veuillez la modifier dans le fichier de langue situé dans /site/languages", + "language.name": "Nom", + "language.updated": "La langue a été mise à jour", + + "languages": "Langages", + "languages.default": "Langue par défaut", + "languages.empty": "Il n’y a pas encore de langues", + "languages.secondary": "Langues secondaires", + "languages.secondary.empty": "Il n’y a pas encore de langues secondaires", + + "license": "Licence", + "license.buy": "Acheter une licence", + "license.register": "S’enregistrer", + "license.manage": "Gérer vos licences", + "license.register.help": "Vous avez reçu votre numéro de licence par courriel après l'achat. Veuillez le copier et le coller ici pour l'enregistrer.", + "license.register.label": "Veuillez saisir votre numéro de licence", + "license.register.success": "Merci pour votre soutien à Kirby", + "license.unregistered": "Ceci est une démo non enregistrée de Kirby", + "license.unregistered.label": "Non enregistré", + + "link": "Lien", + "link.text": "Texte du lien", + + "loading": "Chargement", + + "lock.unsaved": "Modifications non enregistrées", + "lock.unsaved.empty": "Il n’y a plus de modifications non enregistrées", + "lock.isLocked": "Modifications non enregistrées par {email}", + "lock.file.isLocked": "Le fichier est actuellement édité par {email} et ne peut être modifié.", + "lock.page.isLocked": "La page est actuellement éditée par {email} et ne peut être modifiée.", + "lock.unlock": "Déverrouiller", + "lock.isUnlocked": "Vos modifications non enregistrées ont été écrasées pas un autre utilisateur. Vous pouvez télécharger vos modifications pour les fusionner manuellement.", + + "login": "Connexion", + "login.code.label.login": "Code de connexion", + "login.code.label.password-reset": "Code de réinitialisation du mot de passe", + "login.code.placeholder.email": "000 000", + "login.code.text.email": "Si votre adresse de courriel est enregistrée, le code demandé vous sera envoyé par courriel.", + "login.email.login.body": "Bonjour {user.nameOrEmail},\n\nVous avez récemment demandé un code de connexion pour le Panel de {site}.\nLe codede connexion suivant sera valide pendant {timeout} minutes :\n\n{code}\n\nSi vous n’avez pas demandé de codede connexion, veuillez ignorer cet email ou contacter votre administrateur si vous avez des questions.\nPar sécurité, merci de ne PAS faire suivre cet email.", + "login.email.login.subject": "Votre code de connexion", + "login.email.password-reset.body": "Bonjour {user.nameOrEmail},\n\nVous avez récemment demandé un code de réinitialisation de mot de passe pour le Panel de {site}.\nLe code de réinitialisation de mot de passe suivant sera valide pendant {timeout} minutes :\n\n{code}\n\nSi vous n’avez pas demandé de code de réinitialisation de mot de passe, veuillez ignorer cet email ou contacter votre administrateur si vous avez des questions.\nPar sécurité, merci de ne PAS faire suivre cet email.", + "login.email.password-reset.subject": "Votre code de réinitialisation du mot de passe", + "login.remember": "Rester connecté", + "login.reset": "Réinitialiser le mot de passe", + "login.toggleText.code.email": "Se connecter par courriel", + "login.toggleText.code.email-password": "Se connecter avec un mot de passe", + "login.toggleText.password-reset.email": "Mot de passe oublié ?", + "login.toggleText.password-reset.email-password": "← Retour à la connexion", + + "logout": "Se déconnecter", + + "menu": "Menu", + "meridiem": "AM/PM", + "mime": "Type de médias", + "minutes": "Minutes", + + "month": "Mois", + "months.april": "Avril", + "months.august": "Août", + "months.december": "Décembre", + "months.february": "Février", + "months.january": "Janvier", + "months.july": "Juillet", + "months.june": "Juin", + "months.march": "Mars", + "months.may": "Mai", + "months.november": "Novembre", + "months.october": "Octobre", + "months.september": "Septembre", + + "more": "Plus", + "name": "Nom", + "next": "Suivant", + "no": "non", + "off": "off", + "on": "on", + "open": "Ouvrir", + "open.newWindow": "Ouvrir dans une nouvelle fenêtre", + "options": "Options", + "options.none": "Pas d’options", + + "orientation": "Orientation", + "orientation.landscape": "Paysage", + "orientation.portrait": "Portrait", + "orientation.square": "Carré", + + "page.blueprint": "Cette page n’a pas encore de blueprint. Vous pouvez en définir les paramètres dans /site/blueprints/pages/{blueprint}.yml", + "page.changeSlug": "Modifier l’URL", + "page.changeSlug.fromTitle": "Créer à partir du titre", + "page.changeStatus": "Changer le statut", + "page.changeStatus.position": "Veuillez sélectionner une position", + "page.changeStatus.select": "Sélectionner un nouveau statut", + "page.changeTemplate": "Changer de modèle", + "page.delete.confirm": "Voulez-vous vraiment supprimer {title} ?", + "page.delete.confirm.subpages": "Cette page contient des sous-pages.
Toutes les sous-pages seront également supprimées.", + "page.delete.confirm.title": "Veuillez saisir le titre de la page pour confirmer", + "page.draft.create": "Créer un brouillon", + "page.duplicate.appendix": "Copier", + "page.duplicate.files": "Copier les fichiers", + "page.duplicate.pages": "Copier les pages", + "page.sort": "Modifier la position", + "page.status": "Statut", + "page.status.draft": "Brouillon", + "page.status.draft.description": "Cette page est un brouillon et n’est visible que pour les éditeurs connectés ou par un lien secret", + "page.status.listed": "Public", + "page.status.listed.description": "La page est publique pour tout le monde", + "page.status.unlisted": "Non listé", + "page.status.unlisted.description": "La page est uniquement accessible par son URL", + + "pages": "Pages", + "pages.empty": "Pas encore de pages", + "pages.status.draft": "Brouillons", + "pages.status.listed": "Publié", + "pages.status.unlisted": "Non listé", + + "pagination.page": "Page", + + "password": "Mot de passe", + "paste": "Coller", + "paste.after": "Coller après", + "pixel": "Pixel", + "plugins": "Plugins", + "prev": "Précédent", + "preview": "Prévisualiser", + "remove": "Supprimer", + "rename": "Renommer", + "replace": "Remplacer", + "retry": "Essayer à nouveau", + "revert": "Revenir", + "revert.confirm": "Voulez-vous vraiment supprimer toutes les modifications non-enregistrées ?", + + "role": "Rôle", + "role.admin.description": "L’administrateur dispose de tous les droits", + "role.admin.title": "Administrateur", + "role.all": "Tous", + "role.empty": "Il n’y a aucun utilisateur avec ce rôle", + "role.description.placeholder": "Pas de description", + "role.nobody.description": "Ceci est un rôle de secours sans aucune permission.", + "role.nobody.title": "Personne", + + "save": "Enregistrer", + "search": "Rechercher", + "search.min": "Entrez {min} caractères pour rechercher", + "search.all": "Tout afficher", + "search.results.none": "Pas de résultats", + + "section.required": "Cette section est obligatoire", + + "security": "Sécurité", + "select": "Sélectionner", + "server": "Serveur", + "settings": "Paramètres", + "show": "Afficher", + "site.blueprint": "Ce site n’a pas encore de blueprint. Vous pouvez en définir les paramètres dans /site/blueprints/site.yml", + "size": "Poids", + "slug": "Identifiant de l’URL", + "sort": "Trier", + + "stats.empty": "Aucun rapport", + "system.issues.content": "Le dossier content semble exposé", + "system.issues.debug": "Le débogage doit être désactivé en production", + "system.issues.git": "Le dossier .git semble exposé", + "system.issues.https": "Nous recommandons HTTPS pour tous vos sites", + "system.issues.kirby": "Le dossier kirby semble exposé", + "system.issues.site": "Le dossier site semble exposé", + + "title": "Titre", + "template": "Modèle", + "today": "Aujourd’hui", + + "toolbar.button.code": "Code", + "toolbar.button.bold": "Gras", + "toolbar.button.email": "Courriel", + "toolbar.button.headings": "Titres", + "toolbar.button.heading.1": "Titre 1", + "toolbar.button.heading.2": "Titre 2", + "toolbar.button.heading.3": "Titre 3", + "toolbar.button.heading.4": "Titre 4", + "toolbar.button.heading.5": "Titre 5", + "toolbar.button.heading.6": "Titre 6", + "toolbar.button.italic": "Italique", + "toolbar.button.file": "Fichier", + "toolbar.button.file.select": "Sélectionner un fichier", + "toolbar.button.file.upload": "Transférer un fichier", + "toolbar.button.link": "Lien", + "toolbar.button.paragraph": "Paragraphe", + "toolbar.button.strike": "Barré", + "toolbar.button.ol": "Liste ordonnée", + "toolbar.button.underline": "Souligné", + "toolbar.button.ul": "Liste non-ordonnée", + + "translation.author": "Kirby Team", + "translation.direction": "ltr", + "translation.name": "Français", + "translation.locale": "fr_FR", + + "upload": "Transférer", + "upload.error.cantMove": "Le fichier transféré n’a pu être déplacé", + "upload.error.cantWrite": "Le fichier n’a pu être écrit sur le disque", + "upload.error.default": "Le fichier n’a pu être transféré", + "upload.error.extension": "Le transfert de fichier a été stoppé par une extension", + "upload.error.formSize": "Le fichier transféré excède la directive MAX_FILE_SIZE spécifiée dans le formulaire", + "upload.error.iniPostSize": "Le fichier transféré excède la directive post_max_size spécifiée dans php.ini", + "upload.error.iniSize": "Le fichier transféré excède la directive upload_max_filesize spécifiée dans php.ini", + "upload.error.noFile": "Aucun fichier n’a été transféré", + "upload.error.noFiles": "Aucun fichier n’a été transféré", + "upload.error.partial": "Le fichier n’a été que partiellement transféré", + "upload.error.tmpDir": "Un dossier temporaire est manquant", + "upload.errors": "Erreur", + "upload.progress": "Transfert en cours…", + + "url": "Url", + "url.placeholder": "https://example.com", + + "user": "Utilisateur", + "user.blueprint": "Vous pouvez définir de nouvelles sections et champs de formulaires pour ce rôle d'utilisateur dans /site/blueprints/users/{blueprint}.yml", + "user.changeEmail": "Modifier le courriel", + "user.changeLanguage": "Modifier la langue", + "user.changeName": "Renommer cet utilisateur", + "user.changePassword": "Modifier le mot de passe", + "user.changePassword.new": "Nouveau mot de passe", + "user.changePassword.new.confirm": "Confirmer le nouveau mot de passe…", + "user.changeRole": "Modifier le rôle", + "user.changeRole.select": "Sélectionner un nouveau rôle", + "user.create": "Ajouter un nouvel utilisateur", + "user.delete": "Supprimer cet utilisateur", + "user.delete.confirm": "Voulez-vous vraiment supprimer
{email} ?", + + "users": "Utilisateurs", + + "version": "Version", + + "view.account": "Votre compte", + "view.installation": "Installation", + "view.languages": "Langages", + "view.resetPassword": "Réinitialiser le mot de passe", + "view.site": "Site", + "view.system": "Système", + "view.users": "Utilisateurs", + + "welcome": "Bienvenue", + "year": "Année", + "yes": "oui" } diff --git a/kirby/i18n/translations/hu.json b/kirby/i18n/translations/hu.json index 27cb8d7..24a2534 100644 --- a/kirby/i18n/translations/hu.json +++ b/kirby/i18n/translations/hu.json @@ -1,730 +1,574 @@ { - "account.changeName": "Név megváltoztatása", - "account.delete": "Fiók törlése", - "account.delete.confirm": "Tényleg törölni szeretnéd a fiókodat? Azonnal kijelentkeztetünk és ez a folyamat visszavonhatatlan.", - - "activate": "Activate", - "add": "Hozz\u00e1ad", - "alpha": "Alpha", - "author": "Szerző", - "avatar": "Profilkép", - "back": "Vissza", - "cancel": "M\u00e9gsem", - "change": "M\u00f3dos\u00edt\u00e1s", - "close": "Bez\u00e1r", - "changes": "Changes", - "confirm": "Mentés", - "collapse": "Bezárás", - "collapse.all": "Összes bezárása", - "color": "Color", - "coordinates": "Coordinates", - "copy": "Másol", - "copy.all": "Összes másolása", - "copy.success": "{count} copied!", - "create": "Létrehoz", - "custom": "Custom", - - "date": "Dátum", - "date.select": "Dátum kiválasztása", - - "day": "Nap", - "days.fri": "p\u00e9", - "days.mon": "h\u00e9", - "days.sat": "szo", - "days.sun": "va", - "days.thu": "cs\u00fc", - "days.tue": "ke", - "days.wed": "sze", - - "debugging": "Hibakeresés", - - "delete": "T\u00f6rl\u00e9s", - "delete.all": "Összes törlése", - - "dialog.fields.empty": "This dialog has no fields", - "dialog.files.empty": "Nincsenek fájlok kiválasztva", - "dialog.pages.empty": "Nincsenek oldalak kiválasztva", - "dialog.text.empty": "This dialog does not define any text", - "dialog.users.empty": "Nincsenek felhasználók kiválasztva", - - "dimensions": "Méretek", - "disable": "Disable", - "disabled": "Inaktív", - "discard": "Visszavon\u00e1s", - - "drawer.fields.empty": "This drawer has no fields", - - "domain": "Domain", - "download": "Letöltés", - "duplicate": "Másolat", - - "edit": "Aloldal szerkeszt\u00e9se", - - "email": "Email", - "email.placeholder": "mail@pelda.hu", - - "enter": "Enter", - "entries": "Entries", - "entry": "Entry", - - "environment": "Környezet", - - "error": "Error", - "error.access.code": "Érvénytelen kód", - "error.access.login": "Érvénytelen bejelentkezés", - "error.access.panel": "Nincs jogosultságod megnyitni a panelt", - "error.access.view": "Nincs hozzáférésed a panel ezen részéhez", - - "error.avatar.create.fail": "A profilkép feltöltése nem sikerült", - "error.avatar.delete.fail": "A profilkép nem törölhető", - "error.avatar.dimensions.invalid": "A profilkép maximális szélessége és magassága 3000 pixel lehet", - "error.avatar.mime.forbidden": "A profilkép formátuma csak JPEG vagy PNG lehet", - - "error.blueprint.notFound": "A \"{name}\" oldalsablon nem tölthető be", - - "error.blocks.max.plural": "Legfeljebb {max} blokk adható hozzá", - "error.blocks.max.singular": "Csak egyetlen blokk adható hozzá", - "error.blocks.min.plural": "Legalább {min} blokkot hozzá kell adnod", - "error.blocks.min.singular": "Legalább egy blokkot hozzá kell adnod", - "error.blocks.validation": "There's an error on the \"{field}\" field in block {index} using the \"{fieldset}\" block type", - - "error.cache.type.invalid": "Invalid cache type \"{type}\"", - - "error.email.preset.notFound": "A \"{name}\" email-beállítás nem található", - - "error.field.converter.invalid": "Érvénytelen konverter: \"{converter}\"", - "error.field.type.missing": "Field \"{ name }\": The field type \"{ type }\" does not exist", - - "error.file.changeName.empty": "A név nem lehet üres", - "error.file.changeName.permission": "Nincs jogosultságod megváltoztatni a \"{filename}\" fájl nevét", - "error.file.changeTemplate.invalid": "The template for the file \"{id}\" cannot be changed to \"{template}\" (valid: \"{blueprints}\")", - "error.file.changeTemplate.permission": "You are not allowed to change the template for the file \"{id}\"", - - "error.file.duplicate": "Már létezik \"{filename}\" nevű fájl", - "error.file.extension.forbidden": "Tiltott kiterjeszt\u00e9s\u0171 f\u00e1jl", - "error.file.extension.invalid": "Érvénytelen kiterjesztés: {extension}", - "error.file.extension.missing": "Kiterjeszt\u00e9s n\u00e9lk\u00fcli f\u00e1jl nem t\u00f6lthet\u0151 fel", - "error.file.maxheight": "A kép nem lehet magasabb {height} pixelnél", - "error.file.maxsize": "A fájl túl nagy", - "error.file.maxwidth": "A kép nem lehet szélesebb {width} pixelnél", - "error.file.mime.differs": "A feltöltött fájlnak azonos \"{mime}\" típusúnak kell lennie", - "error.file.mime.forbidden": "A \"{mime}\" típusú médiafájlok nem engedélyezettek", - "error.file.mime.invalid": "Érvénytelen mime-típus: {mime}", - "error.file.mime.missing": "A \"{filename}\" fájl típusa nem állapítható meg", - "error.file.minheight": "A képnek legalább {height} pixel magasnak kell lennie", - "error.file.minsize": "A fájl túl kicsi", - "error.file.minwidth": "A képnek legalább {width} pixel szélesnek kell lennie", - "error.file.name.unique": "The filename must be unique", - "error.file.name.missing": "A fálj neve nem lehet üres", - "error.file.notFound": "A \"{filename}\" fájl nem található", - "error.file.orientation": "A képnek \"{orientation}\" tájolásúnak kell lennie", - "error.file.type.forbidden": "Nem tölthetsz fel \"{type}\" típusú fájlokat", - "error.file.type.invalid": "Érvénytelen fájltípus: {type}", - "error.file.undefined": "A f\u00e1jl nem tal\u00e1lhat\u00f3", - - "error.form.incomplete": "Kérlek javítsd ki az összes hibát az űrlapon", - "error.form.notSaved": "Az űrlap nem menthető", - - "error.language.code": "Kérlek, add meg a nyelv érvényes kódját", - "error.language.duplicate": "A nyelv már létezik", - "error.language.name": "Kérlek, add meg a nyelv érvényes nevét", - "error.language.notFound": "A nyelv nem található", - - "error.layout.validation.block": "There's an error on the \"{field}\" field in block {blockIndex} using the \"{fieldset}\" block type in layout {layoutIndex}", - "error.layout.validation.settings": "Hibát találtunk a(z) {index} elrendezés beállításaiban", - - "error.license.domain": "The domain for the license is missing", - "error.license.email": "Kérlek adj meg egy valós email-címet", - "error.license.format": "Please enter a valid license code", - "error.license.verification": "A licensz nem ellenőrizhető", - - "error.login.totp.confirm.invalid": "Érvénytelen kód", - "error.login.totp.confirm.missing": "Please enter the current code", - - "error.object.validation": "There’s an error in the \"{label}\" field:\n{message}", - - "error.offline": "A Panel jelenleg nem elérhető", - - "error.page.changeSlug.permission": "Nem változtathatod meg az URL-előtagot: \"{slug}\"", - "error.page.changeSlug.reserved": "The path of top-level pages must not start with \"{path}\"", - "error.page.changeStatus.incomplete": "Az oldal hibákat tartalmaz és nem publikálható", - "error.page.changeStatus.permission": "Az oldal státusza nem változtatható meg", - "error.page.changeStatus.toDraft.invalid": "A(z) \"{slug}\" oldalt nem lehet piszkozattá alakítani", - "error.page.changeTemplate.invalid": "A \"{slug}\" oldal sablonját nem lehet megváltoztatni", - "error.page.changeTemplate.permission": "Nincs jogosultságod megváltoztatni a sablont ehhez: \"{slug}\"", - "error.page.changeTitle.empty": "A cím nem lehet üres", - "error.page.changeTitle.permission": "Nincs jogosultságod megváltoztatni a címet: \"{slug}\"", - "error.page.create.permission": "Nincs jogosultságod az oldal létrehozásához: \"{slug}\"", - "error.page.delete": "A(z) \"{slug}\" oldal nem törölhető", - "error.page.delete.confirm": "Megerősítéshez add meg az oldal címét", - "error.page.delete.hasChildren": "Az oldalnak vannak aloldalai és nem törölhető", - "error.page.delete.permission": "Nincs jogosultságod a(z) \"{slug}\" oldal törléséhez", - "error.page.draft.duplicate": "Van már egy másik oldal ezzel az URL-lel: \"{slug}\"", - "error.page.duplicate": "Van már egy másik oldal ezzel az URL-lel: \"{slug}\"", - "error.page.duplicate.permission": "Nincs engedélyed a(z) \"{slug}\" másolat keszítéséhez", - "error.page.move.ancestor": "The page cannot be moved into itself", - "error.page.move.directory": "The page directory cannot be moved", - "error.page.move.duplicate": "A sub page with the URL appendix \"{slug}\" already exists", - "error.page.move.notFound": "The moved page could not be found", - "error.page.move.permission": "You are not allowed to move \"{slug}\"", - "error.page.move.template": "The \"{template}\" template is not accepted as a subpage of \"{parent}\"", - "error.page.notFound": "Az oldal nem tal\u00e1lhat\u00f3", - "error.page.num.invalid": "Kérlek megfelelő oldalszámozást adj meg. Negatív szám itt nem használható.", - "error.page.slug.invalid": "Kérlek érvényes URL-kiterjesztést adj meg", - "error.page.slug.maxlength": "Az URL maximum \"{length}\" karakter hosszúságú lehet", - "error.page.sort.permission": "A(z) \"{slug}\" oldal nem illeszthető a sorrendbe", - "error.page.status.invalid": "Kérlek add meg a megfelelő oldalstátuszt", - "error.page.undefined": "Az oldal nem tal\u00e1lhat\u00f3", - "error.page.update.permission": "Nincs jogosultságod a(z) \"{slug}\" oldal frissítéséhez", - - "error.section.files.max.plural": "Maximum {max} fájlt adhatsz hozzá a(z) \"{section}\" szekcióhoz", - "error.section.files.max.singular": "Nem adhatsz hozzá egynél több fájlt a(z) \"{section}\" szekcióhoz", - "error.section.files.min.plural": "A \"{section}\" szakasz legalább {min} fájlt igényel", - "error.section.files.min.singular": "A \"{section}\" szakasz legalább egy fájlt igényel", - - "error.section.pages.max.plural": "Maximum {max} oldalt adhatsz hozzá a(z) \"{section}\" szekcióhoz", - "error.section.pages.max.singular": "Nem adhatsz hozzá egynél több oldalt a(z) \"{section}\" szekcióhoz", - "error.section.pages.min.plural": "A \"{section}\" szakasz legalább {min} oldalt igényel", - "error.section.pages.min.singular": "A \"{section}\" szakasz legalább egy oldalt igényel", - - "error.section.notLoaded": "A(z) \"{name}\" szekció nem tölthető be", - "error.section.type.invalid": "A szekció típusa (\"{type}\") nem megfelelő", - - "error.site.changeTitle.empty": "A cím nem lehet üres", - "error.site.changeTitle.permission": "Nincs jogosultságod megváltoztatni az honlap címét", - "error.site.update.permission": "Nincs jogosultságod frissíteni a honlapot", - - "error.structure.validation": "There's an error on the \"{field}\" field in row {index}", - - "error.template.default.notFound": "Az alapértelmezett sablon nem létezik", - - "error.unexpected": "Váratlan hiba történt! További információért engedélyezd a hibakeresés módot: https://getkirby.com/docs/reference/system/options/debug", - - "error.user.changeEmail.permission": "Nincs jogosultságod megváltoztatni \"{name}\" felhasználó email-címét", - "error.user.changeLanguage.permission": "Nincs jogosultságod megváltoztatni \"{name}\" felhasználó nyelvi beállításait", - "error.user.changeName.permission": "Nincs jogosultságod megváltoztatni \"{name}\" felhasználó nevét", - "error.user.changePassword.permission": "Nincs jogosultságod megváltoztatni \"{name}\" felhasználó jelszavát", - "error.user.changeRole.lastAdmin": "Az egyedüli adminisztrátor szerepkörét nem lehet megváltoztatni", - "error.user.changeRole.permission": "Nincs jogosultságod megváltoztatni \"{name}\" felhasználó szerepkörét", - "error.user.changeRole.toAdmin": "Nincs jogosultságod előléptetni a felhasználót adminisztrátorrá", - "error.user.create.permission": "Nincs jogosultságod létrehozni ezt a felhasználót", - "error.user.delete": "A felhaszn\u00e1l\u00f3 nem t\u00f6r\u00f6lhet\u0151", - "error.user.delete.lastAdmin": "Nem t\u00f6r\u00f6lheted az egyetlen adminisztr\u00e1tort", - "error.user.delete.lastUser": "Nem törölheted az egyetlen felhasználót", - "error.user.delete.permission": "Nincs jogosults\u00e1god t\u00f6r\u00f6lni ezt a felhaszn\u00e1l\u00f3t", - "error.user.duplicate": "Már létezik felhasználó \"{email}\" email-címmel", - "error.user.email.invalid": "Kérlek adj meg egy valós email-címet", - "error.user.language.invalid": "Kérlek add meg a megfelelő nyelvi beállítást", - "error.user.notFound": "A felhaszn\u00e1l\u00f3 nem tal\u00e1lhat\u00f3", - "error.user.password.excessive": "Please enter a valid password. Passwords must not be longer than 1000 characters.", - "error.user.password.invalid": "Kérlek adj meg egy megfelelő jelszót. A jelszónak legalább 8 karakter hosszúságúnak kell lennie.", - "error.user.password.notSame": "K\u00e9rlek er\u0151s\u00edtsd meg a jelsz\u00f3t", - "error.user.password.undefined": "A felhasználónak nincs jelszó megadva", - "error.user.password.wrong": "Hibás jelszó", - "error.user.role.invalid": "Kérlek adj meg egy megfelelő szerepkört", - "error.user.undefined": "A felhasználó nem található", - "error.user.update.permission": "Nincs jogosultságod frissíteni \"{name}\" felhasználó adatait", - - "error.validation.accepted": "Kérlek erősítsd meg", - "error.validation.alpha": "Kérlek csak kis betűket használj (a-z)", - "error.validation.alphanum": "Kérlek csak kis betűket és számjegyeket használj (a-z, 0-9)", - "error.validation.anchor": "Please enter a correct link anchor", - "error.validation.between": "Kérlek egy \"{min}\" és \"{max}\" közötti értéket adj meg", - "error.validation.boolean": "Kérlek erősítsd meg vagy vesd el", - "error.validation.color": "Please enter a valid color in the {format} format", - "error.validation.contains": "Kérlek olyan értéket adj meg, amely tartalmazza ezt: \"{needle}\"", - "error.validation.date": "Kérlek megfelelő dátumot adj meg", - "error.validation.date.after": "Kérlek olyan dátumot adj meg, amely későbbi ennél: {date}", - "error.validation.date.before": "Kérlek olyan dátumot adj meg, amely korábbi ennél: {date}", - "error.validation.date.between": "Kérlek {min} és {max} közötti dátumot adj meg", - "error.validation.denied": "Kérlek vesd el", - "error.validation.different": "Az érték nem lehet \"{other}\"", - "error.validation.email": "Kérlek adj meg egy valós email-címet", - "error.validation.endswith": "Az értéknek erre kell végződnie: \"{end}\"", - "error.validation.filename": "Kérlek megfelelő fájlnevet adj meg", - "error.validation.in": "Kérlek adj meg egyet az alábbiak közül: ({in})", - "error.validation.integer": "Kérlek valós számot adj meg", - "error.validation.ip": "Kérlek megfelelő IP-címet adj meg", - "error.validation.less": "A megadott érték kevesebb legyen, mint {max}", - "error.validation.linkType": "The link type is not allowed", - "error.validation.match": "A megadott érték nem felel meg az elvárt struktúrának", - "error.validation.max": "A megadott érték egyenlő vagy kevesebb legyen, mint {max}", - "error.validation.maxlength": "Kérlek rövidebb értéket adj meg (legfeljebb {max} karakter)", - "error.validation.maxwords": "Kérlek ide legfeljebb {max} szót írj", - "error.validation.min": "A megadott érték egyenlő vagy nagyobb legyen, mint {min}", - "error.validation.minlength": "Kérlek hosszabb értéket adj meg (legalább {min} karakter)", - "error.validation.minwords": "Kérlek ide legalább {min} szót írj", - "error.validation.more": "A megadott érték legyen nagyobb, mint {min} ", - "error.validation.notcontains": "Kérlek olyan értéket adj meg, amely nem tartalmazza ezt: \"{needle}\" ", - "error.validation.notin": "Kérlek egyiket se használd az alábbiak közül: ({notIn})", - "error.validation.option": "Kérlek válassz egy megfelelő opciót", - "error.validation.num": "Kérlek adj meg egy megfelelő számot", - "error.validation.required": "Kérlek írj be valamit", - "error.validation.same": "Kérlek írd be: \"{other}\"", - "error.validation.size": "Az értéknek az alábbi méretűnek kell lennie: \"{size}\"", - "error.validation.startswith": "Az értéknek ezzel kell kezdődnie: \"{start}\"", - "error.validation.tel": "Please enter an unformatted phone number", - "error.validation.time": "Kérlek megfelelő időt adj meg", - "error.validation.time.after": "Kérlek olyan időpontot adj meg, amely későbbi ennél: {time}", - "error.validation.time.before": "Kérlek olyan időpontot adj meg, amely korábbi ennél: {time}", - "error.validation.time.between": "Kérlek {min} és {max} közötti időpontot adj meg", - "error.validation.uuid": "Please enter a valid UUID", - "error.validation.url": "Kérlek megfelelő URL-t adj meg", - - "expand": "Kinyitás", - "expand.all": "Összes kinyitása", - - "field.invalid": "The field is invalid", - "field.required": "Kötelező mező", - "field.blocks.changeType": "Típus megváltoztatása", - "field.blocks.code.name": "Kód", - "field.blocks.code.language": "Nyelv", - "field.blocks.code.placeholder": "A megjelenítendő kód …", - "field.blocks.delete.confirm": "Tényleg törölni szeretnéd ezt a blokkot?", - "field.blocks.delete.confirm.all": "Tényleg minden blokkot törölni szeretnél?", - "field.blocks.delete.confirm.selected": "Tényleg törölni szeretnéd a kijelölt blokkokat?", - "field.blocks.empty": "Még nincsenek blokkok", - "field.blocks.fieldsets.empty": "No fieldsets yet", - "field.blocks.fieldsets.label": "Kérlek válassz blokktípust …", - "field.blocks.fieldsets.paste": "Press {{ shortcut }} to import layouts/blocks from your clipboard Only those allowed in the current field will get inserted.", - "field.blocks.gallery.name": "Galéria", - "field.blocks.gallery.images.empty": "Még nincsenek képek", - "field.blocks.gallery.images.label": "Képek", - "field.blocks.heading.level": "Szint", - "field.blocks.heading.name": "Címsor", - "field.blocks.heading.text": "Szöveg", - "field.blocks.heading.placeholder": "Címsor …", - "field.blocks.image.alt": "Alternatív szöveg", - "field.blocks.image.caption": "Képaláírás", - "field.blocks.image.crop": "Körülvágás", - "field.blocks.image.link": "Link", - "field.blocks.image.location": "A kép helye", - "field.blocks.image.location.internal": "This website", - "field.blocks.image.location.external": "External source", - "field.blocks.image.name": "Kép", - "field.blocks.image.placeholder": "Kép kiválasztása", - "field.blocks.image.ratio": "Képarány", - "field.blocks.image.url": "Kép URL-je", - "field.blocks.line.name": "Vonal", - "field.blocks.list.name": "Lista", - "field.blocks.markdown.name": "Markdown", - "field.blocks.markdown.label": "Szöveg", - "field.blocks.markdown.placeholder": "Markdown …", - "field.blocks.quote.name": "Idézet", - "field.blocks.quote.text.label": "Szöveg", - "field.blocks.quote.text.placeholder": "Idézet szövege …", - "field.blocks.quote.citation.label": "Idézet szerzője", - "field.blocks.quote.citation.placeholder": "Szerző …", - "field.blocks.text.name": "Szöveg", - "field.blocks.text.placeholder": "Szöveg …", - "field.blocks.video.autoplay": "Autoplay", - "field.blocks.video.caption": "Képaláírás", - "field.blocks.video.controls": "Controls", - "field.blocks.video.location": "A kép helye", - "field.blocks.video.loop": "Loop", - "field.blocks.video.muted": "Muted", - "field.blocks.video.name": "Videó", - "field.blocks.video.placeholder": "Videó URL-jének megadása", - "field.blocks.video.poster": "Poster", - "field.blocks.video.preload": "Preload", - "field.blocks.video.url.label": "Videó URL", - "field.blocks.video.url.placeholder": "https://youtube.com/?v=", - - "field.files.empty": "Nincs fálj kiválasztva", - - "field.layout.change": "Change layout", - "field.layout.delete": "Elrendezés törlése", - "field.layout.delete.confirm": "Tényleg törölni szeretnéd ezt az elrendezést?", - "field.layout.delete.confirm.all": "Do you really want to delete all layouts?", - "field.layout.empty": "Még nincsenek sorok", - "field.layout.select": "Válassz elrendezést", - - "field.object.empty": "No information yet", - - "field.pages.empty": "Nincs oldal kiválasztva", - - "field.structure.delete.confirm": "Biztos t\u00f6r\u00f6lni szeretn\u00e9d ezt a bejegyz\u00e9st?", - "field.structure.delete.confirm.all": "Do you really want to delete all entries?", - "field.structure.empty": "Nincs m\u00e9g bejegyz\u00e9s", - - "field.users.empty": "Nincs felhasználó kiválasztva", - - "fields.empty": "No fields yet", - - "file": "Fájl", - "file.blueprint": "Ehhez a fájlhoz még nem tartozik oldalsablon. Itt hozhatod létre: /site/blueprints/files/{blueprint}.yml", - "file.changeTemplate": "Sablon módosítása", - "file.changeTemplate.notice": "Changing the file's template will remove content for fields that don't match in type. If the new template defines certain rules, e.g. image dimensions, those will also be applied irreversibly. Use with caution.", - "file.delete.confirm": "Biztos törölni akarod ezt a fájlt:
{filename}?", - "file.focus.placeholder": "Set focal point", - "file.focus.reset": "Remove focal point", - "file.focus.title": "Focus", - "file.sort": "Sorrend megváltoztatása", - - "files": "Fájlok", - "files.empty": "Még nincsenek fájlok", - - "filter": "Filter", - - "hide": "Elrejtés", - "hour": "Óra", - "hue": "Hue", - "import": "Importálás", - "info": "Info", - "insert": "Beilleszt", - "insert.after": "Beszúrás mögé", - "insert.before": "Beszúrás elé", - "install": "Telepítés", - - "installation": "Telepítés", - "installation.completed": "A panel sikeresen telepítve", - "installation.disabled": "A panel telepítője alapértelmezés szerint le van tiltva a nyilvános szervereken. Kérlek, futtassd a telepítőt egy helyi gépen vagy engedélyezze a panel.install opcióval.", - "installation.issues.accounts": "A /site/accounts mappa nem létezik, vagy nem írható", - "installation.issues.content": "A /content mappa nem létezik vagy nem írható", - "installation.issues.curl": "A CURL bővítmény engedélyezése szükséges", - "installation.issues.headline": "A panel telepítése sikertelen", - "installation.issues.mbstring": "Az MB String bővítmény engedélyezése szükséges", - "installation.issues.media": "A /media mappa nem létezik vagy nem írható", - "installation.issues.php": "Bizonyosodj meg róla, hogy az általad használt PHP-verzió PHP 8+", - "installation.issues.sessions": "A /site/sessions könyvtár nem létezik vagy nem írható", - - "language": "Nyelv", - "language.code": "Kód", - "language.convert": "Alapértelmezettnek jelölés", - "language.convert.confirm": "

Tényleg az alaőértelmezett nyelvre szeretnéd konvertálni ezt: {name}? Ez a művelet nem vonható vissza.

Ha{name} olyat is tartalmaz, amelynek nincs megfelelő fordítása, a honlapod egyes részei az új alapértelmezett nyelv hiányosságai miatt üresek maradhatnak.

", - "language.create": "Új nyelv hozzáadása", - "language.default": "Alapértelmezett nyelv", - "language.delete.confirm": "Tényleg törölni szeretnéd a(z) {name} nyelvet, annak minden fordításával együtt? Ez a művelet nem vonható vissza!", - "language.deleted": "A nyelv törölve lett", - "language.direction": "Olvasási irány", - "language.direction.ltr": "Balról jobbra", - "language.direction.rtl": "Jobbról balra", - "language.locale": "PHP locale sztring", - "language.locale.warning": "Egyedi nyelvi készletet használsz. Kérlek módosítsd a nyelvhez tartozó fájlt az alábbi mappában: /site/languages", - "language.name": "Név", - "language.secondary": "Secondary language", - "language.settings": "Language settings", - "language.updated": "A nyelv frissítve lett", - "language.variables": "Language variables", - "language.variables.empty": "No translations yet", - - "language.variable.delete.confirm": "Do you really want to delete the variable for {key}?", - "language.variable.key": "Key", - "language.variable.notFound": "The variable could not be found", - "language.variable.value": "Value", - - "languages": "Nyelvek", - "languages.default": "Alapértelmezett nyelv", - "languages.empty": "Nincsnek még nyelvek", - "languages.secondary": "Másodlagos nyelvek", - "languages.secondary.empty": "Nincsnek még másodlagos nyelvek", - - "license": "Kirby licenc", - "license.activate": "Activate it now", - "license.activate.label": "Please activate your license", - "license.activate.domain": "Your license will be activated for {host}.", - "license.activate.local": "You are about to activate your Kirby license for your local domain {host}. If this site will be deployed to a public domain, please activate it there instead. If {host} is the domain you want to use your license for, please continue.", - "license.activated": "Activated", - "license.buy": "Licenc vásárlása", - "license.code": "Kód", - "license.code.help": "You received your license code after the purchase via email. Please copy and paste it here.", - "license.code.label": "Kérlek írd be a licenc-kódot", - "license.status.active.info": "Includes new major versions until {date}", - "license.status.active.label": "Valid license", - "license.status.demo.info": "This is a demo installation", - "license.status.demo.label": "Demo", - "license.status.inactive.info": "Renew license to update to new major versions", - "license.status.inactive.label": "No new major versions", - "license.status.legacy.bubble": "Ready to renew your license?", - "license.status.legacy.info": "Your license does not cover this version", - "license.status.legacy.label": "Please renew your license", - "license.status.missing.bubble": "Ready to launch your site?", - "license.status.missing.info": "No valid license", - "license.status.missing.label": "Please activate your license", - "license.manage": "Manage your licenses", - "license.purchased": "Purchased", - "license.success": "Köszönjük, hogy támogatod a Kirby-t", - "license.unregistered.label": "Unregistered", - - "link": "Link", - "link.text": "Link szövege", - - "loading": "Betöltés", - - "lock.unsaved": "Nem mentett változások", - "lock.unsaved.empty": "Nincsenek nem mentett változások", - "lock.isLocked": "Unsaved changes by {email}", - "lock.unlock": "Kinyit", - "lock.unlock.submit": "Unlock and overwrite unsaved changes by {email}", - "lock.isUnlocked": "Was unlocked by another user", - - "login": "Bejelentkezés", - "login.code.label.login": "Bejelentkezéshez szükséges kód", - "login.code.label.password-reset": "Jelszóvisszaállításhoz szükséges kód", - "login.code.placeholder.email": "000 000", - "login.code.placeholder.totp": "000000", - "login.code.text.email": "Amennyiben az email-címed létezik a rendszerben, a kódot oda küldjük el.", - "login.code.text.totp": "Please enter the one‑time code from your authenticator app.", - "login.email.login.body": "Helló {user.nameOrEmail},\n\nNemrégiben bejelentkezési kódot igényeltél a(z) {site} Paneljéhez.\nAz alábbi kód {timeout} percig lesz érvényes:\n\n{code}\n\nHa nem te igényelted a kódot, kérlek hagyd figyelmen kívül ezt az emailt, kérdések esetén pedig vedd fel a kapcsolatot az oldal Adminisztrátorával.\nBiztonsági okokból kérjük NE továbbítsd ezt az emailt.", - "login.email.login.subject": "Bejelentkezési kódod", - "login.email.password-reset.body": "Helló {user.nameOrEmail},\n\nNemrégiben jelszóvisszaállítási kódot igényeltél a(z) {site} Paneljéhez.\nAz alábbi jelszóvisszaállítási kód {timeout} percig lesz érvényes:\n\n{code}\n\nHa nem te igényelted a jelszóvisszaállítási kódot, kérlek hagyd figyelmen kívül ezt az emailt, kérdések esetén pedig vedd fel a kapcsolatot az oldal Adminisztrátorával.\nBiztonsági okokból kérjük NE továbbítsd ezt az emailt.", - "login.email.password-reset.subject": "Jelszóvisszaállítási kódod", - "login.remember": "Maradjak bejelentkezve", - "login.reset": "Jelszó visszaállítása", - "login.toggleText.code.email": "Bejelentkezés emaillel", - "login.toggleText.code.email-password": "Bejelentkezés jelszóval", - "login.toggleText.password-reset.email": "Elfelejtetted a jelszavad?", - "login.toggleText.password-reset.email-password": "← Vissza a bejelentkezéshez", - "login.totp.enable.option": "Set up one‑time codes", - "login.totp.enable.intro": "Authenticator apps can generate one‑time codes that are used as a second factor when signing into your account.", - "login.totp.enable.qr.label": "1. Scan this QR code", - "login.totp.enable.qr.help": "Unable to scan? Add the setup key {secret} manually to your authenticator app.", - "login.totp.enable.confirm.headline": "2. Confirm with generated code", - "login.totp.enable.confirm.text": "Your app generates a new one‑time code every 30 seconds. Enter the current code to complete the setup:", - "login.totp.enable.confirm.label": "Current code", - "login.totp.enable.confirm.help": "After this setup, we will ask you for a one‑time code every time you log in.", - "login.totp.enable.success": "One‑time codes enabled", - "login.totp.disable.option": "Disable one‑time codes", - "login.totp.disable.label": "Enter your password to disable one‑time codes", - "login.totp.disable.help": "In the future, a different second factor like a login code sent via email will be requested when you log in. You can always set up one‑time codes again later.", - "login.totp.disable.admin": "

This will disable one‑time codes for {user}.

In the future, a different second factor like a login code sent via email will be requested when they log in. {user} can set up one‑time codes again after their next login.

", - "login.totp.disable.success": "One‑time codes disabled", - - "logout": "Kijelentkezés", - - "merge": "Merge", - "menu": "Menü", - "meridiem": "DE/DU", - "mime": "Média-típus", - "minutes": "Perc", - - "month": "Hónap", - "months.april": "\u00e1prilis", - "months.august": "augusztus", - "months.december": "december", - "months.february": "február", - "months.january": "janu\u00e1r", - "months.july": "j\u00falius", - "months.june": "j\u00fanius", - "months.march": "m\u00e1rcius", - "months.may": "m\u00e1jus", - "months.november": "november", - "months.october": "okt\u00f3ber", - "months.september": "szeptember", - - "more": "Több", - "move": "Move", - "name": "Név", - "next": "Következő", - "night": "Night", - "no": "nem", - "off": "ki", - "on": "be", - "open": "Megnyitás", - "open.newWindow": "Megnyitás új ablakban", - "option": "Option", - "options": "Beállítások", - "options.none": "Nincsnek beállítások", - "options.all": "Show all {count} options", - - "orientation": "Tájolás", - "orientation.landscape": "Fekvő", - "orientation.portrait": "Álló", - "orientation.square": "Négyzetes", - - "page": "Oldal", - "page.blueprint": "Ehhez az oldalhoz még nem tartozik oldalsablon. Itt hozhatod létre: /site/blueprints/pages/{blueprint}.yml", - "page.changeSlug": "URL v\u00e1ltoztat\u00e1sa", - "page.changeSlug.fromTitle": "L\u00e9trehoz\u00e1s c\u00edmb\u0151l", - "page.changeStatus": "Állapot módosítása", - "page.changeStatus.position": "Kérlek válaszd ki a pozíciót", - "page.changeStatus.select": "Új állapot kiválasztása", - "page.changeTemplate": "Sablon módosítása", - "page.changeTemplate.notice": "Changing the page's template will remove content for fields that don't match in type. Use with caution.", - "page.create": "Create as {status}", - "page.delete.confirm": "Biztos vagy benne, hogy törlöd az alábbi oldalt: {title}?", - "page.delete.confirm.subpages": "Ehhez az oldalhoz aloldalak tartoznak.
Az oldal törlésekor a hozzá tartozó aloldalak is törlődnek.", - "page.delete.confirm.title": "Megerősítéshez add meg az oldal címét", - "page.duplicate.appendix": "Másol", - "page.duplicate.files": "Fájlok másolása", - "page.duplicate.pages": "Oldalak másolása", - "page.move": "Move page", - "page.sort": "Sorrend megváltoztatása", - "page.status": "Állapot", - "page.status.draft": "Piszkozat", - "page.status.draft.description": "Ez az oldal jelenleg piszkozat és csak bejelentkezett szerkesztők számára, vagy egy titkos linken keresztül érhető el", - "page.status.listed": "Publikus", - "page.status.listed.description": "Az oldal mindenki számára elérhető", - "page.status.unlisted": "Nem listázott", - "page.status.unlisted.description": "Az oldal csak URL-en keresztül érhető el", - - "pages": "Oldalak", - "pages.empty": "Nincs még bejegyzés", - "pages.status.draft": "Piszkozatok", - "pages.status.listed": "Publikálva", - "pages.status.unlisted": "Nem listázott", - - "pagination.page": "Oldal", - - "password": "Jelsz\u00f3", - "paste": "Beillesztés", - "paste.after": "Beillesztés utána", - "paste.success": "{count} pasted!", - "pixel": "Pixel", - "plugin": "Plugin", - "plugins": "Pluginek", - "prev": "Előző", - "preview": "Előnézet", - "remove": "Eltávolítás", - "rename": "Átnevezés", - "renew": "Renew", - "replace": "Cser\u00e9l", - "replace.with": "Replace with", - "retry": "Próbáld újra", - "revert": "Visszavon\u00e1s", - "revert.confirm": "Tényleg törölni szeretnél minden nem mentett változtatást?", - - "role": "Szerepkör", - "role.admin.description": "Az adminisztrátornak minden joga van", - "role.admin.title": "Admin", - "role.all": "Összes", - "role.empty": "Nincsenek felhasználók ilyen szerepkörrel", - "role.description.placeholder": "Nincs leírás", - "role.nobody.description": "Ez a visszatérő szabály a nem rendelkező jogosultsághoz", - "role.nobody.title": "Senki", - - "save": "Ment\u00e9s", - "search": "Keresés", - "search.min": "A kereséshez írj be minimum {min} karaktert", - "search.all": "Show all {count} results", - "search.results.none": "Nincs találat", - - "section.invalid": "The section is invalid", - "section.required": "Ez a szakasz kötelező", - - "security": "Security", - "select": "Kiválasztás", - "server": "Szerver", - "settings": "Beállítások", - "show": "Mutat", - "site.blueprint": "Ehhez a weblaphoz még nem tartozik oldalsablon. Itt hozhatod létre: /site/blueprints/site.yml", - "size": "Méret", - "slug": "URL n\u00e9v", - "sort": "Rendezés", - "sort.drag": "Drag to sort …", - "split": "Split", - - "stats.empty": "No reports", - "status": "Állapot", - - "system.info.copy": "Copy info", - "system.info.copied": "System info copied", - "system.issues.content": "The content folder seems to be exposed", - "system.issues.eol.kirby": "Your installed Kirby version has reached end-of-life and will not receive further security updates", - "system.issues.eol.plugin": "Your installed version of the { plugin } plugin is has reached end-of-life and will not receive further security updates", - "system.issues.eol.php": "Your installed PHP release { release } has reached end-of-life and will not receive further security updates", - "system.issues.debug": "Debugging must be turned off in production", - "system.issues.git": "The .git folder seems to be exposed", - "system.issues.https": "We recommend HTTPS for all your sites", - "system.issues.kirby": "The kirby folder seems to be exposed", - "system.issues.site": "The site folder seems to be exposed", - "system.issues.vulnerability.kirby": "Your installation might be affected by the following vulnerability ({ severity } severity): { description }", - "system.issues.vulnerability.plugin": "Your installation might be affected by the following vulnerability in the { plugin } plugin ({ severity } severity): { description }", - "system.updateStatus": "Update status", - "system.updateStatus.error": "Could not check for updates", - "system.updateStatus.not-vulnerable": "No known vulnerabilities", - "system.updateStatus.security-update": "Free security update { version } available", - "system.updateStatus.security-upgrade": "Upgrade { version } with security fixes available", - "system.updateStatus.unreleased": "Unreleased version", - "system.updateStatus.up-to-date": "Up to date", - "system.updateStatus.update": "Free update { version } available", - "system.updateStatus.upgrade": "Upgrade { version } available", - - "tel": "Phone", - "tel.placeholder": "+49123456789", - "template": "Sablon", - "title": "Cím", - "today": "Ma", - - "toolbar.button.clear": "Clear formatting", - "toolbar.button.code": "Kód", - "toolbar.button.bold": "F\u00e9lk\u00f6v\u00e9r sz\u00f6veg", - "toolbar.button.email": "Email", - "toolbar.button.headings": "Címsor", - "toolbar.button.heading.1": "Címsor 1", - "toolbar.button.heading.2": "Címsor 2", - "toolbar.button.heading.3": "Címsor 3", - "toolbar.button.heading.4": "Címsor 4", - "toolbar.button.heading.5": "Címsor 5", - "toolbar.button.heading.6": "Címsor 6", - "toolbar.button.italic": "Dőlt szöveg", - "toolbar.button.file": "Fájl", - "toolbar.button.file.select": "Válassz egy fájlt", - "toolbar.button.file.upload": "Fájl feltöltése", - "toolbar.button.link": "Link", - "toolbar.button.paragraph": "Bekezdés", - "toolbar.button.strike": "Áthúzott szöveg", - "toolbar.button.sub": "Subscript", - "toolbar.button.sup": "Superscript", - "toolbar.button.ol": "Rendezett lista", - "toolbar.button.underline": "Aláhúzott szöveg", - "toolbar.button.ul": "Rendezetlen lista", - - "translation.author": "A Kirby csapata", - "translation.direction": "ltr", - "translation.name": "Magyar", - "translation.locale": "hu_HU", - - "type": "Type", - - "upload": "Feltöltés", - "upload.error.cantMove": "A feltöltött fájlt nem sikerült áthelyezni", - "upload.error.cantWrite": "Hiba a fájl lemezre írása közben", - "upload.error.default": "A fájlt nem sikerült feltölteni", - "upload.error.extension": "A fájlfeltöltés egy kiterjesztés miatt megszakadt", - "upload.error.formSize": "A feltöltendő fájl mérete nagyobb, mint az űrlap MAX_FILE_SIZE szabályában beállított érték", - "upload.error.iniPostSize": "A feltöltendő fájl mérete nagyobb, mint a php.ini post_max_size szabályában beállított érték", - "upload.error.iniSize": "A feltöltendő fájl mérete nagyobb, mint a php.ini upload_max_filesize szabályában beállított érték", - "upload.error.noFile": "Nem lett fájl feltöltve", - "upload.error.noFiles": "Nem lettek fájlok feltöltve", - "upload.error.partial": "A fájl feltöltése csak részben sikerült", - "upload.error.tmpDir": "Hiányzik egy átmeneti mappa", - "upload.errors": "Hiba", - "upload.progress": "Feltöltés...", - - "url": "Url", - "url.placeholder": "https://pelda.hu", - - "user": "Felhasználó", - "user.blueprint": "További szakaszokat és mezőket adhatsz meg ehhez a felhasználói szerepkörhöz itt: /site/blueprints/users/{blueprint}.yml", - "user.changeEmail": "Email módosítása", - "user.changeLanguage": "Nyelv módosítása", - "user.changeName": "Felhasználó átnevezése", - "user.changePassword": "Jelszó módosítása", - "user.changePassword.new": "Új jelszó", - "user.changePassword.new.confirm": "Az új jelszó megerősítése", - "user.changeRole": "Szerepkör módosítása", - "user.changeRole.select": "Új szerepkör kiválasztása", - "user.create": "Új felhasználó hozzáadása", - "user.delete": "Felhasználó törlése", - "user.delete.confirm": "Biztos törlöd ezt a felhasználót:
{email}?", - - "users": "Felhasználók", - - "version": "Kirby verzi\u00f3", - "version.current": "Current version", - "version.latest": "Latest version", - "versionInformation": "Version information", - - "view.account": "Fi\u00f3kod", - "view.installation": "Telep\u00edt\u00e9s", - "view.languages": "Nyelvek", - "view.resetPassword": "Jelszó visszaállítása", - "view.site": "Weboldal", - "view.system": "Rendszer", - "view.users": "Felhaszn\u00e1l\u00f3k", - - "welcome": "Üdvözlünk", - "year": "Év", - "yes": "igen" + "account.changeName": "Név megváltoztatása", + "account.delete": "Fiók törlése", + "account.delete.confirm": "Tényleg törölni szeretnéd a fiókodat? Azonnal kijelentkeztetünk és ez a folyamat visszavonhatatlan.", + + "add": "Hozz\u00e1ad", + "author": "Szerző", + "avatar": "Profilkép", + "back": "Vissza", + "cancel": "M\u00e9gsem", + "change": "M\u00f3dos\u00edt\u00e1s", + "close": "Bez\u00e1r", + "confirm": "Mentés", + "collapse": "Bezárás", + "collapse.all": "Összes bezárása", + "copy": "Másol", + "copy.all": "Összes másolása", + "create": "Létrehoz", + + "date": "Dátum", + "date.select": "Dátum kiválasztása", + + "day": "Nap", + "days.fri": "p\u00e9", + "days.mon": "h\u00e9", + "days.sat": "szo", + "days.sun": "va", + "days.thu": "cs\u00fc", + "days.tue": "ke", + "days.wed": "sze", + + "debugging": "Hibakeresés", + + "delete": "T\u00f6rl\u00e9s", + "delete.all": "Összes törlése", + + "dialog.files.empty": "Nincsenek fájlok kiválasztva", + "dialog.pages.empty": "Nincsenek oldalak kiválasztva", + "dialog.users.empty": "Nincsenek felhasználók kiválasztva", + + "dimensions": "Méretek", + "disabled": "Inaktív", + "discard": "Visszavon\u00e1s", + "download": "Letöltés", + "duplicate": "Másolat", + + "edit": "Aloldal szerkeszt\u00e9se", + + "email": "Email", + "email.placeholder": "mail@pelda.hu", + + "entries": "Entries", + "entry": "Entry", + + "environment": "Környezet", + + "error.access.code": "Érvénytelen kód", + "error.access.login": "Érvénytelen bejelentkezés", + "error.access.panel": "Nincs jogosultságod megnyitni a panelt", + "error.access.view": "Nincs hozzáférésed a panel ezen részéhez", + + "error.avatar.create.fail": "A profilkép feltöltése nem sikerült", + "error.avatar.delete.fail": "A profilkép nem törölhető", + "error.avatar.dimensions.invalid": "A profilkép maximális szélessége és magassága 3000 pixel lehet", + "error.avatar.mime.forbidden": "A profilkép formátuma csak JPEG vagy PNG lehet", + + "error.blueprint.notFound": "A \"{name}\" oldalsablon nem tölthető be", + + "error.blocks.max.plural": "Legfeljebb {max} blokk adható hozzá", + "error.blocks.max.singular": "Csak egyetlen blokk adható hozzá", + "error.blocks.min.plural": "Legalább {min} blokkot hozzá kell adnod", + "error.blocks.min.singular": "Legalább egy blokkot hozzá kell adnod", + "error.blocks.validation": "Hiba van az alábbi blokkban: {index}", + + "error.email.preset.notFound": "A \"{name}\" email-beállítás nem található", + + "error.field.converter.invalid": "Érvénytelen konverter: \"{converter}\"", + + "error.file.changeName.empty": "A név nem lehet üres", + "error.file.changeName.permission": "Nincs jogosultságod megváltoztatni a \"{filename}\" fájl nevét", + "error.file.duplicate": "Már létezik \"{filename}\" nevű fájl", + "error.file.extension.forbidden": "Tiltott kiterjeszt\u00e9s\u0171 f\u00e1jl", + "error.file.extension.invalid": "Érvénytelen kiterjesztés: {extension}", + "error.file.extension.missing": "Kiterjeszt\u00e9s n\u00e9lk\u00fcli f\u00e1jl nem t\u00f6lthet\u0151 fel", + "error.file.maxheight": "A kép nem lehet magasabb {height} pixelnél", + "error.file.maxsize": "A fájl túl nagy", + "error.file.maxwidth": "A kép nem lehet szélesebb {width} pixelnél", + "error.file.mime.differs": "A feltöltött fájlnak azonos \"{mime}\" típusúnak kell lennie", + "error.file.mime.forbidden": "A \"{mime}\" típusú médiafájlok nem engedélyezettek", + "error.file.mime.invalid": "Érvénytelen mime-típus: {mime}", + "error.file.mime.missing": "A \"{filename}\" fájl típusa nem állapítható meg", + "error.file.minheight": "A képnek legalább {height} pixel magasnak kell lennie", + "error.file.minsize": "A fájl túl kicsi", + "error.file.minwidth": "A képnek legalább {width} pixel szélesnek kell lennie", + "error.file.name.missing": "A fálj neve nem lehet üres", + "error.file.notFound": "A \"{filename}\" fájl nem található", + "error.file.orientation": "A képnek \"{orientation}\" tájolásúnak kell lennie", + "error.file.type.forbidden": "Nem tölthetsz fel \"{type}\" típusú fájlokat", + "error.file.type.invalid": "Érvénytelen fájltípus: {type}", + "error.file.undefined": "A f\u00e1jl nem tal\u00e1lhat\u00f3", + + "error.form.incomplete": "Kérlek javítsd ki az összes hibát az űrlapon", + "error.form.notSaved": "Az űrlap nem menthető", + + "error.language.code": "Kérlek, add meg a nyelv érvényes kódját", + "error.language.duplicate": "A nyelv már létezik", + "error.language.name": "Kérlek, add meg a nyelv érvényes nevét", + "error.language.notFound": "A nyelv nem található", + + "error.layout.validation.block": "Hibát találtunk az alábbi blokkban: {blockIndex} az alábbi elrendezésben: {layoutIndex}", + "error.layout.validation.settings": "Hibát találtunk a(z) {index} elrendezés beállításaiban", + + "error.license.format": "Kérlek, add meg az évényes lincensz kulcsot", + "error.license.email": "Kérlek adj meg egy valós email-címet", + "error.license.verification": "A licensz nem ellenőrizhető", + + "error.offline": "A Panel jelenleg nem elérhető", + + "error.page.changeSlug.permission": "Nem változtathatod meg az URL-előtagot: \"{slug}\"", + "error.page.changeStatus.incomplete": "Az oldal hibákat tartalmaz és nem publikálható", + "error.page.changeStatus.permission": "Az oldal státusza nem változtatható meg", + "error.page.changeStatus.toDraft.invalid": "A(z) \"{slug}\" oldalt nem lehet piszkozattá alakítani", + "error.page.changeTemplate.invalid": "A \"{slug}\" oldal sablonját nem lehet megváltoztatni", + "error.page.changeTemplate.permission": "Nincs jogosultságod megváltoztatni a sablont ehhez: \"{slug}\"", + "error.page.changeTitle.empty": "A cím nem lehet üres", + "error.page.changeTitle.permission": "Nincs jogosultságod megváltoztatni a címet: \"{slug}\"", + "error.page.create.permission": "Nincs jogosultságod az oldal létrehozásához: \"{slug}\"", + "error.page.delete": "A(z) \"{slug}\" oldal nem törölhető", + "error.page.delete.confirm": "Megerősítéshez add meg az oldal címét", + "error.page.delete.hasChildren": "Az oldalnak vannak aloldalai és nem törölhető", + "error.page.delete.permission": "Nincs jogosultságod a(z) \"{slug}\" oldal törléséhez", + "error.page.draft.duplicate": "Van már egy másik oldal ezzel az URL-lel: \"{slug}\"", + "error.page.duplicate": "Van már egy másik oldal ezzel az URL-lel: \"{slug}\"", + "error.page.duplicate.permission": "Nincs engedélyed a(z) \"{slug}\" másolat keszítéséhez", + "error.page.notFound": "Az oldal nem tal\u00e1lhat\u00f3", + "error.page.num.invalid": "Kérlek megfelelő oldalszámozást adj meg. Negatív szám itt nem használható.", + "error.page.slug.invalid": "Kérlek érvényes URL-kiterjesztést adj meg", + "error.page.slug.maxlength": "Az URL maximum \"{length}\" karakter hosszúságú lehet", + "error.page.sort.permission": "A(z) \"{slug}\" oldal nem illeszthető a sorrendbe", + "error.page.status.invalid": "Kérlek add meg a megfelelő oldalstátuszt", + "error.page.undefined": "Az oldal nem tal\u00e1lhat\u00f3", + "error.page.update.permission": "Nincs jogosultságod a(z) \"{slug}\" oldal frissítéséhez", + + "error.section.files.max.plural": "Maximum {max} fájlt adhatsz hozzá a(z) \"{section}\" szekcióhoz", + "error.section.files.max.singular": "Nem adhatsz hozzá egynél több fájlt a(z) \"{section}\" szekcióhoz", + "error.section.files.min.plural": "A \"{section}\" szakasz legalább {min} fájlt igényel", + "error.section.files.min.singular": "A \"{section}\" szakasz legalább egy fájlt igényel", + + "error.section.pages.max.plural": "Maximum {max} oldalt adhatsz hozzá a(z) \"{section}\" szekcióhoz", + "error.section.pages.max.singular": "Nem adhatsz hozzá egynél több oldalt a(z) \"{section}\" szekcióhoz", + "error.section.pages.min.plural": "A \"{section}\" szakasz legalább {min} oldalt igényel", + "error.section.pages.min.singular": "A \"{section}\" szakasz legalább egy oldalt igényel", + + "error.section.notLoaded": "A(z) \"{name}\" szekció nem tölthető be", + "error.section.type.invalid": "A szekció típusa (\"{type}\") nem megfelelő", + + "error.site.changeTitle.empty": "A cím nem lehet üres", + "error.site.changeTitle.permission": "Nincs jogosultságod megváltoztatni az honlap címét", + "error.site.update.permission": "Nincs jogosultságod frissíteni a honlapot", + + "error.template.default.notFound": "Az alapértelmezett sablon nem létezik", + + "error.unexpected": "Váratlan hiba történt! További információért engedélyezd a hibakeresés módot: https://getkirby.com/docs/reference/system/options/debug", + + "error.user.changeEmail.permission": "Nincs jogosultságod megváltoztatni \"{name}\" felhasználó email-címét", + "error.user.changeLanguage.permission": "Nincs jogosultságod megváltoztatni \"{name}\" felhasználó nyelvi beállításait", + "error.user.changeName.permission": "Nincs jogosultságod megváltoztatni \"{name}\" felhasználó nevét", + "error.user.changePassword.permission": "Nincs jogosultságod megváltoztatni \"{name}\" felhasználó jelszavát", + "error.user.changeRole.lastAdmin": "Az egyedüli adminisztrátor szerepkörét nem lehet megváltoztatni", + "error.user.changeRole.permission": "Nincs jogosultságod megváltoztatni \"{name}\" felhasználó szerepkörét", + "error.user.changeRole.toAdmin": "Nincs jogosultságod előléptetni a felhasználót adminisztrátorrá", + "error.user.create.permission": "Nincs jogosultságod létrehozni ezt a felhasználót", + "error.user.delete": "A felhaszn\u00e1l\u00f3 nem t\u00f6r\u00f6lhet\u0151", + "error.user.delete.lastAdmin": "Nem t\u00f6r\u00f6lheted az egyetlen adminisztr\u00e1tort", + "error.user.delete.lastUser": "Nem törölheted az egyetlen felhasználót", + "error.user.delete.permission": "Nincs jogosults\u00e1god t\u00f6r\u00f6lni ezt a felhaszn\u00e1l\u00f3t", + "error.user.duplicate": "Már létezik felhasználó \"{email}\" email-címmel", + "error.user.email.invalid": "Kérlek adj meg egy valós email-címet", + "error.user.language.invalid": "Kérlek add meg a megfelelő nyelvi beállítást", + "error.user.notFound": "A felhaszn\u00e1l\u00f3 nem tal\u00e1lhat\u00f3", + "error.user.password.excessive": "Please enter a valid password. Passwords must not be longer than 1000 characters.", + "error.user.password.invalid": "Kérlek adj meg egy megfelelő jelszót. A jelszónak legalább 8 karakter hosszúságúnak kell lennie.", + "error.user.password.notSame": "K\u00e9rlek er\u0151s\u00edtsd meg a jelsz\u00f3t", + "error.user.password.undefined": "A felhasználónak nincs jelszó megadva", + "error.user.password.wrong": "Hibás jelszó", + "error.user.role.invalid": "Kérlek adj meg egy megfelelő szerepkört", + "error.user.undefined": "A felhasználó nem található", + "error.user.update.permission": "Nincs jogosultságod frissíteni \"{name}\" felhasználó adatait", + + "error.validation.accepted": "Kérlek erősítsd meg", + "error.validation.alpha": "Kérlek csak kis betűket használj (a-z)", + "error.validation.alphanum": "Kérlek csak kis betűket és számjegyeket használj (a-z, 0-9)", + "error.validation.between": "Kérlek egy \"{min}\" és \"{max}\" közötti értéket adj meg", + "error.validation.boolean": "Kérlek erősítsd meg vagy vesd el", + "error.validation.contains": "Kérlek olyan értéket adj meg, amely tartalmazza ezt: \"{needle}\"", + "error.validation.date": "Kérlek megfelelő dátumot adj meg", + "error.validation.date.after": "Kérlek olyan dátumot adj meg, amely későbbi ennél: {date}", + "error.validation.date.before": "Kérlek olyan dátumot adj meg, amely korábbi ennél: {date}", + "error.validation.date.between": "Kérlek {min} és {max} közötti dátumot adj meg", + "error.validation.denied": "Kérlek vesd el", + "error.validation.different": "Az érték nem lehet \"{other}\"", + "error.validation.email": "Kérlek adj meg egy valós email-címet", + "error.validation.endswith": "Az értéknek erre kell végződnie: \"{end}\"", + "error.validation.filename": "Kérlek megfelelő fájlnevet adj meg", + "error.validation.in": "Kérlek adj meg egyet az alábbiak közül: ({in})", + "error.validation.integer": "Kérlek valós számot adj meg", + "error.validation.ip": "Kérlek megfelelő IP-címet adj meg", + "error.validation.less": "A megadott érték kevesebb legyen, mint {max}", + "error.validation.match": "A megadott érték nem felel meg az elvárt struktúrának", + "error.validation.max": "A megadott érték egyenlő vagy kevesebb legyen, mint {max}", + "error.validation.maxlength": "Kérlek rövidebb értéket adj meg (legfeljebb {max} karakter)", + "error.validation.maxwords": "Kérlek ide legfeljebb {max} szót írj", + "error.validation.min": "A megadott érték egyenlő vagy nagyobb legyen, mint {min}", + "error.validation.minlength": "Kérlek hosszabb értéket adj meg (legalább {min} karakter)", + "error.validation.minwords": "Kérlek ide legalább {min} szót írj", + "error.validation.more": "A megadott érték legyen nagyobb, mint {min} ", + "error.validation.notcontains": "Kérlek olyan értéket adj meg, amely nem tartalmazza ezt: \"{needle}\" ", + "error.validation.notin": "Kérlek egyiket se használd az alábbiak közül: ({notIn})", + "error.validation.option": "Kérlek válassz egy megfelelő opciót", + "error.validation.num": "Kérlek adj meg egy megfelelő számot", + "error.validation.required": "Kérlek írj be valamit", + "error.validation.same": "Kérlek írd be: \"{other}\"", + "error.validation.size": "Az értéknek az alábbi méretűnek kell lennie: \"{size}\"", + "error.validation.startswith": "Az értéknek ezzel kell kezdődnie: \"{start}\"", + "error.validation.time": "Kérlek megfelelő időt adj meg", + "error.validation.time.after": "Kérlek olyan időpontot adj meg, amely későbbi ennél: {time}", + "error.validation.time.before": "Kérlek olyan időpontot adj meg, amely korábbi ennél: {time}", + "error.validation.time.between": "Kérlek {min} és {max} közötti időpontot adj meg", + "error.validation.url": "Kérlek megfelelő URL-t adj meg", + + "expand": "Kinyitás", + "expand.all": "Összes kinyitása", + + "field.required": "Kötelező mező", + "field.blocks.changeType": "Típus megváltoztatása", + "field.blocks.code.name": "Kód", + "field.blocks.code.language": "Nyelv", + "field.blocks.code.placeholder": "A megjelenítendő kód …", + "field.blocks.delete.confirm": "Tényleg törölni szeretnéd ezt a blokkot?", + "field.blocks.delete.confirm.all": "Tényleg minden blokkot törölni szeretnél?", + "field.blocks.delete.confirm.selected": "Tényleg törölni szeretnéd a kijelölt blokkokat?", + "field.blocks.empty": "Még nincsenek blokkok", + "field.blocks.fieldsets.label": "Kérlek válassz blokktípust …", + "field.blocks.fieldsets.paste": "Blokk beszúrásához a vágólapról használd a {{ shortcut }} billentyűkombinációt", + "field.blocks.gallery.name": "Galéria", + "field.blocks.gallery.images.empty": "Még nincsenek képek", + "field.blocks.gallery.images.label": "Képek", + "field.blocks.heading.level": "Szint", + "field.blocks.heading.name": "Címsor", + "field.blocks.heading.text": "Szöveg", + "field.blocks.heading.placeholder": "Címsor …", + "field.blocks.image.alt": "Alternatív szöveg", + "field.blocks.image.caption": "Képaláírás", + "field.blocks.image.crop": "Körülvágás", + "field.blocks.image.link": "Link", + "field.blocks.image.location": "A kép helye", + "field.blocks.image.name": "Kép", + "field.blocks.image.placeholder": "Kép kiválasztása", + "field.blocks.image.ratio": "Képarány", + "field.blocks.image.url": "Kép URL-je", + "field.blocks.line.name": "Vonal", + "field.blocks.list.name": "Lista", + "field.blocks.markdown.name": "Markdown", + "field.blocks.markdown.label": "Szöveg", + "field.blocks.markdown.placeholder": "Markdown …", + "field.blocks.quote.name": "Idézet", + "field.blocks.quote.text.label": "Szöveg", + "field.blocks.quote.text.placeholder": "Idézet szövege …", + "field.blocks.quote.citation.label": "Idézet szerzője", + "field.blocks.quote.citation.placeholder": "Szerző …", + "field.blocks.text.name": "Szöveg", + "field.blocks.text.placeholder": "Szöveg …", + "field.blocks.video.caption": "Képaláírás", + "field.blocks.video.name": "Videó", + "field.blocks.video.placeholder": "Videó URL-jének megadása", + "field.blocks.video.url.label": "Videó URL", + "field.blocks.video.url.placeholder": "https://youtube.com/?v=", + + "field.files.empty": "Nincs fálj kiválasztva", + + "field.layout.delete": "Elrendezés törlése", + "field.layout.delete.confirm": "Tényleg törölni szeretnéd ezt az elrendezést?", + "field.layout.empty": "Még nincsenek sorok", + "field.layout.select": "Válassz elrendezést", + + "field.pages.empty": "Nincs oldal kiválasztva", + "field.structure.delete.confirm": "Biztos t\u00f6r\u00f6lni szeretn\u00e9d ezt a bejegyz\u00e9st?", + "field.structure.empty": "Nincs m\u00e9g bejegyz\u00e9s", + "field.users.empty": "Nincs felhasználó kiválasztva", + + "file.blueprint": "Ehhez a fájlhoz még nem tartozik oldalsablon. Itt hozhatod létre: /site/blueprints/files/{blueprint}.yml", + "file.delete.confirm": "Biztos törölni akarod ezt a fájlt:
{filename}?", + "file.sort": "Sorrend megváltoztatása", + + "files": "Fájlok", + "files.empty": "Még nincsenek fájlok", + + "hide": "Elrejtés", + "hour": "Óra", + "import": "Importálás", + "info": "Info", + "insert": "Beilleszt", + "insert.after": "Beszúrás mögé", + "insert.before": "Beszúrás elé", + "install": "Telepítés", + + "installation": "Telepítés", + "installation.completed": "A panel sikeresen telepítve", + "installation.disabled": "A panel telepítője alapértelmezés szerint le van tiltva a nyilvános szervereken. Kérlek, futtassd a telepítőt egy helyi gépen vagy engedélyezze a panel.install opcióval.", + "installation.issues.accounts": "A /site/accounts mappa nem létezik, vagy nem írható", + "installation.issues.content": "A /content mappa nem létezik vagy nem írható", + "installation.issues.curl": "A CURL bővítmény engedélyezése szükséges", + "installation.issues.headline": "A panel telepítése sikertelen", + "installation.issues.mbstring": "Az MB String bővítmény engedélyezése szükséges", + "installation.issues.media": "A /media mappa nem létezik vagy nem írható", + "installation.issues.php": "Bizonyosodj meg róla, hogy az általad használt PHP-verzió PHP 7+", + "installation.issues.server": "A Kirby az alábbi szervereken futtatható: Apache, Nginx vagy Caddy", + "installation.issues.sessions": "A /site/sessions könyvtár nem létezik vagy nem írható", + + "language": "Nyelv", + "language.code": "Kód", + "language.convert": "Alapértelmezettnek jelölés", + "language.convert.confirm": "

Tényleg az alaőértelmezett nyelvre szeretnéd konvertálni ezt: {name}? Ez a művelet nem vonható vissza.

Ha{name} olyat is tartalmaz, amelynek nincs megfelelő fordítása, a honlapod egyes részei az új alapértelmezett nyelv hiányosságai miatt üresek maradhatnak.

", + "language.create": "Új nyelv hozzáadása", + "language.delete.confirm": "Tényleg törölni szeretnéd a(z) {name} nyelvet, annak minden fordításával együtt? Ez a művelet nem vonható vissza!", + "language.deleted": "A nyelv törölve lett", + "language.direction": "Olvasási irány", + "language.direction.ltr": "Balról jobbra", + "language.direction.rtl": "Jobbról balra", + "language.locale": "PHP locale sztring", + "language.locale.warning": "Egyedi nyelvi készletet használsz. Kérlek módosítsd a nyelvhez tartozó fájlt az alábbi mappában: /site/languages", + "language.name": "Név", + "language.updated": "A nyelv frissítve lett", + + "languages": "Nyelvek", + "languages.default": "Alapértelmezett nyelv", + "languages.empty": "Nincsnek még nyelvek", + "languages.secondary": "Másodlagos nyelvek", + "languages.secondary.empty": "Nincsnek még másodlagos nyelvek", + + "license": "Kirby licenc", + "license.buy": "Licenc vásárlása", + "license.register": "Regisztráció", + "license.manage": "Manage your licenses", + "license.register.help": "A vásárlás után emailben küldjük el a licenc-kódot. Regisztrációhoz másold ide a kapott kódot.", + "license.register.label": "Kérlek írd be a licenc-kódot", + "license.register.success": "Köszönjük, hogy támogatod a Kirby-t", + "license.unregistered": "Jelenleg a Kirby nem regisztrált próbaverzióját használod", + "license.unregistered.label": "Unregistered", + + "link": "Link", + "link.text": "Link szövege", + + "loading": "Betöltés", + + "lock.unsaved": "Nem mentett változások", + "lock.unsaved.empty": "Nincsenek nem mentett változások", + "lock.isLocked": "Nem mentett {email} változások", + "lock.file.isLocked": "A fájlt jelenleg {email} szerkeszti és nem módosítható.", + "lock.page.isLocked": "Az oldalt jelenleg {email} szerkeszti és nem módosítható.", + "lock.unlock": "Kinyit", + "lock.isUnlocked": "A nem mentett módosításokat egy másik felhasználó felülírta. A módosításokat manuálisan egyesítheted.", + + "login": "Bejelentkezés", + "login.code.label.login": "Bejelentkezéshez szükséges kód", + "login.code.label.password-reset": "Jelszóvisszaállításhoz szükséges kód", + "login.code.placeholder.email": "000 000", + "login.code.text.email": "Amennyiben az email-címed létezik a rendszerben, a kódot oda küldjük el.", + "login.email.login.body": "Helló {user.nameOrEmail},\n\nNemrégiben bejelentkezési kódot igényeltél a(z) {site} Paneljéhez.\nAz alábbi kód {timeout} percig lesz érvényes:\n\n{code}\n\nHa nem te igényelted a kódot, kérlek hagyd figyelmen kívül ezt az emailt, kérdések esetén pedig vedd fel a kapcsolatot az oldal Adminisztrátorával.\nBiztonsági okokból kérjük NE továbbítsd ezt az emailt.", + "login.email.login.subject": "Bejelentkezési kódod", + "login.email.password-reset.body": "Helló {user.nameOrEmail},\n\nNemrégiben jelszóvisszaállítási kódot igényeltél a(z) {site} Paneljéhez.\nAz alábbi jelszóvisszaállítási kód {timeout} percig lesz érvényes:\n\n{code}\n\nHa nem te igényelted a jelszóvisszaállítási kódot, kérlek hagyd figyelmen kívül ezt az emailt, kérdések esetén pedig vedd fel a kapcsolatot az oldal Adminisztrátorával.\nBiztonsági okokból kérjük NE továbbítsd ezt az emailt.", + "login.email.password-reset.subject": "Jelszóvisszaállítási kódod", + "login.remember": "Maradjak bejelentkezve", + "login.reset": "Jelszó visszaállítása", + "login.toggleText.code.email": "Bejelentkezés emaillel", + "login.toggleText.code.email-password": "Bejelentkezés jelszóval", + "login.toggleText.password-reset.email": "Elfelejtetted a jelszavad?", + "login.toggleText.password-reset.email-password": "← Vissza a bejelentkezéshez", + + "logout": "Kijelentkezés", + + "menu": "Menü", + "meridiem": "DE/DU", + "mime": "Média-típus", + "minutes": "Perc", + + "month": "Hónap", + "months.april": "\u00e1prilis", + "months.august": "augusztus", + "months.december": "december", + "months.february": "február", + "months.january": "janu\u00e1r", + "months.july": "j\u00falius", + "months.june": "j\u00fanius", + "months.march": "m\u00e1rcius", + "months.may": "m\u00e1jus", + "months.november": "november", + "months.october": "okt\u00f3ber", + "months.september": "szeptember", + + "more": "Több", + "name": "Név", + "next": "Következő", + "no": "nem", + "off": "ki", + "on": "be", + "open": "Megnyitás", + "open.newWindow": "Megnyitás új ablakban", + "options": "Beállítások", + "options.none": "Nincsnek beállítások", + + "orientation": "Tájolás", + "orientation.landscape": "Fekvő", + "orientation.portrait": "Álló", + "orientation.square": "Négyzetes", + + "page.blueprint": "Ehhez az oldalhoz még nem tartozik oldalsablon. Itt hozhatod létre: /site/blueprints/pages/{blueprint}.yml", + "page.changeSlug": "URL v\u00e1ltoztat\u00e1sa", + "page.changeSlug.fromTitle": "L\u00e9trehoz\u00e1s c\u00edmb\u0151l", + "page.changeStatus": "Állapot módosítása", + "page.changeStatus.position": "Kérlek válaszd ki a pozíciót", + "page.changeStatus.select": "Új állapot kiválasztása", + "page.changeTemplate": "Sablon módosítása", + "page.delete.confirm": "Biztos vagy benne, hogy törlöd az alábbi oldalt: {title}?", + "page.delete.confirm.subpages": "Ehhez az oldalhoz aloldalak tartoznak.
Az oldal törlésekor a hozzá tartozó aloldalak is törlődnek.", + "page.delete.confirm.title": "Megerősítéshez add meg az oldal címét", + "page.draft.create": "Piszkozat létrehozása", + "page.duplicate.appendix": "Másol", + "page.duplicate.files": "Fájlok másolása", + "page.duplicate.pages": "Oldalak másolása", + "page.sort": "Sorrend megváltoztatása", + "page.status": "Állapot", + "page.status.draft": "Piszkozat", + "page.status.draft.description": "Ez az oldal jelenleg piszkozat és csak bejelentkezett szerkesztők számára, vagy egy titkos linken keresztül érhető el", + "page.status.listed": "Publikus", + "page.status.listed.description": "Az oldal mindenki számára elérhető", + "page.status.unlisted": "Nem listázott", + "page.status.unlisted.description": "Az oldal csak URL-en keresztül érhető el", + + "pages": "Oldalak", + "pages.empty": "Nincs még bejegyzés", + "pages.status.draft": "Piszkozatok", + "pages.status.listed": "Publikálva", + "pages.status.unlisted": "Nem listázott", + + "pagination.page": "Oldal", + + "password": "Jelsz\u00f3", + "paste": "Beillesztés", + "paste.after": "Beillesztés utána", + "pixel": "Pixel", + "plugins": "Pluginek", + "prev": "Előző", + "preview": "Előnézet", + "remove": "Eltávolítás", + "rename": "Átnevezés", + "replace": "Cser\u00e9l", + "retry": "Próbáld újra", + "revert": "Visszavon\u00e1s", + "revert.confirm": "Tényleg törölni szeretnél minden nem mentett változtatást?", + + "role": "Szerepkör", + "role.admin.description": "Az adminisztrátornak minden joga van", + "role.admin.title": "Admin", + "role.all": "Összes", + "role.empty": "Nincsenek felhasználók ilyen szerepkörrel", + "role.description.placeholder": "Nincs leírás", + "role.nobody.description": "Ez a visszatérő szabály a nem rendelkező jogosultsághoz", + "role.nobody.title": "Senki", + + "save": "Ment\u00e9s", + "search": "Keresés", + "search.min": "A kereséshez írj be minimum {min} karaktert", + "search.all": "Összes mutatása", + "search.results.none": "Nincs találat", + + "section.required": "Ez a szakasz kötelező", + + "security": "Security", + "select": "Kiválasztás", + "server": "Szerver", + "settings": "Beállítások", + "show": "Mutat", + "site.blueprint": "Ehhez a weblaphoz még nem tartozik oldalsablon. Itt hozhatod létre: /site/blueprints/site.yml", + "size": "Méret", + "slug": "URL n\u00e9v", + "sort": "Rendezés", + + "stats.empty": "No reports", + "system.issues.content": "The content folder seems to be exposed", + "system.issues.debug": "Debugging must be turned off in production", + "system.issues.git": "The .git folder seems to be exposed", + "system.issues.https": "We recommend HTTPS for all your sites", + "system.issues.kirby": "The kirby folder seems to be exposed", + "system.issues.site": "The site folder seems to be exposed", + + "title": "Cím", + "template": "Sablon", + "today": "Ma", + + "toolbar.button.code": "Kód", + "toolbar.button.bold": "F\u00e9lk\u00f6v\u00e9r sz\u00f6veg", + "toolbar.button.email": "Email", + "toolbar.button.headings": "Címsor", + "toolbar.button.heading.1": "Címsor 1", + "toolbar.button.heading.2": "Címsor 2", + "toolbar.button.heading.3": "Címsor 3", + "toolbar.button.heading.4": "Címsor 4", + "toolbar.button.heading.5": "Címsor 5", + "toolbar.button.heading.6": "Címsor 6", + "toolbar.button.italic": "Dőlt szöveg", + "toolbar.button.file": "Fájl", + "toolbar.button.file.select": "Válassz egy fájlt", + "toolbar.button.file.upload": "Fájl feltöltése", + "toolbar.button.link": "Link", + "toolbar.button.paragraph": "Bekezdés", + "toolbar.button.strike": "Áthúzott szöveg", + "toolbar.button.ol": "Rendezett lista", + "toolbar.button.underline": "Aláhúzott szöveg", + "toolbar.button.ul": "Rendezetlen lista", + + "translation.author": "A Kirby csapata", + "translation.direction": "ltr", + "translation.name": "Magyar", + "translation.locale": "hu_HU", + + "upload": "Feltöltés", + "upload.error.cantMove": "A feltöltött fájlt nem sikerült áthelyezni", + "upload.error.cantWrite": "Hiba a fájl lemezre írása közben", + "upload.error.default": "A fájlt nem sikerült feltölteni", + "upload.error.extension": "A fájlfeltöltés egy kiterjesztés miatt megszakadt", + "upload.error.formSize": "A feltöltendő fájl mérete nagyobb, mint az űrlap MAX_FILE_SIZE szabályában beállított érték", + "upload.error.iniPostSize": "A feltöltendő fájl mérete nagyobb, mint a php.ini post_max_size szabályában beállított érték", + "upload.error.iniSize": "A feltöltendő fájl mérete nagyobb, mint a php.ini upload_max_filesize szabályában beállított érték", + "upload.error.noFile": "Nem lett fájl feltöltve", + "upload.error.noFiles": "Nem lettek fájlok feltöltve", + "upload.error.partial": "A fájl feltöltése csak részben sikerült", + "upload.error.tmpDir": "Hiányzik egy átmeneti mappa", + "upload.errors": "Hiba", + "upload.progress": "Feltöltés...", + + "url": "Url", + "url.placeholder": "https://pelda.hu", + + "user": "Felhasználó", + "user.blueprint": "További szakaszokat és mezőket adhatsz meg ehhez a felhasználói szerepkörhöz itt: /site/blueprints/users/{blueprint}.yml", + "user.changeEmail": "Email módosítása", + "user.changeLanguage": "Nyelv módosítása", + "user.changeName": "Felhasználó átnevezése", + "user.changePassword": "Jelszó módosítása", + "user.changePassword.new": "Új jelszó", + "user.changePassword.new.confirm": "Az új jelszó megerősítése", + "user.changeRole": "Szerepkör módosítása", + "user.changeRole.select": "Új szerepkör kiválasztása", + "user.create": "Új felhasználó hozzáadása", + "user.delete": "Felhasználó törlése", + "user.delete.confirm": "Biztos törlöd ezt a felhasználót:
{email}?", + + "users": "Felhasználók", + + "version": "Kirby verzi\u00f3", + + "view.account": "Fi\u00f3kod", + "view.installation": "Telep\u00edt\u00e9s", + "view.languages": "Nyelvek", + "view.resetPassword": "Jelszó visszaállítása", + "view.site": "Weboldal", + "view.system": "Rendszer", + "view.users": "Felhaszn\u00e1l\u00f3k", + + "welcome": "Üdvözlünk", + "year": "Év", + "yes": "igen" } diff --git a/kirby/i18n/translations/id.json b/kirby/i18n/translations/id.json index e4af95b..f716037 100644 --- a/kirby/i18n/translations/id.json +++ b/kirby/i18n/translations/id.json @@ -1,730 +1,574 @@ { - "account.changeName": "Ubah nama Anda", - "account.delete": "Hapus akun Anda", - "account.delete.confirm": "Anda yakin menghapus akun? Anda akan dikeluarkan segera. Akun Anda tidak dapat dipulihkan.", - - "activate": "Activate", - "add": "Tambah", - "alpha": "Alpha", - "author": "Penulis", - "avatar": "Gambar profil", - "back": "Kembali", - "cancel": "Batal", - "change": "Ubah", - "close": "Tutup", - "changes": "Perubahan", - "confirm": "Oke", - "collapse": "Lipat", - "collapse.all": "Lipat Semua", - "color": "Warna", - "coordinates": "Koordinat", - "copy": "Salin", - "copy.all": "Salin semua", - "copy.success": "{count} disalin!", - "create": "Buat", - "custom": "Kustom", - - "date": "Tanggal", - "date.select": "Pilih tanggal", - - "day": "Hari", - "days.fri": "Jum", - "days.mon": "Sen", - "days.sat": "Sab", - "days.sun": "Min", - "days.thu": "Kam", - "days.tue": "Sel", - "days.wed": "Rab", - - "debugging": "Debugging", - - "delete": "Hapus", - "delete.all": "Hapus semua", - - "dialog.fields.empty": "Dialog ini tidak memiliki bidang", - "dialog.files.empty": "Tidak ada berkas untuk dipilih", - "dialog.pages.empty": "Tidak ada halaman untuk dipilih", - "dialog.text.empty": "Dialog ini tidak mendefinisikan teks apa pun", - "dialog.users.empty": "Tidak ada pengguna untuk dipilih", - - "dimensions": "Dimensi", - "disable": "Disable", - "disabled": "Dimatikan", - "discard": "Buang", - - "drawer.fields.empty": "Drawer ini tidak memiliki bidang", - - "domain": "Domain", - "download": "Unduh", - "duplicate": "Duplikasi", - - "edit": "Sunting", - - "email": "Surel", - "email.placeholder": "surel@contoh.com", - - "enter": "Masuk", - "entries": "Entri", - "entry": "Entri", - - "environment": "Lingkungan", - - "error": "Kesalahan", - "error.access.code": "Kode tidak valid", - "error.access.login": "Upaya masuk tidak valid", - "error.access.panel": "Anda tidak diizinkan mengakses panel", - "error.access.view": "Anda tidak diizinkan mengakses bagian panel ini", - - "error.avatar.create.fail": "Gambar profil tidak dapat diunggah", - "error.avatar.delete.fail": "Gambar profil tidak dapat dihapus", - "error.avatar.dimensions.invalid": "Pastikan lebar dan tinggi gambar profil di bawah 3000 piksel", - "error.avatar.mime.forbidden": "Gambar profil harus berupa berkas JPEG atau PNG", - - "error.blueprint.notFound": "Cetak biru \"{name}\" tidak dapat dimuat", - - "error.blocks.max.plural": "Anda tidak boleh menambahkan lebih dari {max} blok", - "error.blocks.max.singular": "Anda tidak boleh menambahkan lebih dari satu blok", - "error.blocks.min.plural": "Anda setidaknya menambahkan {min} blok", - "error.blocks.min.singular": "Anda setidaknya menambahkan satu blok", - "error.blocks.validation": "Ada kesalahan di bidang \"{field}\" di blok {index} menggunakan \"{fieldset}\" tipe blok", - - "error.cache.type.invalid": "Tipe tembolok tidak valid \"{type}\"", - - "error.email.preset.notFound": "Surel \"{name}\" tidak dapat ditemukan", - - "error.field.converter.invalid": "Konverter \"{converter}\" tidak valid", - "error.field.type.missing": "Bidang \"{ name }\": Tipe bidang \"{ type }\" tidak ada", - - "error.file.changeName.empty": "Nama harus diisi", - "error.file.changeName.permission": "Anda tidak diizinkan mengubah nama berkas \"{filename}\"", - "error.file.changeTemplate.invalid": "Templat untuk berkas \"{id}\" tidak dapat diubah menjadi \"{template}\" (valid: \"{blueprints}\")", - "error.file.changeTemplate.permission": "Anda tidak diizinkan mengubah templat untuk berkas \"{id}\"", - - "error.file.duplicate": "Berkas dengan nama \"{filename}\" sudah ada", - "error.file.extension.forbidden": "Ekstensi \"{extension}\" tidak diizinkan", - "error.file.extension.invalid": "Ekstensi tidak valid: {extension}", - "error.file.extension.missing": "Berkas \"{filename}\" harus memiliki ekstensi", - "error.file.maxheight": "Tinggi gambar tidak boleh melebihi {height} piksel", - "error.file.maxsize": "Berkas terlalu besar", - "error.file.maxwidth": "Lebar gambar tidak boleh melebihi {width} piksel", - "error.file.mime.differs": "Berkas yang diunggah harus memiliki tipe mime sama \"{mime}\"", - "error.file.mime.forbidden": "Media dengan tipe mime \"{mime}\" tidak diizinkan", - "error.file.mime.invalid": "Tipe mime tidak valid: {mime}", - "error.file.mime.missing": "Tipe media untuk \"{filename}\" tidak dapat dideteksi", - "error.file.minheight": "Tinggi gambar setidaknya {height} piksel", - "error.file.minsize": "Berkas terlalu kecil", - "error.file.minwidth": "Lebar gambar setidaknya {width} piksel", - "error.file.name.unique": "Nama berkas harus unik", - "error.file.name.missing": "Nama berkas harus diisi", - "error.file.notFound": "Berkas \"{filename}\" tidak dapat ditemukan", - "error.file.orientation": "Orientasi gambar harus \"{orientation}\"", - "error.file.type.forbidden": "Anda tidak diizinkan mengunggah berkas dengan tipe {type}", - "error.file.type.invalid": "Tipe berkas tidak valid: {type}", - "error.file.undefined": "Berkas tidak dapat ditemukan", - - "error.form.incomplete": "Pastikan semua bidang telah diisi dengan benar…", - "error.form.notSaved": "Formulir tidak dapat disimpan", - - "error.language.code": "Masukkan kode bahasa yang valid", - "error.language.duplicate": "Bahasa sudah ada", - "error.language.name": "Masukkan nama bahasa yang valid", - "error.language.notFound": "Bahasa tidak ditemukan", - - "error.layout.validation.block": "Ada kesalahan pada bidang \"{field}\" di blok {blockIndex} menggunakan tipe blok \"{fieldset}\" di tata letak {layoutIndex}", - "error.layout.validation.settings": "Ada kesalahan di pengaturan tata letak {index}", - - "error.license.domain": "The domain for the license is missing", - "error.license.email": "Masukkan surel yang valid", - "error.license.format": "Please enter a valid license code", - "error.license.verification": "Lisensi tidak dapat diverifikasi", - - "error.login.totp.confirm.invalid": "Kode tidak valid", - "error.login.totp.confirm.missing": "Please enter the current code", - - "error.object.validation": "Ada kesalahan di bidang \"{label}\":\n{message}", - - "error.offline": "Panel saat ini luring", - - "error.page.changeSlug.permission": "Anda tidak diizinkan mengubah akhiran URL untuk \"{slug}\"", - "error.page.changeSlug.reserved": "Alur halaman-halaman level atas tidak boleh diawali dengan \"{path}\"", - "error.page.changeStatus.incomplete": "Halaman memiliki kesalahan dan tidak dapat diterbitkan", - "error.page.changeStatus.permission": "Status halaman ini tidak dapat diubah", - "error.page.changeStatus.toDraft.invalid": "Halaman \"{slug}\" tidak dapat dikonversi menjadi draf", - "error.page.changeTemplate.invalid": "Templat untuk halaman \"{slug}\" tidak dapat diubah", - "error.page.changeTemplate.permission": "Anda tidak diizinkan mengubah templat dari \"{slug}\"", - "error.page.changeTitle.empty": "Judul harus diisi", - "error.page.changeTitle.permission": "Anda tidak diizinkan mengubah judul dari \"{slug}\"", - "error.page.create.permission": "Anda tidak diizinkan membuat \"{slug}\"", - "error.page.delete": "Halaman \"{slug}\" tidak dapat dihapus", - "error.page.delete.confirm": "Masukkan judul halaman untuk mengonfirmasi", - "error.page.delete.hasChildren": "Halaman ini memiliki sub-halaman dan tidak dapat dihapus", - "error.page.delete.permission": "Anda tidak diizinkan menghapus \"{slug}\"", - "error.page.draft.duplicate": "Draf halaman dengan akhiran URL \"{slug}\" sudah ada", - "error.page.duplicate": "Halaman dengan akhiran URL \"{slug}\" sudah ada", - "error.page.duplicate.permission": "Anda tidak diizinkan menduplikasi \"{slug}\"", - "error.page.move.ancestor": "Halaman tidak dapat dipindahkan ke dirinya sendiri", - "error.page.move.directory": "Direktori halaman tidak dapat dipindahkan", - "error.page.move.duplicate": "Suatu sub halaman dengan akhiran URL \"{slug}\" sudah ada", - "error.page.move.notFound": "Halaman yang dipindahkan tidak dapat ditemukan", - "error.page.move.permission": "Anda tidak diizinkan memindahkan \"{slug}\"", - "error.page.move.template": "Templat \"{template}\" tidak dapat diterima sebagai sub halaman dari \"{parent}\"", - "error.page.notFound": "Halaman \"{slug}\" tidak dapat ditemukan", - "error.page.num.invalid": "Masukkan nomor urut yang valid. Nomor tidak boleh negatif.", - "error.page.slug.invalid": "Masukkan akhiran URL yang valid", - "error.page.slug.maxlength": "Panjang slug harus kurang dari \"{length}\" karakter", - "error.page.sort.permission": "Halaman \"{slug}\" tidak dapat diurutkan", - "error.page.status.invalid": "Atur status halaman yang valid", - "error.page.undefined": "Halaman tidak dapat ditemukan", - "error.page.update.permission": "Anda tidak diizinkan memperbaharui \"{slug}\"", - - "error.section.files.max.plural": "Anda hanya boleh menambahkan maksimal {max} berkas ke bagian \"{section}\"", - "error.section.files.max.singular": "Anda hanya boleh menambahkan satu berkas ke bagian \"{section}\"", - "error.section.files.min.plural": "Bagian \"{section}\" setidaknya memiliki {min} berkas", - "error.section.files.min.singular": "Bagian \"{section}\" setidaknya memiliki satu berkas", - - "error.section.pages.max.plural": "Anda hanya boleh menambahkan maksimal {max} halaman ke bagian \"{section}\"", - "error.section.pages.max.singular": "Anda hanya boleh menambahkan satu halaman ke bagian \"{section}\"", - "error.section.pages.min.plural": "Bagian \"{section}\" setidaknya memiliki {min} halaman", - "error.section.pages.min.singular": "Bagian \"{section}\" setidaknya memiliki satu halaman", - - "error.section.notLoaded": "Bagian \"{name}\" tidak dapat dimuat", - "error.section.type.invalid": "Tipe bagian \"{type}\" tidak valid", - - "error.site.changeTitle.empty": "Judul harus diisi", - "error.site.changeTitle.permission": "Anda tidak diizinkan mengubah judul situs", - "error.site.update.permission": "Anda tidak diizinkan memperbaharui situs", - - "error.structure.validation": "Ada kesalahan pada bidang \"{field}\" di baris {index}", - - "error.template.default.notFound": "Templat bawaan tidak ada", - - "error.unexpected": "Kesalahan tidak terduga terjadi! Hidupkan mode debug untuk informasi lebih lanjut: https://getkirby.com/docs/reference/system/options/debug", - - "error.user.changeEmail.permission": "Anda tidak diizinkan mengubah surel dari pengguna \"{name}\"", - "error.user.changeLanguage.permission": "Anda tidak diizinkan mengubah bahasa dari pengguna \"{name}\"", - "error.user.changeName.permission": "Anda tidak diizinkan mengubah nama dari pengguna \"{name}\"", - "error.user.changePassword.permission": "Anda tidak diizinkan mengubah sandi dari pengguna \"{name}\"", - "error.user.changeRole.lastAdmin": "Peran dari admin satu-satunya tidak dapat diubah", - "error.user.changeRole.permission": "Anda tidak diizinkan mengubah peran dari pengguna \"{name}\"", - "error.user.changeRole.toAdmin": "Anda tidak diizinkan mempromosikan seseorang menjadi admin", - "error.user.create.permission": "Anda tidak diizinkan membuat pengguna ini", - "error.user.delete": "Pengguna \"{nama}\" tidak dapat dihapus", - "error.user.delete.lastAdmin": "Admin satu-satunya tidak dapat dihapus", - "error.user.delete.lastUser": "Pengguna satu-satunya tidak dapat dihapus", - "error.user.delete.permission": "Anda tidak diizinkan menghapus pengguna \"{name}\"", - "error.user.duplicate": "Pengguna dengan surel \"{email}\" sudah ada", - "error.user.email.invalid": "Masukkan surel yang valid", - "error.user.language.invalid": "Masukkan bahasa yang valid", - "error.user.notFound": "Pengguna \"{name}\" tidak dapat ditemukan", - "error.user.password.excessive": "Masukkan sandi yang valid. Sandi tidak boleh lebih dari 1000 karakter.", - "error.user.password.invalid": "Masukkan sandi yang valid. Sandi setidaknya mengandung 8 karakter.", - "error.user.password.notSame": "Sandi tidak cocok", - "error.user.password.undefined": "Pengguna tidak memiliki sandi", - "error.user.password.wrong": "Kata sandi salah", - "error.user.role.invalid": "Masukkan peran yang valid", - "error.user.undefined": "Pengguna tidak dapat ditemukan", - "error.user.update.permission": "Anda tidak diizinkan memperbaharui pengguna \"{name}\"", - - "error.validation.accepted": "Mohon konfirmasi", - "error.validation.alpha": "Masukkan hanya karakter a-z", - "error.validation.alphanum": "Masukkan hanya karakter a-z atau 0-9", - "error.validation.anchor": "Masukkan tautan yang valid", - "error.validation.between": "Masukkan nilai antara \"{min}\" dan \"{max}\"", - "error.validation.boolean": "Mohon konfirmasi atau tolak", - "error.validation.color": "Masukkan warna yang valid dalam format {format}", - "error.validation.contains": "Masukkan nilai yang mengandung \"{needle}\"", - "error.validation.date": "Masukkan tanggal yang valid", - "error.validation.date.after": "Masukkan tanggal setelah {date}", - "error.validation.date.before": "Masukkan tanggal sebelum {date}", - "error.validation.date.between": "Masukkan tanggal antara {min} dan {max}", - "error.validation.denied": "Mohon tolak", - "error.validation.different": "Nilai harus selain \"{other}\"", - "error.validation.email": "Masukkan surel yang valid", - "error.validation.endswith": "Nilai harus diakhiri dengan \"{end}\"", - "error.validation.filename": "Masukkan nama berkas yang valid", - "error.validation.in": "Masukkan satu dari berikut: ({in})", - "error.validation.integer": "Masukkan bilangan bulat yang valid", - "error.validation.ip": "Masukkan IP yang valid", - "error.validation.less": "Masukkan nilai kurang dari {max}", - "error.validation.linkType": "Tipe tautan tidak diizinkan", - "error.validation.match": "Nilai tidak cocok dengan pola yang semestinya", - "error.validation.max": "Masukkan nilai yang sama dengan atau kurang dari {max}", - "error.validation.maxlength": "Masukkan nilai yang lebih pendek. (maksimal {max} karakter)", - "error.validation.maxwords": "Masukkan tidak lebih dari {max} kata", - "error.validation.min": "Masukkan nilai yang sama dengan atau lebih dari {min}", - "error.validation.minlength": "Masukkan nilai yang lebih panjang. (minimal {min} karakter)", - "error.validation.minwords": "Masukkan setidaknya {min} kata", - "error.validation.more": "Masukkan nilai yang lebih besar dari {min}", - "error.validation.notcontains": "Masukkan nilai yang tidak mengandung \"{needle}\"", - "error.validation.notin": "Jangan masukkan satupun: ({notIn})", - "error.validation.option": "Pilih opsi yang valid", - "error.validation.num": "Masukkan nomor yang valid", - "error.validation.required": "Masukkan sesuatu", - "error.validation.same": "Masukkan \"{other}\"", - "error.validation.size": "Ukuran dari nilai harus \"{size}\"", - "error.validation.startswith": "Nilai harus diawali dengan \"{start}\"", - "error.validation.tel": "Masukkan nomor telepon tanpa format", - "error.validation.time": "Masukkan waktu yang valid", - "error.validation.time.after": "Masukkan waktu setelah {time}", - "error.validation.time.before": "Masukkan waktu sebelum {time}", - "error.validation.time.between": "Masukkan waktu antara {min} dan {max}", - "error.validation.uuid": "Masukkan UUID yang valid", - "error.validation.url": "Masukkan URL yang valid", - - "expand": "Luaskan", - "expand.all": "Luaskan Semua", - - "field.invalid": "Bidang tidak valid", - "field.required": "Bidang ini wajib", - "field.blocks.changeType": "Ubah tipe", - "field.blocks.code.name": "Kode", - "field.blocks.code.language": "Bahasa", - "field.blocks.code.placeholder": "Kode Anda …", - "field.blocks.delete.confirm": "Anda yakin menghapus blok ini?", - "field.blocks.delete.confirm.all": "Anda yakin menghapus semua blok?", - "field.blocks.delete.confirm.selected": "Anda yakin menghapus blok yang dipilih?", - "field.blocks.empty": "Belum ada blok", - "field.blocks.fieldsets.empty": "Belum ada set bidang", - "field.blocks.fieldsets.label": "Pilih tipe blok …", - "field.blocks.fieldsets.paste": "Press {{ shortcut }} to import layouts/blocks from your clipboard Only those allowed in the current field will get inserted.", - "field.blocks.gallery.name": "Galeri", - "field.blocks.gallery.images.empty": "Belum ada gambar", - "field.blocks.gallery.images.label": "Gambar", - "field.blocks.heading.level": "Level", - "field.blocks.heading.name": "Penajukan", - "field.blocks.heading.text": "Teks", - "field.blocks.heading.placeholder": "Penajukan …", - "field.blocks.image.alt": "Teks alternatif", - "field.blocks.image.caption": "Keterangan", - "field.blocks.image.crop": "Pangkas", - "field.blocks.image.link": "Tautan", - "field.blocks.image.location": "Lokasi", - "field.blocks.image.location.internal": "This website", - "field.blocks.image.location.external": "External source", - "field.blocks.image.name": "Gambar", - "field.blocks.image.placeholder": "Pilih gambar", - "field.blocks.image.ratio": "Rasio", - "field.blocks.image.url": "URL Gambar", - "field.blocks.line.name": "Line", - "field.blocks.list.name": "Daftar", - "field.blocks.markdown.name": "Markdown", - "field.blocks.markdown.label": "Teks", - "field.blocks.markdown.placeholder": "Markdown …", - "field.blocks.quote.name": "Kutipan", - "field.blocks.quote.text.label": "Teks", - "field.blocks.quote.text.placeholder": "Kutipan …", - "field.blocks.quote.citation.label": "Sitasi", - "field.blocks.quote.citation.placeholder": "oleh …", - "field.blocks.text.name": "Teks", - "field.blocks.text.placeholder": "Teks …", - "field.blocks.video.autoplay": "Autoplay", - "field.blocks.video.caption": "Deskripsi", - "field.blocks.video.controls": "Controls", - "field.blocks.video.location": "Lokasi", - "field.blocks.video.loop": "Loop", - "field.blocks.video.muted": "Muted", - "field.blocks.video.name": "Video", - "field.blocks.video.placeholder": "Masukkan URL video", - "field.blocks.video.poster": "Poster", - "field.blocks.video.preload": "Preload", - "field.blocks.video.url.label": "URL Video", - "field.blocks.video.url.placeholder": "https://youtube.com/?v=", - - "field.files.empty": "Belum ada berkas yang dipilih", - - "field.layout.change": "Change layout", - "field.layout.delete": "Hapus tata letak", - "field.layout.delete.confirm": "Anda yakin menghapus tata letak ini?", - "field.layout.delete.confirm.all": "Do you really want to delete all layouts?", - "field.layout.empty": "Belum ada baris", - "field.layout.select": "Pilih tata letak", - - "field.object.empty": "No information yet", - - "field.pages.empty": "Belum ada halaman yang dipilih", - - "field.structure.delete.confirm": "Anda yakin menghapus baris ini?", - "field.structure.delete.confirm.all": "Do you really want to delete all entries?", - "field.structure.empty": "Belum ada entri", - - "field.users.empty": "Belum ada pengguna yang dipilih", - - "fields.empty": "No fields yet", - - "file": "Berkas", - "file.blueprint": "This file has no blueprint yet. You can define the setup in /site/blueprints/files/{blueprint}.yml", - "file.changeTemplate": "Ubah templat", - "file.changeTemplate.notice": "Changing the file's template will remove content for fields that don't match in type. If the new template defines certain rules, e.g. image dimensions, those will also be applied irreversibly. Use with caution.", - "file.delete.confirm": "Anda yakin menghapus
{filename}?", - "file.focus.placeholder": "Set focal point", - "file.focus.reset": "Remove focal point", - "file.focus.title": "Focus", - "file.sort": "Ubah posisi", - - "files": "Berkas", - "files.empty": "Belum ada berkas", - - "filter": "Filter", - - "hide": "Sembunyikan", - "hour": "Jam", - "hue": "Hue", - "import": "Import", - "info": "Info", - "insert": "Sisipkan", - "insert.after": "Sisipkan setelah", - "insert.before": "Sisipkan sebelum", - "install": "Pasang", - - "installation": "Pemasangan", - "installation.completed": "Panel sudah dipasang", - "installation.disabled": "Pemasang panel dimatikan di server publik secara bawaan. Mohon jalankan di server lokal atau ubah opsi panel.install untuk menjalankan di server saat ini.", - "installation.issues.accounts": "Folder /site/accounts tidak ada atau tidak dapat ditulis", - "installation.issues.content": "Folder /content tidak ada atau tidak dapat ditulis", - "installation.issues.curl": "Ekstensi CURL diperlukan", - "installation.issues.headline": "Panel tidak dapat dipasang", - "installation.issues.mbstring": "Ekstensi MB String diperlukan", - "installation.issues.media": "Folder /media tidak ada atau tidak dapat ditulis", - "installation.issues.php": "Pastikan Anda menggunakan PHP 8+", - "installation.issues.sessions": "Folder /site/sessions tidak ada atau tidak dapat ditulis", - - "language": "Bahasa", - "language.code": "Kode", - "language.convert": "Atur sebagai bawaan", - "language.convert.confirm": "

Anda yakin mengubah {name} menjadi bahasa bawaan? Ini tidak dapat dibatalkan.

Jika {name} memiliki konten yang tidak diterjemahkan, tidak akan ada pengganti yang valid dan dapat menyebabkan beberapa bagian dari situs Anda menjadi kosong.

", - "language.create": "Tambah bahasa baru", - "language.default": "Bahasa bawaan", - "language.delete.confirm": "Anda yakin menghapus bahasa {name} termasuk semua terjemahannya? Ini tidak dapat dibatalkan!", - "language.deleted": "Bahasa sudah dihapus", - "language.direction": "Arah baca", - "language.direction.ltr": "Kiri ke kanan", - "language.direction.rtl": "Kanan ke kiri", - "language.locale": "String \"PHP locale\"", - "language.locale.warning": "Anda menggunakan pengaturan lokal ubah suaian. Ubah di berkas bahasa di /site/languages", - "language.name": "Nama", - "language.secondary": "Secondary language", - "language.settings": "Language settings", - "language.updated": "Bahasa sudah diperbaharui", - "language.variables": "Language variables", - "language.variables.empty": "No translations yet", - - "language.variable.delete.confirm": "Do you really want to delete the variable for {key}?", - "language.variable.key": "Key", - "language.variable.notFound": "The variable could not be found", - "language.variable.value": "Value", - - "languages": "Bahasa", - "languages.default": "Bahasa bawaan", - "languages.empty": "Belum ada bahasa", - "languages.secondary": "Bahasa sekunder", - "languages.secondary.empty": "Belum ada bahasa sekunder", - - "license": "Lisensi Kirby", - "license.activate": "Activate it now", - "license.activate.label": "Please activate your license", - "license.activate.domain": "Your license will be activated for {host}.", - "license.activate.local": "You are about to activate your Kirby license for your local domain {host}. If this site will be deployed to a public domain, please activate it there instead. If {host} is the domain you want to use your license for, please continue.", - "license.activated": "Activated", - "license.buy": "Beli lisensi", - "license.code": "Kode", - "license.code.help": "You received your license code after the purchase via email. Please copy and paste it here.", - "license.code.label": "Masukkan kode lisensi Anda", - "license.status.active.info": "Includes new major versions until {date}", - "license.status.active.label": "Valid license", - "license.status.demo.info": "This is a demo installation", - "license.status.demo.label": "Demo", - "license.status.inactive.info": "Renew license to update to new major versions", - "license.status.inactive.label": "No new major versions", - "license.status.legacy.bubble": "Ready to renew your license?", - "license.status.legacy.info": "Your license does not cover this version", - "license.status.legacy.label": "Please renew your license", - "license.status.missing.bubble": "Ready to launch your site?", - "license.status.missing.info": "No valid license", - "license.status.missing.label": "Please activate your license", - "license.manage": "Manage your licenses", - "license.purchased": "Purchased", - "license.success": "Terima kasih atas dukungan untuk Kirby", - "license.unregistered.label": "Unregistered", - - "link": "Tautan", - "link.text": "Teks tautan", - - "loading": "Memuat", - - "lock.unsaved": "Perubahan belum tersimpan", - "lock.unsaved.empty": "Tidak ada lagi perubahan belum tersimpan", - "lock.isLocked": "Unsaved changes by {email}", - "lock.unlock": "Buka kunci", - "lock.unlock.submit": "Unlock and overwrite unsaved changes by {email}", - "lock.isUnlocked": "Was unlocked by another user", - - "login": "Masuk", - "login.code.label.login": "Kode masuk", - "login.code.label.password-reset": "Kode atur ulang sandi", - "login.code.placeholder.email": "000 000", - "login.code.placeholder.totp": "000000", - "login.code.text.email": "Jika alamat surel terdaftar, kode yang diminta dikirim via surel", - "login.code.text.totp": "Please enter the one‑time code from your authenticator app.", - "login.email.login.body": "Hi {user.nameOrEmail},\n\nYou recently requested a login code for the Panel of {site}.\nThe following login code will be valid for {timeout} minutes:\n\n{code}\n\nIf you did not request a login code, please ignore this email or contact your administrator if you have questions.\nFor security, please DO NOT forward this email.", - "login.email.login.subject": "Kode masuk Anda", - "login.email.password-reset.body": "Hi {user.nameOrEmail},\n\nYou recently requested a password reset code for the Panel of {site}.\nThe following password reset code will be valid for {timeout} minutes:\n\n{code}\n\nIf you did not request a password reset code, please ignore this email or contact your administrator if you have questions.\nFor security, please DO NOT forward this email.", - "login.email.password-reset.subject": "Kode atur ulang sandi Anda", - "login.remember": "Biarkan tetap masuk", - "login.reset": "Atur ulang sandi", - "login.toggleText.code.email": "Masuk via surel", - "login.toggleText.code.email-password": "Masuk dengan sandi", - "login.toggleText.password-reset.email": "Lupa sandi Anda?", - "login.toggleText.password-reset.email-password": "← Kembali ke masuk", - "login.totp.enable.option": "Set up one‑time codes", - "login.totp.enable.intro": "Authenticator apps can generate one‑time codes that are used as a second factor when signing into your account.", - "login.totp.enable.qr.label": "1. Scan this QR code", - "login.totp.enable.qr.help": "Unable to scan? Add the setup key {secret} manually to your authenticator app.", - "login.totp.enable.confirm.headline": "2. Confirm with generated code", - "login.totp.enable.confirm.text": "Your app generates a new one‑time code every 30 seconds. Enter the current code to complete the setup:", - "login.totp.enable.confirm.label": "Current code", - "login.totp.enable.confirm.help": "After this setup, we will ask you for a one‑time code every time you log in.", - "login.totp.enable.success": "One‑time codes enabled", - "login.totp.disable.option": "Disable one‑time codes", - "login.totp.disable.label": "Enter your password to disable one‑time codes", - "login.totp.disable.help": "In the future, a different second factor like a login code sent via email will be requested when you log in. You can always set up one‑time codes again later.", - "login.totp.disable.admin": "

This will disable one‑time codes for {user}.

In the future, a different second factor like a login code sent via email will be requested when they log in. {user} can set up one‑time codes again after their next login.

", - "login.totp.disable.success": "One‑time codes disabled", - - "logout": "Keluar", - - "merge": "Merge", - "menu": "Menu", - "meridiem": "AM/PM", - "mime": "Tipe Media", - "minutes": "Menit", - - "month": "Bulan", - "months.april": "April", - "months.august": "Agustus", - "months.december": "Desember", - "months.february": "Februari", - "months.january": "Januari", - "months.july": "Juli", - "months.june": "Juni", - "months.march": "Maret", - "months.may": "Mei", - "months.november": "November", - "months.october": "Oktober", - "months.september": "September", - - "more": "Lebih lanjut", - "move": "Move", - "name": "Nama", - "next": "Selanjutnya", - "night": "Night", - "no": "tidak", - "off": "mati", - "on": "hidup", - "open": "Buka", - "open.newWindow": "Buka di jendela baru", - "option": "Option", - "options": "Opsi", - "options.none": "Tidak ada opsi", - "options.all": "Show all {count} options", - - "orientation": "Orientasi", - "orientation.landscape": "Rebah", - "orientation.portrait": "Tegak", - "orientation.square": "Persegi", - - "page": "Halaman", - "page.blueprint": "This page has no blueprint yet. You can define the setup in /site/blueprints/pages/{blueprint}.yml", - "page.changeSlug": "Ubah URL", - "page.changeSlug.fromTitle": "Buat dari judul", - "page.changeStatus": "Ubah status", - "page.changeStatus.position": "Pilih posisi", - "page.changeStatus.select": "Pilih status baru", - "page.changeTemplate": "Ubah templat", - "page.changeTemplate.notice": "Changing the page's template will remove content for fields that don't match in type. Use with caution.", - "page.create": "Create as {status}", - "page.delete.confirm": "Anda yakin menghapus {title}?", - "page.delete.confirm.subpages": "Halaman ini memiliki sub-halaman.
Semua sub-halaman akan ikut dihapus.", - "page.delete.confirm.title": "Masukkan judul halaman untuk mengonfirmasi", - "page.duplicate.appendix": "Salin", - "page.duplicate.files": "Salin berkas", - "page.duplicate.pages": "Salin halaman", - "page.move": "Move page", - "page.sort": "Ubah posisi", - "page.status": "Status", - "page.status.draft": "Draf", - "page.status.draft.description": "Halaman ini ada pada mode draf dan hanya dapat dilihat oleh penyunting atau via tautan rahasia", - "page.status.listed": "Publik", - "page.status.listed.description": "Halaman publik untuk siapapun", - "page.status.unlisted": "Tidak tercantum", - "page.status.unlisted.description": "Halaman hanya dapat diakses via URL", - - "pages": "Halaman", - "pages.empty": "Belum ada halaman", - "pages.status.draft": "Draf", - "pages.status.listed": "Dipublikasikan", - "pages.status.unlisted": "Tidak tercantum", - - "pagination.page": "Halaman", - - "password": "Sandi", - "paste": "Paste", - "paste.after": "Paste after", - "paste.success": "{count} pasted!", - "pixel": "Piksel", - "plugin": "Plugin", - "plugins": "Plugins", - "prev": "Sebelumnya", - "preview": "Pratinjau", - "remove": "Hapus", - "rename": "Ubah nama", - "renew": "Renew", - "replace": "Ganti", - "replace.with": "Replace with", - "retry": "Coba lagi", - "revert": "Kembalikan", - "revert.confirm": "Anda yakin menghapus semua perubahan yang belum tersimpan?", - - "role": "Peran", - "role.admin.description": "Admin memiliki semua izin", - "role.admin.title": "Admin", - "role.all": "Semua", - "role.empty": "Tidak ada pengguna dengan peran ini", - "role.description.placeholder": "Tidak ada deskripsi", - "role.nobody.description": "Ini adalah peran cadangan tanpa permisi apapun", - "role.nobody.title": "Tidak siapapun", - - "save": "Simpan", - "search": "Cari", - "search.min": "Masukkan {min} karakter untuk mencari", - "search.all": "Show all {count} results", - "search.results.none": "Tidak ada hasil", - - "section.invalid": "Bagian ini tidak valid", - "section.required": "Bagian ini wajib", - - "security": "Keamanan", - "select": "Pilih", - "server": "Peladen", - "settings": "Pengaturan", - "show": "Tampilkan", - "site.blueprint": "Situs ini belum memiliki cetak biru. Anda dapat mendefinisikannya di /site/blueprints/site.yml", - "size": "Ukuran", - "slug": "Akhiran URL", - "sort": "Urutkan", - "sort.drag": "Geser untuk mengurutkan …", - "split": "Pisahkan", - - "stats.empty": "Tidak ada laporan", - "status": "Status", - - "system.info.copy": "Copy info", - "system.info.copied": "System info copied", - "system.issues.content": "Folder konten nampaknya terekspos", - "system.issues.eol.kirby": "Versi instalasi Kirby Anda sudah mencapai akhir dan tidak akan lagi mendapat pembaruan keamanan", - "system.issues.eol.plugin": "Versi instalasi plugin { plugin } Anda sudah mencapai akhir dan tidak akan lagi mendapatkan pembaruan keamanan", - "system.issues.eol.php": "Your installed PHP release { release } has reached end-of-life and will not receive further security updates", - "system.issues.debug": "Debugging must be turned off in production", - "system.issues.git": "The .git folder seems to be exposed", - "system.issues.https": "We recommend HTTPS for all your sites", - "system.issues.kirby": "The kirby folder seems to be exposed", - "system.issues.site": "The site folder seems to be exposed", - "system.issues.vulnerability.kirby": "Instalasi Anda mungkin terpengaruh oleh celah keamanan berikut ({ severity } severity): { description }", - "system.issues.vulnerability.plugin": "Instalasi Anda mungkin terpengaruh oleh celah keamanan di dalam plugin { plugin } ({ severity } severity): { description }", - "system.updateStatus": "Update status", - "system.updateStatus.error": "Could not check for updates", - "system.updateStatus.not-vulnerable": "No known vulnerabilities", - "system.updateStatus.security-update": "Free security update { version } available", - "system.updateStatus.security-upgrade": "Upgrade { version } with security fixes available", - "system.updateStatus.unreleased": "Unreleased version", - "system.updateStatus.up-to-date": "Up to date", - "system.updateStatus.update": "Free update { version } available", - "system.updateStatus.upgrade": "Upgrade { version } available", - - "tel": "Phone", - "tel.placeholder": "+49123456789", - "template": "Templat", - "title": "Judul", - "today": "Hari ini", - - "toolbar.button.clear": "Clear formatting", - "toolbar.button.code": "Kode", - "toolbar.button.bold": "Tebal", - "toolbar.button.email": "Surel", - "toolbar.button.headings": "Penajukan", - "toolbar.button.heading.1": "Penajukan 1", - "toolbar.button.heading.2": "Penajukan 2", - "toolbar.button.heading.3": "Penajukan 3", - "toolbar.button.heading.4": "Heading 4", - "toolbar.button.heading.5": "Heading 5", - "toolbar.button.heading.6": "Heading 6", - "toolbar.button.italic": "Miring", - "toolbar.button.file": "Berkas", - "toolbar.button.file.select": "Pilih berkas", - "toolbar.button.file.upload": "Unggah berkas", - "toolbar.button.link": "Tautan", - "toolbar.button.paragraph": "Paragraph", - "toolbar.button.strike": "Coret", - "toolbar.button.sub": "Subscript", - "toolbar.button.sup": "Superscript", - "toolbar.button.ol": "Daftar berurut", - "toolbar.button.underline": "Garis bawah", - "toolbar.button.ul": "Daftar tidak berurut", - - "translation.author": "Tim Kirby", - "translation.direction": "ltr", - "translation.name": "Bahasa Indonesia", - "translation.locale": "id_ID", - - "type": "Type", - - "upload": "Unggah", - "upload.error.cantMove": "Berkas unggahan tidak dapat dipindahkan", - "upload.error.cantWrite": "Gagal menyimpan berkas", - "upload.error.default": "Berkas tidak dapat diunggah", - "upload.error.extension": "Unggahan berkas diblokir dengan ekstensi", - "upload.error.formSize": "Berkas unggahan mencapai acuan MAX_FILE_SIZE yang diatur di formulir", - "upload.error.iniPostSize": "Berkas unggahan mencapai acuan post_max_size di php.ini", - "upload.error.iniSize": "Berkas unggahan mencapai acuan upload_max_filesize di php.ini", - "upload.error.noFile": "Tidak ada berkas diunggah", - "upload.error.noFiles": "Tidak ada berkas diunggah", - "upload.error.partial": "Berkas unggahan hanya berhasil diunggah sebagian", - "upload.error.tmpDir": "Folder sementara tidak ada", - "upload.errors": "Kesalahan", - "upload.progress": "Mengunggah…", - - "url": "Url", - "url.placeholder": "https://contoh.com", - - "user": "Pengguna", - "user.blueprint": "You can define additional sections and form fields for this user role in /site/blueprints/users/{blueprint}.yml", - "user.changeEmail": "Ubah surel", - "user.changeLanguage": "Ubah bahasa", - "user.changeName": "Ubah nama pengguna ini", - "user.changePassword": "Ubah sandi", - "user.changePassword.new": "Sandi baru", - "user.changePassword.new.confirm": "Konfirmasi sandi baru…", - "user.changeRole": "Ubah peran", - "user.changeRole.select": "Pilih peran baru", - "user.create": "Tambah pengguna baru", - "user.delete": "Hapus pengguna ini", - "user.delete.confirm": "Anda yakin menghapus
{email}?", - - "users": "Pengguna", - - "version": "Versi", - "version.current": "Current version", - "version.latest": "Latest version", - "versionInformation": "Version information", - - "view.account": "Akun Anda", - "view.installation": "Pemasangan", - "view.languages": "Bahasa", - "view.resetPassword": "Atur ulang sandi", - "view.site": "Situs", - "view.system": "System", - "view.users": "Pengguna", - - "welcome": "Selamat datang", - "year": "Tahun", - "yes": "ya" + "account.changeName": "Change your name", + "account.delete": "Delete your account", + "account.delete.confirm": "Do you really want to delete your account? You will be logged out immediately. Your account cannot be recovered.", + + "add": "Tambah", + "author": "Author", + "avatar": "Gambar profil", + "back": "Kembali", + "cancel": "Batal", + "change": "Ubah", + "close": "Tutup", + "confirm": "Oke", + "collapse": "Lipat", + "collapse.all": "Lipat Semua", + "copy": "Salin", + "copy.all": "Copy all", + "create": "Buat", + + "date": "Tanggal", + "date.select": "Pilih tanggal", + + "day": "Hari", + "days.fri": "Jum", + "days.mon": "Sen", + "days.sat": "Sab", + "days.sun": "Min", + "days.thu": "Kam", + "days.tue": "Sel", + "days.wed": "Rab", + + "debugging": "Debugging", + + "delete": "Hapus", + "delete.all": "Hapus semua", + + "dialog.files.empty": "Tidak ada berkas untuk dipilih", + "dialog.pages.empty": "Tidak ada halaman untuk dipilih", + "dialog.users.empty": "Tidak ada pengguna untuk dipilih", + + "dimensions": "Dimensi", + "disabled": "Dimatikan", + "discard": "Buang", + "download": "Unduh", + "duplicate": "Duplikasi", + + "edit": "Sunting", + + "email": "Surel", + "email.placeholder": "surel@contoh.com", + + "entries": "Entries", + "entry": "Entry", + + "environment": "Environment", + + "error.access.code": "Kode tidak valid", + "error.access.login": "Upaya masuk tidak valid", + "error.access.panel": "Anda tidak diizinkan mengakses panel", + "error.access.view": "Anda tidak diizinkan mengakses bagian panel ini", + + "error.avatar.create.fail": "Gambar profil tidak dapat diunggah", + "error.avatar.delete.fail": "Gambar profil tidak dapat dihapus", + "error.avatar.dimensions.invalid": "Pastikan lebar dan tinggi gambar profil di bawah 3000 piksel", + "error.avatar.mime.forbidden": "Gambar profil harus berupa berkas JPEG atau PNG", + + "error.blueprint.notFound": "Cetak biru \"{name}\" tidak dapat dimuat", + + "error.blocks.max.plural": "Anda tidak boleh menambahkan lebih dari {max} blok", + "error.blocks.max.singular": "Anda tidak boleh menambahkan lebih dari satu blok", + "error.blocks.min.plural": "Anda setidaknya menambahkan {min} blok", + "error.blocks.min.singular": "Anda setidaknya menambahkan satu blok", + "error.blocks.validation": "Ada kesalahan di blok {index}", + + "error.email.preset.notFound": "Surel \"{name}\" tidak dapat ditemukan", + + "error.field.converter.invalid": "Konverter \"{converter}\" tidak valid", + + "error.file.changeName.empty": "Nama harus diisi", + "error.file.changeName.permission": "Anda tidak diizinkan mengubah nama berkas \"{filename}\"", + "error.file.duplicate": "Berkas dengan nama \"{filename}\" sudah ada", + "error.file.extension.forbidden": "Ekstensi \"{extension}\" tidak diizinkan", + "error.file.extension.invalid": "Ekstensi tidak valid: {extension}", + "error.file.extension.missing": "Berkas \"{filename}\" harus memiliki ekstensi", + "error.file.maxheight": "Tinggi gambar tidak boleh melebihi {height} piksel", + "error.file.maxsize": "Berkas terlalu besar", + "error.file.maxwidth": "Lebar gambar tidak boleh melebihi {width} piksel", + "error.file.mime.differs": "Berkas yang diunggah harus memiliki tipe mime sama \"{mime}\"", + "error.file.mime.forbidden": "Media dengan tipe mime \"{mime}\" tidak diizinkan", + "error.file.mime.invalid": "Tipe mime tidak valid: {mime}", + "error.file.mime.missing": "Tipe media untuk \"{filename}\" tidak dapat dideteksi", + "error.file.minheight": "Tinggi gambar setidaknya {height} piksel", + "error.file.minsize": "Berkas terlalu kecil", + "error.file.minwidth": "Lebar gambar setidaknya {width} piksel", + "error.file.name.missing": "Nama berkas harus diisi", + "error.file.notFound": "Berkas \"{filename}\" tidak dapat ditemukan", + "error.file.orientation": "Orientasi gambar harus \"{orientation}\"", + "error.file.type.forbidden": "Anda tidak diizinkan mengunggah berkas dengan tipe {type}", + "error.file.type.invalid": "Tipe berkas tidak valid: {type}", + "error.file.undefined": "Berkas tidak dapat ditemukan", + + "error.form.incomplete": "Pastikan semua bidang telah diisi dengan benar…", + "error.form.notSaved": "Formulir tidak dapat disimpan", + + "error.language.code": "Masukkan kode bahasa yang valid", + "error.language.duplicate": "Bahasa sudah ada", + "error.language.name": "Masukkan nama bahasa yang valid", + "error.language.notFound": "The language could not be found", + + "error.layout.validation.block": "Ada kesalahan di blok {blockIndex} di tata letak {layoutIndex}", + "error.layout.validation.settings": "Ada kesalahan di pengaturan tata letak {index}", + + "error.license.format": "Masukkan kode lisensi yang valid", + "error.license.email": "Masukkan surel yang valid", + "error.license.verification": "Lisensi tidak dapat diverifikasi", + + "error.offline": "The Panel is currently offline", + + "error.page.changeSlug.permission": "Anda tidak diizinkan mengubah akhiran URL untuk \"{slug}\"", + "error.page.changeStatus.incomplete": "Halaman memiliki kesalahan dan tidak dapat diterbitkan", + "error.page.changeStatus.permission": "Status halaman ini tidak dapat diubah", + "error.page.changeStatus.toDraft.invalid": "Halaman \"{slug}\" tidak dapat dikonversi menjadi draf", + "error.page.changeTemplate.invalid": "Templat untuk halaman \"{slug}\" tidak dapat diubah", + "error.page.changeTemplate.permission": "Anda tidak diizinkan mengubah templat dari \"{slug}\"", + "error.page.changeTitle.empty": "Judul harus diisi", + "error.page.changeTitle.permission": "Anda tidak diizinkan mengubah judul dari \"{slug}\"", + "error.page.create.permission": "Anda tidak diizinkan membuat \"{slug}\"", + "error.page.delete": "Halaman \"{slug}\" tidak dapat dihapus", + "error.page.delete.confirm": "Masukkan judul halaman untuk mengonfirmasi", + "error.page.delete.hasChildren": "Halaman ini memiliki sub-halaman dan tidak dapat dihapus", + "error.page.delete.permission": "Anda tidak diizinkan menghapus \"{slug}\"", + "error.page.draft.duplicate": "Draf halaman dengan akhiran URL \"{slug}\" sudah ada", + "error.page.duplicate": "Halaman dengan akhiran URL \"{slug}\" sudah ada", + "error.page.duplicate.permission": "Anda tidak diizinkan menduplikasi \"{slug}\"", + "error.page.notFound": "Halaman \"{slug}\" tidak dapat ditemukan", + "error.page.num.invalid": "Masukkan nomor urut yang valid. Nomor tidak boleh negatif.", + "error.page.slug.invalid": "Masukkan akhiran URL yang valid", + "error.page.slug.maxlength": "Panjang slug harus kurang dari \"{length}\" karakter", + "error.page.sort.permission": "Halaman \"{slug}\" tidak dapat diurutkan", + "error.page.status.invalid": "Atur status halaman yang valid", + "error.page.undefined": "Halaman tidak dapat ditemukan", + "error.page.update.permission": "Anda tidak diizinkan memperbaharui \"{slug}\"", + + "error.section.files.max.plural": "Anda hanya boleh menambahkan maksimal {max} berkas ke bagian \"{section}\"", + "error.section.files.max.singular": "Anda hanya boleh menambahkan satu berkas ke bagian \"{section}\"", + "error.section.files.min.plural": "Bagian \"{section}\" setidaknya memiliki {min} berkas", + "error.section.files.min.singular": "Bagian \"{section}\" setidaknya memiliki satu berkas", + + "error.section.pages.max.plural": "Anda hanya boleh menambahkan maksimal {max} halaman ke bagian \"{section}\"", + "error.section.pages.max.singular": "Anda hanya boleh menambahkan satu halaman ke bagian \"{section}\"", + "error.section.pages.min.plural": "Bagian \"{section}\" setidaknya memiliki {min} halaman", + "error.section.pages.min.singular": "Bagian \"{section}\" setidaknya memiliki satu halaman", + + "error.section.notLoaded": "Bagian \"{name}\" tidak dapat dimuat", + "error.section.type.invalid": "Tipe bagian \"{type}\" tidak valid", + + "error.site.changeTitle.empty": "Judul harus diisi", + "error.site.changeTitle.permission": "Anda tidak diizinkan mengubah judul situs", + "error.site.update.permission": "Anda tidak diizinkan memperbaharui situs", + + "error.template.default.notFound": "Templat bawaan tidak ada", + + "error.unexpected": "An unexpected error occurred! Enable debug mode for more info: https://getkirby.com/docs/reference/system/options/debug", + + "error.user.changeEmail.permission": "Anda tidak diizinkan mengubah surel dari pengguna \"{name}\"", + "error.user.changeLanguage.permission": "Anda tidak diizinkan mengubah bahasa dari pengguna \"{name}\"", + "error.user.changeName.permission": "Anda tidak diizinkan mengubah nama dari pengguna \"{name}\"", + "error.user.changePassword.permission": "Anda tidak diizinkan mengubah sandi dari pengguna \"{name}\"", + "error.user.changeRole.lastAdmin": "Peran dari admin satu-satunya tidak dapat diubah", + "error.user.changeRole.permission": "Anda tidak diizinkan mengubah peran dari pengguna \"{name}\"", + "error.user.changeRole.toAdmin": "Anda tidak diizinkan mempromosikan seseorang menjadi admin", + "error.user.create.permission": "Anda tidak diizinkan membuat pengguna ini", + "error.user.delete": "Pengguna \"{nama}\" tidak dapat dihapus", + "error.user.delete.lastAdmin": "Admin satu-satunya tidak dapat dihapus", + "error.user.delete.lastUser": "Pengguna satu-satunya tidak dapat dihapus", + "error.user.delete.permission": "Anda tidak diizinkan menghapus pengguna \"{name}\"", + "error.user.duplicate": "Pengguna dengan surel \"{email}\" sudah ada", + "error.user.email.invalid": "Masukkan surel yang valid", + "error.user.language.invalid": "Masukkan bahasa yang valid", + "error.user.notFound": "Pengguna \"{name}\" tidak dapat ditemukan", + "error.user.password.excessive": "Please enter a valid password. Passwords must not be longer than 1000 characters.", + "error.user.password.invalid": "Masukkan sandi yang valid. Sandi setidaknya mengandung 8 karakter.", + "error.user.password.notSame": "Sandi tidak cocok", + "error.user.password.undefined": "Pengguna tidak memiliki sandi", + "error.user.password.wrong": "Kata sandi salah", + "error.user.role.invalid": "Masukkan peran yang valid", + "error.user.undefined": "Pengguna tidak dapat ditemukan", + "error.user.update.permission": "Anda tidak diizinkan memperbaharui pengguna \"{name}\"", + + "error.validation.accepted": "Mohon konfirmasi", + "error.validation.alpha": "Masukkan hanya karakter a-z", + "error.validation.alphanum": "Masukkan hanya karakter a-z atau 0-9", + "error.validation.between": "Masukkan nilai antara \"{min}\" dan \"{max}\"", + "error.validation.boolean": "Mohon konfirmasi atau tolak", + "error.validation.contains": "Masukkan nilai yang mengandung \"{needle}\"", + "error.validation.date": "Masukkan tanggal yang valid", + "error.validation.date.after": "Masukkan tanggal setelah {date}", + "error.validation.date.before": "Masukkan tanggal sebelum {date}", + "error.validation.date.between": "Masukkan tanggal antara {min} dan {max}", + "error.validation.denied": "Mohon tolak", + "error.validation.different": "Nilai harus selain \"{other}\"", + "error.validation.email": "Masukkan surel yang valid", + "error.validation.endswith": "Nilai harus diakhiri dengan \"{end}\"", + "error.validation.filename": "Masukkan nama berkas yang valid", + "error.validation.in": "Masukkan satu dari berikut: ({in})", + "error.validation.integer": "Masukkan bilangan bulat yang valid", + "error.validation.ip": "Masukkan IP yang valid", + "error.validation.less": "Masukkan nilai kurang dari {max}", + "error.validation.match": "Nilai tidak cocok dengan pola yang semestinya", + "error.validation.max": "Masukkan nilai yang sama dengan atau kurang dari {max}", + "error.validation.maxlength": "Masukkan nilai yang lebih pendek. (maksimal {max} karakter)", + "error.validation.maxwords": "Masukkan tidak lebih dari {max} kata", + "error.validation.min": "Masukkan nilai yang sama dengan atau lebih dari {min}", + "error.validation.minlength": "Masukkan nilai yang lebih panjang. (minimal {min} karakter)", + "error.validation.minwords": "Masukkan setidaknya {min} kata", + "error.validation.more": "Masukkan nilai yang lebih besar dari {min}", + "error.validation.notcontains": "Masukkan nilai yang tidak mengandung \"{needle}\"", + "error.validation.notin": "Jangan masukkan satupun: ({notIn})", + "error.validation.option": "Pilih opsi yang valid", + "error.validation.num": "Masukkan nomor yang valid", + "error.validation.required": "Masukkan sesuatu", + "error.validation.same": "Masukkan \"{other}\"", + "error.validation.size": "Ukuran dari nilai harus \"{size}\"", + "error.validation.startswith": "Nilai harus diawali dengan \"{start}\"", + "error.validation.time": "Masukkan waktu yang valid", + "error.validation.time.after": "Masukkan waktu setelah {time}", + "error.validation.time.before": "Masukkan waktu sebelum {time}", + "error.validation.time.between": "Masukkan waktu antara {min} dan {max}", + "error.validation.url": "Masukkan URL yang valid", + + "expand": "Luaskan", + "expand.all": "Luaskan Semua", + + "field.required": "Bidang ini wajib", + "field.blocks.changeType": "Ubah tipe", + "field.blocks.code.name": "Kode", + "field.blocks.code.language": "Bahasa", + "field.blocks.code.placeholder": "Kode Anda …", + "field.blocks.delete.confirm": "Anda yakin menghapus blok ini?", + "field.blocks.delete.confirm.all": "Anda yakin menghapus semua blok?", + "field.blocks.delete.confirm.selected": "Anda yakin menghapus blok yang dipilih?", + "field.blocks.empty": "Belum ada blok", + "field.blocks.fieldsets.label": "Pilih tipe blok …", + "field.blocks.fieldsets.paste": "Press {{ shortcut }} to paste/import blocks from your clipboard", + "field.blocks.gallery.name": "Galeri", + "field.blocks.gallery.images.empty": "Belum ada gambar", + "field.blocks.gallery.images.label": "Gambar", + "field.blocks.heading.level": "Level", + "field.blocks.heading.name": "Penajukan", + "field.blocks.heading.text": "Teks", + "field.blocks.heading.placeholder": "Penajukan …", + "field.blocks.image.alt": "Teks alternatif", + "field.blocks.image.caption": "Keterangan", + "field.blocks.image.crop": "Pangkas", + "field.blocks.image.link": "Tautan", + "field.blocks.image.location": "Lokasi", + "field.blocks.image.name": "Gambar", + "field.blocks.image.placeholder": "Pilih gambar", + "field.blocks.image.ratio": "Rasio", + "field.blocks.image.url": "URL Gambar", + "field.blocks.line.name": "Line", + "field.blocks.list.name": "Daftar", + "field.blocks.markdown.name": "Markdown", + "field.blocks.markdown.label": "Teks", + "field.blocks.markdown.placeholder": "Markdown …", + "field.blocks.quote.name": "Kutipan", + "field.blocks.quote.text.label": "Teks", + "field.blocks.quote.text.placeholder": "Kutipan …", + "field.blocks.quote.citation.label": "Sitasi", + "field.blocks.quote.citation.placeholder": "oleh …", + "field.blocks.text.name": "Teks", + "field.blocks.text.placeholder": "Teks …", + "field.blocks.video.caption": "Deskripsi", + "field.blocks.video.name": "Video", + "field.blocks.video.placeholder": "Masukkan URL video", + "field.blocks.video.url.label": "URL Video", + "field.blocks.video.url.placeholder": "https://youtube.com/?v=", + + "field.files.empty": "Belum ada berkas yang dipilih", + + "field.layout.delete": "Hapus tata letak", + "field.layout.delete.confirm": "Anda yakin menghapus tata letak ini?", + "field.layout.empty": "Belum ada baris", + "field.layout.select": "Pilih tata letak", + + "field.pages.empty": "Belum ada halaman yang dipilih", + "field.structure.delete.confirm": "Anda yakin menghapus baris ini?", + "field.structure.empty": "Belum ada entri", + "field.users.empty": "Belum ada pengguna yang dipilih", + + "file.blueprint": "This file has no blueprint yet. You can define the setup in /site/blueprints/files/{blueprint}.yml", + "file.delete.confirm": "Anda yakin menghapus
{filename}?", + "file.sort": "Ubah posisi", + + "files": "Berkas", + "files.empty": "Belum ada berkas", + + "hide": "Sembunyikan", + "hour": "Jam", + "import": "Import", + "info": "Info", + "insert": "Sisipkan", + "insert.after": "Sisipkan setelah", + "insert.before": "Sisipkan sebelum", + "install": "Pasang", + + "installation": "Pemasangan", + "installation.completed": "Panel sudah dipasang", + "installation.disabled": "Pemasang panel dimatikan di server publik secara bawaan. Mohon jalankan di server lokal atau ubah opsi panel.install untuk menjalankan di server saat ini.", + "installation.issues.accounts": "Folder /site/accounts tidak ada atau tidak dapat ditulis", + "installation.issues.content": "Folder /content tidak ada atau tidak dapat ditulis", + "installation.issues.curl": "Ekstensi CURL diperlukan", + "installation.issues.headline": "Panel tidak dapat dipasang", + "installation.issues.mbstring": "Ekstensi MB String diperlukan", + "installation.issues.media": "Folder /media tidak ada atau tidak dapat ditulis", + "installation.issues.php": "Pastikan Anda menggunakan PHP 7+", + "installation.issues.server": "Kirby memerlukan Apache, Nginx, atau Caddy", + "installation.issues.sessions": "Folder /site/sessions tidak ada atau tidak dapat ditulis", + + "language": "Bahasa", + "language.code": "Kode", + "language.convert": "Atur sebagai bawaan", + "language.convert.confirm": "

Anda yakin mengubah {name} menjadi bahasa bawaan? Ini tidak dapat dibatalkan.

Jika {name} memiliki konten yang tidak diterjemahkan, tidak akan ada pengganti yang valid dan dapat menyebabkan beberapa bagian dari situs Anda menjadi kosong.

", + "language.create": "Tambah bahasa baru", + "language.delete.confirm": "Anda yakin menghapus bahasa {name} termasuk semua terjemahannya? Ini tidak dapat dibatalkan!", + "language.deleted": "Bahasa sudah dihapus", + "language.direction": "Arah baca", + "language.direction.ltr": "Kiri ke kanan", + "language.direction.rtl": "Kanan ke kiri", + "language.locale": "String \"PHP locale\"", + "language.locale.warning": "Anda menggunakan pengaturan lokal ubah suaian. Ubah di berkas bahasa di /site/languages", + "language.name": "Nama", + "language.updated": "Bahasa sudah diperbaharui", + + "languages": "Bahasa", + "languages.default": "Bahasa bawaan", + "languages.empty": "Belum ada bahasa", + "languages.secondary": "Bahasa sekunder", + "languages.secondary.empty": "Belum ada bahasa sekunder", + + "license": "Lisensi Kirby", + "license.buy": "Beli lisensi", + "license.register": "Daftar", + "license.manage": "Manage your licenses", + "license.register.help": "Anda menerima kode lisensi via surel setelah pembelian. Salin dan tempel kode tersebut untuk mendaftarkan.", + "license.register.label": "Masukkan kode lisensi Anda", + "license.register.success": "Terima kasih atas dukungan untuk Kirby", + "license.unregistered": "Ini adalah demo tidak diregistrasi dari Kirby", + "license.unregistered.label": "Unregistered", + + "link": "Tautan", + "link.text": "Teks tautan", + + "loading": "Memuat", + + "lock.unsaved": "Perubahan belum tersimpan", + "lock.unsaved.empty": "Tidak ada lagi perubahan belum tersimpan", + "lock.isLocked": "Perubahan belum tersimpan oleh {email}", + "lock.file.isLocked": "Berkas sedang disunting oleh {email} dan tidak dapat diubah.", + "lock.page.isLocked": "Halaman sedang disunting oleh {email} dan tidak dapat diubah.", + "lock.unlock": "Buka kunci", + "lock.isUnlocked": "Perubahan Anda yang belum tersimpan telah terubah oleh pengguna lain. Anda dapat mengunduh perubahan Anda untuk menggabungkannya manual.", + + "login": "Masuk", + "login.code.label.login": "Kode masuk", + "login.code.label.password-reset": "Kode atur ulang sandi", + "login.code.placeholder.email": "000 000", + "login.code.text.email": "Jika alamat surel terdaftar, kode yang diminta dikirim via surel", + "login.email.login.body": "Hi {user.nameOrEmail},\n\nYou recently requested a login code for the Panel of {site}.\nThe following login code will be valid for {timeout} minutes:\n\n{code}\n\nIf you did not request a login code, please ignore this email or contact your administrator if you have questions.\nFor security, please DO NOT forward this email.", + "login.email.login.subject": "Kode masuk Anda", + "login.email.password-reset.body": "Hi {user.nameOrEmail},\n\nYou recently requested a password reset code for the Panel of {site}.\nThe following password reset code will be valid for {timeout} minutes:\n\n{code}\n\nIf you did not request a password reset code, please ignore this email or contact your administrator if you have questions.\nFor security, please DO NOT forward this email.", + "login.email.password-reset.subject": "Kode atur ulang sandi Anda", + "login.remember": "Biarkan tetap masuk", + "login.reset": "Atur ulang sandi", + "login.toggleText.code.email": "Masuk via surel", + "login.toggleText.code.email-password": "Masuk dengan sandi", + "login.toggleText.password-reset.email": "Lupa sandi Anda?", + "login.toggleText.password-reset.email-password": "← Kembali ke masuk", + + "logout": "Keluar", + + "menu": "Menu", + "meridiem": "AM/PM", + "mime": "Tipe Media", + "minutes": "Menit", + + "month": "Bulan", + "months.april": "April", + "months.august": "Agustus", + "months.december": "Desember", + "months.february": "Februari", + "months.january": "Januari", + "months.july": "Juli", + "months.june": "Juni", + "months.march": "Maret", + "months.may": "Mei", + "months.november": "November", + "months.october": "Oktober", + "months.september": "September", + + "more": "Lebih lanjut", + "name": "Nama", + "next": "Selanjutnya", + "no": "tidak", + "off": "mati", + "on": "hidup", + "open": "Buka", + "open.newWindow": "Buka di jendela baru", + "options": "Opsi", + "options.none": "Tidak ada opsi", + + "orientation": "Orientasi", + "orientation.landscape": "Rebah", + "orientation.portrait": "Tegak", + "orientation.square": "Persegi", + + "page.blueprint": "This page has no blueprint yet. You can define the setup in /site/blueprints/pages/{blueprint}.yml", + "page.changeSlug": "Ubah URL", + "page.changeSlug.fromTitle": "Buat dari judul", + "page.changeStatus": "Ubah status", + "page.changeStatus.position": "Pilih posisi", + "page.changeStatus.select": "Pilih status baru", + "page.changeTemplate": "Ubah templat", + "page.delete.confirm": "Anda yakin menghapus {title}?", + "page.delete.confirm.subpages": "Halaman ini memiliki sub-halaman.
Semua sub-halaman akan ikut dihapus.", + "page.delete.confirm.title": "Masukkan judul halaman untuk mengonfirmasi", + "page.draft.create": "Buat draf", + "page.duplicate.appendix": "Salin", + "page.duplicate.files": "Salin berkas", + "page.duplicate.pages": "Salin halaman", + "page.sort": "Ubah posisi", + "page.status": "Status", + "page.status.draft": "Draf", + "page.status.draft.description": "Halaman ini ada pada mode draf dan hanya dapat dilihat oleh penyunting atau via tautan rahasia", + "page.status.listed": "Publik", + "page.status.listed.description": "Halaman publik untuk siapapun", + "page.status.unlisted": "Tidak tercantum", + "page.status.unlisted.description": "Halaman hanya dapat diakses via URL", + + "pages": "Halaman", + "pages.empty": "Belum ada halaman", + "pages.status.draft": "Draf", + "pages.status.listed": "Dipublikasikan", + "pages.status.unlisted": "Tidak tercantum", + + "pagination.page": "Halaman", + + "password": "Sandi", + "paste": "Paste", + "paste.after": "Paste after", + "pixel": "Piksel", + "plugins": "Plugins", + "prev": "Sebelumnya", + "preview": "Pratinjau", + "remove": "Hapus", + "rename": "Ubah nama", + "replace": "Ganti", + "retry": "Coba lagi", + "revert": "Kembalikan", + "revert.confirm": "Anda yakin menghapus semua perubahan yang belum tersimpan?", + + "role": "Peran", + "role.admin.description": "Admin memiliki semua izin", + "role.admin.title": "Admin", + "role.all": "Semua", + "role.empty": "Tidak ada pengguna dengan peran ini", + "role.description.placeholder": "Tidak ada deskripsi", + "role.nobody.description": "Ini adalah peran cadangan tanpa permisi apapun", + "role.nobody.title": "Tidak siapapun", + + "save": "Simpan", + "search": "Cari", + "search.min": "Masukkan {min} karakter untuk mencari", + "search.all": "Tampilkan semua", + "search.results.none": "Tidak ada hasil", + + "section.required": "Bagian ini wajib", + + "security": "Security", + "select": "Pilih", + "server": "Server", + "settings": "Pengaturan", + "show": "Tampilkan", + "site.blueprint": "Situs ini belum memiliki cetak biru. Anda dapat mendefinisikannya di /site/blueprints/site.yml", + "size": "Ukuran", + "slug": "Akhiran URL", + "sort": "Urutkan", + + "stats.empty": "No reports", + "system.issues.content": "The content folder seems to be exposed", + "system.issues.debug": "Debugging must be turned off in production", + "system.issues.git": "The .git folder seems to be exposed", + "system.issues.https": "We recommend HTTPS for all your sites", + "system.issues.kirby": "The kirby folder seems to be exposed", + "system.issues.site": "The site folder seems to be exposed", + + "title": "Judul", + "template": "Templat", + "today": "Hari ini", + + "toolbar.button.code": "Kode", + "toolbar.button.bold": "Tebal", + "toolbar.button.email": "Surel", + "toolbar.button.headings": "Penajukan", + "toolbar.button.heading.1": "Penajukan 1", + "toolbar.button.heading.2": "Penajukan 2", + "toolbar.button.heading.3": "Penajukan 3", + "toolbar.button.heading.4": "Heading 4", + "toolbar.button.heading.5": "Heading 5", + "toolbar.button.heading.6": "Heading 6", + "toolbar.button.italic": "Miring", + "toolbar.button.file": "Berkas", + "toolbar.button.file.select": "Pilih berkas", + "toolbar.button.file.upload": "Unggah berkas", + "toolbar.button.link": "Tautan", + "toolbar.button.paragraph": "Paragraph", + "toolbar.button.strike": "Coret", + "toolbar.button.ol": "Daftar berurut", + "toolbar.button.underline": "Garis bawah", + "toolbar.button.ul": "Daftar tidak berurut", + + "translation.author": "Tim Kirby", + "translation.direction": "ltr", + "translation.name": "Bahasa Indonesia", + "translation.locale": "id_ID", + + "upload": "Unggah", + "upload.error.cantMove": "Berkas unggahan tidak dapat dipindahkan", + "upload.error.cantWrite": "Gagal menyimpan berkas", + "upload.error.default": "Berkas tidak dapat diunggah", + "upload.error.extension": "Unggahan berkas diblokir dengan ekstensi", + "upload.error.formSize": "Berkas unggahan mencapai acuan MAX_FILE_SIZE yang diatur di formulir", + "upload.error.iniPostSize": "Berkas unggahan mencapai acuan post_max_size di php.ini", + "upload.error.iniSize": "Berkas unggahan mencapai acuan upload_max_filesize di php.ini", + "upload.error.noFile": "Tidak ada berkas diunggah", + "upload.error.noFiles": "Tidak ada berkas diunggah", + "upload.error.partial": "Berkas unggahan hanya berhasil diunggah sebagian", + "upload.error.tmpDir": "Folder sementara tidak ada", + "upload.errors": "Kesalahan", + "upload.progress": "Mengunggah…", + + "url": "Url", + "url.placeholder": "https://contoh.com", + + "user": "Pengguna", + "user.blueprint": "You can define additional sections and form fields for this user role in /site/blueprints/users/{blueprint}.yml", + "user.changeEmail": "Ubah surel", + "user.changeLanguage": "Ubah bahasa", + "user.changeName": "Ubah nama pengguna ini", + "user.changePassword": "Ubah sandi", + "user.changePassword.new": "Sandi baru", + "user.changePassword.new.confirm": "Konfirmasi sandi baru…", + "user.changeRole": "Ubah peran", + "user.changeRole.select": "Pilih peran baru", + "user.create": "Tambah pengguna baru", + "user.delete": "Hapus pengguna ini", + "user.delete.confirm": "Anda yakin menghapus
{email}?", + + "users": "Pengguna", + + "version": "Versi", + + "view.account": "Akun Anda", + "view.installation": "Pemasangan", + "view.languages": "Bahasa", + "view.resetPassword": "Atur ulang sandi", + "view.site": "Situs", + "view.system": "System", + "view.users": "Pengguna", + + "welcome": "Selamat datang", + "year": "Tahun", + "yes": "ya" } diff --git a/kirby/i18n/translations/is_IS.json b/kirby/i18n/translations/is_IS.json index 0608b5c..6b77d0b 100644 --- a/kirby/i18n/translations/is_IS.json +++ b/kirby/i18n/translations/is_IS.json @@ -1,730 +1,574 @@ { - "account.changeName": "Breyta nafninu þínu", - "account.delete": "Eyða notandareikning þínum", - "account.delete.confirm": "Ertu alveg viss um að þú viljir endanlega eyða reikningnum þínum? Þú munt verða útskráð/ur án tafar. Ómögulegt verður að endurheimta reikninginn þinn.", - - "activate": "Virkja", - "add": "Bæta við", - "alpha": "Gagnsæi", - "author": "Höfundur", - "avatar": "Prófíl mynd", - "back": "Til baka", - "cancel": "Hætta við", - "change": "Breyta", - "close": "Loka", - "changes": "Breytingar", - "confirm": "OK", - "collapse": "Fella", - "collapse.all": "Fella allt", - "color": "Litur", - "coordinates": "Hnit", - "copy": "Afrita", - "copy.all": "Afrita allt", - "copy.success": "Afritaði {count}!", - "create": "Stofna", - "custom": "Sérstillt", - - "date": "Dagsetning", - "date.select": "Veldu dagsetningu", - - "day": "Dagur", - "days.fri": "Fös", - "days.mon": "Mán", - "days.sat": "Lau", - "days.sun": "Sun", - "days.thu": "Fim", - "days.tue": "Þri", - "days.wed": "Mið", - - "debugging": "Aflúsun", - - "delete": "Eyða", - "delete.all": "Eyða hreint öllu", - - "dialog.fields.empty": "Þessi valmynd hefur engin svið", - "dialog.files.empty": "Engar skrár til að velja úr", - "dialog.pages.empty": "Engar síður til að velja úr", - "dialog.text.empty": "þessi valmynd skilgreinir engan texta", - "dialog.users.empty": "Engir notendur til að velja úr", - - "dimensions": "Rýmd", - "disable": "Afvirkja", - "disabled": "Óvirkt", - "discard": "Hunsa", - - "drawer.fields.empty": "Þessi skúffa hefur engin svið", - - "domain": "Lén", - "download": "Hlaða niður", - "duplicate": "Klóna", - - "edit": "Breyta", - - "email": "Netfang", - "email.placeholder": "nafn@netfang.is", - - "enter": "Venda", - "entries": "Færslur", - "entry": "Færsla", - - "environment": "Umhverfi", - - "error": "Villa", - "error.access.code": "Ógildur kóði", - "error.access.login": "Ógild innskráning", - "error.access.panel": "Þú hefur ekkert leyfi til að nota panelinn", - "error.access.view": "Þú hefur ekkert leyfi til að nota þennan hluta panelsins", - - "error.avatar.create.fail": "Það gekk ekki að hlaða inn prófílmyndinni", - "error.avatar.delete.fail": "Ekki tókst að eyða prófílmyndinni", - "error.avatar.dimensions.invalid": "Vinsamlegast hafðu myndina ekki breiðari né hærri en 3000 punkta", - "error.avatar.mime.forbidden": "Snið myndarinnar þarf að vera af gerðinni JPEG eða PNG", - - "error.blueprint.notFound": "Ekki tókst að hlaða bláprentið: \"{name}\". Reyndu aftur?", - - "error.blocks.max.plural": "Ekki fleiri en {max} bálka", - "error.blocks.max.singular": "Ekki meira en einn bálkur", - "error.blocks.min.plural": "Minnst {min}. bálka", - "error.blocks.min.singular": "Allavegana einn bálkur takk", - "error.blocks.validation": "Það er villa í {field} sviðinu í bálkinum {index} sem notar {fieldset} bálkgerðina", - - "error.cache.type.invalid": "Ógyld skyndiminnisgerð \"{type}\"", - - "error.email.preset.notFound": "Netfangstillingarnar: \"{name}\" fundust ekki", - - "error.field.converter.invalid": "Ógildur umbreytari \"{converter}\"", - "error.field.type.missing": "Sviðið \"{ name }\": Sviðgerðin er \"{type}\" er alls ekki til.", - - "error.file.changeName.empty": "Nafn skal fylla út", - "error.file.changeName.permission": "Þú mátt ekkert breyta nafninu á skránni \"{filename}\"", - "error.file.changeTemplate.invalid": "Sniðmátinu fyrir skránna \"{id}\" er ekki hægt að breyta í \"{template}\" (gild: \"{blueprints}\")", - "error.file.changeTemplate.permission": "Þú mátt ekkert breyta sniðmátinu fyrir skránna \"{id}\"", - - "error.file.duplicate": "Skrá með nafninu \"{filename}\" er nú þegar til", - "error.file.extension.forbidden": "Skrárendingin \"{extension}\" er ekki leyfð", - "error.file.extension.invalid": "Óleyfilegt skrársnið hér: {extension}", - "error.file.extension.missing": "Skrárendinguna fyrir \"{filename}\" vantar", - "error.file.maxheight": "Hæð myndarinnar má ekki vera meiri en {height} punktar", - "error.file.maxsize": "Skráinn er alltof stór", - "error.file.maxwidth": "Breydd myndarinnar má alls ekki vera meiri en {width} punktar", - "error.file.mime.differs": "Upphlaðna skráin þarf að vera sömu tegundar: \"{mime}\"", - "error.file.mime.forbidden": "Gagnasniðið \"{mime}\" er ekki leyft hér", - "error.file.mime.invalid": "Ógyllt gagnasnið: {mime}", - "error.file.mime.missing": "Gagnasnið skránnar \"{filename}\" er óþekkt", - "error.file.minheight": "Hæð myndarinnar þarf að vera minnst {height} punktar", - "error.file.minsize": "Skráin er of smá", - "error.file.minwidth": "Breidd myndarinnar þarf að vera minnst {width} punktar", - "error.file.name.unique": "Skrárnafnið þarf að vera einstakt", - "error.file.name.missing": "Skrárnafnið má ekki skilja eftir tómt", - "error.file.notFound": "Skráin \"{filename}\" fannst ekki", - "error.file.orientation": "Snið myndarinnar þarf að vera \"{orientation}\"", - "error.file.type.forbidden": "Þú mátt ekkert hlaða inn {type} skrám", - "error.file.type.invalid": "Ógild skrártegund: {type}", - "error.file.undefined": "Skráin fannst ekki", - - "error.form.incomplete": "Vinsamlegast lagfærðu villurnar í forminu…", - "error.form.notSaved": "Ekki tókst að vista upplýsingar úr forminu", - - "error.language.code": "Gófúslega settu inn gildan kóða fyrir tungumál", - "error.language.duplicate": "Þetta tungumál er nú þegar skráð", - "error.language.name": "Gott og gyllt nafn fyrir tungumálið", - "error.language.notFound": "Tungumálið fannst ekkert", - - "error.layout.validation.block": "Það er villa í {field} sviðinu í bálkinum {blockIndex} sem notar {fieldset} bálkgerðina í rammanum {layoutIndex}", - "error.layout.validation.settings": "Hér er villa í sitllingum fyrir ramman {index}", - - "error.license.domain": "Lénið fyrir skráningarleyfið vantar", - "error.license.email": "Almennilegt netfang hér", - "error.license.format": "Vinsamlegast og fyrir alla muni settu inn gildan leyfiskóða", - "error.license.verification": "Ekki heppnaðist að staðfesta leyfið", - - "error.login.totp.confirm.invalid": "Ógildur kóði", - "error.login.totp.confirm.missing": "Settu inn núverandi lykilkóða", - - "error.object.validation": "Það er villa í \"{label}\" sviðinu:\n{message}", - - "error.offline": "Stjórnborðið er óvirkt eins og stendur.", - - "error.page.changeSlug.permission": "Þú hefur ekkert leyfi til þess að breyta slóðarviðskeytinu fyrir \"{slug}\"", - "error.page.changeSlug.reserved": "Slóð síðna í rótinni verður að byrja með \"{path}\"", - "error.page.changeStatus.incomplete": "Það eru villur á síðunni og við getum ekki gefið hana út", - "error.page.changeStatus.permission": "Stöðu síðunnar var ekki hægt að breyta", - "error.page.changeStatus.toDraft.invalid": "Síðunni \"{slug}\" er ekki hægt að breyta í uppkast", - "error.page.changeTemplate.invalid": "Sniðmáti fyrir síðuna \"{slug}\" er ekki hægt að breyta", - "error.page.changeTemplate.permission": "Þú hefur engan veginn leyfi til að breyta sniðmáti fyrir síðuna \"{slug}\"", - "error.page.changeTitle.empty": "Titillinn getur ekki verið óskilgreindur", - "error.page.changeTitle.permission": "Þú mátt ekki breyta titlinum fyrir \"{slug}\"", - "error.page.create.permission": "Þú hefur ekki leyfi til að stofna \"{slug}\"", - "error.page.delete": "Síðunni \"{slug}\" er ekki hægt að eyða", - "error.page.delete.confirm": "Ritaðu titil síðunnar til að staðfesta", - "error.page.delete.hasChildren": "Síðan hefur undirsíður og er því ekki hægt að eyða", - "error.page.delete.permission": "Þú mátt ekkert eyða \"{slug}\"", - "error.page.draft.duplicate": "Uppkast með slóðinni \"{slug}\" er þegar til", - "error.page.duplicate": "Síða með slóðinni \"{slug}\" er þegar til", - "error.page.duplicate.permission": "Þú mátt ekki klóna \"{slug}\"", - "error.page.move.ancestor": "Það er ekki hægt að færa síðuna á sjálfa sig.", - "error.page.move.directory": "Ekki er reyndist unnt að færa möppu síðunnar.", - "error.page.move.duplicate": "Undirsíða með slóðinni og forskeytinu \"{slug}\" er núþegar til", - "error.page.move.notFound": "Síðan sem færð var finnst því miður ekki", - "error.page.move.permission": "Þú mátt ekkert færa \"{slug}\"", - "error.page.move.template": "Sniðmátið \"{template}\" er ekki gillt sem undirsíða af \"{parent}\"", - "error.page.notFound": "Síðan \"{slug}\" fannst ekkert", - "error.page.num.invalid": "Veldu ákjósanlega raðtölu. Neikvæðar tölur bannaðar.", - "error.page.slug.invalid": "Veldu ákjósanlega vefslóð", - "error.page.slug.maxlength": "Vefslóð þarf að vera a.m.k. \"{length}\" stafir", - "error.page.sort.permission": "Ekki reyndist unnt að raða síðunni \"{slug}\"", - "error.page.status.invalid": "Ákjósanlega síðustöðu takk", - "error.page.undefined": "Síðan fannst ekkert", - "error.page.update.permission": "Þú mátt ekkert uppfæra síðuna \"{slug}\"", - - "error.section.files.max.plural": "Ekki fleiri en {max} skrár í \"{section}\" svæðið", - "error.section.files.max.singular": "Aðeins ein skrá í \"{section}\" svæðið", - "error.section.files.min.plural": "\"{section}\" svæðið krefst a.m.k. {min} skrá sem innihalds", - "error.section.files.min.singular": "\"{section}\" þarf minnst eina skrá til að það virki", - - "error.section.pages.max.plural": "Alls ekki fleiri en {max} síður í \"{section}\" svæðið", - "error.section.pages.max.singular": "Ekki fleiri en ein síða í \"{section}\" svæðið", - "error.section.pages.min.plural": "\"{section}\" svæðið krefst a.m.k {min}. síðna", - "error.section.pages.min.singular": "\"{section}\" krefst a.m.k. einnar síðu", - - "error.section.notLoaded": "Svæðið \"{name}\" var því miður ekki hægt að sækja", - "error.section.type.invalid": "Svæðiðsgerðin \"{type}\" er því miður ekki gild", - - "error.site.changeTitle.empty": "Ekki skilja titilinn eftir tóman", - "error.site.changeTitle.permission": "Þú mátt ekkert breyta titil vefsvæðisins", - "error.site.update.permission": "Þú mátt ekkert uppfæra vefsvæðið", - - "error.structure.validation": "Það er villa í \"{field}\" sviðinu í röð {index}", - - "error.template.default.notFound": "Ekkert sjálfgefið sniðmát fannst", - - "error.unexpected": "Það átti sér stað óvænt villa. Notaðu lúsarleitarhaminn (e. debug mode) til að skilja þetta betur. \nFyrir nánari upplýsingar: https://getkirby.com/docs/reference/system/options/debug", - - "error.user.changeEmail.permission": "Þú mátt ekkert breyta netfangi notandans \"{name}\"", - "error.user.changeLanguage.permission": "Þú hefur ekki leyfi til að breyta tungumáli notandans \"{name}\"", - "error.user.changeName.permission": "Þú mátt alls ekki breyta nafni notandans \"{name}\"", - "error.user.changePassword.permission": "Þér er harðbannað að breyta lykilorði notandans \"{name}\"", - "error.user.changeRole.lastAdmin": "Þetta er síðasti stjórinn og því má ekki breyta hlutverki", - "error.user.changeRole.permission": "Þú hefur ekki leyfi til að breyta hlutverki fyrir notandan \"{name}\"", - "error.user.changeRole.toAdmin": "Þú hefur ekkert leyfi til að gera notendur að stjórum", - "error.user.create.permission": "Þú mátt ekki stofna þennan notanda", - "error.user.delete": "Ekki reyndist unnt að eyða notandanum \"{name}\"", - "error.user.delete.lastAdmin": "Síðasta stjóranum er ekki hægt að eyða", - "error.user.delete.lastUser": "Síðasta notandanum er ekki hægt að eyða", - "error.user.delete.permission": "Þú mátt ekkert eyða notandanum \"{name}\"", - "error.user.duplicate": "Nú þegar finnst notandi með þetta netfang: \"{email}\"", - "error.user.email.invalid": "Vinsamlegast ákjósanlegt netfang", - "error.user.language.invalid": "Vinsamlegast ákjósanlegt tungumál", - "error.user.notFound": "Þessi notandi; \"{name}\" fannst ekki", - "error.user.password.excessive": "Vinsamlegast settu inn gilt lykilorð. Lykilorð hér meiga ekki vera lengri en 1000 stafabil.", - "error.user.password.invalid": "Veldu ákjósanlegt lykilorð. Minnst 8 stafa langt.", - "error.user.password.notSame": "Lykilorðin stemma ekki", - "error.user.password.undefined": "Þessi notandi hefur ekki lykilorð", - "error.user.password.wrong": "Rangt lykilorð", - "error.user.role.invalid": "Veldu ákjósanlegt hlutverk", - "error.user.undefined": "Notandinn fannst ekkert", - "error.user.update.permission": "Þú mátt ekkert breyta notandanum \"{name}\"", - - "error.validation.accepted": "Staðfestu", - "error.validation.alpha": "Aðeins stafir úr Enska stafrófinu, a-z", - "error.validation.alphanum": "Aðeins stafir úr Enska stafrófinu, a-z eða tölustafir 0-9", - "error.validation.anchor": "Vinsamlegast rétt og gillt merki", - "error.validation.between": "Gildi milli \"{min}\" og \"{max}\"", - "error.validation.boolean": "Staðfestu eða hafnaðu þessu", - "error.validation.color": "Endilega settu inn gildan lit í sniðinu {format}", - "error.validation.contains": "Settu inni gildi er inniheldur \"{needle}\"", - "error.validation.date": "Ákjósanlega dagsetningu", - "error.validation.date.after": "Dagsetningu eftir {date}", - "error.validation.date.before": "Dagsetningu fyrir {date}", - "error.validation.date.between": "Dagsetningu milli {min} og {max}", - "error.validation.denied": "Hafnaðu", - "error.validation.different": "Gildið má ekki vera \"{other}\"", - "error.validation.email": "Ákjósanlegt netfang", - "error.validation.endswith": "Gildið verður að enda á \"{end}\"", - "error.validation.filename": "Ákjósanlegt skrárnafn", - "error.validation.in": "Vinsamlegast skráðu eitt af eftirfarandi: ({in})", - "error.validation.integer": "Skráðu heiltölu", - "error.validation.ip": "Skráðu ákjósanlega IP tölu", - "error.validation.less": "Skráðu gildi lægra en {max}", - "error.validation.linkType": "Þessi tengilsgerð er ekki leyfð hér um slóðir.", - "error.validation.match": "Gildið er ekki eftir væntingum", - "error.validation.max": "Skráðu gildi sem er ekki hærra en {max}", - "error.validation.maxlength": "Veldu eitthvað styttra. (hámark {max} stafir)", - "error.validation.maxwords": "Ekki skrá fleiri en {max}. orð", - "error.validation.min": "Skráðu gildi ekki lægra en {min}", - "error.validation.minlength": "Hafðu þetta lengra en {min}. stafi", - "error.validation.minwords": "Lágmark {min}. orð", - "error.validation.more": "Eitthvað hærra en {min}", - "error.validation.notcontains": "Skráðu eitthvað sem inniheldur ekki \"{needle}\"", - "error.validation.notin": "Ekki skrá neitt af þessu: ({notIn})", - "error.validation.option": "Veldu ákjósanlegan kost", - "error.validation.num": "Notaðu tölugildi", - "error.validation.required": "Skráðu eitthvað", - "error.validation.same": "Skráðu \"{other}\"", - "error.validation.size": "Gildið þarf að vera \"{size}\"", - "error.validation.startswith": "Þetta þarf að byrja á \"{start}\"", - "error.validation.tel": "Vinsamlegast ósniðið símanúmer hér.", - "error.validation.time": "Ákjósanlegur tími", - "error.validation.time.after": "Veldu tíma eftir {time}", - "error.validation.time.before": "Veldu tíma fyrir{time}", - "error.validation.time.between": "Veldu tíma milli {min} og {max}", - "error.validation.uuid": "Vinsamlegast gillt UUID (Notandakenni)", - "error.validation.url": "Ákjósanleg vefslóð", - - "expand": "Þenja út", - "expand.all": "Þenja allt út", - - "field.invalid": "Þetta svið er bara ógillt sem stendur.", - "field.required": "Þetta svið er nauðsynlegt", - "field.blocks.changeType": "Breyta um bálkagerð", - "field.blocks.code.name": "Kóði", - "field.blocks.code.language": "Tungumal", - "field.blocks.code.placeholder": "Kóðinn þinn …", - "field.blocks.delete.confirm": "Ætlarðu virkilega að eyða þessum bálk?", - "field.blocks.delete.confirm.all": "Ertu nú alveg viss um að þú viljir eyða öllum þessum bálkum?", - "field.blocks.delete.confirm.selected": "Viltu virkilega eyða völdum bálkum?", - "field.blocks.empty": "Öngvir bálkar enn", - "field.blocks.fieldsets.empty": "Engin sviðasett enn", - "field.blocks.fieldsets.label": "Veldu bálkagerð …", - "field.blocks.fieldsets.paste": "Ýttu á {{ shortcut }} til þess að flytja raðir/bálka hingað Aðeins þeir sem eru gildir hér mun verða færðir hingað.", - "field.blocks.gallery.name": "Myndasafn", - "field.blocks.gallery.images.empty": "Engar myndir enn", - "field.blocks.gallery.images.label": "Myndir", - "field.blocks.heading.level": "Stig", - "field.blocks.heading.name": "Fyrirsögn", - "field.blocks.heading.text": "Texti/Prósi", - "field.blocks.heading.placeholder": "Fyrirsögn …", - "field.blocks.image.alt": "ALT texti", - "field.blocks.image.caption": "Myndartexti", - "field.blocks.image.crop": "Kroppa", - "field.blocks.image.link": "Tengill", - "field.blocks.image.location": "Staðsetning", - "field.blocks.image.location.internal": "Þetta vefsvæði", - "field.blocks.image.location.external": "Ytri kelda", - "field.blocks.image.name": "Mynd", - "field.blocks.image.placeholder": "Veldu mynd", - "field.blocks.image.ratio": "Hlutfall", - "field.blocks.image.url": "Slóð myndar", - "field.blocks.line.name": "Lína", - "field.blocks.list.name": "Listi", - "field.blocks.markdown.name": "Markdown", - "field.blocks.markdown.label": "Texti", - "field.blocks.markdown.placeholder": "Markdown …", - "field.blocks.quote.name": "Tilvitnun", - "field.blocks.quote.text.label": "Innihald tilvitnunar", - "field.blocks.quote.text.placeholder": "Þessi tilvitnun …", - "field.blocks.quote.citation.label": "Heimild", - "field.blocks.quote.citation.placeholder": "eftir …", - "field.blocks.text.name": "Prósi", - "field.blocks.text.placeholder": "Þessi prósi …", - "field.blocks.video.autoplay": "Sjálfspila", - "field.blocks.video.caption": "Myndskeiðstexti", - "field.blocks.video.controls": "Stjórnhnappar", - "field.blocks.video.location": "Staðsetning", - "field.blocks.video.loop": "Lykkja", - "field.blocks.video.muted": "Þaggað", - "field.blocks.video.name": "Myndskeið", - "field.blocks.video.placeholder": "Vefslóð myndskeiðs (URL)", - "field.blocks.video.poster": "Plakkat", - "field.blocks.video.preload": "Forhlaða", - "field.blocks.video.url.label": "Vefslóð", - "field.blocks.video.url.placeholder": "https://youtube.com/?v=", - - "field.files.empty": "Engar skrár valdar ennþá", - - "field.layout.change": "Breyta uppsetningu ramma", - "field.layout.delete": "Eyða ramma", - "field.layout.delete.confirm": "Ætlarðu virkilega að eyða þessum ramma?", - "field.layout.delete.confirm.all": "Ætlarðu virkilega að eyða öllum römmum?", - "field.layout.empty": "Nei. Engir rammar enn.", - "field.layout.select": "Veldu rammategund", - - "field.object.empty": "Engar upplýsingar enn", - - "field.pages.empty": "Engar síður valdar ennþá", - - "field.structure.delete.confirm": "Viltu virkilega eyða þessari röð?", - "field.structure.delete.confirm.all": "Ætlar þú virkilega að eyða öllum færslum?", - "field.structure.empty": "Engar færslur enn", - - "field.users.empty": "Engir notendur valdir enn", - - "fields.empty": "Hér eru engin svið enn", - - "file": "Skrár", - "file.blueprint": "Þessi skrá hefur ekki skipan (e. blueprint) ennþá. Þú mátt skilgreina skipanina í /site/blueprints/{template}.yml", - "file.changeTemplate": "Breyta sniðmáti", - "file.changeTemplate.notice": "Að breyta sniðmáti skránnar mun fjarlæjga efnið er tilheyrir þeim sviðum er ekki passar við viðkomandi gerð. Ef nýja sniðmátið er skilgreint með ákveðnum reglum s.s. stærð mynda þá verða þær breytingar óafturkræfar. Notist með gát.", - "file.delete.confirm": "Ætlarðu virkilega að eyða
{filename}?", - "file.focus.placeholder": "Settu brennipunkt", - "file.focus.reset": "Fjarlægðu brennipunkt", - "file.focus.title": "Fókus", - "file.sort": "Breyta röðun", - - "files": "Skrár", - "files.empty": "Engar skrár enn", - - "filter": "Sigta", - - "hide": "Fela", - "hour": "Klukkustund", - "hue": "Blær", - "import": "Hlaða inn", - "info": "Upplýsingar", - "insert": "Setja inn", - "insert.after": "Setja eftir", - "insert.before": "Setja fyrir", - "install": "Setja upp", - - "installation": "Uppsettning", - "installation.completed": "Panellinn er uppsettur", - "installation.disabled": "Paneluppsetning er sjálfgefið óvirk á vefþjónum á Veraldarvefnum. Reyndu frekar að setja Panelinn upp í lokuðu umhverfi eða virkjaðu panel.install möguleikan.", - "installation.issues.accounts": "/site/accounts mappan er annaðhvort ekki til eða er ekki skrifanleg.", - "installation.issues.content": "/content mappan er annaðhvort ekki til eða er ekki skrifanleg", - "installation.issues.curl": "CURL viðbótin er hér bráðnauðsynleg", - "installation.issues.headline": "Uppsetning Panelsins mistókst hrapalega", - "installation.issues.mbstring": "MB String er hér bráðnauðsynleg", - "installation.issues.media": "/media mappan er annaðhvort ekki til eða er ekki skrifanleg", - "installation.issues.php": "Notaðu PHP 8+", - "installation.issues.sessions": "/site/sessions mappan er annaðhvort ekki til eða er ekki skrifanleg", - - "language": "Tungumál", - "language.code": "Kóði", - "language.convert": "Gera sjálfgefið", - "language.convert.confirm": "

Ertu viss um að þú viljir breyta {name} í sjálfgefið (lesist aðal) tungumál? Þessu verður ekki viðsnúið.

Ef {name} hefur innihald sem ekki hefur verið þýtt, þá verða engir möguleikar til þrautarvara og hluti vefsins gæti birtst tómur.

", - "language.create": "Bættu við nýju tungumáli", - "language.default": "Aðal tungumál", - "language.delete.confirm": "Ertu nú viss um að þú viljir eyða {name} og öllum tilheyrandi þýðingum? Þetta verður ekki tekið til baka!", - "language.deleted": "Tungumálinu hefur verið eytt", - "language.direction": "Lesátt", - "language.direction.ltr": "Vinstra til hægri", - "language.direction.rtl": "Hægra til vinstri", - "language.locale": "PHP locale strengur", - "language.locale.warning": "Þú ert að nota sérsniðna locale uppsetningu. Vinsamlegast breyttu tungumálaskránni á slóðinni /site/languages", - "language.name": "Nafn tungumáls", - "language.secondary": "Auka tungumál", - "language.settings": "Tungumálastillingar", - "language.updated": "Tungumálið hefur verið uppfært", - "language.variables": "Tungumálabreytur", - "language.variables.empty": "Engar þýðingar enn", - - "language.variable.delete.confirm": "Ertu viss um að þú viljir nú fjarlægja breytuna fyrir {key}?", - "language.variable.key": "Lykill", - "language.variable.notFound": "Breytan fannst hreint ekki", - "language.variable.value": "Gildi", - - "languages": "Tungumál", - "languages.default": "Aðal tungumál", - "languages.empty": "Það eru engin frekari tungumál skilgreind enn", - "languages.secondary": "Auka tungumál", - "languages.secondary.empty": "Það eru engin auka tungumál skilgreind enn", - - "license": "Leyfi", - "license.activate": "Virkja þetta nú", - "license.activate.label": "Vinsamlegast virkjaðu leyfið þitt", - "license.activate.domain": "Leyfið þitt verður virkjað fyrir og tengt við {host}.", - "license.activate.local": "Þú ert að fara virkja leyfið þitt fyrir staðbundinn (e. local) vef: {host}. Ef það er meiningin að færa vefinn síðar út á netið þá vinsamlegast virkjaðu leyfið þar. Ef {host} er lénið sem þú vilt tengja leyfið við þá vinsamlegast haltu áfram.", - "license.activated": "Virkjað", - "license.buy": "Kaupa leyfi", - "license.code": "Kóðasnið", - "license.code.help": "Þú fékkst leyfiskóðan sendan í tölvupósti eftir að þú borgaðir fyrir leyfið. Vinsamlegast afritaðu hann hingað.", - "license.code.label": "Vinsamlegast settu inn leyfiskóðan", - "license.status.active.info": "Felur í sér allar útgáfur þar til {date}", - "license.status.active.label": "Gilt skráningarleyfi", - "license.status.demo.info": "Þessi uppsetning er til prófunar.", - "license.status.demo.label": "Prófunarútgáfa", - "license.status.inactive.info": "Endurnýja skráningarleyfi fyrir uppfærslur á nýjum útgáfum", - "license.status.inactive.label": "Engar nýjar útgáfur", - "license.status.legacy.bubble": "Klár í að endurnýja skráningarleyfið?", - "license.status.legacy.info": "Skráningarleyfið þitt og sá kóði sem fylgir gildir ekkert fyrir þessa útgáfu", - "license.status.legacy.label": "Vinsamlegast endurnýjaðu skráningarleyfið þitt", - "license.status.missing.bubble": "Er allt tilbúið til að gefa vefinn út?", - "license.status.missing.info": "Ekkert gilt skráningarleyfi", - "license.status.missing.label": "Vinsamlegast virkjaðu leyfið þitt", - "license.manage": "Sýslaðu með leyfin þín", - "license.purchased": "Verslað", - "license.success": "Þakka þér fyrir að velja Kirby", - "license.unregistered.label": "Óskráð", - - "link": "Tengill", - "link.text": "Tengilstexti", - - "loading": "Hleð", - - "lock.unsaved": "Óvistað breytingar", - "lock.unsaved.empty": "Það eru öngvar óvistaðar breytingar", - "lock.isLocked": "Óvistaðar breytingar framkvæmdar af {email}", - "lock.unlock": "Aflæsa", - "lock.unlock.submit": "Aflæsa og yfirskrifa óvistaðar breytingar framkvæmdar af {email}", - "lock.isUnlocked": "Læsing fjalægð af öðrum notanda", - - "login": "Innskrá", - "login.code.label.login": "Innskráningarkóði", - "login.code.label.password-reset": "Kóði fyrir endurstillingu lykilorðs", - "login.code.placeholder.email": "000 000", - "login.code.placeholder.totp": "000000", - "login.code.text.email": "Ef netfangið þitt er skráð þá bíður þín nýr tölvupóstur.", - "login.code.text.totp": "Settu inn kóðan frá auðkenningar appinu.", - "login.email.login.body": "Já halló {user.nameOrEmail},\n\nNýlega baðstu um innskráningarkóða fyrir bakendan á {site}.\nEftirfarandi kóði er virkur í {timeout} mínútur:\n\n{code}\n\nEf þú óskaðir ekki eftir þessu þá hunsaðu þennan tölvupóst eða talaðu við vefstjóran ef þú vilt fræðast nánar.\nAf öryggisástæðum vinsamlegast áframsendu þennan tölvupóst ALLS EKKI.", - "login.email.login.subject": "Innskráningarkóðinn þinn", - "login.email.password-reset.body": "Nei halló {user.nameOrEmail},\n\nNýverið baðstu um að lykilorði þínu væri endurstillt fyrir bakendan á {site}. \nEftirfarandi kóði er virkur í {timeout} mínútur:\n\n{code}\n\nEf þú óskaðir ekki eftir þessu þá hunsaðu þennan tölvupóst eða talaðu við vefstjóran ef þú vilt fræðast nánar.\nAf öryggisástæðum vinsamlegast áframsendu þennan tölvupóst ALLS EKKI.", - "login.email.password-reset.subject": "Kóðinn þinn fyrir endurstillingu lykilorðs", - "login.remember": "Vista innskráningu", - "login.reset": "Endurheimta lykilorð takk", - "login.toggleText.code.email": "Innskrá með netfangi", - "login.toggleText.code.email-password": "Innskrá með lykilorði", - "login.toggleText.password-reset.email": "Mannstu ekki lykilorðið?", - "login.toggleText.password-reset.email-password": "← Aftur í innskráningu", - "login.totp.enable.option": "Setja upp einnota kóða.", - "login.totp.enable.intro": "Auðkenningaröpp framleiða einnota sex stafa kóða sem notaður er seinni þáttur þegar þú skráir þig inn.", - "login.totp.enable.qr.label": "Skannaðu QR kóðan.", - "login.totp.enable.qr.help": "Virkar ekki að skanna? Bættu við uppsetningarkóðanum {secret} fyrir auðkenningarappið.", - "login.totp.enable.confirm.headline": "2. Staðfestu með auðkenningar kóða", - "login.totp.enable.confirm.text": "Appið þitt framleiðir nýjan einnota kóða á 30 sekúndna fresti. Setti inn núverandi kóða til að ljúka uppsetningu.", - "login.totp.enable.confirm.label": "Núverandi kóði", - "login.totp.enable.confirm.help": "Eftir uppsetninguna þá munum við biðja um einnota kóða í hvert skipti sem þú skráir þig inn.", - "login.totp.enable.success": "Einnota skráningarkóði virkjaður", - "login.totp.disable.option": "Afvirkjaðir einnota kóðar.", - "login.totp.disable.label": "Sláðu inn lykilorðið þitt til að afvirkja einnota kóða.", - "login.totp.disable.help": "Framveigis þá mun nýr seinniþáttar kóði verða sendur í tölvupósti til þín þegar þú skráir þig inn. Þú munt alltaf geta sett upp einnota kóðana aftur síðar.", - "login.totp.disable.admin": "

Þetta mun afvirkja einnota kóða fyrir {user}.

Framvegis mun nýr seinniþáttarkóði verða sendur í tölvupósti þegar notendur skrá sig inn. {user} getur sett upp einnota kóðana eftir næstu innskráningu.

", - "login.totp.disable.success": "Einnota skráningarkóði afvirkjaður", - - "logout": "Útskrá", - - "merge": "Splæsa", - "menu": "Valmynd", - "meridiem": "AM/PM", - "mime": "Miðilsgerð", - "minutes": "Mínútur", - - "month": "Mánuður", - "months.april": "Apríl", - "months.august": "Ágúst", - "months.december": "Desember", - "months.february": "Febrúar", - "months.january": "Janúar", - "months.july": "Júlí", - "months.june": "Júní", - "months.march": "Mars", - "months.may": "Maí", - "months.november": "Nóvember", - "months.october": "Október", - "months.september": "September", - - "more": "Meira", - "move": "Færa", - "name": "Nafn", - "next": "Næst", - "night": "Nótt", - "no": "nei", - "off": "Af", - "on": "Á", - "open": "Opna", - "open.newWindow": "Opna í nýjum glugga", - "option": "Kostur", - "options": "Valmöguleikar", - "options.none": "Engir valmöguleikar", - "options.all": "Sýna alla {count} möguleika", - - "orientation": "Snúningur", - "orientation.landscape": "Langsnið", - "orientation.portrait": "Skammsnið", - "orientation.square": "Ferningur", - - "page": "Síða", - "page.blueprint": "Þessi síða hefur ekki skipan (e. blueprint) ennþá. Þú mátt skilgreina skipanina í /site/blueprints/{template}.yml", - "page.changeSlug": "Breyta vefslóð", - "page.changeSlug.fromTitle": "Slóð af titli", - "page.changeStatus": "Breyta stöðu", - "page.changeStatus.position": "Veldu ákjósanlega röðun", - "page.changeStatus.select": "Veldu nýja stöðu", - "page.changeTemplate": "Breyta sniðmáti", - "page.changeTemplate.notice": "Að breyta sniðmáti síðunnar mun fjarlægja efni fyrir svið er ekki passa við gerð nýja sniðmátsins. Notist með gát.", - "page.create": "Stofna", - "page.delete.confirm": "Viltu virkilega farga {title}?", - "page.delete.confirm.subpages": "Þessi síða hefur undirsíður.
Þeim mun verða fargað líka.", - "page.delete.confirm.title": "Skráðu síðutitilinn til staðfestingar", - "page.duplicate.appendix": "Afrita", - "page.duplicate.files": "Afrita skrár", - "page.duplicate.pages": "Afrita síður", - "page.move": "Færa síðu", - "page.sort": "Breyta röðun", - "page.status": "Staða", - "page.status.draft": "Uppkast", - "page.status.draft.description": "Þessi síða er uppkast og er aðeins sýnileg vefstjórum eða gegnum laumu tengil.", - "page.status.listed": "Útgefin og listuð", - "page.status.listed.description": "Síðan er útgefin og listuð.", - "page.status.unlisted": "Útgefin en ólistuð", - "page.status.unlisted.description": "Síðan er útgefin en þó ólistuð.", - - "pages": "Síður", - "pages.empty": "Engar síður enn", - "pages.status.draft": "Uppköst", - "pages.status.listed": "Útgefnar og listaðar", - "pages.status.unlisted": "Útgefnar en ólistaðar", - - "pagination.page": "Síða", - - "password": "Lykilorð", - "paste": "Líma", - "paste.after": "Líma eftir", - "paste.success": "{count} límt!", - "pixel": "Punkta", - "plugin": "Viðbót", - "plugins": "Viðbætur", - "prev": "Fyrri", - "preview": "Forskoða", - "remove": "Fjarlægja", - "rename": "Endurnefna", - "renew": "Endurnýja", - "replace": "Setja í stað", - "replace.with": "Endursetja með", - "retry": "Reyndu aftur", - "revert": "Taka upp fyrri siði", - "revert.confirm": "Viltu virkilega eyða öllum óvistuðum breytingum?", - - "role": "Hlutverk", - "role.admin.description": "Stjórinn hefur öll réttindi", - "role.admin.title": "Stjóri", - "role.all": "Öll", - "role.empty": "Það eru engir notendur með þetta hlutverk", - "role.description.placeholder": "Engin lýsing", - "role.nobody.description": "Þetta hlutverk er til þrautarvara en hefur engin réttindi", - "role.nobody.title": "Enginn", - - "save": "Vista", - "search": "Leita", - "search.min": "Lágmark {min} stafir til að leita", - "search.all": "Sýna allar {count} niðurstöður.", - "search.results.none": "Engar niðurstöður", - - "section.invalid": "Þetta svæði er bara ógillt sem stendur.", - "section.required": "Þetta svæði er nauðsynlegt", - - "security": "Öryggi", - "select": "Velja", - "server": "Vefþjónn", - "settings": "Stillingar", - "show": "Sýna", - "site.blueprint": "Þessi vefur hefur ekki skipan (e. blueprint) ennþá. Þú mátt skilgreina skipanina í /site/blueprints/site.yml", - "size": "Stærð", - "slug": "Slóðar viðskeyti", - "sort": "Raða", - "sort.drag": "Dragðu til að raða", - "split": "Skipta", - - "stats.empty": "Engar skýrslur", - "status": "Staða", - - "system.info.copy": "Copy info", - "system.info.copied": "System info copied", - "system.issues.content": "Efnismappan virðist vera berskjölduð", - "system.issues.eol.kirby": "Uppsett Kirby eintak þitt hefur runnið sitt skeið á enda og mun ekki verða uppfært framar", - "system.issues.eol.plugin": "Uppsett eintak þitt af viðbótinni { plugin } hefur runnið sitt skeið á enda og mun ekki verða uppfærð framar", - "system.issues.eol.php": "Núverandi PHP útgáfa {release} hefur runnið sitt skeið og mun ekki verða uppfærð með öryggisuppfærslum.", - "system.issues.debug": "Aflúsun ætti alltaf að vera óvirk í útgefnum vef", - "system.issues.git": ".git mappan virðist vera berskjölduð", - "system.issues.https": "Við mælum harðlega með því að þú notir HTTPS fyrir öll þín vefsvæði", - "system.issues.kirby": "Kirby mappan virðist vera berskjölduð", - "system.issues.site": "Mappa vefsvæðisins virðist vera berskjölduð", - "system.issues.vulnerability.kirby": "Uppsetningin þín gæti verið berskjölduð gagnvart eftirfarandi veikleika: ({ severity } veikleikinn): { description }", - "system.issues.vulnerability.plugin": "Uppsetningin þín gæti verið berskjölduð gagnvart eftirfarandi veikleika í viðbótinni { plugin }: ({ severity } veikleikinn): { description }", - "system.updateStatus": "Uppfærslustaða", - "system.updateStatus.error": "Gat því miður ekki athugað með uppfærslur", - "system.updateStatus.not-vulnerable": "Engir þekktir veikleikar", - "system.updateStatus.security-update": "Ókeypis öryggisuppfærsla { version } fáanleg", - "system.updateStatus.security-upgrade": "Uppfærsla { version } með öryggisuppfærslum fáanleg", - "system.updateStatus.unreleased": "Þróunarútgáfa", - "system.updateStatus.up-to-date": "Allt spikk og span", - "system.updateStatus.update": "Ókeypis uppfærsla { version } fáanleg", - "system.updateStatus.upgrade": "Uppfærsla fyrir { version } fáanleg", - - "tel": "Sími", - "tel.placeholder": "+3548561234", - "template": "Sniðmát", - "title": "Titill", - "today": "Núna", - - "toolbar.button.clear": "Hreinsa snið", - "toolbar.button.code": "Kóðasnið", - "toolbar.button.bold": "Feitletrun", - "toolbar.button.email": "Netfang", - "toolbar.button.headings": "Fyrirsagnir", - "toolbar.button.heading.1": "Fyrirsögn 1", - "toolbar.button.heading.2": "Fyrirsögn 2", - "toolbar.button.heading.3": "Fyrirsögn 3", - "toolbar.button.heading.4": "Fyrirsögn 4", - "toolbar.button.heading.5": "Fyrirsögn 5", - "toolbar.button.heading.6": "Fyrirsögn 6", - "toolbar.button.italic": "Skáletrun", - "toolbar.button.file": "Skrár", - "toolbar.button.file.select": "Veldu skrá", - "toolbar.button.file.upload": "Hlaða inn skrá", - "toolbar.button.link": "Tengill", - "toolbar.button.paragraph": "Efnisgrein", - "toolbar.button.strike": "Gegnumstrika", - "toolbar.button.sub": "Hnéletur", - "toolbar.button.sup": "Höfuðletur", - "toolbar.button.ol": "Raðaður listi", - "toolbar.button.underline": "Undirstrika", - "toolbar.button.ul": "Áherslumerktur listi", - - "translation.author": "Kirby Teymið", - "translation.direction": "ltr", - "translation.name": "Íslenska", - "translation.locale": "is_IS", - - "type": "Gerð", - - "upload": "Hlaða inn", - "upload.error.cantMove": "Innhlöðnu skránni var ekki haggað", - "upload.error.cantWrite": "Það mistókst að skrifa skránna í geymslu", - "upload.error.default": "Ekki heppnaðist að hlaða inn skránni", - "upload.error.extension": "Innhleðsla stöðvuð vegna skrárendingar", - "upload.error.formSize": "Innhlaðna skráin er stærri en MAX_FILE_SIZE leyfilegt er.", - "upload.error.iniPostSize": "Innhlaðna skráin er stærri en því sem nemur í post_max_size stillingunni í php.ini", - "upload.error.iniSize": "Innhlaðna skráin er stærri en því sem nemur í upload_max_filesize stillingunni í php.ini", - "upload.error.noFile": "Engri skrá far hlaðið inn", - "upload.error.noFiles": "Engum skrám var hlaðið inn", - "upload.error.partial": "Innhlöðnu skránni var aðeins sótt að hluta", - "upload.error.tmpDir": "Vantar skruggumöppu", - "upload.errors": "Villa", - "upload.progress": "Hleð inn…", - - "url": "Slóð", - "url.placeholder": "https://tildaem.is/", - - "user": "Notandi", - "user.blueprint": "Þér er óhætt að skilgreina fleiri svæði fyrir þetta notenda hlutverk í /site/blueprints/users/{role}.yml", - "user.changeEmail": "Breyta netfangi", - "user.changeLanguage": "Breyta tungumáli", - "user.changeName": "Endurnefna þennan notanda", - "user.changePassword": "Breyta lykilorð", - "user.changePassword.new": "Nýtt lykilorð", - "user.changePassword.new.confirm": "Staðfestu nýtt lykilorð…", - "user.changeRole": "Breyta hlutverki", - "user.changeRole.select": "Veldu nýtt hlutverk", - "user.create": "Bæta við nýjum notenda", - "user.delete": "Farga þessum notenda", - "user.delete.confirm": "Viltu virkilega eyða
{email}?", - - "users": "Notendur", - - "version": "Útgáfa", - "version.current": "Núverandi útgáfa", - "version.latest": "Nýjasta útgáfa", - "versionInformation": "Útgáfuupplýsingar", - - "view.account": "Þínar stillingar", - "view.installation": "Uppsetning", - "view.languages": "Tungumál", - "view.resetPassword": "Endurstilla lykilorð", - "view.site": "Vefsvæðið", - "view.system": "Kerfi", - "view.users": "Notendur", - - "welcome": "Komið þér fagnandi", - "year": "Ár", - "yes": "já" + "account.changeName": "Breyta nafninu þínu", + "account.delete": "Eyða reikningnum þínum", + "account.delete.confirm": "Ertu alveg viss um að þú viljir endanlega eyða reikningnum þínum? Þú munt verða útskráð/ur án tafar. Ómögulegt verður að endurheimta reikninginn þinn.", + + "add": "Bæta við", + "author": "Höfundur", + "avatar": "Prófíl mynd", + "back": "Til baka", + "cancel": "Hætta við", + "change": "Breyta", + "close": "Loka", + "confirm": "Ok", + "collapse": "Collapse", + "collapse.all": "Collapse All", + "copy": "Afrita", + "copy.all": "Afrita allt", + "create": "Stofna", + + "date": "Dagsetning", + "date.select": "Veldu dagsetningu", + + "day": "Dagur", + "days.fri": "Fös", + "days.mon": "Mán", + "days.sat": "Lau", + "days.sun": "Sun", + "days.thu": "Fim", + "days.tue": "Þri", + "days.wed": "Mið", + + "debugging": "Aflúsun", + + "delete": "Eyða", + "delete.all": "Eyða hreint öllu", + + "dialog.files.empty": "Engar skrár til að velja úr", + "dialog.pages.empty": "Engar síður til að velja úr", + "dialog.users.empty": "Engir notendur til að velja úr", + + "dimensions": "Rýmd", + "disabled": "Óvirkt", + "discard": "Hunsa", + "download": "Hlaða niður", + "duplicate": "Klóna", + + "edit": "Breyta", + + "email": "Netfang", + "email.placeholder": "nafn@netfang.is", + + "entries": "Entries", + "entry": "Entry", + + "environment": "Umhverfi", + + "error.access.code": "Ógildur kóði", + "error.access.login": "Ógild innskráning", + "error.access.panel": "Þú hefur ekkert leyfi til að nota panelinn", + "error.access.view": "Þú hefur ekkert leyfi til að nota þennan hluta panelsins", + + "error.avatar.create.fail": "Það gekk ekki að hlaða inn prófílmyndinni", + "error.avatar.delete.fail": "Ekki tókst að eyða prófílmyndinni", + "error.avatar.dimensions.invalid": "Vinsamlegast hafðu myndina ekki breiðari né hærri en 3000 punkta", + "error.avatar.mime.forbidden": "Snið myndarinnar þarf að vera af gerðinni JPEG eða PNG", + + "error.blueprint.notFound": "Ekki tókst að hlaða bláprentið: \"{name}\". Reyndu aftur?", + + "error.blocks.max.plural": "Ekki fleiri en {max} bálka", + "error.blocks.max.singular": "Ekki meira en einn bálkur", + "error.blocks.min.plural": "Minnst {min}. bálka", + "error.blocks.min.singular": "Allavegana einn bálkur takk", + "error.blocks.validation": "Það er villa í bálki númer {index}. Klikkaðu á bálkinn og finndu villuna. Það er væntanlega rauðlitur rammi utan um villuna.", + + "error.email.preset.notFound": "Netfangstillingarnar: \"{name}\" fundust ekki", + + "error.field.converter.invalid": "Ógildur umbreytari \"{converter}\"", + + "error.file.changeName.empty": "Nafn skal fylla út", + "error.file.changeName.permission": "Þú mátt ekkert breyta nafninu á skránni \"{filename}\"", + "error.file.duplicate": "Skrá með nafninu \"{filename}\" er nú þegar til", + "error.file.extension.forbidden": "Skrárendingin \"{extension}\" er ekki leyfð", + "error.file.extension.invalid": "Óleyfilegt skrársnið hér: {extension}", + "error.file.extension.missing": "Skrárendinguna fyrir \"{filename}\" vantar", + "error.file.maxheight": "Hæð myndarinnar má ekki vera meiri en {height} punktar", + "error.file.maxsize": "Skráinn er alltof stór", + "error.file.maxwidth": "Breydd myndarinnar má alls ekki vera meiri en {width} punktar", + "error.file.mime.differs": "Upphlaðna skráin þarf að vera sömu tegundar: \"{mime}\"", + "error.file.mime.forbidden": "Gagnasniðið \"{mime}\" er ekki leyft hér", + "error.file.mime.invalid": "Ógyllt gagnasnið: {mime}", + "error.file.mime.missing": "Gagnasnið skránnar \"{filename}\" er óþekkt", + "error.file.minheight": "Hæð myndarinnar þarf að vera minnst {height} punktar", + "error.file.minsize": "Skráin er of smá", + "error.file.minwidth": "Breidd myndarinnar þarf að vera minnst {width} punktar", + "error.file.name.missing": "Skrárnafnið má ekki skilja eftir tómt", + "error.file.notFound": "Skráin \"{filename}\" fannst ekki", + "error.file.orientation": "Snið myndarinnar þarf að vera \"{orientation}\"", + "error.file.type.forbidden": "Þú mátt ekkert hlaða inn {type} skrám", + "error.file.type.invalid": "Ógild skrártegund: {type}", + "error.file.undefined": "Skráin fannst ekki", + + "error.form.incomplete": "Vinsamlegast lagfærðu villurnar í forminu…", + "error.form.notSaved": "Ekki tókst að vista upplýsingar úr forminu", + + "error.language.code": "Gófúslega settu inn gildan kóða fyrir tungumál", + "error.language.duplicate": "Þetta tungumál er nú þegar skráð", + "error.language.name": "Gott og gyllt nafn fyrir tungumálið", + "error.language.notFound": "Tungumálið fannst ekkert", + + "error.layout.validation.block": "Það er villa í bálki {blockIndex} í rammanum {layoutIndex}", + "error.layout.validation.settings": "Hér er villa í sitllingum fyrir ramman {index}", + + "error.license.format": "Gildur leyfiskóði hér", + "error.license.email": "Almennilegt netfang hér", + "error.license.verification": "Ekki heppnaðist að staðfesta leyfið", + + "error.offline": "Stjórnborðið er óvirkt eins og stendur.", + + "error.page.changeSlug.permission": "Þú hefur ekkert leyfi til þess að breyta slóðarforskeytinu fyrir \"{slug}\"", + "error.page.changeStatus.incomplete": "Það eru villur á síðunni og við getum ekki gefið hana út", + "error.page.changeStatus.permission": "Stöðu síðunnar var ekki hægt að breyta", + "error.page.changeStatus.toDraft.invalid": "Síðunni \"{slug}\" er ekki hægt að breyta í uppkast", + "error.page.changeTemplate.invalid": "Sniðmáti fyrir síðuna \"{slug}\" er ekki hægt að breyta", + "error.page.changeTemplate.permission": "Þú hefur engan veginn leyfi til að breyta sniðmáti fyrir síðuna \"{slug}\"", + "error.page.changeTitle.empty": "Titillinn getur ekki verið óskilgreindur", + "error.page.changeTitle.permission": "Þú mátt ekki breyta titlinum fyrir \"{slug}\"", + "error.page.create.permission": "Þú hefur ekki leyfi til að stofna \"{slug}\"", + "error.page.delete": "Síðunni \"{slug}\" er ekki hægt að eyða", + "error.page.delete.confirm": "Ritaðu titil síðunnar til að staðfesta", + "error.page.delete.hasChildren": "Síðan hefur undirsíður og er því ekki hægt að eyða", + "error.page.delete.permission": "Þú mátt ekkert eyða \"{slug}\"", + "error.page.draft.duplicate": "Uppkast með slóðinni \"{slug}\" er þegar til", + "error.page.duplicate": "Síða með slóðinni \"{slug}\" er þegar til", + "error.page.duplicate.permission": "Þú mátt ekki klóna \"{slug}\"", + "error.page.notFound": "Síðan \"{slug}\" fannst ekkert", + "error.page.num.invalid": "Veldu ákjósanlega raðtölu. Neikvæðar tölur bannaðar.", + "error.page.slug.invalid": "Veldu ákjósanlega vefslóð", + "error.page.slug.maxlength": "Vefslóð þarf að vera a.m.k. \"{length}\" stafir", + "error.page.sort.permission": "Ekki reyndist unnt að raða síðunni \"{slug}\"", + "error.page.status.invalid": "Ákjósanlega síðustöðu takk", + "error.page.undefined": "Síðan fannst ekkert", + "error.page.update.permission": "Þú mátt ekkert uppfæra síðuna \"{slug}\"", + + "error.section.files.max.plural": "Ekki fleiri en {max} skrár í \"{section}\" svæðið", + "error.section.files.max.singular": "Aðeins ein skrá í \"{section}\" svæðið", + "error.section.files.min.plural": "\"{section}\" svæðið krefst a.m.k. {min} skrá sem innihalds", + "error.section.files.min.singular": "\"{section}\" þarf minnst eina skrá til að það virki", + + "error.section.pages.max.plural": "Alls ekki fleiri en {max} síður í \"{section}\" svæðið", + "error.section.pages.max.singular": "Ekki fleiri en ein síða í \"{section}\" svæðið", + "error.section.pages.min.plural": "\"{section}\" svæðið krefst a.m.k {min}. síðna", + "error.section.pages.min.singular": "\"{section}\" krefst a.m.k. einnar síðu", + + "error.section.notLoaded": "Svæðið \"{name}\" var því miður ekki hægt að sækja", + "error.section.type.invalid": "Svæðiðsgerðin \"{type}\" er því miður ekki gild", + + "error.site.changeTitle.empty": "Ekki skilja titilinn eftir tóman", + "error.site.changeTitle.permission": "Þú mátt ekkert breyta titil vefsvæðisins", + "error.site.update.permission": "Þú mátt ekkert uppfæra vefsvæðið", + + "error.template.default.notFound": "Ekkert sjálfgefið sniðmát fannst", + + "error.unexpected": "Það átti sér stað óvænt villa. Notaðu lúsarleitarhaminn (e. debug mode) til að skilja þetta betur. \nFyrir nánari upplýsingar: https://getkirby.com/docs/reference/system/options/debug", + + "error.user.changeEmail.permission": "Þú mátt ekkert breyta netfangi notandans \"{name}\"", + "error.user.changeLanguage.permission": "Þú hefur ekki leyfi til að breyta tungumáli notandans \"{name}\"", + "error.user.changeName.permission": "Þú mátt alls ekki breyta nafni notandans \"{name}\"", + "error.user.changePassword.permission": "Þér er harðbannað að breyta lykilorði notandans \"{name}\"", + "error.user.changeRole.lastAdmin": "Þetta er síðasti stjórinn og því má ekki breyta hlutverki", + "error.user.changeRole.permission": "Þú hefur ekki leyfi til að breyta hlutverki fyrir notandan \"{name}\"", + "error.user.changeRole.toAdmin": "Þú hefur ekkert leyfi til að gera notendur að stjórum", + "error.user.create.permission": "Þú mátt ekki stofna þennan notanda", + "error.user.delete": "Ekki reyndist unnt að eyða notandanum \"{name}\"", + "error.user.delete.lastAdmin": "Síðasta stjóranum er ekki hægt að eyða", + "error.user.delete.lastUser": "Síðasta notandanum er ekki hægt að eyða", + "error.user.delete.permission": "Þú mátt ekkert eyða notandanum \"{name}\"", + "error.user.duplicate": "Nú þegar finnst notandi með þetta netfang: \"{email}\"", + "error.user.email.invalid": "Vinsamlegast ákjósanlegt netfang", + "error.user.language.invalid": "Vinsamlegast ákjósanlegt tungumál", + "error.user.notFound": "Þessi notandi; \"{name}\" fannst ekki", + "error.user.password.excessive": "Please enter a valid password. Passwords must not be longer than 1000 characters.", + "error.user.password.invalid": "Veldu ákjósanlegt lykilorð. Minnst 8 stafa langt.", + "error.user.password.notSame": "Lykilorðin stemma ekki", + "error.user.password.undefined": "Þessi notandi hefur ekki lykilorð", + "error.user.password.wrong": "Rangt lykilorð", + "error.user.role.invalid": "Veldu ákjósanlegt hlutverk", + "error.user.undefined": "Notandinn fannst ekkert", + "error.user.update.permission": "Þú mátt ekkert breyta notandanum \"{name}\"", + + "error.validation.accepted": "Staðfestu", + "error.validation.alpha": "Aðeins stafir úr Enska stafrófinu, a-z", + "error.validation.alphanum": "Aðeins stafir úr Enska stafrófinu, a-z eða tölustafir 0-9", + "error.validation.between": "Gildi milli \"{min}\" og \"{max}\"", + "error.validation.boolean": "Staðfestu eða hafnaðu þessu", + "error.validation.contains": "Settu inni gildi er inniheldur \"{needle}\"", + "error.validation.date": "Ákjósanlega dagsetningu", + "error.validation.date.after": "Dagsetningu eftir {date}", + "error.validation.date.before": "Dagsetningu fyrir {date}", + "error.validation.date.between": "Dagsetningu milli {min} og {max}", + "error.validation.denied": "Hafnaðu", + "error.validation.different": "Gildið má ekki vera \"{other}\"", + "error.validation.email": "Ákjósanlegt netfang", + "error.validation.endswith": "Gildið verður að enda á \"{end}\"", + "error.validation.filename": "Ákjósanlegt skrárnafn", + "error.validation.in": "Vinsamlegast skráðu eitt af eftirfarandi: ({in})", + "error.validation.integer": "Skráðu heiltölu", + "error.validation.ip": "Skráðu ákjósanlega IP tölu", + "error.validation.less": "Skráðu gildi lægra en {max}", + "error.validation.match": "Gildið er ekki eftir væntingum", + "error.validation.max": "Skráðu gildi sem er ekki hærra en {max}", + "error.validation.maxlength": "Veldu eitthvað styttra. (hámark {max} stafir)", + "error.validation.maxwords": "Ekki skrá fleiri en {max}. orð", + "error.validation.min": "Skráðu gildi ekki lægra en {min}", + "error.validation.minlength": "Hafðu þetta lengra en {min}. stafi", + "error.validation.minwords": "Lágmark {min}. orð", + "error.validation.more": "Eitthvað hærra en {min}", + "error.validation.notcontains": "Skráðu eitthvað sem inniheldur ekki \"{needle}\"", + "error.validation.notin": "Ekki skrá neitt af þessu: ({notIn})", + "error.validation.option": "Veldu ákjósanlegan kost", + "error.validation.num": "Notaðu tölugildi", + "error.validation.required": "Skráðu eitthvað", + "error.validation.same": "Skráðu \"{other}\"", + "error.validation.size": "Gildið þarf að vera \"{size}\"", + "error.validation.startswith": "Þetta þarf að byrja á \"{start}\"", + "error.validation.time": "Ákjósanlegur tími", + "error.validation.time.after": "Veldu tíma eftir {time}", + "error.validation.time.before": "Veldu tíma fyrir{time}", + "error.validation.time.between": "Veldu tíma milli {min} og {max}", + "error.validation.url": "Ákjósanleg vefslóð", + + "expand": "Þenja út", + "expand.all": "Þenja allt út", + + "field.required": "Þetta svið er nauðsynlegt", + "field.blocks.changeType": "Breyta um bálkagerð", + "field.blocks.code.name": "Kóði", + "field.blocks.code.language": "Tungumal", + "field.blocks.code.placeholder": "Kóðinn þinn …", + "field.blocks.delete.confirm": "Ætlarðu virkilega að eyða þessum bálk?", + "field.blocks.delete.confirm.all": "Ertu nú alveg viss um að þú viljir eyða öllum þessum bálkum?", + "field.blocks.delete.confirm.selected": "Viltu virkilega eyða völdum bálkum?", + "field.blocks.empty": "Öngvir bálkar enn", + "field.blocks.fieldsets.label": "Veldu bálkagerð …", + "field.blocks.fieldsets.paste": "Notaðu {{ shortcut }} flýtilyklaaðgerðina til að setja blokkina hér.", + "field.blocks.gallery.name": "Myndasafn", + "field.blocks.gallery.images.empty": "Engar myndir enn", + "field.blocks.gallery.images.label": "Myndir", + "field.blocks.heading.level": "Stig", + "field.blocks.heading.name": "Fyrirsögn", + "field.blocks.heading.text": "Texti/Prósi", + "field.blocks.heading.placeholder": "Fyrirsögn …", + "field.blocks.image.alt": "ALT texti", + "field.blocks.image.caption": "Myndartexti", + "field.blocks.image.crop": "Kroppa", + "field.blocks.image.link": "Tengill", + "field.blocks.image.location": "Staðsetning", + "field.blocks.image.name": "Mynd", + "field.blocks.image.placeholder": "Veldu mynd", + "field.blocks.image.ratio": "Hlutfall", + "field.blocks.image.url": "Slóð myndar", + "field.blocks.line.name": "Lína", + "field.blocks.list.name": "Listi", + "field.blocks.markdown.name": "Markdown", + "field.blocks.markdown.label": "Texti", + "field.blocks.markdown.placeholder": "Markdown …", + "field.blocks.quote.name": "Tilvitnun", + "field.blocks.quote.text.label": "Innihald tilvitnunar", + "field.blocks.quote.text.placeholder": "Þessi tilvitnun …", + "field.blocks.quote.citation.label": "Heimild", + "field.blocks.quote.citation.placeholder": "eftir …", + "field.blocks.text.name": "Prósi", + "field.blocks.text.placeholder": "Þessi prósi …", + "field.blocks.video.caption": "Myndskeiðstexti", + "field.blocks.video.name": "Myndskeið", + "field.blocks.video.placeholder": "Vefslóð myndskeiðs (URL)", + "field.blocks.video.url.label": "Vefslóð", + "field.blocks.video.url.placeholder": "https://youtube.com/?v=", + + "field.files.empty": "Engar skrár valdar ennþá", + + "field.layout.delete": "Eyða ramma", + "field.layout.delete.confirm": "Ætlarðu virkilega að eyða þessum ramma?", + "field.layout.empty": "Nei. Engir rammar enn.", + "field.layout.select": "Veldu rammategund", + + "field.pages.empty": "Engar síður valdar ennþá", + "field.structure.delete.confirm": "Viltu virkilega eyða þessari röð?", + "field.structure.empty": "Engar færslur enn", + "field.users.empty": "Engir notendur valdir enn", + + "file.blueprint": "Þessi skrá hefur ekki skipan (e. blueprint) ennþá. Þú mátt skilgreina skipanina í /site/blueprints/{template}.yml", + "file.delete.confirm": "Ætlarðu virkilega að eyða
{filename}?", + "file.sort": "Breyta röðun", + + "files": "Skrár", + "files.empty": "Engar skrár enn", + + "hide": "Fela", + "hour": "Klukkustund", + "import": "Hlaða inn", + "info": "Info", + "insert": "Setja inn", + "insert.after": "Setja eftir", + "insert.before": "Setja fyrir", + "install": "Setja upp", + + "installation": "Uppsettning", + "installation.completed": "Panellinn er uppsettur", + "installation.disabled": "Paneluppsetning er sjálfgefið óvirk á vefþjónum á Veraldarvefnum. Reyndu frekar að setja Panelinn upp í lokuðu umhverfi eða virkjaðu panel.install möguleikan.", + "installation.issues.accounts": "/site/accounts mappan er annaðhvort ekki til eða er ekki skrifanleg.", + "installation.issues.content": "/content mappan er annaðhvort ekki til eða er ekki skrifanleg", + "installation.issues.curl": "CURL viðbótin er hér bráðnauðsynleg", + "installation.issues.headline": "Uppsetning Panelsins mistókst hrapalega", + "installation.issues.mbstring": "MB String er hér bráðnauðsynleg", + "installation.issues.media": "/media mappan er annaðhvort ekki til eða er ekki skrifanleg", + "installation.issues.php": "Notaðu PHP 7+", + "installation.issues.server": "Kirby krefst Apache, Nginx eða Caddy", + "installation.issues.sessions": "/site/sessions mappan er annaðhvort ekki til eða er ekki skrifanleg", + + "language": "Tungumál", + "language.code": "Kóði", + "language.convert": "Gera sjálfgefið", + "language.convert.confirm": "

Ertu viss um að þú viljir breyta {name} í sjálfgefið (lesist aðal) tungumál? Þessu verður ekki viðsnúið.

Ef {name} hefur innihald sem ekki hefur verið þýtt, þá verða engir möguleikar til þrautarvara og hluti vefsins gæti birtst tómur.

", + "language.create": "Bættu við nýju tungumáli", + "language.delete.confirm": "Ertu nú viss um að þú viljir eyða {name} og öllum tilheyrandi þýðingum? Þetta verður ekki tekið til baka!", + "language.deleted": "Tungumálinu hefur verið eytt", + "language.direction": "Lestursátt (hægri, vinstri)", + "language.direction.ltr": "Vinstra til hægri", + "language.direction.rtl": "Hægra til vinstri", + "language.locale": "PHP locale strengur", + "language.locale.warning": "Þú ert að nota sérsniðna locale uppsetningu. Vinsamlegast breyttu tungumálaskránni á slóðinni /site/languages", + "language.name": "Nafn tungumáls", + "language.updated": "Tungumálið hefur verið uppfært", + + "languages": "Tungumál", + "languages.default": "Aðal tungumál", + "languages.empty": "Það eru engin frekari tungumál skilgreind enn", + "languages.secondary": "Auka tungumál", + "languages.secondary.empty": "Það eru engin auka tungumál skilgreind enn", + + "license": "Leyfi", + "license.buy": "Kaupa leyfi", + "license.register": "Skr\u00E1 Kirby", + "license.manage": "Manage your licenses", + "license.register.help": "Þú fékkst sendan tölvupóst með leyfiskóðanum þegar þú keyptir leyfi. Vinsamlegast afritaðu hann og settu hann hingað til að skrá þig.", + "license.register.label": "Vinsamlegast settu inn leyfiskóðan", + "license.register.success": "Þakka þér fyrir að velja Kirby", + "license.unregistered": "Þetta er óskráð prufueintak af Kirby", + "license.unregistered.label": "Unregistered", + + "link": "Tengill", + "link.text": "Tengilstexti", + + "loading": "Hleð", + + "lock.unsaved": "Óvistað breytingar", + "lock.unsaved.empty": "Það eru öngvar óvistaðar breytingar", + "lock.isLocked": "Óvistaðar breytingar frá {email}", + "lock.file.isLocked": "{email} er að vinna í skránni og þú breytir henni ekki á meðan.", + "lock.page.isLocked": "{email} er að vinna í síðunni og þú breytir henni ekki á meðan.", + "lock.unlock": "Aflæsa", + "lock.isUnlocked": "Þær breytingar sem þú gerðir hafa verið yfirskrifaðar af öðrum notanda. Þú getur sótt þær breytingar og splæst þeim saman við þínar breytingar. Handvirkt.", + + "login": "Innskrá", + "login.code.label.login": "Innskráningarkóði", + "login.code.label.password-reset": "Kóði fyrir endurstillingu lykilorðs", + "login.code.placeholder.email": "000 000", + "login.code.text.email": "Ef netfangið þitt er skráð þá bíður þín nýr tölvupóstur.", + "login.email.login.body": "Já halló {user.nameOrEmail},\n\nNýlega baðstu um innskráningarkóða fyrir bakendan á sorli.is.\nEftirfarandi kóði er virkur í {timeout} mínútur:\n\n{code}\n\nEf þú óskaðir ekki eftir þessu þá hunsaðu þennan tölvupóst eða talaðu við vefstjóran ef þú vilt fræðast nánar.\nAf öryggisástæðum vinsamlegast áframsendu þennan tölvupóst ALLS EKKI.", + "login.email.login.subject": "Innskráningarkóðinn þinn", + "login.email.password-reset.body": "Nei halló {user.nameOrEmail},\n\nNýverið baðstu um að lykilorði þínu væri endurstillt fyrir bakendan á sorli.is. \nEftirfarandi kóði er virkur í {timeout} mínútur:\n\n{code}\n\nEf þú óskaðir ekki eftir þessu þá hunsaðu þennan tölvupóst eða talaðu við vefstjóran ef þú vilt fræðast nánar.\nAf öryggisástæðum vinsamlegast áframsendu þennan tölvupóst ALLS EKKI.", + "login.email.password-reset.subject": "Kóðinn þinn fyrir endurstillingu lykilorðs", + "login.remember": "Vista innskráningu", + "login.reset": "Endurheimta lykilorð takk", + "login.toggleText.code.email": "Innskrá með netfangi", + "login.toggleText.code.email-password": "Innskrá með lykilorði", + "login.toggleText.password-reset.email": "Mannstu ekki lykilorðið?", + "login.toggleText.password-reset.email-password": "← Aftur í innskráningu", + + "logout": "Útskrá", + + "menu": "Valmynd", + "meridiem": "AM/PM", + "mime": "Miðilsgerð", + "minutes": "Mínútur", + + "month": "Mánuður", + "months.april": "Apríl", + "months.august": "Ágúst", + "months.december": "Desember", + "months.february": "Febrúar", + "months.january": "Janúar", + "months.july": "Júlí", + "months.june": "Júní", + "months.march": "Mars", + "months.may": "Maí", + "months.november": "Nóvember", + "months.october": "Október", + "months.september": "September", + + "more": "Meira", + "name": "Nafn", + "next": "Næst", + "no": "nei", + "off": "Af", + "on": "Á", + "open": "Opna", + "open.newWindow": "Opna í nýjum glugga", + "options": "Valmöguleikar", + "options.none": "Engir valmöguleikar", + + "orientation": "Snúningur", + "orientation.landscape": "Langsnið", + "orientation.portrait": "Skammsnið", + "orientation.square": "Ferningur", + + "page.blueprint": "Þessi síða hefur ekki skipan (e. blueprint) ennþá. Þú mátt skilgreina skipanina í /site/blueprints/{template}.yml", + "page.changeSlug": "Breyta vefslóð", + "page.changeSlug.fromTitle": "Slóð af titli", + "page.changeStatus": "Breyta stöðu", + "page.changeStatus.position": "Veldu ákjósanlega röðun", + "page.changeStatus.select": "Veldu nýja stöðu", + "page.changeTemplate": "Breyta sniðmáti", + "page.delete.confirm": "Viltu virkilega farga {title}?", + "page.delete.confirm.subpages": "Þessi síða hefur undirsíður.
Þeim mun verða fargað líka.", + "page.delete.confirm.title": "Skráðu síðutitilinn til staðfestingar", + "page.draft.create": "Stofna uppkast", + "page.duplicate.appendix": "Afrita", + "page.duplicate.files": "Afrita skrár", + "page.duplicate.pages": "Afrita síður", + "page.sort": "Breyta röðun", + "page.status": "Staða", + "page.status.draft": "Uppkast", + "page.status.draft.description": "Þessi síða er uppkast og er aðeins sýnileg höfundum og stjórum eða gegnum falinn tengil.", + "page.status.listed": "Útgefin og listuð", + "page.status.listed.description": "Síðan er aðgengileg öllum og sýnleg í leiðarkerfi vefsins", + "page.status.unlisted": "Útgefin", + "page.status.unlisted.description": "Síðan er aðgengileg öllum en þó ekki sýnileg í leiðarkerfi vefsins", + + "pages": "Síður", + "pages.empty": "Engar síður enn", + "pages.status.draft": "Uppköst", + "pages.status.listed": "Útgefnar og listaðar", + "pages.status.unlisted": "Útgefnar", + + "pagination.page": "Síða", + + "password": "Lykilorð", + "paste": "Líma", + "paste.after": "Líma eftir", + "pixel": "Punkta", + "plugins": "Viðbætur", + "prev": "Fyrri", + "preview": "Forskoða", + "remove": "Fjarlægja", + "rename": "Endurnefna", + "replace": "Setja í stað", + "retry": "Reyndu aftur", + "revert": "Taka upp fyrri siði", + "revert.confirm": "Viltu virkilega eyða öllum óvistuðum breytingum?", + + "role": "Hlutverk", + "role.admin.description": "Stjórinn hefur öll réttindi", + "role.admin.title": "Stjóri", + "role.all": "Öll", + "role.empty": "Það eru engir notendur með þetta hlutverk", + "role.description.placeholder": "Engin lýsing", + "role.nobody.description": "Þetta hlutverk er til þrautarvara en hefur engin réttindi", + "role.nobody.title": "Enginn", + + "save": "Vista", + "search": "Leita", + "search.min": "Lágmark {min} stafir til að leita", + "search.all": "Sýna allt", + "search.results.none": "Engar niðurstöður", + + "section.required": "Þetta svæði er nauðsynlegt", + + "security": "Security", + "select": "Velja", + "server": "Vefþjónn", + "settings": "Stillingar", + "show": "Sýna", + "site.blueprint": "Þessi vefur hefur ekki skipan (e. blueprint) ennþá. Þú mátt skilgreina skipanina í /site/blueprints/site.yml", + "size": "Stærð", + "slug": "Slögg", + "sort": "Raða", + + "stats.empty": "No reports", + "system.issues.content": "The content folder seems to be exposed", + "system.issues.debug": "Debugging must be turned off in production", + "system.issues.git": "The .git folder seems to be exposed", + "system.issues.https": "We recommend HTTPS for all your sites", + "system.issues.kirby": "The kirby folder seems to be exposed", + "system.issues.site": "The site folder seems to be exposed", + + "title": "Titill", + "template": "Sniðmát", + "today": "Núna", + + "toolbar.button.code": "Kóðasnið", + "toolbar.button.bold": "Feitletrun", + "toolbar.button.email": "Netfang", + "toolbar.button.headings": "Fyrirsagnir", + "toolbar.button.heading.1": "Fyrirsögn 1", + "toolbar.button.heading.2": "Fyrirsögn 2", + "toolbar.button.heading.3": "Fyrirsögn 3", + "toolbar.button.heading.4": "Fyrirsögn 4", + "toolbar.button.heading.5": "Fyrirsögn 5", + "toolbar.button.heading.6": "Fyrirsögn 6", + "toolbar.button.italic": "Skáletrun", + "toolbar.button.file": "Skrár", + "toolbar.button.file.select": "Veldu skrá", + "toolbar.button.file.upload": "Hlaða inn skrá", + "toolbar.button.link": "Tengill", + "toolbar.button.paragraph": "Efnisgrein", + "toolbar.button.strike": "Gegnumstrika", + "toolbar.button.ol": "Raðaður listi", + "toolbar.button.underline": "Undirstrika", + "toolbar.button.ul": "Áherslumerktur listi", + + "translation.author": "Kirby Teymið", + "translation.direction": "ltr", + "translation.name": "Íslenska", + "translation.locale": "is_IS", + + "upload": "Hlaða inn", + "upload.error.cantMove": "Innhlöðnu skránni var ekki haggað", + "upload.error.cantWrite": "Það mistókst að skrifa skránna í geymslu", + "upload.error.default": "Ekki heppnaðist að hlaða inn skránni", + "upload.error.extension": "Innhleðsla stöðvuð vegna skrárendingar", + "upload.error.formSize": "Innhlaðna skráin er stærri en MAX_FILE_SIZE leyfilegt er.", + "upload.error.iniPostSize": "Innhlaðna skráin er stærri en því sem nemur í post_max_size stillingunni í php.ini", + "upload.error.iniSize": "Innhlaðna skráin er stærri en því sem nemur í upload_max_filesize stillingunni í php.ini", + "upload.error.noFile": "Engri skrá far hlaðið inn", + "upload.error.noFiles": "Engum skrám var hlaðið inn", + "upload.error.partial": "Innhlöðnu skránni var aðeins sótt að hluta", + "upload.error.tmpDir": "Vantar skruggumöppu", + "upload.errors": "Villa", + "upload.progress": "Hleð inn…", + + "url": "Slóð", + "url.placeholder": "https://tildaem.is/", + + "user": "Notandi", + "user.blueprint": "Þér er óhætt að skilgreina fleiri svæði fyrir þetta notenda hlutverk í /site/blueprints/users/{role}.yml", + "user.changeEmail": "Breyta netfangi", + "user.changeLanguage": "Breyta tungumáli", + "user.changeName": "Endurnefna þennan notanda", + "user.changePassword": "Breyta lykilorð", + "user.changePassword.new": "Nýtt lykilorð", + "user.changePassword.new.confirm": "Staðfestu nýtt lykilorð…", + "user.changeRole": "Breyta hlutverki", + "user.changeRole.select": "Veldu nýtt hlutverk", + "user.create": "Bæta við nýjum notenda", + "user.delete": "Farga þessum notenda", + "user.delete.confirm": "Viltu virkilega eyða
{email}?", + + "users": "Notendur", + + "version": "Útgáfa", + + "view.account": "Notandareikningurinn þinn", + "view.installation": "Uppsetning", + "view.languages": "Tungumál", + "view.resetPassword": "Endurstilla lykilorð", + "view.site": "Vefsvæðið", + "view.system": "Kerfi", + "view.users": "Notendur", + + "welcome": "Komið þér fagnandi", + "year": "Ár", + "yes": "já" } diff --git a/kirby/i18n/translations/it.json b/kirby/i18n/translations/it.json index a4d9a48..38ca74a 100644 --- a/kirby/i18n/translations/it.json +++ b/kirby/i18n/translations/it.json @@ -1,730 +1,574 @@ { - "account.changeName": "Cambia il tuo nome", - "account.delete": "Elimina l'account", - "account.delete.confirm": "Vuoi davvero eliminare il tuo account? Verrai disconnesso immediatamente. Il tuo account non potrà essere recuperato.", - - "activate": "Attiva", - "add": "Aggiungi", - "alpha": "Alpha", - "author": "Autore", - "avatar": "Immagine del profilo", - "back": "Indietro", - "cancel": "Annulla", - "change": "Cambia", - "close": "Chiudi", - "changes": "Changes", - "confirm": "OK", - "collapse": "Comprimi", - "collapse.all": "Comprimi tutto", - "color": "Color", - "coordinates": "Coordinates", - "copy": "Copia", - "copy.all": "Copia tutto", - "copy.success": "{count} copied!", - "create": "Crea", - "custom": "Custom", - - "date": "Data", - "date.select": "Scegli una data", - - "day": "Giorno", - "days.fri": "Ve", - "days.mon": "Lu", - "days.sat": "Sa", - "days.sun": "Do", - "days.thu": "Gi", - "days.tue": "Ma", - "days.wed": "Me", - - "debugging": "Debugging", - - "delete": "Elimina", - "delete.all": "Elimina tutti", - - "dialog.fields.empty": "This dialog has no fields", - "dialog.files.empty": "Nessun file selezionabile", - "dialog.pages.empty": "Nessuna pagina selezionabile", - "dialog.text.empty": "This dialog does not define any text", - "dialog.users.empty": "Nessuno user selezionabile", - - "dimensions": "Dimensioni", - "disable": "Disattiva", - "disabled": "Disabilitato", - "discard": "Abbandona", - - "drawer.fields.empty": "This drawer has no fields", - - "domain": "Dominio", - "download": "Scarica", - "duplicate": "Duplica", - - "edit": "Modifica", - - "email": "Email", - "email.placeholder": "mail@esempio.com", - - "enter": "Enter", - "entries": "Voci", - "entry": "Voce", - - "environment": "Ambiente", - - "error": "Error", - "error.access.code": "Codice non valido", - "error.access.login": "Login invalido", - "error.access.panel": "Non ti è permesso accedere al pannello", - "error.access.view": "Non ti è permesso accedere a questa parte del pannello", - - "error.avatar.create.fail": "Non è stato possibile caricare l'immagine del profilo", - "error.avatar.delete.fail": "Non è stato possibile eliminare l'immagine del profilo", - "error.avatar.dimensions.invalid": "Per favore mantieni l'altezza e la larghezza dell'immagine del profilo inferiore ai 3000 pixel", - "error.avatar.mime.forbidden": "L'immagine del profilo dev'essere un file JPEG o PNG", - - "error.blueprint.notFound": "Non è stato possibile caricare il blueprint \"{name}\"", - - "error.blocks.max.plural": "Non puoi aggiungere più di {max} blocchi", - "error.blocks.max.singular": "Non puoi aggiungere più di un blocco", - "error.blocks.min.plural": "Devi aggiungere almeno {min} blocchi", - "error.blocks.min.singular": "Devi aggiungere almeno un blocco", - "error.blocks.validation": "C'è un errore sul campo \"{field}\" nel blocco {index} che utilizza il tipo di blocco \"{fieldset}\"", - - "error.cache.type.invalid": "Tipo di cache \"{type}\" non valido", - - "error.email.preset.notFound": "Non è stato possibile trovare il preset email \"{name}\"", - - "error.field.converter.invalid": "Convertitore \"{converter}\" non valido", - "error.field.type.missing": "Campo \"{ name }\": il tipo di campo \"{ type }\" non esiste", - - "error.file.changeName.empty": "Il nome non dev'essere vuoto", - "error.file.changeName.permission": "Non ti è permesso modificare il nome di \"{filename}\"", - "error.file.changeTemplate.invalid": "The template for the file \"{id}\" cannot be changed to \"{template}\" (valid: \"{blueprints}\")", - "error.file.changeTemplate.permission": "You are not allowed to change the template for the file \"{id}\"", - - "error.file.duplicate": "Un file con il nome \"{filename}\" esiste già", - "error.file.extension.forbidden": "L'estensione \"{extension}\" non è consentita", - "error.file.extension.invalid": "Estensione non valida: {extension}", - "error.file.extension.missing": "Il file \"{filename}\" non ha estensione", - "error.file.maxheight": "L'immagine non dev'essere più alta di {height} pixel", - "error.file.maxsize": "Il file è troppo pesante", - "error.file.maxwidth": "L'immagine non dev'essere più larga di {width} pixel", - "error.file.mime.differs": "Il file caricato dev'essere dello stesso MIME type \"{mime}\"", - "error.file.mime.forbidden": "Il MIME type \"{mime}\" non è consentito", - "error.file.mime.invalid": "Tipo mime non valido: {mime}", - "error.file.mime.missing": "Il MIME type per \"{filename}\" non può essere rilevato", - "error.file.minheight": "L'immagine dev'essere alta almeno {height} pixel", - "error.file.minsize": "Il file è troppo leggero", - "error.file.minwidth": "L'immagine dev'essere larga almeno {width} pixel", - "error.file.name.unique": "The filename must be unique", - "error.file.name.missing": "Il nome del file non può essere vuoto", - "error.file.notFound": "Il file non \u00e8 stato trovato", - "error.file.orientation": "L'imaggine dev'essere orientata in \"{orientation}\"", - "error.file.type.forbidden": "Non ti è permesso caricare file {type}", - "error.file.type.invalid": "Tipo di file non valido: {type}", - "error.file.undefined": "Il file non \u00e8 stato trovato", - - "error.form.incomplete": "Correggi tutti gli errori nel form...", - "error.form.notSaved": "Non è stato possibile salvare il form", - - "error.language.code": "Inserisci un codice valido per la lingua", - "error.language.duplicate": "La lingua esiste già", - "error.language.name": "Inserisci un nome valido per la lingua", - "error.language.notFound": "La lingua non è stata trovata", - - "error.layout.validation.block": "C'è un errore sul campo \"{field}\" nel blocco {blockIndex} che utilizza il tipo di blocco \"{fieldset}\" nel layout {layoutIndex}", - "error.layout.validation.settings": "C'è un errore nelle impostazioni del layout {index}", - - "error.license.domain": "Il dominio per la licenza è assente", - "error.license.email": "Inserisci un indirizzo email valido", - "error.license.format": "Per favore inserisci un codice di licenza valido", - "error.license.verification": "Non è stato possibile verificare la licenza", - - "error.login.totp.confirm.invalid": "Codice non valido", - "error.login.totp.confirm.missing": "Inserisci il codice attuale", - - "error.object.validation": "C'è un errore nel campo \"{label}\":\n{message}", - - "error.offline": "Il pannello di controllo è attualmente offline", - - "error.page.changeSlug.permission": "Non ti è permesso cambiare l'URL di \"{slug}\"", - "error.page.changeSlug.reserved": "The path of top-level pages must not start with \"{path}\"", - "error.page.changeStatus.incomplete": "La pagina contiene errori e non può essere pubblicata", - "error.page.changeStatus.permission": "Lo stato di questa pagina non può essere cambiato", - "error.page.changeStatus.toDraft.invalid": "La pagina \"{slug}\" non può essere convertita in bozza", - "error.page.changeTemplate.invalid": "Il template della pagina \"{slug}\" non può essere cambiato", - "error.page.changeTemplate.permission": "Non ti è permesso modificare il template di \"{slug}\"", - "error.page.changeTitle.empty": "Il titolo non può essere vuoto", - "error.page.changeTitle.permission": "Non ti è permesso modificare il titolo di \"{slug}\"", - "error.page.create.permission": "Non ti è permesso creare \"{slug}\"", - "error.page.delete": "La pagina \"{slug}\" non può essere eliminata", - "error.page.delete.confirm": "Inserisci il titolo della pagina per confermare", - "error.page.delete.hasChildren": "La pagina ha sottopagine e non può essere eliminata", - "error.page.delete.permission": "Non ti è permesso eliminare \"{slug}\"", - "error.page.draft.duplicate": "Una bozza di pagina con l'URL \"{slug}\" esiste già", - "error.page.duplicate": "Una pagina con l'URL \"{slug}\" esiste già", - "error.page.duplicate.permission": "Non ti è permesso duplicare \"{slug}\"", - "error.page.move.ancestor": "The page cannot be moved into itself", - "error.page.move.directory": "The page directory cannot be moved", - "error.page.move.duplicate": "A sub page with the URL appendix \"{slug}\" already exists", - "error.page.move.notFound": "The moved page could not be found", - "error.page.move.permission": "You are not allowed to move \"{slug}\"", - "error.page.move.template": "The \"{template}\" template is not accepted as a subpage of \"{parent}\"", - "error.page.notFound": "La pagina \"{slug}\" non è stata trovata", - "error.page.num.invalid": "Inserisci un numero di ordinamento valido. I numeri non devono essere negativi", - "error.page.slug.invalid": "Per favore inserisci un suffisso valido per l'URL", - "error.page.slug.maxlength": "Lo \"slug\" dev'essere più corto di \"{length}\" caratteri", - "error.page.sort.permission": "La pagina \"{slug}\" non può essere ordinata", - "error.page.status.invalid": "Imposta uno stato valido per la pagina", - "error.page.undefined": "La pagina non \u00e8 stata trovata", - "error.page.update.permission": "Non ti è permesso modificare \"{slug}\"", - - "error.section.files.max.plural": "Non puoi aggiungere più di {max} file alla sezione \"{section}\"", - "error.section.files.max.singular": "Non puoi aggiungere più di un file alla sezione \"{section}\"", - "error.section.files.min.plural": "La sezione \"{section}\" richiede almeno {min} file", - "error.section.files.min.singular": "La sezione \"{section}\" richiede almeno un file", - - "error.section.pages.max.plural": "Non puoi aggiungere più di {max} pagine alla sezione \"{section}\"", - "error.section.pages.max.singular": "Non puoi aggiungere più di una pagina alla sezione \"{section}\"", - "error.section.pages.min.plural": "La sezione \"{section}\" richiede almeno {min} pagine", - "error.section.pages.min.singular": "La sezione \"{section}\" richiede almeno una pagina", - - "error.section.notLoaded": "Non è stato possibile caricare la sezione \"{name}\"", - "error.section.type.invalid": "Il tipo di sezione \"{type}\" non è valido", - - "error.site.changeTitle.empty": "Il titolo non può essere vuoto", - "error.site.changeTitle.permission": "Non ti è permesso modificare il titolo del sito", - "error.site.update.permission": "Non ti è permesso modificare i contenuti globali del sito", - - "error.structure.validation": "C'è un errore nel campo \"{field}\" nella riga {index}", - - "error.template.default.notFound": "Il template \"default\" non esiste", - - "error.unexpected": "Si è verificato un errore inaspettato! Abilita la modalità \"debug\" per ulteriori informazioni: https://getkirby.com/docs/reference/system/options/debug", - - "error.user.changeEmail.permission": "Non ti è permesso modificare l'indirizzo email di \"{name}\"", - "error.user.changeLanguage.permission": "Non ti è permesso modificare la lingua per l'utente \"{name}\"", - "error.user.changeName.permission": "Non ti è permesso modificare il nome dell'utente \"{name}\"", - "error.user.changePassword.permission": "Non ti è permesso modificare la password dell'utente \"{name}\"", - "error.user.changeRole.lastAdmin": "Il ruolo dell'ultimo amministratore non può esser cambiato", - "error.user.changeRole.permission": "Non ti è permesso modificare il ruolo dell'utente \"{name}\"", - "error.user.changeRole.toAdmin": "Non ti è permesso assegnare il ruolo di amministratore ad altri utenti", - "error.user.create.permission": "Non ti è permesso creare questo utente", - "error.user.delete": "L'utente non pu\u00f2 essere eliminato", - "error.user.delete.lastAdmin": "L'ultimo amministratore non può essere eliminato", - "error.user.delete.lastUser": "L'ultimo utente non può essere eliminato", - "error.user.delete.permission": "Non ti \u00e8 permesso eliminare questo utente ", - "error.user.duplicate": "Esiste già un utente con l'indirizzo email \"{email}\"", - "error.user.email.invalid": "Inserisci un indirizzo email valido", - "error.user.language.invalid": "Inserisci una lingua valida", - "error.user.notFound": "L'utente non \u00e8 stato trovato", - "error.user.password.excessive": "Please enter a valid password. Passwords must not be longer than 1000 characters.", - "error.user.password.invalid": "Per favore inserisci una password valida. Le password devono essere lunghe almeno 8 caratteri", - "error.user.password.notSame": "Le password non corrispondono", - "error.user.password.undefined": "L'utente non ha una password", - "error.user.password.wrong": "Password sbagliata", - "error.user.role.invalid": "Inserisci un ruolo valido", - "error.user.undefined": "L'utente non è stato trovato", - "error.user.update.permission": "Non ti è permesso aggiornare l'utente \"{name}\"", - - "error.validation.accepted": "Per favore conferma", - "error.validation.alpha": "Puoi inserire solo caratteri tra a-z", - "error.validation.alphanum": "Puoi inserire solo caratteri tra a-z e numeri 0-9", - "error.validation.anchor": "Please enter a correct link anchor", - "error.validation.between": "Inserisci un valore tra \"{min}\" e \"{max}\"", - "error.validation.boolean": "Per favore conferma o nega", - "error.validation.color": "Please enter a valid color in the {format} format", - "error.validation.contains": "Inserisci un valore che contiene \"{needle}\"", - "error.validation.date": "Inserisci una data valida", - "error.validation.date.after": "Inserisci una data dopo il {date}", - "error.validation.date.before": "Inserisci una data prima del {date}", - "error.validation.date.between": "Inserisci una data tra {min} e {max}", - "error.validation.denied": "Per favore nega", - "error.validation.different": "Il valore non dev'essere \"{other}\"", - "error.validation.email": "Inserisci un indirizzo email valido", - "error.validation.endswith": "Il valore non deve finire con \"{end}\"", - "error.validation.filename": "Inserisci un nome del file valido", - "error.validation.in": "Inserisci uno dei seguenti valori: ({in})", - "error.validation.integer": "Inserisci un numero intero", - "error.validation.ip": "Inserisci un indirizzo IP valido", - "error.validation.less": "Inserisci un valore inferiore a {max}", - "error.validation.linkType": "The link type is not allowed", - "error.validation.match": "Il valore non corrisponde al pattern previsto", - "error.validation.max": "Inserisci un valore inferiore o uguale a {max}", - "error.validation.maxlength": "Inserisci un testo più corto. (max. {max} caratteri)", - "error.validation.maxwords": "Non inserire più di {max} parola/e", - "error.validation.min": "Inserisci un valore superiore o uguale a {min}", - "error.validation.minlength": "Inserisci un testo più lungo. (min. {min} caratteri)", - "error.validation.minwords": "Inserisci almeno {min} parola/e", - "error.validation.more": "Inserisci un valore superiore a {min}", - "error.validation.notcontains": "Inserisci un valore che non contenga \"{needle}\"", - "error.validation.notin": "Non inserire nessuno dei valori seguenti: ({notIn})", - "error.validation.option": "Seleziona un'opzione valida", - "error.validation.num": "Inserisci un numero valido", - "error.validation.required": "Inserisci qualcosa", - "error.validation.same": "Inserisci \"{other}\"", - "error.validation.size": "La dimensione del valore dev'essere \"{size}\"", - "error.validation.startswith": "Il valore deve iniziare con \"{start}\"", - "error.validation.tel": "Please enter an unformatted phone number", - "error.validation.time": "Inserisci un orario valido", - "error.validation.time.after": "Inserisci un orario dopo le {time}", - "error.validation.time.before": "Inserisci un orario prima delle {time}", - "error.validation.time.between": "Inserisci un orario tra le {min} e le {max}", - "error.validation.uuid": "Please enter a valid UUID", - "error.validation.url": "Inserisci un URL valido", - - "expand": "Espandi", - "expand.all": "Espandi tutto", - - "field.invalid": "The field is invalid", - "field.required": "Il campo è obbligatorio", - "field.blocks.changeType": "Cambia tipo", - "field.blocks.code.name": "Codice", - "field.blocks.code.language": "Lingua", - "field.blocks.code.placeholder": "Il tuo codice …", - "field.blocks.delete.confirm": "Vuoi veramente eliminare questo blocco?", - "field.blocks.delete.confirm.all": "Vuoi veramente eliminare tutti i blocchi? ", - "field.blocks.delete.confirm.selected": "Vuoi veramente eliminare i blocchi selezionati?", - "field.blocks.empty": "Nessun blocco inserito", - "field.blocks.fieldsets.empty": "No fieldsets yet", - "field.blocks.fieldsets.label": "Seleziona il tipo di blocco …", - "field.blocks.fieldsets.paste": "Press {{ shortcut }} to import layouts/blocks from your clipboard Only those allowed in the current field will get inserted.", - "field.blocks.gallery.name": "Galleria", - "field.blocks.gallery.images.empty": "Nessuna immagine inserita", - "field.blocks.gallery.images.label": "Immagini", - "field.blocks.heading.level": "Livello", - "field.blocks.heading.name": "Titolo", - "field.blocks.heading.text": "Testo", - "field.blocks.heading.placeholder": "Titolo …", - "field.blocks.image.alt": "Testo alternativo", - "field.blocks.image.caption": "Didascalia", - "field.blocks.image.crop": "Ritaglio", - "field.blocks.image.link": "Link", - "field.blocks.image.location": "Posizione", - "field.blocks.image.location.internal": "This website", - "field.blocks.image.location.external": "External source", - "field.blocks.image.name": "Immagine", - "field.blocks.image.placeholder": "Seleziona un'immagine", - "field.blocks.image.ratio": "Rapporto", - "field.blocks.image.url": "URL immagine", - "field.blocks.line.name": "Linea", - "field.blocks.list.name": "Lista", - "field.blocks.markdown.name": "Markdown", - "field.blocks.markdown.label": "Testo", - "field.blocks.markdown.placeholder": "Markdown …", - "field.blocks.quote.name": "Citazione", - "field.blocks.quote.text.label": "Testo", - "field.blocks.quote.text.placeholder": "Citazione …", - "field.blocks.quote.citation.label": "Fonte", - "field.blocks.quote.citation.placeholder": "di …", - "field.blocks.text.name": "Testo", - "field.blocks.text.placeholder": "Testo …", - "field.blocks.video.autoplay": "Autoplay", - "field.blocks.video.caption": "Didascalia", - "field.blocks.video.controls": "Controls", - "field.blocks.video.location": "Posizione", - "field.blocks.video.loop": "Loop", - "field.blocks.video.muted": "Muted", - "field.blocks.video.name": "Video", - "field.blocks.video.placeholder": "Inserisci un URL di un video", - "field.blocks.video.poster": "Poster", - "field.blocks.video.preload": "Preload", - "field.blocks.video.url.label": "URL Video", - "field.blocks.video.url.placeholder": "https://youtube.com/?v=", - - "field.files.empty": "Nessun file selezionato", - - "field.layout.change": "Change layout", - "field.layout.delete": "Elimina layout", - "field.layout.delete.confirm": "Vuoi veramente eliminare questo layout?", - "field.layout.delete.confirm.all": "Do you really want to delete all layouts?", - "field.layout.empty": "Nessuna riga inserita", - "field.layout.select": "Scegli un layout", - - "field.object.empty": "Ancora nessuna informazione", - - "field.pages.empty": "Nessuna pagina selezionata", - - "field.structure.delete.confirm": "Vuoi veramente eliminare questo elemento?", - "field.structure.delete.confirm.all": "Vuoi davvero cancellare tutte le voci?", - "field.structure.empty": "Non ci sono ancora elementi.", - - "field.users.empty": "Nessun utente selezionato", - - "fields.empty": "No fields yet", - - "file": "File", - "file.blueprint": "Questo file non ha ancora un blueprint. Puoi definire la sua configurazione in /site/blueprints/files/{blueprint}.yml", - "file.changeTemplate": "Cambia template", - "file.changeTemplate.notice": "Changing the file's template will remove content for fields that don't match in type. If the new template defines certain rules, e.g. image dimensions, those will also be applied irreversibly. Use with caution.", - "file.delete.confirm": "Sei sicuro di voler eliminare questo file?", - "file.focus.placeholder": "Set focal point", - "file.focus.reset": "Remove focal point", - "file.focus.title": "Focus", - "file.sort": "Cambia posizione", - - "files": "Files", - "files.empty": "Nessun file caricato", - - "filter": "Filter", - - "hide": "Nascondi", - "hour": "Ora", - "hue": "Hue", - "import": "Importa", - "info": "Info", - "insert": "Inserisci", - "insert.after": "Inserisci dopo", - "insert.before": "Inserisci prima", - "install": "Installa", - - "installation": "Installazione", - "installation.completed": "Il pannello è stato installato", - "installation.disabled": "L'installazione del pannello è disabilitata di default sui server pubblici. Esegui l'installazione in locale oppure abilitala usando l'opzione panel.install.", - "installation.issues.accounts": "/site/accounts non esiste o non dispone dei permessi di scrittura", - "installation.issues.content": "La cartella /content non esiste o non dispone dei permessi di scrittura", - "installation.issues.curl": "È necessaria l'estensione CURL", - "installation.issues.headline": "Il pannello non può esser installato", - "installation.issues.mbstring": "È necessaria l'estensione MB String", - "installation.issues.media": "La cartella /media non esiste o non dispone dei permessi di scrittura", - "installation.issues.php": "Assicurati di utilizzare PHP 8+", - "installation.issues.sessions": "La cartella /site/sessionsnon esiste o non dispone dei permessi di scrittura", - - "language": "Lingua", - "language.code": "Codice", - "language.convert": "Imposta come predefinito", - "language.convert.confirm": "

Sei sicuro di voler convertire {name} nella lingua predefinita? Questa operazione non può essere annullata.

Se {name} non contiene tutte le traduzioni, non ci sarà più una versione alternativa valida e parti del sito potrebbero rimanere vuote.

", - "language.create": "Aggiungi una nuova lingua", - "language.default": "Lingua di default", - "language.delete.confirm": "Sei sicuro di voler eliminare la lingua {name} con tutte le traduzioni? Non sarà possibile annullare!", - "language.deleted": "La lingua è stata eliminata", - "language.direction": "Direzione di lettura", - "language.direction.ltr": "Sinistra a destra", - "language.direction.rtl": "Destra a sinistra", - "language.locale": "Stringa \"PHP locale\"", - "language.locale.warning": "Stai usando una impostazione personalizzata per il locale. Modificalo nel file della lingua situato in /site/languages", - "language.name": "Nome", - "language.secondary": "Secondary language", - "language.settings": "Language settings", - "language.updated": "La lingua è stata aggiornata", - "language.variables": "Language variables", - "language.variables.empty": "No translations yet", - - "language.variable.delete.confirm": "Do you really want to delete the variable for {key}?", - "language.variable.key": "Key", - "language.variable.notFound": "The variable could not be found", - "language.variable.value": "Value", - - "languages": "Lingue", - "languages.default": "Lingua di default", - "languages.empty": "Non ci sono lingue impostate", - "languages.secondary": "Lingue secondarie", - "languages.secondary.empty": "Non ci sono lingue secondarie impostate", - - "license": "Licenza di Kirby", - "license.activate": "Attiva ora", - "license.activate.label": "Attiva la tua licenza ora", - "license.activate.domain": "La tua licenza sarà attivata per {host}.", - "license.activate.local": "Stai per attivare la licenza per il dominio locale {host}. Se questo sito verrà rilasciato su un dominio pubblico, ti preghiamo di attivarla lì. Se {host} è il dominio per il quale desideri ottenere la licenza di Kirby, procedi pure.", - "license.activated": "Attivata", - "license.buy": "Acquista una licenza", - "license.code": "Codice", - "license.code.help": "Hai ricevuto il codice di licenza tramite email dopo l'acquisto. Per favore inseriscilo per registrare Kirby.", - "license.code.label": "Inserisci il codice di licenza", - "license.status.active.info": "Comprende nuove versioni major entro il {date}", - "license.status.active.label": "Licenza valida", - "license.status.demo.info": "Questa è un'installazione demo", - "license.status.demo.label": "Demo", - "license.status.inactive.info": "Rinnova la licenza per aggiornare a nuove versioni major", - "license.status.inactive.label": "Nessuna nuova versione major", - "license.status.legacy.bubble": "Pronto per rinnovare la licenza?", - "license.status.legacy.info": "La tua licenza non include questa versione", - "license.status.legacy.label": "Per favore rinnova la tua licenza", - "license.status.missing.bubble": "Pronto a lanciare il tuo sito?", - "license.status.missing.info": "Nessuna licenza valida", - "license.status.missing.label": "Attiva la tua licenza ora", - "license.manage": "Gestisci le tue licenze", - "license.purchased": "Acquistata", - "license.success": "Ti ringraziamo per aver supportato Kirby", - "license.unregistered.label": "Non registrato", - - "link": "Link", - "link.text": "Testo del link", - - "loading": "Caricamento", - - "lock.unsaved": "Modifiche non salvate", - "lock.unsaved.empty": "Non ci sono altre modifiche non salvate", - "lock.isLocked": "Unsaved changes by {email}", - "lock.unlock": "Sblocca", - "lock.unlock.submit": "Unlock and overwrite unsaved changes by {email}", - "lock.isUnlocked": "Was unlocked by another user", - - "login": "Accedi", - "login.code.label.login": "Codice di accesso", - "login.code.label.password-reset": "Codice per reimpostare la password", - "login.code.placeholder.email": "000 000", - "login.code.placeholder.totp": "000000", - "login.code.text.email": "Qualora il tuo indirizzo email fosse registrato, il codice richiesto è stato inviato tramite email.", - "login.code.text.totp": "Inserisci il codice monouso dalla tua app di autenticazione.", - "login.email.login.body": "Ciao {user.nameOrEmail},\n\nHai recentemente richiesto un codice di login per il pannello di controllo di {site}.\nIl seguente codice di login sarà valido per {timeout} minuti:\n\n{code}\n\nSe non hai richiesto un codice di login, per favore ignora questa mail o contatta il tuo amministratore in caso di domande.\nPer sicurezza, per favore NON inoltrare questa email.", - "login.email.login.subject": "Il tuo codice di accesso", - "login.email.password-reset.body": "Ciao {user.nameOrEmail},\n\nHai recentemente richiesto di resettare la password per il pannello di controllo di {site}.\nIl seguente codice di reset della password sarà valido per {timeout} minuti:\n\n{code}\n\nSe non hai richiesto di resettare la password per favore ignora questa email o contatta il tuo amministratore in caso di domande.\nPer sicurezza, per favore NON inoltrare questa email.", - "login.email.password-reset.subject": "Il tuo codice di reimpostazione della password", - "login.remember": "Resta collegato", - "login.reset": "Reimposta la password", - "login.toggleText.code.email": "Accedi tramite email", - "login.toggleText.code.email-password": "Accedi con la password", - "login.toggleText.password-reset.email": "Hai dimenticato la password?", - "login.toggleText.password-reset.email-password": "← Torna al login", - "login.totp.enable.option": "Configura i codici monouso", - "login.totp.enable.intro": "Le app di autenticazione generano codici monouso che puoi usare come secondo fattore quando accedi al tuo account.", - "login.totp.enable.qr.label": "1. Scansiona il codice QR", - "login.totp.enable.qr.help": "Impossibile eseguire la scansione? Aggiungi manualmente la chiave di configurazione {secret} alla tua app di autenticazione.", - "login.totp.enable.confirm.headline": "2. Conferma con il codice generato", - "login.totp.enable.confirm.text": "La tua app genera un nuovo codice monouso ogni 30 secondi. Inserisci il codice attuale per completare la configurazione:", - "login.totp.enable.confirm.label": "Codice attuale", - "login.totp.enable.confirm.help": "Dopo la configurazione, ti chiederemo un codice monouso ogni volta che effettuerai l'accesso. ", - "login.totp.enable.success": "Codici monouso attivati", - "login.totp.disable.option": "Disattiva i codici monouso", - "login.totp.disable.label": "Inserisci la tua password per disattivare i codici monouso", - "login.totp.disable.help": "In futuro, un secondo fattore diverso, come un codice login inviato tramite email, sarà richiesto per l'accesso. Potrai sempre reimpostare i codici monouso più tardi.", - "login.totp.disable.admin": "

Questo disattiverà i codici monouso per {user}.

In futuro verrà richiesto un secondo fattore diverso per l'accesso, per esempio un codice inviato per email. {user} potrà impostare nuovamente i codici monouso dopo il suo prossimo accesso.

", - "login.totp.disable.success": "Codici monouso disattivati", - - "logout": "Esci", - - "merge": "Merge", - "menu": "Menu", - "meridiem": "AM/PM", - "mime": "MIME Type", - "minutes": "Minuti", - - "month": "Mese", - "months.april": "Aprile", - "months.august": "Agosto", - "months.december": "Dicembre", - "months.february": "Febbraio", - "months.january": "Gennaio", - "months.july": "Luglio", - "months.june": "Giugno", - "months.march": "Marzo", - "months.may": "Maggio", - "months.november": "Novembre", - "months.october": "Ottobre", - "months.september": "Settembre", - - "more": "Di più", - "move": "Move", - "name": "Nome", - "next": "Prossimo", - "night": "Night", - "no": "no", - "off": "off", - "on": "on", - "open": "Apri", - "open.newWindow": "Apri in una finestra nuova", - "option": "Option", - "options": "Opzioni", - "options.none": "Nessuna opzione", - "options.all": "Mostra tutte le {count} opzioni", - - "orientation": "Orientamento", - "orientation.landscape": "Orizzontale", - "orientation.portrait": "Verticale", - "orientation.square": "Quadrato", - - "page": "Page", - "page.blueprint": "Questa pagina non ha ancora un blueprint. Puoi definire la sua configurazione in /site/blueprints/pages/{blueprint}.yml", - "page.changeSlug": "Modifica URL", - "page.changeSlug.fromTitle": "Crea in base al titolo", - "page.changeStatus": "Cambia stato", - "page.changeStatus.position": "Scegli una posizione", - "page.changeStatus.select": "Seleziona un nuovo stato", - "page.changeTemplate": "Cambia template", - "page.changeTemplate.notice": "Changing the page's template will remove content for fields that don't match in type. Use with caution.", - "page.create": "Crea come \"{status}\"", - "page.delete.confirm": "Sei sicuro di voler eliminare questa pagina?", - "page.delete.confirm.subpages": "Questa pagina ha sottopagine.
Anche tutte le sottopagine verranno eliminate.", - "page.delete.confirm.title": "Inserisci il titolo della pagina per confermare", - "page.duplicate.appendix": "Copia", - "page.duplicate.files": "Copia file", - "page.duplicate.pages": "Copia pagine", - "page.move": "Move page", - "page.sort": "Cambia posizione", - "page.status": "Stato", - "page.status.draft": "Bozza", - "page.status.draft.description": "Questa pagina è una bozza ed è visibile soltanto agli utenti registrati o tramite link segreto", - "page.status.listed": "Pubblico", - "page.status.listed.description": "La pagina è pubblicata per tutti", - "page.status.unlisted": "Non in elenco", - "page.status.unlisted.description": "La pagina è accessibile soltanto tramite URL", - - "pages": "Pagine", - "pages.empty": "Nessuna pagina", - "pages.status.draft": "Bozza", - "pages.status.listed": "Pubblicato", - "pages.status.unlisted": "Non in elenco", - - "pagination.page": "Pagina", - - "password": "Password", - "paste": "Incolla", - "paste.after": "Incolla dopo", - "paste.success": "{count} pasted!", - "pixel": "Pixel", - "plugin": "Plugin", - "plugins": "Plugins", - "prev": "Precedente", - "preview": "Anteprima", - "remove": "Rimuovi", - "rename": "Rinomina", - "renew": "Rinnova", - "replace": "Sostituisci", - "replace.with": "Replace with", - "retry": "Riprova", - "revert": "Abbandona", - "revert.confirm": "Sei sicuro di voler cancellare tutte le modifiche non salvate?", - - "role": "Ruolo", - "role.admin.description": "L'amministratore ha tutti i permessi", - "role.admin.title": "Amministratore", - "role.all": "Tutti", - "role.empty": "Non ci sono utenti con questo ruolo", - "role.description.placeholder": "Nessuna descrizione", - "role.nobody.description": "Questo è un ruolo \"fallback\" senza permessi", - "role.nobody.title": "Nessuno", - - "save": "Salva", - "search": "Cerca", - "search.min": "Inserisci almeno {min} caratteri per la ricerca", - "search.all": "Mostra tutti i {count} risultati", - "search.results.none": "Nessun risultato", - - "section.invalid": "The section is invalid", - "section.required": "La sezione è obbligatoria", - - "security": "Sicurezza", - "select": "Seleziona", - "server": "Server", - "settings": "Impostazioni", - "show": "Mostra", - "site.blueprint": "Il sito non ha ancora un \"blueprint\". Puoi impostarne uno in /site/blueprints/site.yml", - "size": "Dimensioni", - "slug": "URL", - "sort": "Ordina", - "sort.drag": "Drag to sort …", - "split": "Split", - - "stats.empty": "Nessuna segnalazione", - "status": "Stato", - - "system.info.copy": "Copy info", - "system.info.copied": "System info copied", - "system.issues.content": "La cartella content sembra essere esposta", - "system.issues.eol.kirby": "La versione di Kirby installata è giunta alla fine del suo ciclo di vita e non riceverà ulteriori aggiornamenti di sicurezza ", - "system.issues.eol.plugin": "La versione installata del plugin { plugin } è giunta alla fine del suo ciclo di vita e non riceverà ulteriori aggiornamenti di sicurezza", - "system.issues.eol.php": "La versione {release} di PHP installata è giunta alla fine del suo ciclo di vita e non riceverà ulteriori aggiornamenti di sicurezza", - "system.issues.debug": "Il debug deve essere disattivato in produzione", - "system.issues.git": "La cartella .git sembra essere esposta", - "system.issues.https": "Raccomandiamo l'utilizzo di HTTPS per tutti i siti", - "system.issues.kirby": "La cartella kirby sembra essere esposta", - "system.issues.site": "La cartella site sembra essere esposta", - "system.issues.vulnerability.kirby": "La tua installazione potrebbe essere colpita dalla seguente vulnerabilità ({ severity } gravità): { description }", - "system.issues.vulnerability.plugin": "La tua installazione potrebbe essere colpita dalla seguente vulnerabilità nel plugin { plugin } ({ severity } gravità): { description }", - "system.updateStatus": "Aggiorna lo stato", - "system.updateStatus.error": "Impossibile verificare gli aggiornamenti", - "system.updateStatus.not-vulnerable": "Nessuna vulnerabilità conosciuta", - "system.updateStatus.security-update": "Aggiornamento di sicurezza gratuito { version } disponibile", - "system.updateStatus.security-upgrade": "Aggiornamento { version } con le correzioni di sicurezza disponibili", - "system.updateStatus.unreleased": "Versione non rilasciata", - "system.updateStatus.up-to-date": "Aggiornato", - "system.updateStatus.update": "Aggiornamento gratuito { version } disponibile", - "system.updateStatus.upgrade": "Aggiornamento { version } disponibile", - - "tel": "Phone", - "tel.placeholder": "+49123456789", - "template": "Template", - "title": "Titolo", - "today": "Oggi", - - "toolbar.button.clear": "Clear formatting", - "toolbar.button.code": "Codice", - "toolbar.button.bold": "Grassetto", - "toolbar.button.email": "Email", - "toolbar.button.headings": "Titoli", - "toolbar.button.heading.1": "Titolo 1", - "toolbar.button.heading.2": "Titolo 2", - "toolbar.button.heading.3": "Titolo 3", - "toolbar.button.heading.4": "Titolo 4", - "toolbar.button.heading.5": "Titolo 5", - "toolbar.button.heading.6": "Titolo 6", - "toolbar.button.italic": "Corsivo", - "toolbar.button.file": "File", - "toolbar.button.file.select": "Seleziona un file", - "toolbar.button.file.upload": "Carica un file", - "toolbar.button.link": "Link", - "toolbar.button.paragraph": "Paragrafo", - "toolbar.button.strike": "Barrato", - "toolbar.button.sub": "Subscript", - "toolbar.button.sup": "Superscript", - "toolbar.button.ol": "Elenco numerato", - "toolbar.button.underline": "Sottolinea", - "toolbar.button.ul": "Elenco puntato", - - "translation.author": "Kirby Team, Roman Steiner, Manu Moreale", - "translation.direction": "ltr", - "translation.name": "Italiano", - "translation.locale": "it_IT", - - "type": "Tipo", - - "upload": "Carica", - "upload.error.cantMove": "Non è stato possibile spostare il file caricato", - "upload.error.cantWrite": "Impossibile scrivere il file su disco", - "upload.error.default": "Impossibile caricare il file", - "upload.error.extension": "Caricamento del file interrotto per via dell'estensione", - "upload.error.formSize": "La dimensione del file caricato supera la direttiva MAX_FILE_SIZE specificata nel form", - "upload.error.iniPostSize": "La dimensione del file caricato supera la direttiva post_max_size specificata in php.ini", - "upload.error.iniSize": "La dimensione del file caricato supera la direttiva upload_max_filesize specificata in php.ini", - "upload.error.noFile": "Il file non è stato caricato", - "upload.error.noFiles": "Nessun file è stato caricato", - "upload.error.partial": "Il file è stato caricato solo parzialmente", - "upload.error.tmpDir": "Manca la cartella temporanea", - "upload.errors": "Errore", - "upload.progress": "Caricamento...", - - "url": "URL", - "url.placeholder": "https://esempio.com", - - "user": "Utente", - "user.blueprint": "Puoi definire ulteriori sezioni e campi del form aggiuntivi per questo ruolo in /site/blueprints/users/{blueprint}.yml", - "user.changeEmail": "Modifica email", - "user.changeLanguage": "Cambia lingua", - "user.changeName": "Rinomina questo utente", - "user.changePassword": "Cambia password", - "user.changePassword.new": "Nuova password", - "user.changePassword.new.confirm": "Conferma la nuova password...", - "user.changeRole": "Cambia ruolo", - "user.changeRole.select": "Seleziona un nuovo ruolo", - "user.create": "Aggiungi nuovo utente", - "user.delete": "Elimina questo utente", - "user.delete.confirm": "Sei sicuro di voler eliminare l'utente
{email}?", - - "users": "Utenti", - - "version": "Versione di Kirby", - "version.current": "Versione corrente", - "version.latest": "Ultima versione", - "versionInformation": "Informazioni sulla versione", - - "view.account": "Il tuo account", - "view.installation": "Installazione", - "view.languages": "Lingue", - "view.resetPassword": "Reimposta la password", - "view.site": "Sito", - "view.system": "Sistema", - "view.users": "Utenti", - - "welcome": "Benvenuto", - "year": "Anno", - "yes": "sì" + "account.changeName": "Cambia il tuo nome", + "account.delete": "Elimina l'account", + "account.delete.confirm": "Vuoi davvero eliminare il tuo account? Verrai disconnesso immediatamente. Il tuo account non potrà essere recuperato.", + + "add": "Aggiungi", + "author": "Autore", + "avatar": "Immagine del profilo", + "back": "Indietro", + "cancel": "Annulla", + "change": "Cambia", + "close": "Chiudi", + "confirm": "OK", + "collapse": "Comprimi", + "collapse.all": "Comprimi tutto", + "copy": "Copia", + "copy.all": "Copia tutto", + "create": "Crea", + + "date": "Data", + "date.select": "Scegli una data", + + "day": "Giorno", + "days.fri": "Ve", + "days.mon": "Lu", + "days.sat": "Sa", + "days.sun": "Do", + "days.thu": "Gi", + "days.tue": "Ma", + "days.wed": "Me", + + "debugging": "Debugging", + + "delete": "Elimina", + "delete.all": "Elimina tutti", + + "dialog.files.empty": "Nessun file selezionabile", + "dialog.pages.empty": "Nessuna pagina selezionabile", + "dialog.users.empty": "Nessuno user selezionabile", + + "dimensions": "Dimensioni", + "disabled": "Disabilitato", + "discard": "Abbandona", + "download": "Scarica", + "duplicate": "Duplica", + + "edit": "Modifica", + + "email": "Email", + "email.placeholder": "mail@esempio.com", + + "entries": "Entries", + "entry": "Entry", + + "environment": "Ambiente", + + "error.access.code": "Codice non valido", + "error.access.login": "Login Invalido", + "error.access.panel": "Non ti è permesso accedere al pannello", + "error.access.view": "Non ti è permesso accedere a questa parte del pannello", + + "error.avatar.create.fail": "Non è stato possibile caricare l'immagine del profilo", + "error.avatar.delete.fail": "Non è stato possibile eliminare l'immagine del profilo", + "error.avatar.dimensions.invalid": "Per favore mantieni l'altezza e la larghezza dell'immagine del profilo inferiore ai 3000 pixel", + "error.avatar.mime.forbidden": "L'immagine del profilo dev'essere un file JPEG o PNG", + + "error.blueprint.notFound": "Non è stato possibile caricare il blueprint \"{name}\"", + + "error.blocks.max.plural": "Non puoi aggiungere più di {max} blocchi", + "error.blocks.max.singular": "Non puoi aggiungere più di un blocco", + "error.blocks.min.plural": "Devi aggiungere almeno {min} blocchi", + "error.blocks.min.singular": "Devi aggiungere almeno un blocco", + "error.blocks.validation": "C'è un errore nel blocco {index}", + + "error.email.preset.notFound": "Non è stato possibile trovare il preset email \"{name}\"", + + "error.field.converter.invalid": "Convertitore \"{converter}\" non valido", + + "error.file.changeName.empty": "Il nome non dev'essere vuoto", + "error.file.changeName.permission": "Non ti è permesso modificare il nome di \"{filename}\"", + "error.file.duplicate": "Un file con il nome \"{filename}\" esiste già", + "error.file.extension.forbidden": "L'estensione \"{extension}\" non è consentita", + "error.file.extension.invalid": "Estensione non valida: {extension}", + "error.file.extension.missing": "Il file \"{filename}\" non ha estensione", + "error.file.maxheight": "L'immagine non dev'essere più alta di {height} pixel", + "error.file.maxsize": "Il file è troppo pesante", + "error.file.maxwidth": "L'immagine non dev'essere più larga di {width} pixel", + "error.file.mime.differs": "Il file caricato dev'essere dello stesso MIME type \"{mime}\"", + "error.file.mime.forbidden": "Il MIME type \"{mime}\" non è consentito", + "error.file.mime.invalid": "Tipo mime non valido: {mime}", + "error.file.mime.missing": "Il MIME type per \"{filename}\" non può essere rilevato", + "error.file.minheight": "L'immagine dev'essere alta almeno {height} pixel", + "error.file.minsize": "Il file è troppo leggero", + "error.file.minwidth": "L'immagine dev'essere larga almeno {width} pixel", + "error.file.name.missing": "Il nome del file non può essere vuoto", + "error.file.notFound": "Il file non \u00e8 stato trovato", + "error.file.orientation": "L'imaggine dev'essere orientata in \"{orientation}\"", + "error.file.type.forbidden": "Non ti è permesso caricare file {type}", + "error.file.type.invalid": "Tipo di file non valido: {type}", + "error.file.undefined": "Il file non \u00e8 stato trovato", + + "error.form.incomplete": "Correggi tutti gli errori nel form...", + "error.form.notSaved": "Non è stato possibile salvare il form", + + "error.language.code": "Inserisci un codice valido per la lingua", + "error.language.duplicate": "La lingua esiste già", + "error.language.name": "Inserisci un nome valido per la lingua", + "error.language.notFound": "La lingua non è stata trovata", + + "error.layout.validation.block": "C'è un errore nel blocco {blockIndex} nel layout {layoutIndex}", + "error.layout.validation.settings": "C'è un errore nelle impostazioni del layout {index}", + + "error.license.format": "Inserisci un codice di licenza valido", + "error.license.email": "Inserisci un indirizzo email valido", + "error.license.verification": "Non è stato possibile verificare la licenza", + + "error.offline": "Il pannello di controllo è attualmente offline", + + "error.page.changeSlug.permission": "Non ti è permesso cambiare l'URL di \"{slug}\"", + "error.page.changeStatus.incomplete": "La pagina contiene errori e non può essere pubblicata", + "error.page.changeStatus.permission": "Lo stato di questa pagina non può essere cambiato", + "error.page.changeStatus.toDraft.invalid": "La pagina \"{slug}\" non può essere convertita in bozza", + "error.page.changeTemplate.invalid": "Il template della pagina \"{slug}\" non può essere cambiato", + "error.page.changeTemplate.permission": "Non ti è permesso modificare il template di \"{slug}\"", + "error.page.changeTitle.empty": "Il titolo non può essere vuoto", + "error.page.changeTitle.permission": "Non ti è permesso modificare il titolo di \"{slug}\"", + "error.page.create.permission": "Non ti è permesso creare \"{slug}\"", + "error.page.delete": "La pagina \"{slug}\" non può essere eliminata", + "error.page.delete.confirm": "Inserisci il titolo della pagina per confermare", + "error.page.delete.hasChildren": "La pagina ha sottopagine e non può essere eliminata", + "error.page.delete.permission": "Non ti è permesso eliminare \"{slug}\"", + "error.page.draft.duplicate": "Una bozza di pagina con l'URL \"{slug}\" esiste già", + "error.page.duplicate": "Una pagina con l'URL \"{slug}\" esiste già", + "error.page.duplicate.permission": "Non ti è permesso duplicare \"{slug}\"", + "error.page.notFound": "La pagina \"{slug}\" non è stata trovata", + "error.page.num.invalid": "Inserisci un numero di ordinamento valido. I numeri non devono essere negativi", + "error.page.slug.invalid": "Per favore inserisci un suffisso valido per l'URL", + "error.page.slug.maxlength": "Lo \"slug\" dev'essere più corto di \"{length}\" caratteri", + "error.page.sort.permission": "La pagina \"{slug}\" non può essere ordinata", + "error.page.status.invalid": "Imposta uno stato valido per la pagina", + "error.page.undefined": "La pagina non \u00e8 stata trovata", + "error.page.update.permission": "Non ti è permesso modificare \"{slug}\"", + + "error.section.files.max.plural": "Non puoi aggiungere più di {max} file alla sezione \"{section}\"", + "error.section.files.max.singular": "Non puoi aggiungere più di un file alla sezione \"{section}\"", + "error.section.files.min.plural": "La sezione \"{section}\" richiede almeno {min} file", + "error.section.files.min.singular": "La sezione \"{section}\" richiede almeno un file", + + "error.section.pages.max.plural": "Non puoi aggiungere più di {max} pagine alla sezione \"{section}\"", + "error.section.pages.max.singular": "Non puoi aggiungere più di una pagina alla sezione \"{section}\"", + "error.section.pages.min.plural": "La sezione \"{section}\" richiede almeno {min} pagine", + "error.section.pages.min.singular": "La sezione \"{section}\" richiede almeno una pagina", + + "error.section.notLoaded": "Non è stato possibile caricare la sezione \"{name}\"", + "error.section.type.invalid": "Il tipo di sezione \"{type}\" non è valido", + + "error.site.changeTitle.empty": "Il titolo non può essere vuoto", + "error.site.changeTitle.permission": "Non ti è permesso modificare il titolo del sito", + "error.site.update.permission": "Non ti è permesso modificare i contenuti globali del sito", + + "error.template.default.notFound": "Il template \"default\" non esiste", + + "error.unexpected": "Si è verificato un errore inaspettato! Abilita la modalità \"debug\" per ulteriori informazioni: https://getkirby.com/docs/reference/system/options/debug", + + "error.user.changeEmail.permission": "Non ti è permesso modificare l'indirizzo email di \"{name}\"", + "error.user.changeLanguage.permission": "Non ti è permesso modificare la lingua per l'utente \"{name}\"", + "error.user.changeName.permission": "Non ti è permesso modificare il nome dell'utente \"{name}\"", + "error.user.changePassword.permission": "Non ti è permesso modificare la password dell'utente \"{name}\"", + "error.user.changeRole.lastAdmin": "Il ruolo dell'ultimo amministratore non può esser cambiato", + "error.user.changeRole.permission": "Non ti è permesso modificare il ruolo dell'utente \"{name}\"", + "error.user.changeRole.toAdmin": "Non ti è permesso assegnare il ruolo di amministratore ad altri utenti", + "error.user.create.permission": "Non ti è permesso creare questo utente", + "error.user.delete": "L'utente non pu\u00f2 essere eliminato", + "error.user.delete.lastAdmin": "L'ultimo amministratore non può essere eliminato", + "error.user.delete.lastUser": "L'ultimo utente non può essere eliminato", + "error.user.delete.permission": "Non ti \u00e8 permesso eliminare questo utente ", + "error.user.duplicate": "Esiste già un utente con l'indirizzo email \"{email}\"", + "error.user.email.invalid": "Inserisci un indirizzo email valido", + "error.user.language.invalid": "Inserisci una lingua valida", + "error.user.notFound": "L'utente non \u00e8 stato trovato", + "error.user.password.excessive": "Please enter a valid password. Passwords must not be longer than 1000 characters.", + "error.user.password.invalid": "Per favore inserisci una password valida. Le password devono essere lunghe almeno 8 caratteri", + "error.user.password.notSame": "Le password non corrispondono", + "error.user.password.undefined": "L'utente non ha una password", + "error.user.password.wrong": "Password sbagliata", + "error.user.role.invalid": "Inserisci un ruolo valido", + "error.user.undefined": "L'utente non è stato trovato", + "error.user.update.permission": "Non ti è permesso aggiornare l'utente \"{name}\"", + + "error.validation.accepted": "Per favore conferma", + "error.validation.alpha": "Puoi inserire solo caratteri tra a-z", + "error.validation.alphanum": "Puoi inserire solo caratteri tra a-z e numeri 0-9", + "error.validation.between": "Inserisci un valore tra \"{min}\" e \"{max}\"", + "error.validation.boolean": "Per favore conferma o nega", + "error.validation.contains": "Inserisci un valore che contiene \"{needle}\"", + "error.validation.date": "Inserisci una data valida", + "error.validation.date.after": "Inserisci una data dopo il {date}", + "error.validation.date.before": "Inserisci una data prima del {date}", + "error.validation.date.between": "Inserisci una data tra {min} e {max}", + "error.validation.denied": "Per favore nega", + "error.validation.different": "Il valore non dev'essere \"{other}\"", + "error.validation.email": "Inserisci un indirizzo email valido", + "error.validation.endswith": "Il valore non deve finire con \"{end}\"", + "error.validation.filename": "Inserisci un nome del file valido", + "error.validation.in": "Inserisci uno dei seguenti valori: ({in})", + "error.validation.integer": "Inserisci un numero intero", + "error.validation.ip": "Inserisci un indirizzo IP valido", + "error.validation.less": "Inserisci un valore inferiore a {max}", + "error.validation.match": "Il valore non corrisponde al pattern previsto", + "error.validation.max": "Inserisci un valore inferiore o uguale a {max}", + "error.validation.maxlength": "Inserisci un testo più corto. (max. {max} caratteri)", + "error.validation.maxwords": "Non inserire più di {max} parola/e", + "error.validation.min": "Inserisci un valore superiore o uguale a {min}", + "error.validation.minlength": "Inserisci un testo più lungo. (min. {min} caratteri)", + "error.validation.minwords": "Inserisci almeno {min} parola/e", + "error.validation.more": "Inserisci un valore superiore a {min}", + "error.validation.notcontains": "Inserisci un valore che non contenga \"{needle}\"", + "error.validation.notin": "Non inserire nessuno dei valori seguenti: ({notIn})", + "error.validation.option": "Seleziona un'opzione valida", + "error.validation.num": "Inserisci un numero valido", + "error.validation.required": "Inserisci qualcosa", + "error.validation.same": "Inserisci \"{other}\"", + "error.validation.size": "La dimensione del valore dev'essere \"{size}\"", + "error.validation.startswith": "Il valore deve iniziare con \"{start}\"", + "error.validation.time": "Inserisci un orario valido", + "error.validation.time.after": "Inserisci un orario dopo le {time}", + "error.validation.time.before": "Inserisci un orario prima delle {time}", + "error.validation.time.between": "Inserisci un orario tra le {min} e le {max}", + "error.validation.url": "Inserisci un URL valido", + + "expand": "Espandi", + "expand.all": "Espandi tutto", + + "field.required": "Il campo è obbligatorio", + "field.blocks.changeType": "Cambia tipo", + "field.blocks.code.name": "Codice", + "field.blocks.code.language": "Lingua", + "field.blocks.code.placeholder": "Il tuo codice …", + "field.blocks.delete.confirm": "Vuoi veramente eliminare questo blocco?", + "field.blocks.delete.confirm.all": "Vuoi veramente eliminare tutti i blocchi? ", + "field.blocks.delete.confirm.selected": "Vuoi veramente eliminare i blocchi selezionati?", + "field.blocks.empty": "Nessun blocco inserito", + "field.blocks.fieldsets.label": "Seleziona il tipo di blocco …", + "field.blocks.fieldsets.paste": "Premi {{ shortcut }} per incollare/importare i blocchi dagli appunti", + "field.blocks.gallery.name": "Galleria", + "field.blocks.gallery.images.empty": "Nessuna immagine inserita", + "field.blocks.gallery.images.label": "Immagini", + "field.blocks.heading.level": "Livello", + "field.blocks.heading.name": "Titolo", + "field.blocks.heading.text": "Testo", + "field.blocks.heading.placeholder": "Titolo …", + "field.blocks.image.alt": "Testo alternativo", + "field.blocks.image.caption": "Didascalia", + "field.blocks.image.crop": "Ritaglio", + "field.blocks.image.link": "Link", + "field.blocks.image.location": "Posizione", + "field.blocks.image.name": "Immagine", + "field.blocks.image.placeholder": "Seleziona un'immagine", + "field.blocks.image.ratio": "Rapporto", + "field.blocks.image.url": "URL immagine", + "field.blocks.line.name": "Linea", + "field.blocks.list.name": "Lista", + "field.blocks.markdown.name": "Markdown", + "field.blocks.markdown.label": "Testo", + "field.blocks.markdown.placeholder": "Markdown …", + "field.blocks.quote.name": "Citazione", + "field.blocks.quote.text.label": "Testo", + "field.blocks.quote.text.placeholder": "Citazione …", + "field.blocks.quote.citation.label": "Fonte", + "field.blocks.quote.citation.placeholder": "di …", + "field.blocks.text.name": "Testo", + "field.blocks.text.placeholder": "Testo …", + "field.blocks.video.caption": "Didascalia", + "field.blocks.video.name": "Video", + "field.blocks.video.placeholder": "Inserisci un URL di un video", + "field.blocks.video.url.label": "URL Video", + "field.blocks.video.url.placeholder": "https://youtube.com/?v=", + + "field.files.empty": "Nessun file selezionato", + + "field.layout.delete": "Elimina layout", + "field.layout.delete.confirm": "Vuoi veramente eliminare questo layout?", + "field.layout.empty": "Nessuna riga inserita", + "field.layout.select": "Scegli un layout", + + "field.pages.empty": "Nessuna pagina selezionata", + "field.structure.delete.confirm": "Vuoi veramente eliminare questo elemento?", + "field.structure.empty": "Non ci sono ancora elementi.", + "field.users.empty": "Nessun utente selezionato", + + "file.blueprint": "Questo file non ha ancora un blueprint. Puoi definire la sua configurazione in /site/blueprints/files/{blueprint}.yml", + "file.delete.confirm": "Sei sicuro di voler eliminare questo file?", + "file.sort": "Cambia posizione", + + "files": "Files", + "files.empty": "Nessun file caricato", + + "hide": "Nascondi", + "hour": "Ora", + "import": "Importa", + "info": "Info", + "insert": "Inserisci", + "insert.after": "Inserisci dopo", + "insert.before": "Inserisci prima", + "install": "Installa", + + "installation": "Installazione", + "installation.completed": "Il pannello è stato installato", + "installation.disabled": "L'installazione del pannello è disabilitata di default sui server pubblici. Esegui l'installazione in locale oppure abilitala usando l'opzione panel.install.", + "installation.issues.accounts": "/site/accounts non esiste o non dispone dei permessi di scrittura", + "installation.issues.content": "La cartella /content non esiste o non dispone dei permessi di scrittura", + "installation.issues.curl": "È necessaria l'estensione CURL", + "installation.issues.headline": "Il pannello non può esser installato", + "installation.issues.mbstring": "È necessaria l'estensione MB String", + "installation.issues.media": "La cartella /media non esiste o non dispone dei permessi di scrittura", + "installation.issues.php": "Assicurati di utilizzare PHP 7.1+", + "installation.issues.server": "Kirby necessita di Apache, Nginx o Caddy", + "installation.issues.sessions": "La cartella /site/sessionsnon esiste o non dispone dei permessi di scrittura", + + "language": "Lingua", + "language.code": "Codice", + "language.convert": "Imposta come predefinito", + "language.convert.confirm": "

Sei sicuro di voler convertire {name} nella lingua predefinita? Questa operazione non può essere annullata.

Se {name} non contiene tutte le traduzioni, non ci sarà più una versione alternativa valida e parti del sito potrebbero rimanere vuote.

", + "language.create": "Aggiungi una nuova lingua", + "language.delete.confirm": "Sei sicuro di voler eliminare la lingua {name} con tutte le traduzioni? Non sarà possibile annullare!", + "language.deleted": "La lingua è stata eliminata", + "language.direction": "Direzione di lettura", + "language.direction.ltr": "Sinistra a destra", + "language.direction.rtl": "Destra a sinistra", + "language.locale": "Stringa \"PHP locale\"", + "language.locale.warning": "Stai usando una impostazione personalizzata per il locale. Modificalo nel file della lingua situato in /site/languages", + "language.name": "Nome", + "language.updated": "La lingua è stata aggiornata", + + "languages": "Lingue", + "languages.default": "Lingua di default", + "languages.empty": "Non ci sono lingue impostate", + "languages.secondary": "Lingue secondarie", + "languages.secondary.empty": "Non ci sono lingue secondarie impostate", + + "license": "Licenza di Kirby", + "license.buy": "Acquista una licenza", + "license.register": "Registra", + "license.manage": "Manage your licenses", + "license.register.help": "Hai ricevuto il codice di licenza tramite email dopo l'acquisto. Per favore inseriscilo per registrare Kirby.", + "license.register.label": "Inserisci il codice di licenza", + "license.register.success": "Ti ringraziamo per aver supportato Kirby", + "license.unregistered": "Questa è una versione demo di Kirby non registrata", + "license.unregistered.label": "Unregistered", + + "link": "Link", + "link.text": "Testo del link", + + "loading": "Caricamento", + + "lock.unsaved": "Modifiche non salvate", + "lock.unsaved.empty": "Non ci sono altre modifiche non salvate", + "lock.isLocked": "Modifiche non salvate di {email}", + "lock.file.isLocked": "Il file viene attualmente modificato da {email} e non può essere cambiato.", + "lock.page.isLocked": "la pagina viene attualmente modificata da {email} e non può essere cambiata.", + "lock.unlock": "Sblocca", + "lock.isUnlocked": "Un altro utente ha sovrascritto le tue modifiche non salvate. Puoi scaricarle per recuperarle e quindi incorporarle manualmente. ", + + "login": "Accedi", + "login.code.label.login": "Codice di accesso", + "login.code.label.password-reset": "Codice per reimpostare la password", + "login.code.placeholder.email": "000 000", + "login.code.text.email": "Qualora il tuo indirizzo email fosse registrato, il codice richiesto è stato inviato tramite email.", + "login.email.login.body": "Ciao {user.nameOrEmail},\n\nHai recentemente richiesto un codice di login per il pannello di controllo di {site}.\nIl seguente codice di login sarà valido per {timeout} minuti:\n\n{code}\n\nSe non hai richiesto un codice di login, per favore ignora questa mail o contatta il tuo amministratore in caso di domande.\nPer sicurezza, per favore NON inoltrare questa email.", + "login.email.login.subject": "Il tuo codice di accesso", + "login.email.password-reset.body": "Ciao {user.nameOrEmail},\n\nHai recentemente richiesto di resettare la password per il pannello di controllo di {site}.\nIl seguente codice di reset della password sarà valido per {timeout} minuti:\n\n{code}\n\nSe non hai richiesto di resettare la password per favore ignora questa email o contatta il tuo amministratore in caso di domande.\nPer sicurezza, per favore NON inoltrare questa email.", + "login.email.password-reset.subject": "Il tuo codice di reimpostazione della password", + "login.remember": "Resta collegato", + "login.reset": "Reimposta la password", + "login.toggleText.code.email": "Accedi tramite email", + "login.toggleText.code.email-password": "Accedi con la password", + "login.toggleText.password-reset.email": "Hai dimenticato la password?", + "login.toggleText.password-reset.email-password": "← Torna al login", + + "logout": "Esci", + + "menu": "Menu", + "meridiem": "AM/PM", + "mime": "MIME Type", + "minutes": "Minuti", + + "month": "Mese", + "months.april": "Aprile", + "months.august": "Agosto", + "months.december": "Dicembre", + "months.february": "Febbraio", + "months.january": "Gennaio", + "months.july": "Luglio", + "months.june": "Giugno", + "months.march": "Marzo", + "months.may": "Maggio", + "months.november": "Novembre", + "months.october": "Ottobre", + "months.september": "Settembre", + + "more": "Di più", + "name": "Nome", + "next": "Prossimo", + "no": "no", + "off": "off", + "on": "on", + "open": "Apri", + "open.newWindow": "Apri in una finestra nuova", + "options": "Opzioni", + "options.none": "Nessuna opzione", + + "orientation": "Orientamento", + "orientation.landscape": "Orizzontale", + "orientation.portrait": "Verticale", + "orientation.square": "Quadrato", + + "page.blueprint": "Questa pagina non ha ancora un blueprint. Puoi definire la sua configurazione in /site/blueprints/pages/{blueprint}.yml", + "page.changeSlug": "Modifica URL", + "page.changeSlug.fromTitle": "Crea in base al titolo", + "page.changeStatus": "Cambia stato", + "page.changeStatus.position": "Scegli una posizione", + "page.changeStatus.select": "Seleziona un nuovo stato", + "page.changeTemplate": "Cambia template", + "page.delete.confirm": "Sei sicuro di voler eliminare questa pagina?", + "page.delete.confirm.subpages": "Questa pagina ha sottopagine.
Anche tutte le sottopagine verranno eliminate.", + "page.delete.confirm.title": "Inserisci il titolo della pagina per confermare", + "page.draft.create": "Crea bozza", + "page.duplicate.appendix": "Copia", + "page.duplicate.files": "Copia file", + "page.duplicate.pages": "Copia pagine", + "page.sort": "Cambia posizione", + "page.status": "Stato", + "page.status.draft": "Bozza", + "page.status.draft.description": "Questa pagina è una bozza ed è visibile soltanto agli utenti registrati o tramite link segreto", + "page.status.listed": "Pubblico", + "page.status.listed.description": "La pagina è pubblicata per tutti", + "page.status.unlisted": "Non in elenco", + "page.status.unlisted.description": "La pagina è accessibile soltanto tramite URL", + + "pages": "Pagine", + "pages.empty": "Nessuna pagina", + "pages.status.draft": "Bozza", + "pages.status.listed": "Pubblicato", + "pages.status.unlisted": "Non in elenco", + + "pagination.page": "Pagina", + + "password": "Password", + "paste": "Incolla", + "paste.after": "Incolla dopo", + "pixel": "Pixel", + "plugins": "Plugins", + "prev": "Precedente", + "preview": "Anteprima", + "remove": "Rimuovi", + "rename": "Rinomina", + "replace": "Sostituisci", + "retry": "Riprova", + "revert": "Abbandona", + "revert.confirm": "Sei sicuro di voler cancellare tutte le modifiche non salvate?", + + "role": "Ruolo", + "role.admin.description": "L'amministratore ha tutti i permessi", + "role.admin.title": "Amministratore", + "role.all": "Tutti", + "role.empty": "Non ci sono utenti con questo ruolo", + "role.description.placeholder": "Nessuna descrizione", + "role.nobody.description": "Questo è un ruolo \"fallback\" senza permessi", + "role.nobody.title": "Nessuno", + + "save": "Salva", + "search": "Cerca", + "search.min": "Inserisci almeno {min} caratteri per la ricerca", + "search.all": "Mostra tutti", + "search.results.none": "Nessun risultato", + + "section.required": "La sezione è obbligatoria", + + "security": "Security", + "select": "Seleziona", + "server": "Server", + "settings": "Impostazioni", + "show": "Mostra", + "site.blueprint": "Il sito non ha ancora un \"blueprint\". Puoi impostarne uno in /site/blueprints/site.yml", + "size": "Dimensioni", + "slug": "URL", + "sort": "Ordina", + + "stats.empty": "No reports", + "system.issues.content": "The content folder seems to be exposed", + "system.issues.debug": "Debugging must be turned off in production", + "system.issues.git": "The .git folder seems to be exposed", + "system.issues.https": "We recommend HTTPS for all your sites", + "system.issues.kirby": "The kirby folder seems to be exposed", + "system.issues.site": "The site folder seems to be exposed", + + "title": "Titolo", + "template": "Template", + "today": "Oggi", + + "toolbar.button.code": "Codice", + "toolbar.button.bold": "Grassetto", + "toolbar.button.email": "Email", + "toolbar.button.headings": "Titoli", + "toolbar.button.heading.1": "Titolo 1", + "toolbar.button.heading.2": "Titolo 2", + "toolbar.button.heading.3": "Titolo 3", + "toolbar.button.heading.4": "Titolo 4", + "toolbar.button.heading.5": "Titolo 5", + "toolbar.button.heading.6": "Titolo 6", + "toolbar.button.italic": "Corsivo", + "toolbar.button.file": "File", + "toolbar.button.file.select": "Seleziona un file", + "toolbar.button.file.upload": "Carica un file", + "toolbar.button.link": "Link", + "toolbar.button.paragraph": "Paragrafo", + "toolbar.button.strike": "Barrato", + "toolbar.button.ol": "Elenco numerato", + "toolbar.button.underline": "Sottolinea", + "toolbar.button.ul": "Elenco puntato", + + "translation.author": "Kirby Team, Roman Steiner, Manu Moreale", + "translation.direction": "ltr", + "translation.name": "Italiano", + "translation.locale": "it_IT", + + "upload": "Carica", + "upload.error.cantMove": "Non è stato possibile spostare il file caricato", + "upload.error.cantWrite": "Impossibile scrivere il file su disco", + "upload.error.default": "Impossibile caricare il file", + "upload.error.extension": "Caricamento del file interrotto per via dell'estensione", + "upload.error.formSize": "La dimensione del file caricato supera la direttiva MAX_FILE_SIZE specificata nel form", + "upload.error.iniPostSize": "La dimensione del file caricato supera la direttiva post_max_size specificata in php.ini", + "upload.error.iniSize": "La dimensione del file caricato supera la direttiva upload_max_filesize specificata in php.ini", + "upload.error.noFile": "Il file non è stato caricato", + "upload.error.noFiles": "Nessun file è stato caricato", + "upload.error.partial": "Il file è stato caricato solo parzialmente", + "upload.error.tmpDir": "Manca la cartella temporanea", + "upload.errors": "Errore", + "upload.progress": "Caricamento...", + + "url": "URL", + "url.placeholder": "https://esempio.com", + + "user": "Utente", + "user.blueprint": "Puoi definire ulteriori sezioni e campi del form aggiuntivi per questo ruolo in /site/blueprints/users/{blueprint}.yml", + "user.changeEmail": "Modifica email", + "user.changeLanguage": "Cambia lingua", + "user.changeName": "Rinomina questo utente", + "user.changePassword": "Cambia password", + "user.changePassword.new": "Nuova password", + "user.changePassword.new.confirm": "Conferma la nuova password...", + "user.changeRole": "Cambia ruolo", + "user.changeRole.select": "Seleziona un nuovo ruolo", + "user.create": "Aggiungi nuovo utente", + "user.delete": "Elimina questo utente", + "user.delete.confirm": "Sei sicuro di voler eliminare l'utente
{email}?", + + "users": "Utenti", + + "version": "Versione di Kirby", + + "view.account": "Il tuo account", + "view.installation": "Installazione", + "view.languages": "Lingue", + "view.resetPassword": "Reimposta la password", + "view.site": "Sito", + "view.system": "Sistema", + "view.users": "Utenti", + + "welcome": "Benvenuto", + "year": "Anno", + "yes": "sì" } diff --git a/kirby/i18n/translations/ko.json b/kirby/i18n/translations/ko.json index cfb180e..a86ee24 100644 --- a/kirby/i18n/translations/ko.json +++ b/kirby/i18n/translations/ko.json @@ -1,730 +1,574 @@ { - "account.changeName": "이름 변경", - "account.delete": "계정 삭제", - "account.delete.confirm": "계정을 삭제할까요? 계정을 삭제한 뒤에는 즉시 로그아웃되며, 삭제된 계정은 복구할 수 없습니다.", - - "activate": "활성화", - "add": "\ucd94\uac00", - "alpha": "알파", - "author": "저자", - "avatar": "프로필 이미지", - "back": "뒤로", - "cancel": "\ucde8\uc18c", - "change": "\ubcc0\uacbd", - "close": "\ub2eb\uae30", - "changes": "변경", - "confirm": "확인", - "collapse": "접기", - "collapse.all": "모두 접기", - "color": "색", - "coordinates": "좌표", - "copy": "복사", - "copy.all": "모두 복사", - "copy.success": "복사되었습니다. ({count})", - "create": "등록", - "custom": "개인화", - - "date": "날짜", - "date.select": "날짜 지정", - - "day": "일", - "days.fri": "\uae08", - "days.mon": "\uc6d4", - "days.sat": "\ud1a0", - "days.sun": "\uc77c", - "days.thu": "\ubaa9", - "days.tue": "\ud654", - "days.wed": "\uc218", - - "debugging": "디버그", - - "delete": "\uc0ad\uc81c", - "delete.all": "모두 삭제", - - "dialog.fields.empty": "필드가 없습니다.", - "dialog.files.empty": "선택할 파일이 없습니다.", - "dialog.pages.empty": "선택할 페이지가 없습니다.", - "dialog.text.empty": "정의된 텍스트가 없습니다.", - "dialog.users.empty": "선택할 사용자가 없습니다.", - - "dimensions": "크기", - "disable": "비활성화", - "disabled": "비활성화", - "discard": "무시", - - "drawer.fields.empty": "필드가 없습니다.", - - "domain": "도메인", - "download": "다운로드", - "duplicate": "복제", - - "edit": "\ud3b8\uc9d1", - - "email": "\uc774\uba54\uc77c \uc8fc\uc18c", - "email.placeholder": "mail@example.com", - - "enter": "Enter", - "entries": "항목", - "entry": "항목", - - "environment": "구동 환경", - - "error": "오류", - "error.access.code": "코드가 올바르지 않습니다.", - "error.access.login": "로그인할 수 없습니다.", - "error.access.panel": "패널에 접근할 권한이 없습니다.", - "error.access.view": "패널에 접근할 권한이 없습니다.", - - "error.avatar.create.fail": "프로필 이미지를 업로드할 수 없습니다.", - "error.avatar.delete.fail": "\ud504\ub85c\ud544 \uc774\ubbf8\uc9c0\ub97c \uc0ad\uc81c\ud560 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4.", - "error.avatar.dimensions.invalid": "프로필 이미지의 너비와 높이를 3,000픽셀 이하로 설정하세요.", - "error.avatar.mime.forbidden": "프로필 이미지의 확장자(JPG, JPEG, PNG)를 확인하세요.", - - "error.blueprint.notFound": "블루프린트({name})를 불러올 수 없습니다.", - - "error.blocks.max.plural": "블록을 {max}개 이상 추가할 수 없습니다.", - "error.blocks.max.singular": "블록을 하나 이상 추가할 수 없습니다.", - "error.blocks.min.plural": "블록을 {min}개 이상 추가하세요.", - "error.blocks.min.singular": "블록을 하나 이상 추가하세요.", - "error.blocks.validation": "블록 유형({fieldset})을 사용하는 블록({index})의 필드({field})에 오류가 있습니다.", - - "error.cache.type.invalid": "캐시 형식(({type})이 올바르지 않습니다.", - - "error.email.preset.notFound": "기본 이메일 주소({name})가 없습니다.", - - "error.field.converter.invalid": "컨버터({converter})가 올바르지 않습니다.", - "error.field.type.missing": "필드({name}): 필드 타입({type})이 없습니다.", - - "error.file.changeName.empty": "이름을 입력하세요.", - "error.file.changeName.permission": "파일명({filename})을 변경할 권한이 없습니다.", - "error.file.changeTemplate.invalid": "파일({id}) 템플릿을 다음 템플릿({template})으로 변경할 수 없습니다. (valid: \"{blueprints}\")", - "error.file.changeTemplate.permission": "파일({id}) 템플릿을 변경할 수 없습니다.", - - "error.file.duplicate": "파일명이 같은 파일({filename})이 있습니다.", - "error.file.extension.forbidden": "이 확장자({extension})는 업로드할 수 없습니다.", - "error.file.extension.invalid": "확장자({extension})가 올바르지 않습니다.", - "error.file.extension.missing": "파일({filename})에 확장자가 없습니다.", - "error.file.maxheight": "이미지의 높이는 {height}픽셀을 초과할 수 없습니다.", - "error.file.maxsize": "파일이 너무 큽니다.", - "error.file.maxwidth": "이미지의 너비는 {width}픽셀을 초과할 수 없습니다.", - "error.file.mime.differs": "기존 파일과 MIME 형식({mime})이 다릅니다.", - "error.file.mime.forbidden": "이 MIME 형식({mime})은 업로드할 수 없습니다.", - "error.file.mime.invalid": "MIME 형식({mime})이 올바르지 않습니다.", - "error.file.mime.missing": "파일({filename})의 MIME 형식을 확인할 수 없습니다.", - "error.file.minheight": "이미지의 높이를 {height}픽셀 이상으로 설정하세요.", - "error.file.minsize": "파일이 너무 작습니다.", - "error.file.minwidth": "이미지의 너비를 {width}픽셀 이상으로 설정하세요.", - "error.file.name.unique": "고유한 파일명을 지정하세요.", - "error.file.name.missing": "파일명을 입력하세요.", - "error.file.notFound": "파일({filename})이 없습니다.", - "error.file.orientation": "이미지의 비율({orientation})을 확인하세요.", - "error.file.type.forbidden": "이 형식({type})의 파일을 업로드할 권한이 없습니다.", - "error.file.type.invalid": "파일 형식({type})이 올바르지 않습니다.", - "error.file.undefined": "\ud30c\uc77c\uc774 \uc5c6\uc2b5\ub2c8\ub2e4.", - - "error.form.incomplete": "항목에 오류가 있습니다.", - "error.form.notSaved": "항목을 저장할 수 없습니다.", - - "error.language.code": "올바른 언어 코드를 입력하세요.", - "error.language.duplicate": "이미 등록한 언어입니다.", - "error.language.name": "올바른 언어명을 입력하세요.", - "error.language.notFound": "언어를 찾을 수 없습니다.", - - "error.layout.validation.block": "레이아웃({layoutIndex})의 특정 블록 유형({fieldset})을 사용하는 블록({blockIndex})의 특정 필드({field})에 오류가 있습니다.", - "error.layout.validation.settings": "레이아웃({index}) 옵션을 확인하세요.", - - "error.license.domain": "라이선스에 대한 도메인이 누락되었습니다.", - "error.license.email": "올바른 이메일 주소를 입력하세요.", - "error.license.format": "올바른 라이선스 코드를 입력하세요.", - "error.license.verification": "라이선스 키가 올바르지 않습니다.", - - "error.login.totp.confirm.invalid": "코드가 올바르지 않습니다.", - "error.login.totp.confirm.missing": "현재 코드를 입력하세요.", - - "error.object.validation": "필드({label})에 오류가 있습니다.\n{message}", - - "error.offline": "패널이 오프라인 상태입니다.", - - "error.page.changeSlug.permission": "고유 주소({slug})를 변경할 권한이 없습니다.", - "error.page.changeSlug.reserved": "상위 페이지는 이 경로({path})로 시작할 수 없습니다.", - "error.page.changeStatus.incomplete": "페이지를 공개할 수 없습니다.", - "error.page.changeStatus.permission": "페이지 상태를 변경할 수 없습니다.", - "error.page.changeStatus.toDraft.invalid": "페이지({slug}) 상태를 초안으로 변경할 수 없습니다.", - "error.page.changeTemplate.invalid": "페이지({slug}) 템플릿을 변경할 수 없습니다.", - "error.page.changeTemplate.permission": "페이지({slug}) 템플릿을 변경할 권한이 없습니다.", - "error.page.changeTitle.empty": "제목을 입력하세요.", - "error.page.changeTitle.permission": "페이지({slug}) 제목을 변경할 권한이 없습니다.", - "error.page.create.permission": "페이지({slug})를 등록할 권한이 없습니다.", - "error.page.delete": "페이지({slug})를 삭제할 수 없습니다.", - "error.page.delete.confirm": "페이지를 삭제하려면 페이지의 제목을 입력하세요.", - "error.page.delete.hasChildren": "하위 페이지가 있는 페이지는 삭제할 수 없습니다.", - "error.page.delete.permission": "페이지({slug})를 삭제할 권한이 없습니다.", - "error.page.draft.duplicate": "고유 주소({slug})가 같은 초안 페이지가 있습니다.", - "error.page.duplicate": "고유 주소({slug})가 같은 페이지가 있습니다.", - "error.page.duplicate.permission": "페이지({slug})를 복제할 권한이 없습니다.", - "error.page.move.ancestor": "해당 페이지로 이동할 수 없습니다.", - "error.page.move.directory": "페이지 디렉토리는 이동할 수 없습니다.", - "error.page.move.duplicate": "고유 주소({slug})가 같은 서브 페이지가 있습니다.", - "error.page.move.notFound": "이동된 페이지를 찾을 수 없습니다.", - "error.page.move.permission": "페이지({slug})를 이동할 권한이 없습니다.", - "error.page.move.template": "이 템플릿({template})은 이 페이지({parent})의 서브 페이지로 이동할 수 없습니다.", - "error.page.notFound": "페이지({slug})가 없습니다.", - "error.page.num.invalid": "올바른 정수를 입력하세요.", - "error.page.slug.invalid": "올바른 URL을 입력하세요.", - "error.page.slug.maxlength": "고유 주소를 {length}자 이하로 입력하세요.", - "error.page.sort.permission": "페이지({slug})를 정렬할 수 없습니다.", - "error.page.status.invalid": "올바른 상태를 설정하세요.", - "error.page.undefined": "\ud398\uc774\uc9c0\uac00 \uc5c6\uc2b5\ub2c8\ub2e4.", - "error.page.update.permission": "페이지({slug})를 변경할 권한이 없습니다.", - - "error.section.files.max.plural": "이 섹션({section})에는 파일을 {max}개 이상 추가할 수 없습니다.", - "error.section.files.max.singular": "이 섹션({section})에는 파일을 하나 이상 추가할 수 없습니다.", - "error.section.files.min.plural": "이 섹션({section})에는 파일이 {min}개 이상 필요합니다.", - "error.section.files.min.singular": "이 섹션({section})에는 파일이 하나 이상 필요합니다.", - - "error.section.pages.max.plural": "이 섹션({section})에는 페이지를 {max}개 이상 추가할 수 없습니다.", - "error.section.pages.max.singular": "이 섹션({section})에는 페이지를 하나 이상 추가할 수 없습니다.", - "error.section.pages.min.plural": "이 섹션({section})에는 페이지가 {min}개 이상 필요합니다.", - "error.section.pages.min.singular": "이 섹션({section})에는 페이지가 하나 이상 필요합니다.", - - "error.section.notLoaded": "섹션({name})을 확인할 수 없습니다.", - "error.section.type.invalid": "섹션 형식({type})이 올바르지 않습니다.", - - "error.site.changeTitle.empty": "제목을 입력하세요.", - "error.site.changeTitle.permission": "사이트명을 변경할 권한이 없습니다.", - "error.site.update.permission": "사이트 정보를 변경할 권한이 없습니다.", - - "error.structure.validation": "{index}번째 필드({field})에 오류가 있습니다.", - - "error.template.default.notFound": "기본 템플릿이 없습니다.", - - "error.unexpected": "오류가 발생했습니다. 디버그 모드를 활성화해 오류를 확인하세요. https://getkirby.com/docs/reference/system/options/debug", - - "error.user.changeEmail.permission": "사용자({name})의 이메일 주소를 변경할 권한이 없습니다.", - "error.user.changeLanguage.permission": "사용자({name})의 언어를 변경할 권한이 없습니다.", - "error.user.changeName.permission": "사용자명({name})을 변경할 권한이 없습니다.", - "error.user.changePassword.permission": "사용자({name})의 암호를 변경할 권한이 없습니다.", - "error.user.changeRole.lastAdmin": "최종 관리자의 역할은 변경할 수 없습니다.", - "error.user.changeRole.permission": "사용자({name})의 역할을 변경할 권한이 없습니다.", - "error.user.changeRole.toAdmin": "다른 사용자를 관리자로 지정할 권한이 없습니다.", - "error.user.create.permission": "사용자를 등록할 권한이 없습니다.", - "error.user.delete": "사용자({name})를 삭제할 수 없습니다.", - "error.user.delete.lastAdmin": "\ucd5c\uc885 \uad00\ub9ac\uc790\ub294 \uc0ad\uc81c\ud560 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4.", - "error.user.delete.lastUser": "최종 사용자는 삭제할 수 없습니다.", - "error.user.delete.permission": "사용자({name})를 삭제할 권한이 없습니다.", - "error.user.duplicate": "이메일 주소({email})가 같은 사용자가 있습니다.", - "error.user.email.invalid": "올바른 이메일 주소를 입력하세요.", - "error.user.language.invalid": "올바른 언어를 입력하세요.", - "error.user.notFound": "사용자({name})가 없습니다.", - "error.user.password.excessive": "올바른 암호를 입력하세요. 암호는 1,000자를 넘을 수 없습니다.", - "error.user.password.invalid": "암호를 8자 이상으로 설정하세요.", - "error.user.password.notSame": "\uc554\ud638\ub97c \ud655\uc778\ud558\uc138\uc694.", - "error.user.password.undefined": "암호가 설정되지 않았습니다.", - "error.user.password.wrong": "암호가 올바르지 않습니다.", - "error.user.role.invalid": "올바른 역할을 지정하세요.", - "error.user.undefined": "사용자가 없습니다.", - "error.user.update.permission": "사용자({name})의 정보를 변경할 권한이 없습니다.", - - "error.validation.accepted": "확인하세요.", - "error.validation.alpha": "로마자(a~z)만 입력할 수 있습니다.", - "error.validation.alphanum": "로마자(a~z) 또는 숫자(0~9)만 입력할 수 있습니다.", - "error.validation.anchor": "올바른 링크를 입력하세요.", - "error.validation.between": "{min}, {max} 사이의 값을 입력하세요.", - "error.validation.boolean": "확인하거나 취소하세요.", - "error.validation.color": "색상 값은 {format} 형식으로 입력하세요.", - "error.validation.contains": "{needle}에 포함된 값을 입력하세요.", - "error.validation.date": "올바른 날짜를 입력하세요.", - "error.validation.date.after": "{date} 이후 날짜를 입력하세요.", - "error.validation.date.before": "{date} 이전 날짜를 입력하세요.", - "error.validation.date.between": "{min}, {max} 사이의 날짜를 입력하세요.", - "error.validation.denied": "취소하세요.", - "error.validation.different": "{other}에 포함된 값은 입력할 수 없습니다.", - "error.validation.email": "올바른 이메일 주소를 입력하세요.", - "error.validation.endswith": "값은 다음({end})으로 끝나야 합니다.", - "error.validation.filename": "올바른 파일명을 입력하세요.", - "error.validation.in": "{in} 중 하나를 입력하세요.", - "error.validation.integer": "올바른 정수를 입력하세요.", - "error.validation.ip": "올바른 IP 주소를 입력하세요.", - "error.validation.less": "{max} 미만의 값을 입력하세요.", - "error.validation.linkType": "이 형식의 링크는 입력할 수 없습니다.", - "error.validation.match": "입력한 값이 예상 패턴과 일치하지 않습니다.", - "error.validation.max": "{max} 이하의 값을 입력하세요.", - "error.validation.maxlength": "{max}자 이하의 값을 입력하세요.", - "error.validation.maxwords": "{max}자 이하를 입력하세요.", - "error.validation.min": "{min} 이상의 값을 입력하세요.", - "error.validation.minlength": "{min}자 이상의 값을 입력하세요.", - "error.validation.minwords": "{min}자 이상을 입력하세요.", - "error.validation.more": "{min} 이상의 값을 입력하세요.", - "error.validation.notcontains": "{needle}에 포함된 값은 입력할 수 없습니다.", - "error.validation.notin": "{notIn}에 포함된 값은 입력할 수 없습니다.", - "error.validation.option": "올바른 옵션을 선택하세요.", - "error.validation.num": "올바른 숫자를 입력하세요.", - "error.validation.required": "해당 항목을 확인하세요.", - "error.validation.same": "이 값({other})을 입력하세요.", - "error.validation.size": "값의 크기({size})를 확인하세요. ", - "error.validation.startswith": "값은 다음({start})으로 시작해야 합니다.", - "error.validation.tel": "숫자만 입력하세요.", - "error.validation.time": "올바른 시각을 입력하세요.", - "error.validation.time.after": "{time} 이후 시각을 입력하세요.", - "error.validation.time.before": "{time} 이전 시각을 입력하세요.", - "error.validation.time.between": "{min}, {max} 사이의 시각을 입력하세요.", - "error.validation.uuid": "올바른 UUID를 입력하세요.", - "error.validation.url": "올바른 URL을 입력하세요.", - - "expand": "열기", - "expand.all": "모두 열기", - - "field.invalid": "필드가 올바르지 않습니다.", - "field.required": "필드를 채우세요.", - "field.blocks.changeType": "유형 변경", - "field.blocks.code.name": "코드", - "field.blocks.code.language": "언어", - "field.blocks.code.placeholder": "코드", - "field.blocks.delete.confirm": "블록을 삭제할까요?", - "field.blocks.delete.confirm.all": "모든 블록을 삭제할까요?", - "field.blocks.delete.confirm.selected": "선택한 블록을 삭제할까요?", - "field.blocks.empty": "블록이 없습니다.", - "field.blocks.fieldsets.empty": "필드셋이 없습니다.", - "field.blocks.fieldsets.label": "블록 유형을 선택하세요.", - "field.blocks.fieldsets.paste": "{{ shortcut }}를 눌러 클립보드에서 레이아웃 또는 블록을 가져옵니다. 현재 필드에서 허용된 것만 삽입됩니다.", - "field.blocks.gallery.name": "갤러리", - "field.blocks.gallery.images.empty": "이미지가 없습니다.", - "field.blocks.gallery.images.label": "이미지", - "field.blocks.heading.level": "단계", - "field.blocks.heading.name": "제목", - "field.blocks.heading.text": "제목", - "field.blocks.heading.placeholder": "제목", - "field.blocks.image.alt": "대체 텍스트", - "field.blocks.image.caption": "캡션", - "field.blocks.image.crop": "자르기", - "field.blocks.image.link": "링크", - "field.blocks.image.location": "위치", - "field.blocks.image.location.internal": "이 웹사이트", - "field.blocks.image.location.external": "외부 소스", - "field.blocks.image.name": "이미지", - "field.blocks.image.placeholder": "이미지 선택", - "field.blocks.image.ratio": "비율", - "field.blocks.image.url": "이미지 URL", - "field.blocks.line.name": "가로줄", - "field.blocks.list.name": "목록", - "field.blocks.markdown.name": "마크다운", - "field.blocks.markdown.label": "마크다운", - "field.blocks.markdown.placeholder": "마크다운", - "field.blocks.quote.name": "인용문", - "field.blocks.quote.text.label": "인용문", - "field.blocks.quote.text.placeholder": "인용문", - "field.blocks.quote.citation.label": "출처", - "field.blocks.quote.citation.placeholder": "출처", - "field.blocks.text.name": "텍스트", - "field.blocks.text.placeholder": "텍스트", - "field.blocks.video.autoplay": "자동 재생", - "field.blocks.video.caption": "캡션", - "field.blocks.video.controls": "제어 도구", - "field.blocks.video.location": "위치", - "field.blocks.video.loop": "반복", - "field.blocks.video.muted": "음소거", - "field.blocks.video.name": "영상", - "field.blocks.video.placeholder": "영상 URL 입력", - "field.blocks.video.poster": "대표 이미지", - "field.blocks.video.preload": "미리 로드", - "field.blocks.video.url.label": "영상 URL", - "field.blocks.video.url.placeholder": "https://youtube.com/?v=", - - "field.files.empty": "선택한 파일이 없습니다.", - - "field.layout.change": "레이아웃 변경", - "field.layout.delete": "레이아웃 삭제", - "field.layout.delete.confirm": "레이아웃을 삭제할까요?", - "field.layout.delete.confirm.all": "모든 레이아웃을 삭제할까요?", - "field.layout.empty": "행이 없습니다.", - "field.layout.select": "레이아웃 선택", - - "field.object.empty": "정보가 없습니다.", - - "field.pages.empty": "선택한 페이지가 없습니다.", - - "field.structure.delete.confirm": "이 항목을 삭제할까요?", - "field.structure.delete.confirm.all": "모든 항목을 삭제할까요?", - "field.structure.empty": "항목이 없습니다.", - - "field.users.empty": "선택한 사용자가 없습니다.", - - "fields.empty": "필드가 없습니다.", - - "file": "파일", - "file.blueprint": "블루프린트(/site/blueprints/files/{blueprint}.yml)를 설정하세요.", - "file.changeTemplate": "템플릿 변경", - "file.changeTemplate.notice": "템플릿을 변경하면 유형이 일치하지 않은 필드에 입력한 콘텐츠가 삭제됩니다. 템플릿에서 이미지 크기 등 특정 규칙이 지정된 경우 해당 규칙을 되돌릴 수 없습니다.", - "file.delete.confirm": "파일({filename})을 삭제할까요?", - "file.focus.placeholder": "초점 설정", - "file.focus.reset": "초점 삭제", - "file.focus.title": "초점", - "file.sort": "순서 변경", - - "files": "파일", - "files.empty": "파일이 없습니다.", - - "filter": "필터", - - "hide": "숨기기", - "hour": "시", - "hue": "색상", - "import": "가져오기", - "info": "정보", - "insert": "\uc0bd\uc785", - "insert.after": "뒤에 삽입", - "insert.before": "앞에 삽입", - "install": "설치", - - "installation": "설치", - "installation.completed": "패널을 설치했습니다.", - "installation.disabled": "패널 설치 관리자는 로컬 서버에서 실행하거나 panel.install 옵션을 설정하세요.", - "installation.issues.accounts": "/site/accounts 폴더의 쓰기 권한을 확인하세요.", - "installation.issues.content": "/content 폴더의 쓰기 권한을 확인하세요.", - "installation.issues.curl": "cURL 확장 모듈이 필요합니다.", - "installation.issues.headline": "패널을 설치할 수 없습니다.", - "installation.issues.mbstring": "MB String 확장 모듈이 필요합니다.", - "installation.issues.media": "/media 폴더의 쓰기 권한을 확인하세요.", - "installation.issues.php": "PHP 버전이 8 이상인지 확인하세요.", - "installation.issues.sessions": "/site/sessions 폴더의 쓰기 권한을 확인하세요.", - - "language": "\uc5b8\uc5b4", - "language.code": "언어 코드", - "language.convert": "기본 언어로 지정", - "language.convert.confirm": "이 언어({name})를 기본 언어로 지정할까요? 지정한 뒤에는 복원할 수 없으며, 이 언어로 번역되지 않은 항목은 올바르게 표시되지 않을 수 있습니다.", - "language.create": "새 언어 추가", - "language.default": "기본 언어", - "language.delete.confirm": "언어({name})를 삭제할까요? 삭제한 뒤에는 복원할 수 없습니다.", - "language.deleted": "언어를 삭제했습니다.", - "language.direction": "읽기 방향", - "language.direction.ltr": "왼쪽에서 오른쪽", - "language.direction.rtl": "오른쪽에서 왼쪽", - "language.locale": "PHP 로캘 문자열", - "language.locale.warning": "사용자 지정 로캘을 사용 중입니다. /site/languages 폴더의 언어 파일을 수정하세요.", - "language.name": "언어명", - "language.secondary": "보조 언어", - "language.settings": "언어 설정", - "language.updated": "언어를 변경했습니다.", - "language.variables": "언어 변수", - "language.variables.empty": "번역이 없습니다.", - - "language.variable.delete.confirm": "변수({key})를 삭제할까요?", - "language.variable.key": "키", - "language.variable.notFound": "변수를 찾을 수 없습니다.", - "language.variable.value": "값", - - "languages": "언어", - "languages.default": "기본 언어", - "languages.empty": "언어가 없습니다.", - "languages.secondary": "보조 언어", - "languages.secondary.empty": "보조 언어가 없습니다.", - - "license": "라이선스", - "license.activate": "지금 활성화하세요.", - "license.activate.label": "라이선스를 활성화하세요.", - "license.activate.domain": "{host}에 대한 라이선스를 활성화합니다.", - "license.activate.local": "로컬 도메인({host})에 대한 라이선스를 활성화합니다. 현재 도메인({host})이 라이선스를 사용하려는 도메인인과 같다면 계속 진행하세요.", - "license.activated": "활성화됨", - "license.buy": "라이선스 구매", - "license.code": "언어 코드", - "license.code.help": "이메일로 전송된 라이선스 코드를 복사해 붙여넣으세요.", - "license.code.label": "라이선스 코드를 입력하세요.", - "license.status.active.info": "새로운 메이저 버전은 {date}까지 포함됩니다.", - "license.status.active.label": "유효한 라이선스", - "license.status.demo.info": "데모를 설치합니다.", - "license.status.demo.label": "데모", - "license.status.inactive.info": "새로운 메이저 버전으로 업데이트하려면 라이선스를 갱신하세요.", - "license.status.inactive.label": "새로운 메이저 버전이 없습니다.", - "license.status.legacy.bubble": "라이선스를 갱신합니다.", - "license.status.legacy.info": "라이선스가 이 버전을 지원하지 않습니다.", - "license.status.legacy.label": "라이선스를 갱신하세요.", - "license.status.missing.bubble": "사이트를 공개합니다.", - "license.status.missing.info": "유효한 라이선스가 없습니다.", - "license.status.missing.label": "라이선스를 활성화하세요.", - "license.manage": "라이선스 관리", - "license.purchased": "구입했습니다.", - "license.success": "Kirby와 함께해주셔서 감사합니다.", - "license.unregistered.label": "Kirby가 등록되지 않았습니다.", - - "link": "\uc77c\ubc18 \ub9c1\ud06c", - "link.text": "\ubb38\uc790", - - "loading": "로딩 중…", - - "lock.unsaved": "저장되지 않은 항목이 있습니다.", - "lock.unsaved.empty": "모든 페이지를 저장했습니다.", - "lock.isLocked": "사용자({email})의 변경 사항이 저장되지 않았습니다.", - "lock.unlock": "잠금 해제", - "lock.unlock.submit": "사용자({email})의 저장되지 않은 변경 사항을 해제하고 덮어쓰기", - "lock.isUnlocked": "다른 사용자가 잠금을 해제했습니다.", - - "login": "로그인", - "login.code.label.login": "로그인 코드", - "login.code.label.password-reset": "암호 초기화 코드", - "login.code.placeholder.email": "000 000", - "login.code.placeholder.totp": "000000", - "login.code.text.email": "입력한 이메일 주소로 코드를 전송했습니다.", - "login.code.text.totp": "인증 앱에서 생성된 일회용 코드를 입력하세요.", - "login.email.login.body": "{user.nameOrEmail} 님,\n\n{site} 패널에서 요청한 로그인 코드는 다음과 같습니다. 로그인 코드는 {timeout}분 동안 유효합니다.\n\n{code}\n\n로그인 코드를 요청한 적이 없다면, 이 이메일을 무시하거나 관리자에게 문의하세요. 보안을 위해 이 이메일은 다른 사람과 공유하지 마세요.", - "login.email.login.subject": "로그인 코드", - "login.email.password-reset.body": "{user.nameOrEmail} 님,\n\n{site} 패널에서 요청한 암호 초기화 코드는 다음과 같습니다. 암호 초기화 코드는 {timeout}분 동안 유효합니다.\n\n{code}\n\n암호 초기화 코드를 요청한 적이 없다면, 이 이메일을 무시하거나 관리자에게 문의하세요. 보안을 위해 이 이메일은 다른 사람과 공유하지 마세요.", - "login.email.password-reset.subject": "암호 초기화 코드", - "login.remember": "로그인 유지", - "login.reset": "암호 초기화", - "login.toggleText.code.email": "이메일 주소로 로그인", - "login.toggleText.code.email-password": "암호로 로그인", - "login.toggleText.password-reset.email": "암호 찾기", - "login.toggleText.password-reset.email-password": "로그인 화면으로", - "login.totp.enable.option": "일회용 코드 설정", - "login.totp.enable.intro": "인증 앱은 계정에 로그인하기 위한 일회용 코드를 생성할 수 있습니다.", - "login.totp.enable.qr.label": "1. 이 QR 코드를 스캔하세요.", - "login.totp.enable.qr.help": "스캔할 수 없다면 인증 앱에 {secret} 설정 키를 수동으로 추가하세요.", - "login.totp.enable.confirm.headline": "2. 생성된 코드로 확인하세요.", - "login.totp.enable.confirm.text": "앱은 매 30초마다 새로운 일회용 코드를 생성합니다. 설정을 완료하기 위해 현재 코드를 입력하세요.", - "login.totp.enable.confirm.label": "현재 코드", - "login.totp.enable.confirm.help": "로그인할 때마다 일회용 코드를 요청합니다.", - "login.totp.enable.success": "일회용 코드가 활성화되었습니다.", - "login.totp.disable.option": "일회용 코드 비활성화", - "login.totp.disable.label": "비밀번호를 입력해 일회용 코드를 비활성화하세요.", - "login.totp.disable.help": "이후 로그인할 때 이메일로 발송된 로그인 코드와 같은 다른 두 번째 인증 요소를 요청합니다. 언제든 일회용 코드를 나중에 다시 설정할 수 있습니다.", - "login.totp.disable.admin": "사용자({user})의 일회용 코드를 비활성화합니다. 사용자({user})가 로그인할 때 이메일로 전송된 로그인 코드와 같은 다른 두 번째 인증 요소가 요청됩니다. 사용자({user})는 다음 로그인 후에 다시 일회용 코드를 설정할 수 있습니다.", - "login.totp.disable.success": "일회용 코드가 비활성화되었습니다.", - - "logout": "로그아웃", - - "merge": "합치기", - "menu": "메뉴", - "meridiem": "오전/오후", - "mime": "MIME 형식", - "minutes": "분", - - "month": "월", - "months.april": "4\uc6d4", - "months.august": "8\uc6d4", - "months.december": "12\uc6d4", - "months.february": "2월", - "months.january": "1\uc6d4", - "months.july": "7\uc6d4", - "months.june": "6\uc6d4", - "months.march": "3\uc6d4", - "months.may": "5\uc6d4", - "months.november": "11\uc6d4", - "months.october": "10\uc6d4", - "months.september": "9\uc6d4", - - "more": "더 보기", - "move": "이동", - "name": "이름", - "next": "다음", - "night": "밤", - "no": "아니요", - "off": "끔", - "on": "켬", - "open": "열기", - "open.newWindow": "새 창에서 열기", - "option": "옵션", - "options": "옵션", - "options.none": "옵션이 없습니다.", - "options.all": "모든 옵션({count}) 표시", - - "orientation": "비율", - "orientation.landscape": "가로로 긴 사각형", - "orientation.portrait": "세로로 긴 사각형", - "orientation.square": "정사각형", - - "page": "페이지", - "page.blueprint": "블루프린트(/site/blueprints/pages/{blueprint}.yml)를 설정하세요.", - "page.changeSlug": "고유 주소 변경", - "page.changeSlug.fromTitle": "제목에서 가져오기", - "page.changeStatus": "상태 변경", - "page.changeStatus.position": "순서를 지정하세요.", - "page.changeStatus.select": "새 상태 선택", - "page.changeTemplate": "템플릿 변경", - "page.changeTemplate.notice": "템플릿을 변경하면 유형이 일치하지 않은 필드에 입력한 콘텐츠가 삭제됩니다.", - "page.create": "해당 상태({status})로 생성", - "page.delete.confirm": "페이지({title})를 삭제할까요?", - "page.delete.confirm.subpages": "페이지에 하위 페이지가 있습니다. 모든 하위 페이지가 삭제됩니다.", - "page.delete.confirm.title": "페이지 제목을 입력하세요.", - "page.duplicate.appendix": "복사", - "page.duplicate.files": "파일 복사", - "page.duplicate.pages": "페이지 복사", - "page.move": "페이지 이동", - "page.sort": "순서 변경", - "page.status": "상태", - "page.status.draft": "초안", - "page.status.draft.description": "로그인한 사용자나 URL을 통해 접근할 수 있습니다.", - "page.status.listed": "공개", - "page.status.listed.description": "누구나 읽을 수 있습니다.", - "page.status.unlisted": "비공개", - "page.status.unlisted.description": "오직 URL을 통해 접근할 수 있습니다.", - - "pages": "페이지", - "pages.empty": "페이지가 없습니다.", - "pages.status.draft": "초안", - "pages.status.listed": "발행", - "pages.status.unlisted": "비공개", - - "pagination.page": "페이지", - - "password": "\uc554\ud638", - "paste": "붙여넣기", - "paste.after": "뒤로 붙여넣기", - "paste.success": "붙여넣었습니다. ({count})", - "pixel": "픽셀", - "plugin": "플러그인", - "plugins": "플러그인", - "prev": "이전", - "preview": "미리 보기", - "remove": "삭제", - "rename": "이름 변경", - "renew": "갱신", - "replace": "\uad50\uccb4", - "replace.with": "다음으로 교체", - "retry": "\ub2e4\uc2dc \uc2dc\ub3c4", - "revert": "복원", - "revert.confirm": "저장되지 않은 내용을 삭제할까요?", - - "role": "역할", - "role.admin.description": "관리자는 모든 권한이 있습니다.", - "role.admin.title": "관리자", - "role.all": "전체", - "role.empty": "이 역할에 해당하는 사용자가 없습니다.", - "role.description.placeholder": "설명이 없습니다.", - "role.nobody.description": "대체 사용자는 아무 권한이 없습니다.", - "role.nobody.title": "사용자가 없습니다.", - - "save": "\uc800\uc7a5", - "search": "검색", - "search.min": "{min}자 이상 입력하세요.", - "search.all": "모든 결과({count}) 보기", - "search.results.none": "해당하는 결과가 없습니다.", - - "section.invalid": "섹션이 올바르지 않습니다.", - "section.required": "섹션이 필요합니다.", - - "security": "보안", - "select": "선택", - "server": "서버", - "settings": "설정", - "show": "보기", - "site.blueprint": "블루프린트(/site/blueprints/site.yml)를 설정하세요.", - "size": "크기", - "slug": "고유 주소", - "sort": "정렬", - "sort.drag": "Drag to sort …", - "split": "나누기", - - "stats.empty": "관련 기록이 없습니다.", - "status": "상태", - - "system.info.copy": "Copy info", - "system.info.copied": "System info copied", - "system.issues.content": "/content 폴더의 권한을 확인하세요.", - "system.issues.eol.kirby": "설치된 Kirby 버전이 만료되었습니다. 더 이상 보안 업데이트를 받을 수 없습니다.", - "system.issues.eol.plugin": "설치된 플러그인({plugin}의 지원이 종료되었습니다. 더 이상 보안 업데이트를 받을 수 없습니다.", - "system.issues.eol.php": "설치된 PHP 버전({release})이 만료되었습니다. 더 이상 보안 업데이트를 받을 수 없습니다.", - "system.issues.debug": "공개 서버상에서는 디버그 모드를 해제하세요.", - "system.issues.git": "/.git 폴더의 권한을 확인하세요.", - "system.issues.https": "HTTPS를 권장합니다.", - "system.issues.kirby": "/kirby 폴더의 권한을 확인하세요.", - "system.issues.site": "/site 폴더의 권한을 확인하세요.", - "system.issues.vulnerability.kirby": "설치한 시스템에 취약점이 있습니다.\n심각도: {severity}\n{description}", - "system.issues.vulnerability.plugin": "설치한 플러그인({plugin})에 취약점이 있습니다.\n심각도: {severity}\n{ description }", - "system.updateStatus": "업데이트 상태", - "system.updateStatus.error": "업데이트를 확인할 수 없습니다.", - "system.updateStatus.not-vulnerable": "알려진 취약성이 없습니다.", - "system.updateStatus.security-update": "{ version } 버전으로 무료 보안 업데이트", - "system.updateStatus.security-upgrade": "{ version } 버전으로 보안 업그레이드", - "system.updateStatus.unreleased": "출시 전 버전", - "system.updateStatus.up-to-date": "최신 버전입니다.", - "system.updateStatus.update": "{ version } 버전으로 무료 업데이트", - "system.updateStatus.upgrade": "{ version } 버전으로 업그레이드", - - "tel": "Phone", - "tel.placeholder": "+49123456789", - "template": "\ud15c\ud50c\ub9bf", - "title": "제목", - "today": "오늘", - - "toolbar.button.clear": "서식 제거", - "toolbar.button.code": "코드", - "toolbar.button.bold": "강조", - "toolbar.button.email": "이메일 주소", - "toolbar.button.headings": "제목", - "toolbar.button.heading.1": "제목 1", - "toolbar.button.heading.2": "제목 2", - "toolbar.button.heading.3": "제목 3", - "toolbar.button.heading.4": "제목 4", - "toolbar.button.heading.5": "제목 5", - "toolbar.button.heading.6": "제목 6", - "toolbar.button.italic": "강조 2", - "toolbar.button.file": "파일", - "toolbar.button.file.select": "파일 선택", - "toolbar.button.file.upload": "파일 업로드", - "toolbar.button.link": "링크", - "toolbar.button.paragraph": "문단", - "toolbar.button.strike": "취소선", - "toolbar.button.sub": "아래 첨자", - "toolbar.button.sup": "위 첨자", - "toolbar.button.ol": "숫자 목록", - "toolbar.button.underline": "밑줄", - "toolbar.button.ul": "기호 목록", - - "translation.author": "Kirby 팀", - "translation.direction": "ltr", - "translation.name": "한국어", - "translation.locale": "ko_KR", - - "type": "유형", - - "upload": "업로드", - "upload.error.cantMove": "파일을 이동할 수 없습니다.", - "upload.error.cantWrite": "디스크를 읽을 수 없습니다.", - "upload.error.default": "파일을 업로드할 수 없습니다.", - "upload.error.extension": "파일 확장자를 확인하세요.", - "upload.error.formSize": "업로드한 파일이 허용된 크기(MAX_FILE_SIZE)를 초과했습니다.", - "upload.error.iniPostSize": "업로드한 파일이 PHP 환경 설정 파일(php.ini)에서 허용된 크기(post_max_size)를 초과했습니다.", - "upload.error.iniSize": "업로드한 파일이 PHP 환경 설정 파일(php.ini)에서 허용된 크기(upload_max_filesize)를 초과했습니다.", - "upload.error.noFile": "업로드한 파일이 없습니다.", - "upload.error.noFiles": "업로드한 파일이 없습니다.", - "upload.error.partial": "일부 파일을 업로드했습니다.", - "upload.error.tmpDir": "임시 폴더가 없습니다.", - "upload.errors": "오류", - "upload.progress": "업로드 중…", - - "url": "URL", - "url.placeholder": "https://example.com", - - "user": "사용자", - "user.blueprint": "블루프린트(/site/blueprints/users/{blueprint}.yml)에 섹션과 필드를 추가할 수 있습니다.", - "user.changeEmail": "이메일 주소 변경", - "user.changeLanguage": "언어 변경", - "user.changeName": "사용자명 변경", - "user.changePassword": "암호 변경", - "user.changePassword.new": "새 암호", - "user.changePassword.new.confirm": "새 암호 확인", - "user.changeRole": "역할 변경", - "user.changeRole.select": "새 역할 선택", - "user.create": "사용자 추가", - "user.delete": "사용자 삭제", - "user.delete.confirm": "사용자({email})를 삭제할까요?", - - "users": "사용자", - - "version": "버전", - "version.current": "현재 버전", - "version.latest": "최신 버전", - "versionInformation": "버전 정보", - - "view.account": "계정", - "view.installation": "\uc124\uce58", - "view.languages": "언어", - "view.resetPassword": "암호 초기화", - "view.site": "사이트", - "view.system": "시스템", - "view.users": "\uc0ac\uc6a9\uc790", - - "welcome": "반갑습니다.", - "year": "년", - "yes": "네" + "account.changeName": "이름 변경", + "account.delete": "계정 삭제", + "account.delete.confirm": "계정을 삭제할까요? 계정을 삭제한 뒤에는 복구할 수 없습니다.", + + "add": "\ucd94\uac00", + "author": "저자", + "avatar": "프로필 이미지", + "back": "뒤로", + "cancel": "\ucde8\uc18c", + "change": "\ubcc0\uacbd", + "close": "\ub2eb\uae30", + "confirm": "확인", + "collapse": "접기", + "collapse.all": "모두 접기", + "copy": "복사", + "copy.all": "모두 복사", + "create": "등록", + + "date": "날짜", + "date.select": "날짜 지정", + + "day": "일", + "days.fri": "\uae08", + "days.mon": "\uc6d4", + "days.sat": "\ud1a0", + "days.sun": "\uc77c", + "days.thu": "\ubaa9", + "days.tue": "\ud654", + "days.wed": "\uc218", + + "debugging": "디버그", + + "delete": "\uc0ad\uc81c", + "delete.all": "모두 삭제", + + "dialog.files.empty": "선택할 파일이 없습니다.", + "dialog.pages.empty": "선택할 페이지가 없습니다.", + "dialog.users.empty": "선택할 사용자가 없습니다.", + + "dimensions": "크기", + "disabled": "비활성화", + "discard": "무시", + "download": "다운로드", + "duplicate": "복제", + + "edit": "\ud3b8\uc9d1", + + "email": "\uc774\uba54\uc77c \uc8fc\uc18c", + "email.placeholder": "mail@example.com", + + "entries": "항목", + "entry": "항목", + + "environment": "구동 환경", + + "error.access.code": "코드가 올바르지 않습니다.", + "error.access.login": "로그인할 수 없습니다.", + "error.access.panel": "패널에 접근할 권한이 없습니다.", + "error.access.view": "패널에 접근할 권한이 없습니다.", + + "error.avatar.create.fail": "프로필 이미지를 업로드할 수 없습니다.", + "error.avatar.delete.fail": "\ud504\ub85c\ud544 \uc774\ubbf8\uc9c0\ub97c \uc0ad\uc81c\ud560 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4.", + "error.avatar.dimensions.invalid": "프로필 이미지의 너비와 높이를 3,000픽셀 이하로 설정하세요.", + "error.avatar.mime.forbidden": "프로필 이미지의 확장자(JPG, JPEG, PNG)를 확인하세요.", + + "error.blueprint.notFound": "블루프린트({name})를 불러올 수 없습니다.", + + "error.blocks.max.plural": "블록을 {max}개 이상 추가할 수 없습니다.", + "error.blocks.max.singular": "블록을 하나 이상 추가할 수 없습니다.", + "error.blocks.min.plural": "블록을 {min}개 이상 추가하세요.", + "error.blocks.min.singular": "블록을 하나 이상 추가하세요.", + "error.blocks.validation": "블록({index})이 올바르지 않습니다.", + + "error.email.preset.notFound": "기본 이메일 주소({name})가 없습니다.", + + "error.field.converter.invalid": "컨버터({converter})가 올바르지 않습니다.", + + "error.file.changeName.empty": "이름을 입력하세요.", + "error.file.changeName.permission": "파일명({filename})을 변경할 권한이 없습니다.", + "error.file.duplicate": "파일명이 같은 파일({filename})이 있습니다.", + "error.file.extension.forbidden": "이 확장자({extension})는 업로드할 수 없습니다.", + "error.file.extension.invalid": "확장자({extension})가 올바르지 않습니다.", + "error.file.extension.missing": "파일({filename})에 확장자가 없습니다.", + "error.file.maxheight": "이미지의 높이는 {height}픽셀을 초과할 수 없습니다.", + "error.file.maxsize": "파일이 너무 큽니다.", + "error.file.maxwidth": "이미지의 너비는 {width}픽셀을 초과할 수 없습니다.", + "error.file.mime.differs": "기존 파일과 MIME 형식({mime})이 다릅니다.", + "error.file.mime.forbidden": "이 MIME 형식({mime})은 업로드할 수 없습니다.", + "error.file.mime.invalid": "MIME 형식({mime})이 올바르지 않습니다.", + "error.file.mime.missing": "파일({filename})의 MIME 형식을 확인할 수 없습니다.", + "error.file.minheight": "이미지의 높이를 {height}픽셀 이상으로 설정하세요.", + "error.file.minsize": "파일이 너무 작습니다.", + "error.file.minwidth": "이미지의 너비를 {width}픽셀 이상으로 설정하세요.", + "error.file.name.missing": "파일명을 입력하세요.", + "error.file.notFound": "파일({filename})이 없습니다.", + "error.file.orientation": "이미지의 비율({orientation})을 확인하세요.", + "error.file.type.forbidden": "이 형식({type})의 파일을 업로드할 권한이 없습니다.", + "error.file.type.invalid": "파일의 형식({type})이 올바르지 않습니다.", + "error.file.undefined": "\ud30c\uc77c\uc774 \uc5c6\uc2b5\ub2c8\ub2e4.", + + "error.form.incomplete": "항목에 오류가 있습니다.", + "error.form.notSaved": "항목을 저장할 수 없습니다.", + + "error.language.code": "올바른 언어 코드를 입력하세요.", + "error.language.duplicate": "이미 등록한 언어입니다.", + "error.language.name": "올바른 언어명을 입력하세요.", + "error.language.notFound": "언어를 찾을 수 없습니다.", + + "error.layout.validation.block": "레이아웃({layoutIndex})의 블록({blockIndex})을 확인하세요.", + "error.layout.validation.settings": "레이아웃({index})의 옵션을 확인하세요.", + + "error.license.format": "올바른 라이선스 키를 입력하세요.", + "error.license.email": "올바른 이메일 주소를 입력하세요.", + "error.license.verification": "라이선스 키가 올바르지 않습니다.", + + "error.offline": "패널이 오프라인 상태입니다.", + + "error.page.changeSlug.permission": "고유 주소({slug})를 변경할 권한이 없습니다.", + "error.page.changeStatus.incomplete": "페이지를 공개할 수 없습니다.", + "error.page.changeStatus.permission": "페이지의 상태를 변경할 수 없습니다.", + "error.page.changeStatus.toDraft.invalid": "페이지({slug})의 상태를 초안으로 변경할 수 없습니다.", + "error.page.changeTemplate.invalid": "페이지({slug})의 템플릿을 변경할 수 없습니다.", + "error.page.changeTemplate.permission": "페이지({slug})의 템플릿을 변경할 권한이 없습니다.", + "error.page.changeTitle.empty": "제목을 입력하세요.", + "error.page.changeTitle.permission": "페이지({slug})의 제목을 변경할 권한이 없습니다.", + "error.page.create.permission": "페이지({slug})를 등록할 권한이 없습니다.", + "error.page.delete": "페이지({slug})를 삭제할 수 없습니다.", + "error.page.delete.confirm": "페이지를 삭제하려면 페이지의 제목을 입력하세요.", + "error.page.delete.hasChildren": "하위 페이지가 있는 페이지는 삭제할 수 없습니다.", + "error.page.delete.permission": "페이지({slug})를 삭제할 권한이 없습니다.", + "error.page.draft.duplicate": "고유 주소({slug})가 같은 초안 페이지가 있습니다.", + "error.page.duplicate": "고유 주소({slug})가 같은 페이지가 있습니다.", + "error.page.duplicate.permission": "페이지({slug})를 복제할 권한이 없습니다.", + "error.page.notFound": "페이지({slug})가 없습니다.", + "error.page.num.invalid": "올바른 정수를 입력하세요.", + "error.page.slug.invalid": "올바른 URL을 입력하세요.", + "error.page.slug.maxlength": "고유 주소를 {length}자 이하로 입력하세요.", + "error.page.sort.permission": "페이지({slug})를 정렬할 수 없습니다.", + "error.page.status.invalid": "올바른 상태를 설정하세요.", + "error.page.undefined": "\ud398\uc774\uc9c0\uac00 \uc5c6\uc2b5\ub2c8\ub2e4.", + "error.page.update.permission": "페이지({slug})를 변경할 권한이 없습니다.", + + "error.section.files.max.plural": "이 섹션({section})에는 파일을 {max}개 이상 추가할 수 없습니다.", + "error.section.files.max.singular": "이 섹션({section})에는 파일을 하나 이상 추가할 수 없습니다.", + "error.section.files.min.plural": "이 섹션({section})에는 파일이 {min}개 이상 필요합니다.", + "error.section.files.min.singular": "이 섹션({section})에는 파일이 하나 이상 필요합니다.", + + "error.section.pages.max.plural": "이 섹션({section})에는 페이지를 {max}개 이상 추가할 수 없습니다.", + "error.section.pages.max.singular": "이 섹션({section})에는 페이지를 하나 이상 추가할 수 없습니다.", + "error.section.pages.min.plural": "이 섹션({section})에는 페이지가 {min}개 이상 필요합니다.", + "error.section.pages.min.singular": "이 섹션({section})에는 페이지가 하나 이상 필요합니다.", + + "error.section.notLoaded": "섹션({name})을 확인할 수 없습니다.", + "error.section.type.invalid": "섹션의 형식({type})이 올바르지 않습니다.", + + "error.site.changeTitle.empty": "제목을 입력하세요.", + "error.site.changeTitle.permission": "사이트명을 변경할 권한이 없습니다.", + "error.site.update.permission": "사이트의 정보를 변경할 권한이 없습니다.", + + "error.template.default.notFound": "기본 템플릿이 없습니다.", + + "error.unexpected": "오류가 발생했습니다. 디버그 모드를 활성화해 오류를 확인하세요. https://getkirby.com/docs/reference/system/options/debug", + + "error.user.changeEmail.permission": "사용자({name})의 이메일 주소를 변경할 권한이 없습니다.", + "error.user.changeLanguage.permission": "사용자({name})의 언어를 변경할 권한이 없습니다.", + "error.user.changeName.permission": "사용자명({name})을 변경할 권한이 없습니다.", + "error.user.changePassword.permission": "사용자({name})의 암호를 변경할 권한이 없습니다.", + "error.user.changeRole.lastAdmin": "최종 관리자의 역할은 변경할 수 없습니다.", + "error.user.changeRole.permission": "사용자({name})의 역할을 변경할 권한이 없습니다.", + "error.user.changeRole.toAdmin": "다른 사용자를 관리자로 지정할 권한이 없습니다.", + "error.user.create.permission": "사용자를 등록할 권한이 없습니다.", + "error.user.delete": "사용자({name})를 삭제할 수 없습니다.", + "error.user.delete.lastAdmin": "\ucd5c\uc885 \uad00\ub9ac\uc790\ub294 \uc0ad\uc81c\ud560 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4.", + "error.user.delete.lastUser": "최종 사용자는 삭제할 수 없습니다.", + "error.user.delete.permission": "사용자({name})를 삭제할 권한이 없습니다.", + "error.user.duplicate": "이메일 주소({email})가 같은 사용자가 있습니다.", + "error.user.email.invalid": "올바른 이메일 주소를 입력하세요.", + "error.user.language.invalid": "올바른 언어를 입력하세요.", + "error.user.notFound": "사용자({name})가 없습니다.", + "error.user.password.excessive": "Please enter a valid password. Passwords must not be longer than 1000 characters.", + "error.user.password.invalid": "암호를 8자 이상으로 설정하세요.", + "error.user.password.notSame": "\uc554\ud638\ub97c \ud655\uc778\ud558\uc138\uc694.", + "error.user.password.undefined": "암호가 설정되지 않았습니다.", + "error.user.password.wrong": "암호가 올바르지 않습니다.", + "error.user.role.invalid": "올바른 역할을 지정하세요.", + "error.user.undefined": "사용자가 없습니다.", + "error.user.update.permission": "사용자({name})의 정보를 변경할 권한이 없습니다.", + + "error.validation.accepted": "확인하세요.", + "error.validation.alpha": "로마자(a~z)만 입력할 수 있습니다.", + "error.validation.alphanum": "로마자(a~z) 또는 숫자(0~9)만 입력할 수 있습니다.", + "error.validation.between": "{min}, {max} 사이의 값을 입력하세요.", + "error.validation.boolean": "확인하거나 취소하세요.", + "error.validation.contains": "{needle}에 포함된 값을 입력하세요.", + "error.validation.date": "올바른 날짜를 입력하세요.", + "error.validation.date.after": "{date} 이후 날짜를 입력하세요.", + "error.validation.date.before": "{date} 이전 날짜를 입력하세요.", + "error.validation.date.between": "{min}, {max} 사이의 날짜를 입력하세요.", + "error.validation.denied": "취소하세요.", + "error.validation.different": "{other}에 포함된 값은 입력할 수 없습니다.", + "error.validation.email": "올바른 이메일 주소를 입력하세요.", + "error.validation.endswith": "값은 다음({end})으로 끝나야 합니다.", + "error.validation.filename": "올바른 파일명을 입력하세요.", + "error.validation.in": "{in} 중 하나를 입력하세요.", + "error.validation.integer": "올바른 정수를 입력하세요.", + "error.validation.ip": "올바른 IP 주소를 입력하세요.", + "error.validation.less": "{max} 미만의 값을 입력하세요.", + "error.validation.match": "입력한 값이 예상 패턴과 일치하지 않습니다.", + "error.validation.max": "{max} 이하의 값을 입력하세요.", + "error.validation.maxlength": "{max}자 이하의 값을 입력하세요.", + "error.validation.maxwords": "{max}자 이하를 입력하세요.", + "error.validation.min": "{min} 이상의 값을 입력하세요.", + "error.validation.minlength": "{min}자 이상의 값을 입력하세요.", + "error.validation.minwords": "{min}자 이상을 입력하세요.", + "error.validation.more": "{min} 이상의 값을 입력하세요.", + "error.validation.notcontains": "{needle}에 포함된 값은 입력할 수 없습니다.", + "error.validation.notin": "{notIn}에 포함된 값은 입력할 수 없습니다.", + "error.validation.option": "올바른 옵션을 선택하세요.", + "error.validation.num": "올바른 숫자를 입력하세요.", + "error.validation.required": "해당 항목을 확인하세요.", + "error.validation.same": "이 값({other})을 입력하세요.", + "error.validation.size": "값의 크기({size})를 확인하세요. ", + "error.validation.startswith": "값은 다음({start})으로 시작해야 합니다.", + "error.validation.time": "올바른 시각을 입력하세요.", + "error.validation.time.after": "{time} 이후 시각을 입력하세요.", + "error.validation.time.before": "{time} 이전 시각을 입력하세요.", + "error.validation.time.between": "{min}, {max} 사이의 시각을 입력하세요.", + "error.validation.url": "올바른 URL을 입력하세요.", + + "expand": "열기", + "expand.all": "모두 열기", + + "field.required": "필드를 채우세요.", + "field.blocks.changeType": "유형 변경", + "field.blocks.code.name": "코드", + "field.blocks.code.language": "언어", + "field.blocks.code.placeholder": "코드", + "field.blocks.delete.confirm": "블록을 삭제할까요?", + "field.blocks.delete.confirm.all": "모든 블록을 삭제할까요?", + "field.blocks.delete.confirm.selected": "선택한 블록을 삭제할까요?", + "field.blocks.empty": "블록이 없습니다.", + "field.blocks.fieldsets.label": "블록의 유형을 선택하세요.", + "field.blocks.fieldsets.paste": "단축키({{ shortcut }})로 클립보드에서 블록을 가져올 수 있습니다.", + "field.blocks.gallery.name": "갤러리", + "field.blocks.gallery.images.empty": "이미지가 없습니다.", + "field.blocks.gallery.images.label": "이미지", + "field.blocks.heading.level": "단계", + "field.blocks.heading.name": "제목", + "field.blocks.heading.text": "제목", + "field.blocks.heading.placeholder": "제목", + "field.blocks.image.alt": "대체 텍스트", + "field.blocks.image.caption": "캡션", + "field.blocks.image.crop": "자르기", + "field.blocks.image.link": "링크", + "field.blocks.image.location": "위치", + "field.blocks.image.name": "이미지", + "field.blocks.image.placeholder": "이미지 선택", + "field.blocks.image.ratio": "비율", + "field.blocks.image.url": "이미지 URL", + "field.blocks.line.name": "가로줄", + "field.blocks.list.name": "목록", + "field.blocks.markdown.name": "마크다운", + "field.blocks.markdown.label": "마크다운", + "field.blocks.markdown.placeholder": "마크다운", + "field.blocks.quote.name": "인용문", + "field.blocks.quote.text.label": "인용문", + "field.blocks.quote.text.placeholder": "인용문", + "field.blocks.quote.citation.label": "출처", + "field.blocks.quote.citation.placeholder": "출처", + "field.blocks.text.name": "텍스트", + "field.blocks.text.placeholder": "텍스트", + "field.blocks.video.caption": "캡션", + "field.blocks.video.name": "영상", + "field.blocks.video.placeholder": "영상 URL 입력", + "field.blocks.video.url.label": "영상 URL", + "field.blocks.video.url.placeholder": "https://youtube.com/?v=", + + "field.files.empty": "선택한 파일이 없습니다.", + + "field.layout.delete": "레이아웃 삭제", + "field.layout.delete.confirm": "레이아웃을 삭제할까요?", + "field.layout.empty": "행이 없습니다.", + "field.layout.select": "레이아웃 선택", + + "field.pages.empty": "선택한 페이지가 없습니다.", + "field.structure.delete.confirm": "이 항목을 삭제할까요?", + "field.structure.empty": "항목이 없습니다.", + "field.users.empty": "선택한 사용자가 없습니다.", + + "file.blueprint": "블루프린트(/site/blueprints/files/{blueprint}.yml)를 설정하세요.", + "file.delete.confirm": "파일({filename})을 삭제할까요?", + "file.sort": "순서 변경", + + "files": "파일", + "files.empty": "파일이 없습니다.", + + "hide": "숨기기", + "hour": "시", + "import": "가져오기", + "info": "정보", + "insert": "\uc0bd\uc785", + "insert.after": "뒤에 삽입", + "insert.before": "앞에 삽입", + "install": "설치", + + "installation": "설치", + "installation.completed": "패널을 설치했습니다.", + "installation.disabled": "패널 설치 관리자는 로컬 서버에서 실행하거나 panel.install 옵션을 설정하세요.", + "installation.issues.accounts": "/site/accounts 폴더의 쓰기 권한을 확인하세요.", + "installation.issues.content": "/content 폴더의 쓰기 권한을 확인하세요.", + "installation.issues.curl": "cURL 확장 모듈이 필요합니다.", + "installation.issues.headline": "패널을 설치할 수 없습니다.", + "installation.issues.mbstring": "MB String 확장 모듈이 필요합니다.", + "installation.issues.media": "/media 폴더의 쓰기 권한을 확인하세요.", + "installation.issues.php": "PHP 버전이 7 이상인지 확인하세요.", + "installation.issues.server": "Kirby를 실행하려면 Apache, Nginx, 또는 Caddy가 필요합니다.", + "installation.issues.sessions": "/site/sessions 폴더의 쓰기 권한을 확인하세요.", + + "language": "\uc5b8\uc5b4", + "language.code": "언어 코드", + "language.convert": "기본 언어로 지정", + "language.convert.confirm": "이 언어({name})를 기본 언어로 지정할까요? 지정한 뒤에는 복원할 수 없으며, 이 언어로 번역되지 않은 항목은 올바르게 표시되지 않을 수 있습니다.", + "language.create": "새 언어 추가", + "language.delete.confirm": "언어({name})를 삭제할까요? 삭제한 뒤에는 복원할 수 없습니다.", + "language.deleted": "언어를 삭제했습니다.", + "language.direction": "읽기 방향", + "language.direction.ltr": "왼쪽에서 오른쪽", + "language.direction.rtl": "오른쪽에서 왼쪽", + "language.locale": "PHP 로캘 문자열", + "language.locale.warning": "사용자 지정 로캘을 사용 중입니다. /site/languages 폴더의 언어 파일을 수정하세요.", + "language.name": "언어명", + "language.updated": "언어를 변경했습니다.", + + "languages": "언어", + "languages.default": "기본 언어", + "languages.empty": "언어가 없습니다.", + "languages.secondary": "보조 언어", + "languages.secondary.empty": "보조 언어가 없습니다.", + + "license": "라이선스", + "license.buy": "라이선스 구매", + "license.register": "등록", + "license.manage": "라이선스 관리", + "license.register.help": "Kirby를 등록하려면 이메일로 전송받은 라이선스 코드와 이메일 주소를 입력하세요.", + "license.register.label": "라이선스 코드를 입력하세요.", + "license.register.success": "Kirby와 함께해주셔서 감사합니다.", + "license.unregistered": "Kirby가 등록되지 않았습니다.", + "license.unregistered.label": "Kirby가 등록되지 않았습니다.", + + "link": "\uc77c\ubc18 \ub9c1\ud06c", + "link.text": "\ubb38\uc790", + + "loading": "로딩 중…", + + "lock.unsaved": "저장되지 않은 항목이 있습니다.", + "lock.unsaved.empty": "모든 페이지를 저장했습니다.", + "lock.isLocked": "다른 사용자({email})가 수정한 사항이 저장되지 않았습니다.", + "lock.file.isLocked": "파일을 편집할 수 없습니다. 다른 사용자({email})가 편집 중입니다.", + "lock.page.isLocked": "페이지를 편집할 수 없습니다. 다른 사용자({email})가 편집 중입니다.", + "lock.unlock": "잠금 해제", + "lock.isUnlocked": "다른 사용자가 이미 내용을 수정했으므로 현재 내용이 올바르게 저장되지 않았습니다. 저장되지 않은 내용은 다운로드해 수동으로 대치할 수 있습니다.", + + "login": "로그인", + "login.code.label.login": "로그인 코드", + "login.code.label.password-reset": "암호 초기화 코드", + "login.code.placeholder.email": "000 000", + "login.code.text.email": "입력한 이메일 주소로 코드를 전송했습니다.", + "login.email.login.body": "{user.nameOrEmail} 님,\n\n{site} 패널에서 요청한 로그인 코드는 다음과 같습니다. 로그인 코드는 {timeout}분 동안 유효합니다.\n\n{code}\n\n로그인 코드를 요청한 적이 없다면, 이 이메일을 무시하거나 관리자에게 문의하세요. 보안을 위해 이 이메일은 다른 사람과 공유하지 마세요.", + "login.email.login.subject": "로그인 코드", + "login.email.password-reset.body": "{user.nameOrEmail} 님,\n\n{site} 패널에서 요청한 암호 초기화 코드는 다음과 같습니다. 암호 초기화 코드는 {timeout}분 동안 유효합니다.\n\n{code}\n\n암호 초기화 코드를 요청한 적이 없다면, 이 이메일을 무시하거나 관리자에게 문의하세요. 보안을 위해 이 이메일은 다른 사람과 공유하지 마세요.", + "login.email.password-reset.subject": "암호 초기화 코드", + "login.remember": "로그인 유지", + "login.reset": "암호 초기화", + "login.toggleText.code.email": "이메일 주소로 로그인", + "login.toggleText.code.email-password": "암호로 로그인", + "login.toggleText.password-reset.email": "암호 찾기", + "login.toggleText.password-reset.email-password": "로그인 화면으로", + + "logout": "\ub85c\uadf8\uc544\uc6c3", + + "menu": "메뉴", + "meridiem": "오전/오후", + "mime": "MIME 형식", + "minutes": "분", + + "month": "월", + "months.april": "4\uc6d4", + "months.august": "8\uc6d4", + "months.december": "12\uc6d4", + "months.february": "2월", + "months.january": "1\uc6d4", + "months.july": "7\uc6d4", + "months.june": "6\uc6d4", + "months.march": "3\uc6d4", + "months.may": "5\uc6d4", + "months.november": "11\uc6d4", + "months.october": "10\uc6d4", + "months.september": "9\uc6d4", + + "more": "더 보기", + "name": "이름", + "next": "다음", + "no": "아니요", + "off": "끔", + "on": "켬", + "open": "열기", + "open.newWindow": "새 창에서 열기", + "options": "옵션", + "options.none": "옵션이 없습니다.", + + "orientation": "비율", + "orientation.landscape": "가로로 긴 사각형", + "orientation.portrait": "세로로 긴 사각형", + "orientation.square": "정사각형", + + "page.blueprint": "블루프린트(/site/blueprints/pages/{blueprint}.yml)를 설정하세요.", + "page.changeSlug": "고유 주소 변경", + "page.changeSlug.fromTitle": "제목에서 가져오기", + "page.changeStatus": "상태 변경", + "page.changeStatus.position": "순서를 지정하세요.", + "page.changeStatus.select": "새 상태 선택", + "page.changeTemplate": "템플릿 변경", + "page.delete.confirm": "페이지({title})를 삭제할까요?", + "page.delete.confirm.subpages": "페이지에 하위 페이지가 있습니다. 모든 하위 페이지가 삭제됩니다.", + "page.delete.confirm.title": "페이지의 제목을 입력하세요.", + "page.draft.create": "초안 등록", + "page.duplicate.appendix": "복사", + "page.duplicate.files": "파일 복사", + "page.duplicate.pages": "페이지 복사", + "page.sort": "순서 변경", + "page.status": "상태", + "page.status.draft": "초안", + "page.status.draft.description": "로그인한 사용자나 URL을 통해 접근할 수 있습니다.", + "page.status.listed": "공개", + "page.status.listed.description": "누구나 읽을 수 있습니다.", + "page.status.unlisted": "비공개", + "page.status.unlisted.description": "URL을 통해 접근할 수 있습니다.", + + "pages": "페이지", + "pages.empty": "페이지가 없습니다.", + "pages.status.draft": "초안", + "pages.status.listed": "발행", + "pages.status.unlisted": "비공개", + + "pagination.page": "페이지", + + "password": "\uc554\ud638", + "paste": "붙여넣기", + "paste.after": "뒤로 붙여넣기", + "pixel": "픽셀", + "plugins": "플러그인", + "prev": "이전", + "preview": "미리 보기", + "remove": "삭제", + "rename": "이름 변경", + "replace": "\uad50\uccb4", + "retry": "\ub2e4\uc2dc \uc2dc\ub3c4", + "revert": "복원", + "revert.confirm": "저장되지 않은 내용을 삭제할까요?", + + "role": "역할", + "role.admin.description": "관리자는 모든 권한이 있습니다.", + "role.admin.title": "관리자", + "role.all": "전체", + "role.empty": "이 역할에 해당하는 사용자가 없습니다.", + "role.description.placeholder": "설명이 없습니다.", + "role.nobody.description": "대체 사용자는 아무 권한이 없습니다.", + "role.nobody.title": "사용자가 없습니다.", + + "save": "\uc800\uc7a5", + "search": "검색", + "search.min": "{min}자 이상 입력하세요.", + "search.all": "모두 보기", + "search.results.none": "해당하는 결과가 없습니다.", + + "section.required": "섹션이 필요합니다.", + + "security": "보안", + "select": "선택", + "server": "서버", + "settings": "설정", + "show": "보기", + "site.blueprint": "블루프린트(/site/blueprints/site.yml)를 설정하세요.", + "size": "크기", + "slug": "고유 주소", + "sort": "정렬", + + "stats.empty": "관련 기록이 없습니다.", + "system.issues.content": "/content 폴더의 권한을 확인하세요.", + "system.issues.debug": "공개 서버상에서는 디버그 모드를 해제하세요.", + "system.issues.git": "/.git 폴더의 권한을 확인하세요.", + "system.issues.https": "HTTPS를 권장합니다.", + "system.issues.kirby": "/kirby 폴더의 권한을 확인하세요.", + "system.issues.site": "/site 폴더의 권한을 확인하세요.", + + "title": "제목", + "template": "\ud15c\ud50c\ub9bf", + "today": "오늘", + + "toolbar.button.code": "코드", + "toolbar.button.bold": "강조", + "toolbar.button.email": "이메일 주소", + "toolbar.button.headings": "제목", + "toolbar.button.heading.1": "제목 1", + "toolbar.button.heading.2": "제목 2", + "toolbar.button.heading.3": "제목 3", + "toolbar.button.heading.4": "제목 4", + "toolbar.button.heading.5": "제목 5", + "toolbar.button.heading.6": "제목 6", + "toolbar.button.italic": "강조 2", + "toolbar.button.file": "파일", + "toolbar.button.file.select": "파일 선택", + "toolbar.button.file.upload": "파일 업로드", + "toolbar.button.link": "링크", + "toolbar.button.paragraph": "문단", + "toolbar.button.strike": "취소선", + "toolbar.button.ol": "숫자 목록", + "toolbar.button.underline": "밑줄", + "toolbar.button.ul": "기호 목록", + + "translation.author": "Kirby 팀", + "translation.direction": "ltr", + "translation.name": "한국어", + "translation.locale": "ko_KR", + + "upload": "업로드", + "upload.error.cantMove": "파일을 이동할 수 없습니다.", + "upload.error.cantWrite": "디스크를 읽을 수 없습니다.", + "upload.error.default": "파일을 업로드할 수 없습니다.", + "upload.error.extension": "파일 확장자를 확인하세요.", + "upload.error.formSize": "업로드한 파일이 허용된 크기(MAX_FILE_SIZE)를 초과했습니다.", + "upload.error.iniPostSize": "업로드한 파일이 PHP 환경 설정 파일(php.ini)에서 허용된 크기(post_max_size)를 초과했습니다.", + "upload.error.iniSize": "업로드한 파일이 PHP 환경 설정 파일(php.ini)에서 허용된 크기(upload_max_filesize)를 초과했습니다.", + "upload.error.noFile": "업로드한 파일이 없습니다.", + "upload.error.noFiles": "업로드한 파일이 없습니다.", + "upload.error.partial": "일부 파일을 업로드했습니다.", + "upload.error.tmpDir": "임시 폴더가 없습니다.", + "upload.errors": "오류", + "upload.progress": "업로드 중…", + + "url": "URL", + "url.placeholder": "https://example.com", + + "user": "사용자", + "user.blueprint": "블루프린트(/site/blueprints/users/{blueprint}.yml)에 섹션과 필드를 추가할 수 있습니다.", + "user.changeEmail": "이메일 주소 변경", + "user.changeLanguage": "언어 변경", + "user.changeName": "사용자명 변경", + "user.changePassword": "암호 변경", + "user.changePassword.new": "새 암호", + "user.changePassword.new.confirm": "새 암호 확인", + "user.changeRole": "역할 변경", + "user.changeRole.select": "새 역할 선택", + "user.create": "사용자 추가", + "user.delete": "사용자 삭제", + "user.delete.confirm": "사용자({email})를 삭제할까요?", + + "users": "사용자", + + "version": "버전", + + "view.account": "계정", + "view.installation": "\uc124\uce58", + "view.languages": "언어", + "view.resetPassword": "암호 초기화", + "view.site": "사이트", + "view.system": "시스템", + "view.users": "\uc0ac\uc6a9\uc790", + + "welcome": "반갑습니다.", + "year": "년", + "yes": "네" } diff --git a/kirby/i18n/translations/lt.json b/kirby/i18n/translations/lt.json index 248c6ff..bace922 100644 --- a/kirby/i18n/translations/lt.json +++ b/kirby/i18n/translations/lt.json @@ -1,730 +1,574 @@ { - "account.changeName": "Pakeisti savo vardą", - "account.delete": "Panaikinti savo paskyrą", - "account.delete.confirm": "Ar tikrai norite panaikinti savo paskyrą? Jūs iš karto atsijungsite. Paskyros bus neįmanoma atstatyti.", - - "activate": "Aktyvuoti", - "add": "Pridėti", - "alpha": "Alpha", - "author": "Autorius", - "avatar": "Profilio nuotrauka", - "back": "Atgal", - "cancel": "Atšaukti", - "change": "Keisti", - "close": "Uždaryti", - "changes": "Changes", - "confirm": "Ok", - "collapse": "Sutraukti", - "collapse.all": "Sutraukti viską", - "color": "Color", - "coordinates": "Coordinates", - "copy": "Kopijuoti", - "copy.all": "Kopijuoti visus", - "copy.success": "{count} nukopijuota!", - "create": "Sukurti", - "custom": "Custom", - - "date": "Data", - "date.select": "Pasirinkite datą", - - "day": "Diena", - "days.fri": "Pen", - "days.mon": "Pir", - "days.sat": "Šeš", - "days.sun": "Sek", - "days.thu": "Ket", - "days.tue": "Ant", - "days.wed": "Tre", - - "debugging": "Debugging", - - "delete": "Pašalinti", - "delete.all": "Pašalinti viską", - - "dialog.fields.empty": "This dialog has no fields", - "dialog.files.empty": "Nėra failų pasirinkimui", - "dialog.pages.empty": "Nėra puslapių pasirinkimui", - "dialog.text.empty": "This dialog does not define any text", - "dialog.users.empty": "Nėra vartotojų pasirinkimui", - - "dimensions": "Išmatavimai", - "disable": "Išjungti", - "disabled": "Išjungta", - "discard": "Atšaukti", - - "drawer.fields.empty": "This drawer has no fields", - - "domain": "Domenas", - "download": "Parsisiųsti", - "duplicate": "Dublikuoti", - - "edit": "Redaguoti", - - "email": "El. paštas", - "email.placeholder": "info@pavyzdys.lt", - - "enter": "Enter", - "entries": "Įrašai", - "entry": "Įrašas", - - "environment": "Aplinka", - - "error": "Error", - "error.access.code": "Neteisinas kodas", - "error.access.login": "Neteisingas prisijungimo vardas", - "error.access.panel": "Neturite teisės prisijungti prie valdymo pulto", - "error.access.view": "Neturite teisės peržiūrėti šios valdymo pulto dalies", - - "error.avatar.create.fail": "Nepavyko įkelti profilio nuotraukos", - "error.avatar.delete.fail": "Nepavyko pašalinti profilio nuotraukos", - "error.avatar.dimensions.invalid": "Profilio nuotraukos plotis ar aukštis turėtų būti iki 3000 pikselių", - "error.avatar.mime.forbidden": "Profilio nuotrauka turi būti JPEG arba PNG", - - "error.blueprint.notFound": "Blueprint \"{name}\" negali būti užkrautas", - - "error.blocks.max.plural": "Didžiausias įmanomas blokų kiekis: {max}", - "error.blocks.max.singular": "Jūs galite pridėti daugiausiai vieną bloką", - "error.blocks.min.plural": "Minimalus blokų kiekis: {min}", - "error.blocks.min.singular": "Jūs turite pridėti bent vieną bloką", - "error.blocks.validation": "Yra klaida laukelyje \"{field}\" bloke {index} naudojant bloko tipą \"{fieldset}\"", - - "error.cache.type.invalid": "Invalid cache type \"{type}\"", - - "error.email.preset.notFound": "El. pašto paruoštukas \"{name}\" nerastas", - - "error.field.converter.invalid": "Neteisingas konverteris \"{converter}\"", - "error.field.type.missing": "Laukelis \"{ name }\": Šio tipo (\"{ type }\") laukelis neegzistuoja", - - "error.file.changeName.empty": "Pavadinimas negali būti tuščias", - "error.file.changeName.permission": "Neturite teisės pakeisti failo pavadinimo \"{filename}\"", - "error.file.changeTemplate.invalid": "The template for the file \"{id}\" cannot be changed to \"{template}\" (valid: \"{blueprints}\")", - "error.file.changeTemplate.permission": "You are not allowed to change the template for the file \"{id}\"", - - "error.file.duplicate": "Failas su pavadinimu \"{filename}\" jau yra", - "error.file.extension.forbidden": "Failo tipas (plėtinys) \"{extension}\" neleidžiamas", - "error.file.extension.invalid": "Neteisingas plėtinys: {extension}", - "error.file.extension.missing": "Failui \"{filename}\" trūksta tipo (plėtinio)", - "error.file.maxheight": "Failo aukštis neturi viršyti {height} px", - "error.file.maxsize": "Failas per didelis", - "error.file.maxwidth": "Failo plotis neturi viršyti {width} px", - "error.file.mime.differs": "Įkėliamas failas turi būti tokio pat mime tipo \"{mime}\"", - "error.file.mime.forbidden": "Media tipas \"{mime}\" neleidžiamas", - "error.file.mime.invalid": "Neteisingas mime tipas: {mime}", - "error.file.mime.missing": "Failui \"{filename}\" nepavyko atpažinti media (mime) tipo", - "error.file.minheight": "Failo aukštis turi būti bent {height} px", - "error.file.minsize": "Failas per mažas", - "error.file.minwidth": "Failo plotis turi būti bent {width} px", - "error.file.name.unique": "The filename must be unique", - "error.file.name.missing": "Failo pavadinimas negali būti tuščias", - "error.file.notFound": "Failas \"{filename}\" nerastas", - "error.file.orientation": "Failo orientacija turi būti \"{orientation}\"", - "error.file.type.forbidden": "Jūs neturite teisės įkelti {type} tipo failų", - "error.file.type.invalid": "Neteisingas failo tipas: {type}", - "error.file.undefined": "Failas nerastas", - - "error.form.incomplete": "🙏 Prašome ištaisyti visas formos klaidas…", - "error.form.notSaved": "Formos nepavyko išsaugoti", - - "error.language.code": "Prašome įrašyti teisingą kalbos kodą", - "error.language.duplicate": "Tokia kalba jau yra", - "error.language.name": "Prašome įrašyti teisingą kalbos pavadinimą", - "error.language.notFound": "Nepavyko rasti šios kalbos", - - "error.layout.validation.block": "There's an error on the \"{field}\" field in block {blockIndex} using the \"{fieldset}\" block type in layout {layoutIndex}", - "error.layout.validation.settings": "Yra klaida išdėstymo {index} nustatymuose", - - "error.license.domain": "Licencijai trūksta domeno", - "error.license.email": "Prašome įrašyti teisingą el. pašto adresą", - "error.license.format": "Prašome įrašyti teisingą licencijos kodą", - "error.license.verification": "Nepavyko patikrinti licenzijos", - - "error.login.totp.confirm.invalid": "Neteisinas kodas", - "error.login.totp.confirm.missing": "Prašome įrašyti kodą", - - "error.object.validation": "There’s an error in the \"{label}\" field:\n{message}", - - "error.offline": "Valdymo pultas dabar yra offline", - - "error.page.changeSlug.permission": "Neturite teisės pakeisti \"{slug}\" URL", - "error.page.changeSlug.reserved": "The path of top-level pages must not start with \"{path}\"", - "error.page.changeStatus.incomplete": "Puslapis turi klaidų ir negali būti paskelbtas", - "error.page.changeStatus.permission": "Šiam puslapiui negalima pakeisti statuso", - "error.page.changeStatus.toDraft.invalid": "Puslapio \"{slug}\" negalima paversti juodraščiu", - "error.page.changeTemplate.invalid": "Šablono puslapiui \"{slug}\" negalima keisti", - "error.page.changeTemplate.permission": "Neturite leidimo keisti šabloną puslapiui \"{slug}\"", - "error.page.changeTitle.empty": "Pavadinimas negali būti tuščias", - "error.page.changeTitle.permission": "Neturite leidimo keisti pavadinimo puslapiui \"{slug}\"", - "error.page.create.permission": "Neturite leidimo sukurti \"{slug}\"", - "error.page.delete": "Puslapio \"{slug}\" negalima pašalinti", - "error.page.delete.confirm": "Įrašykite puslapio pavadinimą, tam kad patvirtintumėte", - "error.page.delete.hasChildren": "Puslapis turi vidinių puslapių, dėl to negalima jo pašalinti", - "error.page.delete.permission": "Neturite leidimo šalinti \"{slug}\"", - "error.page.draft.duplicate": "Puslapio juodraštis su URL pabaiga \"{slug}\" jau yra", - "error.page.duplicate": "Puslapis su URL pabaiga \"{slug}\" jau yra", - "error.page.duplicate.permission": "Neturite leidimo dubliuoti \"{slug}\"", - "error.page.move.ancestor": "Puslapio negalima perkelti į save patį", - "error.page.move.directory": "The page directory cannot be moved", - "error.page.move.duplicate": "A sub page with the URL appendix \"{slug}\" already exists", - "error.page.move.notFound": "The moved page could not be found", - "error.page.move.permission": "You are not allowed to move \"{slug}\"", - "error.page.move.template": "The \"{template}\" template is not accepted as a subpage of \"{parent}\"", - "error.page.notFound": "Puslapis \"{slug}\" nerastas", - "error.page.num.invalid": "Įrašykite teisingą eiliškumo numerį. Numeris negali būti neigiamas.", - "error.page.slug.invalid": "Įrašykite teisingą URL priedą", - "error.page.slug.maxlength": "url adreso maksimalus simbolių kiekis: \"{length}\"", - "error.page.sort.permission": "Puslapiui \"{slug}\" negalima pakeisti eiliškumo", - "error.page.status.invalid": "Nustatykite teisingą puslapio statusą", - "error.page.undefined": "Puslapis nerastas", - "error.page.update.permission": "Neturite leidimo atnaujinti \"{slug}\"", - - "error.section.files.max.plural": "Į sekciją \"{section}\" negalima pridėti daugiau nei {max} failų", - "error.section.files.max.singular": "Į sekciją \"{section}\" negalima pridėti daugiau nei vieną failą", - "error.section.files.min.plural": "Sekcija \"{section}\" reikalauja bent {min} failų", - "error.section.files.min.singular": "Sekcija \"{section}\" reikalauja bent vieno failo", - - "error.section.pages.max.plural": "Į sekciją \"{section}\" negalima pridėti daugiau nei {max} puslapių", - "error.section.pages.max.singular": "Į sekciją \"{section}\" negalima pridėti daugiau nei vieną puslapį", - "error.section.pages.min.plural": "Sekcija \"{section}\" reikalauja bent {min} puslapių", - "error.section.pages.min.singular": "Sekcija \"{section}\" reikalauja bent vieno puslapio", - - "error.section.notLoaded": "Sekcija \"{name}\" negali būti užkrauta", - "error.section.type.invalid": "Sekcijos tipas \"{type}\" yra neteisingas", - - "error.site.changeTitle.empty": "Pavadinimas negali būti tuščias", - "error.site.changeTitle.permission": "Neturite leidimo keisti svetainės pavadinimo", - "error.site.update.permission": "Neturite leidimo atnaujinti svetainės", - - "error.structure.validation": "There's an error on the \"{field}\" field in row {index}", - - "error.template.default.notFound": "Nėra šablono pagal nutylėjimą", - - "error.unexpected": "An unexpected error occurred! Enable debug mode for more info: https://getkirby.com/docs/reference/system/options/debug", - - "error.user.changeEmail.permission": "Neturite leidimo keisti vartotojo \"{name}\" el. paštą", - "error.user.changeLanguage.permission": "Neturite leidimo keisti vartotojo \"{name}\" kalbą", - "error.user.changeName.permission": "Neturite leidimo keisti vartotojo \"{name}\" vardą", - "error.user.changePassword.permission": "Neturite leidimo keisti vartotojo \"{name}\" slaptažodį", - "error.user.changeRole.lastAdmin": "Vienintelio administratoriaus rolės negalima pakeisti", - "error.user.changeRole.permission": "Neturite leidimo pakeisti vartotojo \"{name}\" rolės", - "error.user.changeRole.toAdmin": "Jūs neturite teisių suteikti administratoriaus rolę", - "error.user.create.permission": "Neturite leidimo sukurti šį vartotoją", - "error.user.delete": "Vartotojo \"{name}\" negalima pašalinti", - "error.user.delete.lastAdmin": "Vienintelio administratoriaus negalima pašalinti", - "error.user.delete.lastUser": "Vienintelio vartotojo negalima pašalinti", - "error.user.delete.permission": "Neturite leidimo pašalinti vartotoją \"{name}\"", - "error.user.duplicate": "Vartotojas su el. paštu \"{email}\" jau yra", - "error.user.email.invalid": "Įrašykite teisingą el. pašto adresą", - "error.user.language.invalid": "Įrašykite teisingą kalbą", - "error.user.notFound": "Vartotojas \"{name}\" nerastas", - "error.user.password.excessive": "Please enter a valid password. Passwords must not be longer than 1000 characters.", - "error.user.password.invalid": "Prašome įrašyti galiojantį slaptažodį. Slaptažodį turi sudaryti bent 8 simboliai.", - "error.user.password.notSame": "Slaptažodžiai nesutampa", - "error.user.password.undefined": "Vartotojas neturi slaptažodžio", - "error.user.password.wrong": "Neteisingas slaptažodis", - "error.user.role.invalid": "Įrašykite teisingą rolę", - "error.user.undefined": "Vartotojas nerastas", - "error.user.update.permission": "Neturite teisės keisti vartotojo \"{name}\"", - - "error.validation.accepted": "Prašome patvirtinti", - "error.validation.alpha": "Prašome įrašyti tik raides a-z", - "error.validation.alphanum": "Prašome įrašyti tik raides a-z arba skaičius 0-9", - "error.validation.anchor": "Please enter a correct link anchor", - "error.validation.between": "Prašome įrašyti reikšmę tarp \"{min}\" ir \"{max}\"", - "error.validation.boolean": "Patvirtinkite arba atšaukite", - "error.validation.color": "Please enter a valid color in the {format} format", - "error.validation.contains": "Prašome įrašyti reikšmę, kuri turėtų \"{needle}\"", - "error.validation.date": "Prašome įrašyti korektišką datą", - "error.validation.date.after": "Įrašykite datą nuo {date}", - "error.validation.date.before": "Įrašykite datą iki {date}", - "error.validation.date.between": "Įrašykite datą tarp {min} ir {max}", - "error.validation.denied": "Prašome neleisti", - "error.validation.different": "Reikšmė neturi būti \"{other}\"", - "error.validation.email": "Prašome įrašyti korektišką el. paštą", - "error.validation.endswith": "Reikšmė turi baigtis su \"{end}\"", - "error.validation.filename": "Prašome įrašyti teisingą failo pavadinimą", - "error.validation.in": "Prašome įrašyti vieną iš šių: ({in})", - "error.validation.integer": "Prašome įrašyti teisingą sveiką skaičių", - "error.validation.ip": "Prašome įrašyti teisingą IP adresą", - "error.validation.less": "Prašome įrašyti mažiau nei {max}", - "error.validation.linkType": "The link type is not allowed", - "error.validation.match": "Reikšmė nesutampa su laukiamu šablonu", - "error.validation.max": "Prašome įrašyti reikšmę lygią arba didesnę, nei {max}", - "error.validation.maxlength": "Prašome įrašyti trumpesnę reikšmę. (max. {max} characters)", - "error.validation.maxwords": "Please enter no more than {max} word(s)", - "error.validation.min": "Please enter a value equal to or greater than {min}", - "error.validation.minlength": "Prašome įrašyti ilgesnę reikšmę. (min. {min} characters)", - "error.validation.minwords": "Prašome įrašyti bent {min} žodžius", - "error.validation.more": "Prašome įrašyti daugiau nei {min}", - "error.validation.notcontains": "Prašome įrašyti reikšmę, kuri neturi \"{needle}\"", - "error.validation.notin": "Prašome neįrašyti vieną iš šių: ({notIn})", - "error.validation.option": "Prašome pasirinkti korektišką opciją", - "error.validation.num": "Prašome įrašyti teisingą numerį", - "error.validation.required": "Prašome įrašyti ką nors", - "error.validation.same": "Prašome įrašyti \"{other}\"", - "error.validation.size": "Reikšmės dydis turi būti \"{size}\"", - "error.validation.startswith": "Reikšmė turi prasidėti su \"{start}\"", - "error.validation.tel": "Please enter an unformatted phone number", - "error.validation.time": "Prašome įrašyti korektišką laiką", - "error.validation.time.after": "Įrašykite laiką po {time}", - "error.validation.time.before": "Įrašykite laiką prieš {time}", - "error.validation.time.between": "Įrašykite laiką tarp {min} ir {max}", - "error.validation.uuid": "Please enter a valid UUID", - "error.validation.url": "Prašome įrašyti teisingą URL", - - "expand": "Išskleisti", - "expand.all": "Išskleisti viską", - - "field.invalid": "The field is invalid", - "field.required": "Laukas privalomas", - "field.blocks.changeType": "Pakeisti tipą", - "field.blocks.code.name": "Kodas", - "field.blocks.code.language": "Kalba", - "field.blocks.code.placeholder": "Jūsų kodas ...", - "field.blocks.delete.confirm": "Ar tikrai norite pašalinti šį bloką?", - "field.blocks.delete.confirm.all": "Ar tikrai norite pašalinti visus blokus?", - "field.blocks.delete.confirm.selected": "Ar tikrai norite pašalinti pasirinktus blokus?", - "field.blocks.empty": "Dar nėra blokų", - "field.blocks.fieldsets.empty": "No fieldsets yet", - "field.blocks.fieldsets.label": "Pasirinkite bloko tipą ...", - "field.blocks.fieldsets.paste": "Press {{ shortcut }} to import layouts/blocks from your clipboard Only those allowed in the current field will get inserted.", - "field.blocks.gallery.name": "Galerija", - "field.blocks.gallery.images.empty": "Dar nėra nuotraukų", - "field.blocks.gallery.images.label": "Nuotraukos", - "field.blocks.heading.level": "Lygis", - "field.blocks.heading.name": "Antraštė", - "field.blocks.heading.text": "Tekstas", - "field.blocks.heading.placeholder": "Antraštė ...", - "field.blocks.image.alt": "Alternatyvus tekstas", - "field.blocks.image.caption": "Aprašymas", - "field.blocks.image.crop": "Kirpti", - "field.blocks.image.link": "Nuoroda", - "field.blocks.image.location": "Šaltinis", - "field.blocks.image.location.internal": "This website", - "field.blocks.image.location.external": "External source", - "field.blocks.image.name": "Nuotrauka", - "field.blocks.image.placeholder": "Pasirinkite nuotrauką", - "field.blocks.image.ratio": "Proporcijos", - "field.blocks.image.url": "Nuotraukos URL", - "field.blocks.line.name": "Linija", - "field.blocks.list.name": "Sąrašas", - "field.blocks.markdown.name": "Markdown", - "field.blocks.markdown.label": "Tekstas", - "field.blocks.markdown.placeholder": "Markdown ...", - "field.blocks.quote.name": "Citata", - "field.blocks.quote.text.label": "Tekstas", - "field.blocks.quote.text.placeholder": "Citata ...", - "field.blocks.quote.citation.label": "Citatos turinys", - "field.blocks.quote.citation.placeholder": "autorius", - "field.blocks.text.name": "Tekstas", - "field.blocks.text.placeholder": "Tekstas ...", - "field.blocks.video.autoplay": "Autoplay", - "field.blocks.video.caption": "Aprašymas", - "field.blocks.video.controls": "Controls", - "field.blocks.video.location": "Šaltinis", - "field.blocks.video.loop": "Loop", - "field.blocks.video.muted": "Muted", - "field.blocks.video.name": "Video", - "field.blocks.video.placeholder": "Įrašykite video URL", - "field.blocks.video.poster": "Poster", - "field.blocks.video.preload": "Preload", - "field.blocks.video.url.label": "Video-URL", - "field.blocks.video.url.placeholder": "https://youtube.com/?v=", - - "field.files.empty": "Pasirinkti", - - "field.layout.change": "Change layout", - "field.layout.delete": "Pašalinti eilutę", - "field.layout.delete.confirm": "Ar tikrai norite pašalinti šią eilutę", - "field.layout.delete.confirm.all": "Do you really want to delete all layouts?", - "field.layout.empty": "Dar nėra eilučių", - "field.layout.select": "Pasirinkite išdėstymą", - - "field.object.empty": "Dar nėra informacijos", - - "field.pages.empty": "Dar nėra puslapių", - - "field.structure.delete.confirm": "Ar tikrai norite pašalinti šią eilutę?", - "field.structure.delete.confirm.all": "Ar tikrai norite išrtinti visus įrašus?", - "field.structure.empty": "Dar nėra įrašų", - - "field.users.empty": "Dar nėra vartotojų", - - "fields.empty": "No fields yet", - - "file": "Failas", - "file.blueprint": "Šis failas dar neturi blueprint. Galite nustatyti jį per /site/blueprints/files/{blueprint}.yml", - "file.changeTemplate": "Pakeisti šabloną", - "file.changeTemplate.notice": "Changing the file's template will remove content for fields that don't match in type. If the new template defines certain rules, e.g. image dimensions, those will also be applied irreversibly. Use with caution.", - "file.delete.confirm": "Ar tikrai norite pašalinti
{filename}?", - "file.focus.placeholder": "Set focal point", - "file.focus.reset": "Remove focal point", - "file.focus.title": "Focus", - "file.sort": "Pakeisti poziciją", - - "files": "Failai", - "files.empty": "Įkelti", - - "filter": "Filter", - - "hide": "Paslėpti", - "hour": "Valanda", - "hue": "Hue", - "import": "Importuoti", - "info": "Info", - "insert": "Įterpti", - "insert.after": "Įterpti po", - "insert.before": "Įterpti prieš", - "install": "Įdiegti", - - "installation": "Įdiegimas", - "installation.completed": "Valdymo pultas įdiegtas", - "installation.disabled": "Pagal nutylėjimą valdymo pulto įdiegimas viešuose serveriuose yra negalimas. Prašome įdiegti lokalioje aplinkoje arba įgalinkite jį su panel.install opcija.", - "installation.issues.accounts": "Katalogas /site/accounts neegzistuoja arba neturi įrašymo teisių", - "installation.issues.content": "Katalogas /content neegzistuoja arba neturi įrašymo teisių", - "installation.issues.curl": "Plėtinys CURL yra privalomas", - "installation.issues.headline": "Nepavyko įdiegti valdymo pulto", - "installation.issues.mbstring": "Plėtinys MB String yra privalomas", - "installation.issues.media": "Katalogas /media neegzistuoja arba neturi įrašymo teisių", - "installation.issues.php": "Įsitikinkite, kad naudojama PHP 8+", - "installation.issues.sessions": "Katalogas /site/sessions neegzistuoja arba neturi įrašymo teisių", - - "language": "Kalba", - "language.code": "Kodas", - "language.convert": "Padaryti pagrindinį", - "language.convert.confirm": "

Do you really want to convert {name} to the default language? This cannot be undone.

If {name} has untranslated content, there will no longer be a valid fallback and parts of your site might be empty.

", - "language.create": "Pridėti naują kalbą", - "language.default": "Pagrindinė kalba", - "language.delete.confirm": "Ar tikrai norite pašalinti {name} kalbą, kartu su visais vertimais? Grąžinti nebus įmanoma! 🙀", - "language.deleted": "Kalba pašalinta", - "language.direction": "Skaitymo kryptis", - "language.direction.ltr": "Iš kairės į dešinę", - "language.direction.rtl": "Iš dešinės į kairę", - "language.locale": "PHP locale string", - "language.locale.warning": "Jūs naudojate pasirinktinį lokalės nustatymą. Prašome pakeisti jį faile /site/languages", - "language.name": "Pavadinimas", - "language.secondary": "Secondary language", - "language.settings": "Language settings", - "language.updated": "Kalba atnaujinta", - "language.variables": "Language variables", - "language.variables.empty": "No translations yet", - - "language.variable.delete.confirm": "Do you really want to delete the variable for {key}?", - "language.variable.key": "Key", - "language.variable.notFound": "The variable could not be found", - "language.variable.value": "Value", - - "languages": "Kalbos", - "languages.default": "Pagrindinė kalba", - "languages.empty": "Dar nėra kalbų", - "languages.secondary": "Papildomos kalbos", - "languages.secondary.empty": "Dar nėra papildomų kalbų", - - "license": "Licenzija", - "license.activate": "Aktyvuoti dabar", - "license.activate.label": "Prašome aktyvuoti jūsų licenciją", - "license.activate.domain": "Jūsų licencija bus akvytuota šiam domenui: {host}", - "license.activate.local": "Jūs ruošiatės aktyvuoti jūsų Kirby licenciją vietiniam domenui {host}. Jei ši svetainė veiks su viešu domenu, aktyvuokite jį. Arba jei {host} yra tikrai tas domenas, kurį norite naudoti, galite tęsti.", - "license.activated": "Aktyvuota", - "license.buy": "Pirkti licenziją", - "license.code": "Kodas", - "license.code.help": "Jūs gavote licencijos kodą po pirkimo el. paštu. Nukopijuokite jį ir įterpkite čia.", - "license.code.label": "Prašome įrašyti jūsų licenzijos kodą", - "license.status.active.info": "Įeina naujos pagrindinės versijos iki {date}", - "license.status.active.label": "Galiojanti licencija", - "license.status.demo.info": "Tai demo versija", - "license.status.demo.label": "Demo", - "license.status.inactive.info": "Atnaujinkite licenciją, kad būtų galimybė atnaujinti iki naujų pagrindinių versijų", - "license.status.inactive.label": "Nėra naujų pagrindinių versijų", - "license.status.legacy.bubble": "Pasiruošę atnaujinti jūsų licenciją?", - "license.status.legacy.info": "Jūsų licencija negalioja šiai versijai", - "license.status.legacy.label": "Prašome atnaujinti jūsų licenciją", - "license.status.missing.bubble": "Pasiruošę paleisti naują svetainę?", - "license.status.missing.info": "Nėra galiojančios licencijos", - "license.status.missing.label": "Prašome aktyvuoti jūsų licenciją", - "license.manage": "Valdyti savo licencijas", - "license.purchased": "Nupirkta", - "license.success": "Ačiū, kad palaikote Kirby", - "license.unregistered.label": "Neregistruota", - - "link": "Nuoroda", - "link.text": "Nuorodos tekstas", - - "loading": "Kraunasi", - - "lock.unsaved": "Neišsaugoti pakeitimai", - "lock.unsaved.empty": "Nebeliko neišsaugotų pakeitimų", - "lock.isLocked": "Unsaved changes by {email}", - "lock.unlock": "Atrakinti", - "lock.unlock.submit": "Unlock and overwrite unsaved changes by {email}", - "lock.isUnlocked": "Was unlocked by another user", - - "login": "Prisijungti", - "login.code.label.login": "Prisijungimo kodas", - "login.code.label.password-reset": "Slaptažodžio atstatymo kodas", - "login.code.placeholder.email": "000 000", - "login.code.placeholder.totp": "000000", - "login.code.text.email": "Jei jūsų el. paštas yra užregistruotas, užklaistas kodas buvo išsiųstas el. paštu.", - "login.code.text.totp": "Prašome įrašyti vienkartinį kodą iš jūsų autentifikavimo programėlės.", - "login.email.login.body": "Sveiki, {user.nameOrEmail},\n\nNeseniai užklausėte prisijungimo kodo svetainėje {site}.\nŠis kodas galios {timeout} min.:\n\n{code}\n\nJei neprašėte šio kodo, tiesiog ignoruokite, arba susisiekite su administratoriumi.\nDėl saugumo, prašome NEPERSIŲSTI šio laiško.", - "login.email.login.subject": "Jūsų prisijungimo kodas", - "login.email.password-reset.body": "Sveiki, {user.nameOrEmail},\n\nNeseniai užklausėte naujo slaptažodžio kūrimo kodo svetainėje {site}.\nŠis kodas galios {timeout} min.:\n\n{code}\n\nJei neprašėte šio kodo, tiesiog ignoruokite, arba susisiekite su administratoriumi.\nDėl saugumo, prašome NEPERSIŲSTI šio laiško", - "login.email.password-reset.subject": "Jūsų slaptažodžio atstatymo kodas ", - "login.remember": "Likti prisijungus", - "login.reset": "Sukurti naują slaptažodį", - "login.toggleText.code.email": "Prisijungti su el. paštu", - "login.toggleText.code.email-password": "Prisijungti su slaptažodžiu", - "login.toggleText.password-reset.email": "Pamiršote slaptažodį?", - "login.toggleText.password-reset.email-password": "← Atgal į prisijungimą", - "login.totp.enable.option": "Nustatyti vienkartinius kodus", - "login.totp.enable.intro": "Autentifikavimo programėlės gali generuoti vienkartinius kodus, kurie bus naudojami kaip 2-factor prisijungiant prie svetainės.", - "login.totp.enable.qr.label": "1. Nuskenuokite šį QR kodą", - "login.totp.enable.qr.help": "Negalite nuskenuoti? Pridėkite raktą {secret} rankiniu būdu į savo autentifikavimo programėlę.", - "login.totp.enable.confirm.headline": "2. Patvirtinti su sugeneruotu kodu", - "login.totp.enable.confirm.text": "Jūsų programėlė generuoja naują vienkartinį kodą kas 30 sekundžių. Įrašykite dabartinį kodą, norėdami užbaigti:", - "login.totp.enable.confirm.label": "Dabartinis kodas", - "login.totp.enable.confirm.help": "Po šio nustatymo, iš jūsų bus prašomas vienkartinis kodas jungiantis kiekvieną kartą.", - "login.totp.enable.success": "Vienkartiniai kodai įjungti", - "login.totp.disable.option": "Išjungti vienkartinius kodus", - "login.totp.disable.label": "Įrašykite savo slaptažodį norėdami išjungti vienkartinius kodus", - "login.totp.disable.help": "Ateityje kitoks 2-factor bus prašomas prisijungiant, pvz. login kodas, siunčiamas el. paštu. Jūs galite visada nustatyti vienkartinius kodus vėl vėliau.", - "login.totp.disable.admin": "

Tai išjungs vienkartinius kodus vartotojui {user}. Ateityje kitoks 2-factor bus prašomas prisijungiant, pvz. login kodas, siunčiamas el. paštu. Jūs galite visada nustatyti vienkartinius kodus vėl vėliau. {user} galės nustatyti vienkartinius kodus, kai jungsis kitą kartą.", - "login.totp.disable.success": "Vienkartiniai kodai išjungti", - - "logout": "Atsijungti", - - "merge": "Merge", - "menu": "Meniu", - "meridiem": "AM/PM", - "mime": "Media Tipas", - "minutes": "Minutės", - - "month": "Mėnuo", - "months.april": "Balandis", - "months.august": "August", - "months.december": "Gruodis", - "months.february": "Vasaris", - "months.january": "Sausis", - "months.july": "Liepa", - "months.june": "Birželis", - "months.march": "Kovas", - "months.may": "Gegužė", - "months.november": "Lapkritis", - "months.october": "Spalis", - "months.september": "Rugsėjis", - - "more": "Daugiau", - "move": "Move", - "name": "Pavadinimas", - "next": "Toliau", - "night": "Night", - "no": "ne", - "off": "ne", - "on": "taip", - "open": "Atidaryti", - "open.newWindow": "Atidaryti naujame lange", - "option": "Option", - "options": "Pasirinkimai", - "options.none": "Nėra pasirinkimų", - "options.all": "Rodyti visas {count} opcijas", - - "orientation": "Orientacija", - "orientation.landscape": "Horizontali", - "orientation.portrait": "Portretas", - "orientation.square": "Kvadratas", - - "page": "Puslapis", - "page.blueprint": "Šis puslapis dar neturi blueprint. Galite jį nustatyti per /site/blueprints/pages/{blueprint}.yml", - "page.changeSlug": "Pakeisti URL", - "page.changeSlug.fromTitle": "Sukurti URL pagal pavadinimą", - "page.changeStatus": "Pakeisti statusą", - "page.changeStatus.position": "Pasirinkite poziciją", - "page.changeStatus.select": "Pasirinkite statusą", - "page.changeTemplate": "Pakeisti šabloną", - "page.changeTemplate.notice": "Changing the page's template will remove content for fields that don't match in type. Use with caution.", - "page.create": "Sukurti kaip {status}", - "page.delete.confirm": "🙀 Ar tikrai norite pašalinti puslapį {title}?", - "page.delete.confirm.subpages": "Šis puslapis turi sub-puslapių.
Visi sub-puslapiai taip pat bus pašalinti.", - "page.delete.confirm.title": "Įrašykite puslapio pavadinimą tam, kad patvirtinti", - "page.duplicate.appendix": "Kopijuoti", - "page.duplicate.files": "Kopijuoti failus", - "page.duplicate.pages": "Kopijuoti puslapius", - "page.move": "Perkelti puslapį", - "page.sort": "Pakeisti poziciją", - "page.status": "Statusas", - "page.status.draft": "Juodraštis", - "page.status.draft.description": "Šis puslapis yra juodraščio režime ir prieinamas tik redaktoriams arba per slaptą nuorodą", - "page.status.listed": "Paskelbtas", - "page.status.listed.description": "Matomas viešai visiems", - "page.status.unlisted": "Nerodomas", - "page.status.unlisted.description": "Rodomas viešai visiems, bet tik per URL", - - "pages": "Puslapiai", - "pages.empty": "Dar nėra puslapių", - "pages.status.draft": "Juodraščiai", - "pages.status.listed": "Paskelbti", - "pages.status.unlisted": "Nerodomi", - - "pagination.page": "Puslapis", - - "password": "Slaptažodis", - "paste": "Įterpti", - "paste.after": "Įterpti po", - "paste.success": "{count} pasted!", - "pixel": "Pikselis", - "plugin": "Įskiepas", - "plugins": "Įskiepai", - "prev": "Ankstesnis", - "preview": "Peržiūra", - "remove": "Pašalinti", - "rename": "Pervadinti", - "renew": "Atnaujinti", - "replace": "Apkeisti", - "replace.with": "Replace with", - "retry": "Bandyti dar", - "revert": "Grąžinti", - "revert.confirm": "Ar tikrai norite atšaukti visus neišsaugotus pakeitimus?", - - "role": "Rolė", - "role.admin.description": "Admin turi visas teises", - "role.admin.title": "Admin", - "role.all": "Visos", - "role.empty": "Nėra vartotojų su tokia role", - "role.description.placeholder": "Be aprašymo", - "role.nobody.description": "Ši rolė bus naudojama jei nenustatytos jokios teisės", - "role.nobody.title": "Niekas", - - "save": "Išsaugoti", - "search": "Ieškoti", - "search.min": "Minimalus simbolių kiekis paieškai: {min}", - "search.all": "Parodyti visus {count} rezultatus", - "search.results.none": "Nėra rezultatų", - - "section.invalid": "The section is invalid", - "section.required": "Sekcija privaloma", - - "security": "Saugumas", - "select": "Pasirinkti", - "server": "Serveris", - "settings": "Nustatymai", - "show": "Rodyti", - "site.blueprint": "Svetainė neturi blueprint. Jūs galite nustatyti jį /site/blueprints/site.yml", - "size": "Dydis", - "slug": "URL pabaiga", - "sort": "Rikiuoti", - "sort.drag": "Drag to sort …", - "split": "Split", - - "stats.empty": "Nėra pranešimų", - "status": "Statusas", - - "system.info.copy": "Copy info", - "system.info.copied": "System info copied", - "system.issues.content": "The content folder seems to be exposed", - "system.issues.eol.kirby": "Your installed Kirby version has reached end-of-life and will not receive further security updates", - "system.issues.eol.plugin": "Your installed version of the { plugin } plugin is has reached end-of-life and will not receive further security updates", - "system.issues.eol.php": "Jūsų PHP versija { release } pasiekė gyvenimo galą ir daugiau negaus saugumo atnaujinimų", - "system.issues.debug": "Debugging must be turned off in production", - "system.issues.git": "The .git folder seems to be exposed", - "system.issues.https": "Rekomenduojame HTTPS visoms svetainėms", - "system.issues.kirby": "The kirby folder seems to be exposed", - "system.issues.site": "The site folder seems to be exposed", - "system.issues.vulnerability.kirby": "Your installation might be affected by the following vulnerability ({ severity } severity): { description }", - "system.issues.vulnerability.plugin": "Your installation might be affected by the following vulnerability in the { plugin } plugin ({ severity } severity): { description }", - "system.updateStatus": "Atnaujinimų statusas", - "system.updateStatus.error": "Nepavyko patikrinti atnaujinimų", - "system.updateStatus.not-vulnerable": "Nėra žinomų saugumo spragų", - "system.updateStatus.security-update": "Prieinamas nemokamas saugumo atnaujinimas { version }", - "system.updateStatus.security-upgrade": "Prieinama nauja { version } versija su saugumo atnaujinimais", - "system.updateStatus.unreleased": "Neišleista versija", - "system.updateStatus.up-to-date": "Naujausia versija", - "system.updateStatus.update": "Prieinamas nemokamas atnaujinimas { version }", - "system.updateStatus.upgrade": "Prieinamas atnaujinimas { version }", - - "tel": "Phone", - "tel.placeholder": "+49123456789", - "template": "Puslapio šablonas", - "title": "Pavadinimas", - "today": "Šiandien", - - "toolbar.button.clear": "Clear formatting", - "toolbar.button.code": "Kodas", - "toolbar.button.bold": "Bold", - "toolbar.button.email": "El. paštas", - "toolbar.button.headings": "Antraštės", - "toolbar.button.heading.1": "Heading 1", - "toolbar.button.heading.2": "Heading 2", - "toolbar.button.heading.3": "Heading 3", - "toolbar.button.heading.4": "Antrašte 4", - "toolbar.button.heading.5": "Antrašte 5", - "toolbar.button.heading.6": "Antrašte 6", - "toolbar.button.italic": "Italic", - "toolbar.button.file": "Failas", - "toolbar.button.file.select": "Pasirinkite failą", - "toolbar.button.file.upload": "Įkelti failą", - "toolbar.button.link": "Nuoroda", - "toolbar.button.paragraph": "Paragrafas", - "toolbar.button.strike": "Perbraukimas", - "toolbar.button.sub": "Subscript", - "toolbar.button.sup": "Superscript", - "toolbar.button.ol": "Sąrašas su skaičiais", - "toolbar.button.underline": "Pabraukimas", - "toolbar.button.ul": "Sąrašas su taškais", - - "translation.author": "Roman U", - "translation.direction": "ltr", - "translation.name": "Lietuvių", - "translation.locale": "lt_LT", - - "type": "Type", - - "upload": "Įkelti", - "upload.error.cantMove": "Įkeltas failas negali būti perkeltas", - "upload.error.cantWrite": "Nepavyko įrašyti failo į diską", - "upload.error.default": "Nepavyko įkelti failo", - "upload.error.extension": "Neįmanoma įkelti tokio tipo failo", - "upload.error.formSize": "Įkeltas failas viršija MAX_FILE_SIZE nustatymą, kuris buvo nurodytas formoje", - "upload.error.iniPostSize": "Įkeliamas failas viršija post_max_size nustatymą iš php.ini", - "upload.error.iniSize": "Įkeltas failas viršija upload_max_filesize nustatymą faile php.ini", - "upload.error.noFile": "Failas nebuvo įkeltas", - "upload.error.noFiles": "Failai nebuvo įkelti", - "upload.error.partial": "Failas įkeltas tik iš dalies", - "upload.error.tmpDir": "Trūksta laikinojo katalogo", - "upload.errors": "Klaida", - "upload.progress": "Įkėlimas…", - - "url": "Url", - "url.placeholder": "https://example.com", - - "user": "Vartotojas", - "user.blueprint": "Galite nustatyti papildomas sekcijas ir formos laukelius šiam vartotojui per /site/blueprints/users/{blueprint}.yml", - "user.changeEmail": "Keisti el. paštą", - "user.changeLanguage": "Keisti kalbą", - "user.changeName": "Pervadinti vartotoją", - "user.changePassword": "Keisti slaptažodį", - "user.changePassword.new": "Naujas slaptažodis", - "user.changePassword.new.confirm": "Patvirtinti naują slaptažodį…", - "user.changeRole": "Keisti rolę", - "user.changeRole.select": "Pasirinkti naują rolę", - "user.create": "Pridėti naują vartotoją", - "user.delete": "Pašalinti šį vartotoją", - "user.delete.confirm": "Ar tikrai norite pašalinti vartotoją
{email}?", - - "users": "Vartotojai", - - "version": "Versija", - "version.current": "Dabartinė versija", - "version.latest": "Naujausia versija", - "versionInformation": "Versijos informacija", - - "view.account": "Jūsų paskyra", - "view.installation": "Installation", - "view.languages": "Kalbos", - "view.resetPassword": "Sukurti naują slaptažodį", - "view.site": "Svetainė", - "view.system": "Sistema", - "view.users": "Vartotojai", - - "welcome": "Sveiki", - "year": "Metai", - "yes": "taip" + "account.changeName": "Change your name", + "account.delete": "Delete your account", + "account.delete.confirm": "Do you really want to delete your account? You will be logged out immediately. Your account cannot be recovered.", + + "add": "Pridėti", + "author": "Author", + "avatar": "Profilio nuotrauka", + "back": "Atgal", + "cancel": "Atšaukti", + "change": "Keisti", + "close": "Uždaryti", + "confirm": "Ok", + "collapse": "Sutraukti", + "collapse.all": "Sutraukti viską", + "copy": "Kopijuoti", + "copy.all": "Kopijuoti visus", + "create": "Sukurti", + + "date": "Data", + "date.select": "Pasirinkite datą", + + "day": "Diena", + "days.fri": "Pen", + "days.mon": "Pir", + "days.sat": "Šeš", + "days.sun": "Sek", + "days.thu": "Ket", + "days.tue": "Ant", + "days.wed": "Tre", + + "debugging": "Debugging", + + "delete": "Pašalinti", + "delete.all": "Pašalinti viską", + + "dialog.files.empty": "Nėra failų pasirinkimui", + "dialog.pages.empty": "Nėra puslapių pasirinkimui", + "dialog.users.empty": "Nėra vartotojų pasirinkimui", + + "dimensions": "Išmatavimai", + "disabled": "Išjungta", + "discard": "Atšaukti", + "download": "Parsisiųsti", + "duplicate": "Dublikuoti", + + "edit": "Redaguoti", + + "email": "El. paštas", + "email.placeholder": "mail@example.com", + + "entries": "Entries", + "entry": "Entry", + + "environment": "Environment", + + "error.access.code": "Neteisinas kodas", + "error.access.login": "Neteisingas prisijungimo vardas", + "error.access.panel": "Neturite teisės prisijungti prie valdymo pulto", + "error.access.view": "Neturite teisės peržiūrėti šios valdymo pulto dalies", + + "error.avatar.create.fail": "Nepavyko įkelti profilio nuotraukos", + "error.avatar.delete.fail": "Nepavyko pašalinti profilio nuotraukos", + "error.avatar.dimensions.invalid": "Profilio nuotraukos plotis ar aukštis turėtų būti iki 3000 pikselių", + "error.avatar.mime.forbidden": "Profilio nuotrauka turi būti JPEG arba PNG", + + "error.blueprint.notFound": "Blueprint \"{name}\" negali būti užkrautas", + + "error.blocks.max.plural": "Didžiausias įmanomas blokų kiekis: {max}", + "error.blocks.max.singular": "Jūs galite pridėti daugiausiai vieną bloką", + "error.blocks.min.plural": "Minimalus blokų kiekis: {min}", + "error.blocks.min.singular": "Jūs turite pridėti bent vieną bloką", + "error.blocks.validation": "Bloke {index} yra klaida", + + "error.email.preset.notFound": "El. pašto paruoštukas \"{name}\" nerastas", + + "error.field.converter.invalid": "Neteisingas konverteris \"{converter}\"", + + "error.file.changeName.empty": "Pavadinimas negali būti tuščias", + "error.file.changeName.permission": "Neturite teisės pakeisti failo pavadinimo \"{filename}\"", + "error.file.duplicate": "Failas su pavadinimu \"{filename}\" jau yra", + "error.file.extension.forbidden": "Failo tipas (plėtinys) \"{extension}\" neleidžiamas", + "error.file.extension.invalid": "Neteisingas plėtinys: {extension}", + "error.file.extension.missing": "Failui \"{filename}\" trūksta tipo (plėtinio)", + "error.file.maxheight": "Failo aukštis neturi viršyti {height} px", + "error.file.maxsize": "Failas per didelis", + "error.file.maxwidth": "Failo plotis neturi viršyti {width} px", + "error.file.mime.differs": "Įkėliamas failas turi būti tokio pat mime tipo \"{mime}\"", + "error.file.mime.forbidden": "Media tipas \"{mime}\" neleidžiamas", + "error.file.mime.invalid": "Neteisingas mime tipas: {mime}", + "error.file.mime.missing": "Failui \"{filename}\" nepavyko atpažinti media (mime) tipo", + "error.file.minheight": "Failo aukštis turi būti bent {height} px", + "error.file.minsize": "Failas per mažas", + "error.file.minwidth": "Failo plotis turi būti bent {width} px", + "error.file.name.missing": "Failo pavadinimas negali būti tuščias", + "error.file.notFound": "Failas \"{filename}\" nerastas", + "error.file.orientation": "Failo orientacija turi būti \"{orientation}\"", + "error.file.type.forbidden": "Jūs neturite teisės įkelti {type} tipo failų", + "error.file.type.invalid": "Neteisingas failo tipas: {type}", + "error.file.undefined": "Failas nerastas", + + "error.form.incomplete": "🙏 Prašome ištaisyti visas formos klaidas…", + "error.form.notSaved": "Formos nepavyko išsaugoti", + + "error.language.code": "Prašome įrašyti teisingą kalbos kodą", + "error.language.duplicate": "Tokia kalba jau yra", + "error.language.name": "Prašome įrašyti teisingą kalbos pavadinimą", + "error.language.notFound": "Nepavyko rasti šios kalbos", + + "error.layout.validation.block": "Yra klaida bloke {blockIndex} išdėstyme {layoutIndex}", + "error.layout.validation.settings": "Yra klaida išdėstymo {index} nustatymuose", + + "error.license.format": "Prašome įrašyti teisingą licenzijos kodą", + "error.license.email": "Prašome įrašyti teisingą el. pašto adresą", + "error.license.verification": "Nepavyko patikrinti licenzijos", + + "error.offline": "The Panel is currently offline", + + "error.page.changeSlug.permission": "Neturite teisės pakeisti \"{slug}\" URL", + "error.page.changeStatus.incomplete": "Puslapis turi klaidų ir negali būti paskelbtas", + "error.page.changeStatus.permission": "Šiam puslapiui negalima pakeisti statuso", + "error.page.changeStatus.toDraft.invalid": "Puslapio \"{slug}\" negalima paversti juodraščiu", + "error.page.changeTemplate.invalid": "Šablono puslapiui \"{slug}\" negalima keisti", + "error.page.changeTemplate.permission": "Neturite leidimo keisti šabloną puslapiui \"{slug}\"", + "error.page.changeTitle.empty": "Pavadinimas negali būti tuščias", + "error.page.changeTitle.permission": "Neturite leidimo keisti pavadinimo puslapiui \"{slug}\"", + "error.page.create.permission": "Neturite leidimo sukurti \"{slug}\"", + "error.page.delete": "Puslapio \"{slug}\" negalima pašalinti", + "error.page.delete.confirm": "Įrašykite puslapio pavadinimą, tam kad patvirtintumėte", + "error.page.delete.hasChildren": "Puslapis turi vidinių puslapių, dėl to negalima jo pašalinti", + "error.page.delete.permission": "Neturite leidimo šalinti \"{slug}\"", + "error.page.draft.duplicate": "Puslapio juodraštis su URL pabaiga \"{slug}\" jau yra", + "error.page.duplicate": "Puslapis su URL pabaiga \"{slug}\" jau yra", + "error.page.duplicate.permission": "Neturite leidimo dubliuoti \"{slug}\"", + "error.page.notFound": "Puslapis \"{slug}\" nerastas", + "error.page.num.invalid": "Įrašykite teisingą eiliškumo numerį. Numeris negali būti neigiamas.", + "error.page.slug.invalid": "Įrašykite teisingą URL priedą", + "error.page.slug.maxlength": "url adreso maksimalus simbolių kiekis: \"{length}\"", + "error.page.sort.permission": "Puslapiui \"{slug}\" negalima pakeisti eiliškumo", + "error.page.status.invalid": "Nustatykite teisingą puslapio statusą", + "error.page.undefined": "Puslapis nerastas", + "error.page.update.permission": "Neturite leidimo atnaujinti \"{slug}\"", + + "error.section.files.max.plural": "Į sekciją \"{section}\" negalima pridėti daugiau nei {max} failų", + "error.section.files.max.singular": "Į sekciją \"{section}\" negalima pridėti daugiau nei vieną failą", + "error.section.files.min.plural": "Sekcija \"{section}\" reikalauja bent {min} failų", + "error.section.files.min.singular": "Sekcija \"{section}\" reikalauja bent vieno failo", + + "error.section.pages.max.plural": "Į sekciją \"{section}\" negalima pridėti daugiau nei {max} puslapių", + "error.section.pages.max.singular": "Į sekciją \"{section}\" negalima pridėti daugiau nei vieną puslapį", + "error.section.pages.min.plural": "Sekcija \"{section}\" reikalauja bent {min} puslapių", + "error.section.pages.min.singular": "Sekcija \"{section}\" reikalauja bent vieno puslapio", + + "error.section.notLoaded": "Sekcija \"{name}\" negali būti užkrauta", + "error.section.type.invalid": "Sekcijos tipas \"{type}\" yra neteisingas", + + "error.site.changeTitle.empty": "Pavadinimas negali būti tuščias", + "error.site.changeTitle.permission": "Neturite leidimo keisti svetainės pavadinimo", + "error.site.update.permission": "Neturite leidimo atnaujinti svetainės", + + "error.template.default.notFound": "Nėra šablono pagal nutylėjimą", + + "error.unexpected": "An unexpected error occurred! Enable debug mode for more info: https://getkirby.com/docs/reference/system/options/debug", + + "error.user.changeEmail.permission": "Neturite leidimo keisti vartotojo \"{name}\" el. paštą", + "error.user.changeLanguage.permission": "Neturite leidimo keisti vartotojo \"{name}\" kalbą", + "error.user.changeName.permission": "Neturite leidimo keisti vartotojo \"{name}\" vardą", + "error.user.changePassword.permission": "Neturite leidimo keisti vartotojo \"{name}\" slaptažodį", + "error.user.changeRole.lastAdmin": "Vienintelio administratoriaus rolės negalima pakeisti", + "error.user.changeRole.permission": "Neturite leidimo pakeisti vartotojo \"{name}\" rolės", + "error.user.changeRole.toAdmin": "Jūs neturite teisių suteikti administratoriaus rolę", + "error.user.create.permission": "Neturite leidimo sukurti šį vartotoją", + "error.user.delete": "Vartotojo \"{name}\" negalima pašalinti", + "error.user.delete.lastAdmin": "Vienintelio administratoriaus negalima pašalinti", + "error.user.delete.lastUser": "Vienintelio vartotojo negalima pašalinti", + "error.user.delete.permission": "Neturite leidimo pašalinti vartotoją \"{name}\"", + "error.user.duplicate": "Vartotojas su el. paštu \"{email}\" jau yra", + "error.user.email.invalid": "Įrašykite teisingą el. pašto adresą", + "error.user.language.invalid": "Įrašykite teisingą kalbą", + "error.user.notFound": "Vartotojas \"{name}\" nerastas", + "error.user.password.excessive": "Please enter a valid password. Passwords must not be longer than 1000 characters.", + "error.user.password.invalid": "Prašome įrašyti galiojantį slaptažodį. Slaptažodį turi sudaryti bent 8 simboliai.", + "error.user.password.notSame": "Slaptažodžiai nesutampa", + "error.user.password.undefined": "Vartotojas neturi slaptažodžio", + "error.user.password.wrong": "Neteisingas slaptažodis", + "error.user.role.invalid": "Įrašykite teisingą rolę", + "error.user.undefined": "Vartotojas nerastas", + "error.user.update.permission": "Neturite teisės keisti vartotojo \"{name}\"", + + "error.validation.accepted": "Prašome patvirtinti", + "error.validation.alpha": "Prašome įrašyti tik raides a-z", + "error.validation.alphanum": "Prašome įrašyti tik raides a-z arba skaičius 0-9", + "error.validation.between": "Prašome įrašyti reikšmę tarp \"{min}\" ir \"{max}\"", + "error.validation.boolean": "Patvirtinkite arba atšaukite", + "error.validation.contains": "Prašome įrašyti reikšmę, kuri turėtų \"{needle}\"", + "error.validation.date": "Prašome įrašyti korektišką datą", + "error.validation.date.after": "Įrašykite datą nuo {date}", + "error.validation.date.before": "Įrašykite datą iki {date}", + "error.validation.date.between": "Įrašykite datą tarp {min} ir {max}", + "error.validation.denied": "Prašome neleisti", + "error.validation.different": "Reikšmė neturi būti \"{other}\"", + "error.validation.email": "Prašome įrašyti korektišką el. paštą", + "error.validation.endswith": "Reikšmė turi baigtis su \"{end}\"", + "error.validation.filename": "Prašome įrašyti teisingą failo pavadinimą", + "error.validation.in": "Prašome įrašyti vieną iš šių: ({in})", + "error.validation.integer": "Prašome įrašyti teisingą sveiką skaičių", + "error.validation.ip": "Prašome įrašyti teisingą IP adresą", + "error.validation.less": "Prašome įrašyti mažiau nei {max}", + "error.validation.match": "Reikšmė nesutampa su laukiamu šablonu", + "error.validation.max": "Prašome įrašyti reikšmę lygią arba didesnę, nei {max}", + "error.validation.maxlength": "Prašome įrašyti trumpesnę reikšmę. (max. {max} characters)", + "error.validation.maxwords": "Please enter no more than {max} word(s)", + "error.validation.min": "Please enter a value equal to or greater than {min}", + "error.validation.minlength": "Prašome įrašyti ilgesnę reikšmę. (min. {min} characters)", + "error.validation.minwords": "Prašome įrašyti bent {min} žodžius", + "error.validation.more": "Prašome įrašyti daugiau nei {min}", + "error.validation.notcontains": "Prašome įrašyti reikšmę, kuri neturi \"{needle}\"", + "error.validation.notin": "Prašome neįrašyti vieną iš šių: ({notIn})", + "error.validation.option": "Prašome pasirinkti korektišką opciją", + "error.validation.num": "Prašome įrašyti teisingą numerį", + "error.validation.required": "Prašome įrašyti ką nors", + "error.validation.same": "Prašome įrašyti \"{other}\"", + "error.validation.size": "Reikšmės dydis turi būti \"{size}\"", + "error.validation.startswith": "Reikšmė turi prasidėti su \"{start}\"", + "error.validation.time": "Prašome įrašyti korektišką laiką", + "error.validation.time.after": "Įrašykite laiką po {time}", + "error.validation.time.before": "Įrašykite laiką prieš {time}", + "error.validation.time.between": "Įrašykite laiką tarp {min} ir {max}", + "error.validation.url": "Prašome įrašyti teisingą URL", + + "expand": "Išskleisti", + "expand.all": "Išskleisti viską", + + "field.required": "Laukas privalomas", + "field.blocks.changeType": "Pakeisti tipą", + "field.blocks.code.name": "Kodas", + "field.blocks.code.language": "Kalba", + "field.blocks.code.placeholder": "Jūsų kodas ...", + "field.blocks.delete.confirm": "Ar tikrai norite pašalinti šį bloką?", + "field.blocks.delete.confirm.all": "Ar tikrai norite pašalinti visus blokus?", + "field.blocks.delete.confirm.selected": "Ar tikrai norite pašalinti pasirinktus blokus?", + "field.blocks.empty": "Dar nėra blokų", + "field.blocks.fieldsets.label": "Pasirinkite bloko tipą ...", + "field.blocks.fieldsets.paste": "Spauskite {{ shortcut }} įterpti/importuoti nukopijuotus blokus", + "field.blocks.gallery.name": "Galerija", + "field.blocks.gallery.images.empty": "Dar nėra nuotraukų", + "field.blocks.gallery.images.label": "Nuotraukos", + "field.blocks.heading.level": "Lygis", + "field.blocks.heading.name": "Antraštė", + "field.blocks.heading.text": "Tekstas", + "field.blocks.heading.placeholder": "Antraštė ...", + "field.blocks.image.alt": "Alternatyvus tekstas", + "field.blocks.image.caption": "Aprašymas", + "field.blocks.image.crop": "Kirpti", + "field.blocks.image.link": "Nuoroda", + "field.blocks.image.location": "Šaltinis", + "field.blocks.image.name": "Nuotrauka", + "field.blocks.image.placeholder": "Pasirinkite nuotrauką", + "field.blocks.image.ratio": "Proporcijos", + "field.blocks.image.url": "Nuotraukos URL", + "field.blocks.line.name": "Linija", + "field.blocks.list.name": "Sąrašas", + "field.blocks.markdown.name": "Markdown", + "field.blocks.markdown.label": "Tekstas", + "field.blocks.markdown.placeholder": "Markdown ...", + "field.blocks.quote.name": "Citata", + "field.blocks.quote.text.label": "Tekstas", + "field.blocks.quote.text.placeholder": "Citata ...", + "field.blocks.quote.citation.label": "Citatos turinys", + "field.blocks.quote.citation.placeholder": "autorius", + "field.blocks.text.name": "Tekstas", + "field.blocks.text.placeholder": "Tekstas ...", + "field.blocks.video.caption": "Aprašymas", + "field.blocks.video.name": "Video", + "field.blocks.video.placeholder": "Įrašykite video URL", + "field.blocks.video.url.label": "Video-URL", + "field.blocks.video.url.placeholder": "https://youtube.com/?v=", + + "field.files.empty": "Pasirinkti", + + "field.layout.delete": "Pašalinti eilutę", + "field.layout.delete.confirm": "Ar tikrai norite pašalinti šią eilutę", + "field.layout.empty": "Dar nėra eilučių", + "field.layout.select": "Pasirinkite išdėstymą", + + "field.pages.empty": "Dar nėra puslapių", + "field.structure.delete.confirm": "Ar tikrai norite pašalinti šią eilutę?", + "field.structure.empty": "Dar nėra įrašų", + "field.users.empty": "Dar nėra vartotojų", + + "file.blueprint": "Šis failas dar neturi blueprint. Galite nustatyti jį per /site/blueprints/files/{blueprint}.yml", + "file.delete.confirm": "Ar tikrai norite pašalinti
{filename}?", + "file.sort": "Pakeisti poziciją", + + "files": "Failai", + "files.empty": "Įkelti", + + "hide": "Paslėpti", + "hour": "Valanda", + "import": "Importuoti", + "info": "Info", + "insert": "Įterpti", + "insert.after": "Įterpti po", + "insert.before": "Įterpti prieš", + "install": "Įdiegti", + + "installation": "Įdiegimas", + "installation.completed": "Valdymo pultas įdiegtas", + "installation.disabled": "Pagal nutylėjimą valdymo pulto įdiegimas viešuose serveriuose yra negalimas. Prašome įdiegti lokalioje aplinkoje arba įgalinkite jį su panel.install opcija.", + "installation.issues.accounts": "Katalogas /site/accounts neegzistuoja arba neturi įrašymo teisių", + "installation.issues.content": "Katalogas /content neegzistuoja arba neturi įrašymo teisių", + "installation.issues.curl": "Plėtinys CURL yra privalomas", + "installation.issues.headline": "Nepavyko įdiegti valdymo pulto", + "installation.issues.mbstring": "Plėtinys MB String yra privalomas", + "installation.issues.media": "Katalogas /media neegzistuoja arba neturi įrašymo teisių", + "installation.issues.php": "Įsitikinkite, kad naudojama PHP 7+", + "installation.issues.server": "Kirby reikalauja Apache, Nginx arba Caddy", + "installation.issues.sessions": "Katalogas /site/sessions neegzistuoja arba neturi įrašymo teisių", + + "language": "Kalba", + "language.code": "Kodas", + "language.convert": "Padaryti pagrindinį", + "language.convert.confirm": "

Do you really want to convert {name} to the default language? This cannot be undone.

If {name} has untranslated content, there will no longer be a valid fallback and parts of your site might be empty.

", + "language.create": "Pridėti naują kalbą", + "language.delete.confirm": "Ar tikrai norite pašalinti {name} kalbą, kartu su visais vertimais? Grąžinti nebus įmanoma! 🙀", + "language.deleted": "Kalba pašalinta", + "language.direction": "Skaitymo kryptis", + "language.direction.ltr": "Iš kairės į dešinę", + "language.direction.rtl": "Iš dešinės į kairę", + "language.locale": "PHP locale string", + "language.locale.warning": "Jūs naudojate pasirinktinį lokalės nustatymą. Prašome pakeisti jį faile /site/languages", + "language.name": "Pavadinimas", + "language.updated": "Kalba atnaujinta", + + "languages": "Kalbos", + "languages.default": "Pagrindinė kalba", + "languages.empty": "Dar nėra kalbų", + "languages.secondary": "Papildomos kalbos", + "languages.secondary.empty": "Dar nėra papildomų kalbų", + + "license": "Licenzija", + "license.buy": "Pirkti licenziją", + "license.register": "Registruoti", + "license.manage": "Manage your licenses", + "license.register.help": "Licenzijos kodą gavote el. paštu po apmokėjimo. Prašome įterpti čia, kad sistema būtų užregistruota.", + "license.register.label": "Prašome įrašyti jūsų licenzijos kodą", + "license.register.success": "Ačiū, kad palaikote Kirby", + "license.unregistered": "Tai neregistruota Kirby demo versija", + "license.unregistered.label": "Unregistered", + + "link": "Nuoroda", + "link.text": "Nuorodos tekstas", + + "loading": "Kraunasi", + + "lock.unsaved": "Neišsaugoti pakeitimai", + "lock.unsaved.empty": "Nebeliko neišsaugotų pakeitimų", + "lock.isLocked": "Vartotojo {email} neišsaugoti pakeitimai", + "lock.file.isLocked": "Šį failą dabar redaguoja kitas vartotojas {email}, tad jo negalima pekeisti.", + "lock.page.isLocked": "Šį puslapį dabar redaguoja kitas vartotojas {email}, tad jo negalima pekeisti.", + "lock.unlock": "Atrakinti", + "lock.isUnlocked": "Jūsų neišsaugoti pakeitimai buvo perrašyti kito vartotojo. Galite parsisiųsti savo pakeitimus ir įkelti juos rankiniu būdu.", + + "login": "Prisijungti", + "login.code.label.login": "Prisijungimo kodas", + "login.code.label.password-reset": "Slaptažodžio atstatymo kodas", + "login.code.placeholder.email": "000 000", + "login.code.text.email": "Jei jūsų el. paštas yra užregistruotas, užklaistas kodas buvo išsiųstas el. paštu.", + "login.email.login.body": "Sveiki, {user.nameOrEmail},\n\nNeseniai užklausėte prisijungimo kodo svetainėje {site}.\nŠis kodas galios {timeout} min.:\n\n{code}\n\nJei neprašėte šio kodo, tiesiog ignoruokite, arba susisiekite su administratoriumi.\nDėl saugumo, prašome NEPERSIŲSTI šio laiško.", + "login.email.login.subject": "Jūsų prisijungimo kodas", + "login.email.password-reset.body": "Sveiki, {user.nameOrEmail},\n\nNeseniai užklausėte naujo slaptažodžio kūrimo kodo svetainėje {site}.\nŠis kodas galios {timeout} min.:\n\n{code}\n\nJei neprašėte šio kodo, tiesiog ignoruokite, arba susisiekite su administratoriumi.\nDėl saugumo, prašome NEPERSIŲSTI šio laiško", + "login.email.password-reset.subject": "Jūsų slaptažodžio atstatymo kodas ", + "login.remember": "Likti prisijungus", + "login.reset": "Sukurti naują slaptažodį", + "login.toggleText.code.email": "Prisijungti su el. paštu", + "login.toggleText.code.email-password": "Prisijungti su slaptažodžiu", + "login.toggleText.password-reset.email": "Pamiršote slaptažodį?", + "login.toggleText.password-reset.email-password": "← Atgal į prisijungimą", + + "logout": "Atsijungti", + + "menu": "Meniu", + "meridiem": "AM/PM", + "mime": "Media Tipas", + "minutes": "Minutės", + + "month": "Mėnuo", + "months.april": "Balandis", + "months.august": "August", + "months.december": "Gruodis", + "months.february": "Vasaris", + "months.january": "Sausis", + "months.july": "Liepa", + "months.june": "Birželis", + "months.march": "Kovas", + "months.may": "Gegužė", + "months.november": "Lapkritis", + "months.october": "Spalis", + "months.september": "Rugsėjis", + + "more": "Daugiau", + "name": "Pavadinimas", + "next": "Toliau", + "no": "ne", + "off": "ne", + "on": "taip", + "open": "Atidaryti", + "open.newWindow": "Atidaryti naujame lange", + "options": "Pasirinkimai", + "options.none": "Nėra pasirinkimų", + + "orientation": "Orientacija", + "orientation.landscape": "Horizontali", + "orientation.portrait": "Portretas", + "orientation.square": "Kvadratas", + + "page.blueprint": "Šis puslapis dar neturi blueprint. Galite jį nustatyti per /site/blueprints/pages/{blueprint}.yml", + "page.changeSlug": "Pakeisti URL", + "page.changeSlug.fromTitle": "Sukurti URL pagal pavadinimą", + "page.changeStatus": "Pakeisti statusą", + "page.changeStatus.position": "Pasirinkite poziciją", + "page.changeStatus.select": "Pasirinkite statusą", + "page.changeTemplate": "Pakeisti šabloną", + "page.delete.confirm": "🙀 Ar tikrai norite pašalinti puslapį {title}?", + "page.delete.confirm.subpages": "Šis puslapis turi sub-puslapių.
Visi sub-puslapiai taip pat bus pašalinti.", + "page.delete.confirm.title": "Įrašykite puslapio pavadinimą tam, kad patvirtinti", + "page.draft.create": "Sukurti juodraštį", + "page.duplicate.appendix": "Kopijuoti", + "page.duplicate.files": "Kopijuoti failus", + "page.duplicate.pages": "Kopijuoti puslapius", + "page.sort": "Pakeisti poziciją", + "page.status": "Statusas", + "page.status.draft": "Juodraštis", + "page.status.draft.description": "Šis puslapis yra juodraščio režime ir prieinamas tik redaktoriams arba per slaptą nuorodą", + "page.status.listed": "Paskelbtas", + "page.status.listed.description": "Matomas viešai visiems", + "page.status.unlisted": "Nerodomas", + "page.status.unlisted.description": "Rodomas viešai visiems, bet tik per URL", + + "pages": "Puslapiai", + "pages.empty": "Dar nėra puslapių", + "pages.status.draft": "Juodraščiai", + "pages.status.listed": "Paskelbti", + "pages.status.unlisted": "Nerodomi", + + "pagination.page": "Puslapis", + + "password": "Slaptažodis", + "paste": "Įterpti", + "paste.after": "Įterpti po", + "pixel": "Pikselis", + "plugins": "Plugins", + "prev": "Ankstesnis", + "preview": "Peržiūra", + "remove": "Pašalinti", + "rename": "Pervadinti", + "replace": "Apkeisti", + "retry": "Bandyti dar", + "revert": "Grąžinti", + "revert.confirm": "Ar tikrai norite atšaukti visus neišsaugotus pakeitimus?", + + "role": "Rolė", + "role.admin.description": "Admin turi visas teises", + "role.admin.title": "Admin", + "role.all": "Visos", + "role.empty": "Nėra vartotojų su tokia role", + "role.description.placeholder": "Be aprašymo", + "role.nobody.description": "Ši rolė bus naudojama jei nenustatytos jokios teisės", + "role.nobody.title": "Niekas", + + "save": "Išsaugoti", + "search": "Ieškoti", + "search.min": "Minimalus simbolių kiekis paieškai: {min}", + "search.all": "Rodyti viską", + "search.results.none": "Nėra rezultatų", + + "section.required": "Sekcija privaloma", + + "security": "Security", + "select": "Pasirinkti", + "server": "Server", + "settings": "Nustatymai", + "show": "Rodyti", + "site.blueprint": "Svetainė neturi blueprint. Jūs galite nustatyti jį /site/blueprints/site.yml", + "size": "Dydis", + "slug": "URL pabaiga", + "sort": "Rikiuoti", + + "stats.empty": "No reports", + "system.issues.content": "The content folder seems to be exposed", + "system.issues.debug": "Debugging must be turned off in production", + "system.issues.git": "The .git folder seems to be exposed", + "system.issues.https": "We recommend HTTPS for all your sites", + "system.issues.kirby": "The kirby folder seems to be exposed", + "system.issues.site": "The site folder seems to be exposed", + + "title": "Pavadinimas", + "template": "Puslapio šablonas", + "today": "Šiandien", + + "toolbar.button.code": "Kodas", + "toolbar.button.bold": "Bold", + "toolbar.button.email": "El. paštas", + "toolbar.button.headings": "Antraštės", + "toolbar.button.heading.1": "Heading 1", + "toolbar.button.heading.2": "Heading 2", + "toolbar.button.heading.3": "Heading 3", + "toolbar.button.heading.4": "Antrašte 4", + "toolbar.button.heading.5": "Antrašte 5", + "toolbar.button.heading.6": "Antrašte 6", + "toolbar.button.italic": "Italic", + "toolbar.button.file": "Failas", + "toolbar.button.file.select": "Pasirinkite failą", + "toolbar.button.file.upload": "Įkelti failą", + "toolbar.button.link": "Nuoroda", + "toolbar.button.paragraph": "Paragrafas", + "toolbar.button.strike": "Perbraukimas", + "toolbar.button.ol": "Sąrašas su skaičiais", + "toolbar.button.underline": "Pabraukimas", + "toolbar.button.ul": "Sąrašas su taškais", + + "translation.author": "Roman U", + "translation.direction": "ltr", + "translation.name": "Lietuvių", + "translation.locale": "lt_LT", + + "upload": "Įkelti", + "upload.error.cantMove": "Įkeltas failas negali būti perkeltas", + "upload.error.cantWrite": "Nepavyko įrašyti failo į diską", + "upload.error.default": "Nepavyko įkelti failo", + "upload.error.extension": "Neįmanoma įkelti tokio tipo failo", + "upload.error.formSize": "Įkeltas failas viršija MAX_FILE_SIZE nustatymą, kuris buvo nurodytas formoje", + "upload.error.iniPostSize": "Įkeliamas failas viršija post_max_size nustatymą iš php.ini", + "upload.error.iniSize": "Įkeltas failas viršija upload_max_filesize nustatymą faile php.ini", + "upload.error.noFile": "Failas nebuvo įkeltas", + "upload.error.noFiles": "Failai nebuvo įkelti", + "upload.error.partial": "Failas įkeltas tik iš dalies", + "upload.error.tmpDir": "Trūksta laikinojo katalogo", + "upload.errors": "Klaida", + "upload.progress": "Įkėlimas…", + + "url": "Url", + "url.placeholder": "https://example.com", + + "user": "Vartotojas", + "user.blueprint": "Galite nustatyti papildomas sekcijas ir formos laukelius šiam vartotojui per /site/blueprints/users/{blueprint}.yml", + "user.changeEmail": "Keisti el. paštą", + "user.changeLanguage": "Keisti kalbą", + "user.changeName": "Pervadinti vartotoją", + "user.changePassword": "Keisti slaptažodį", + "user.changePassword.new": "Naujas slaptažodis", + "user.changePassword.new.confirm": "Patvirtinti naują slaptažodį…", + "user.changeRole": "Keisti rolę", + "user.changeRole.select": "Pasirinkti naują rolę", + "user.create": "Pridėti naują vartotoją", + "user.delete": "Pašalinti šį vartotoją", + "user.delete.confirm": "Ar tikrai norite pašalinti vartotoją
{email}?", + + "users": "Vartotojai", + + "version": "Versija", + + "view.account": "Jūsų paskyra", + "view.installation": "Installation", + "view.languages": "Kalbos", + "view.resetPassword": "Sukurti naują slaptažodį", + "view.site": "Svetainė", + "view.system": "System", + "view.users": "Vartotojai", + + "welcome": "Sveiki", + "year": "Metai", + "yes": "taip" } diff --git a/kirby/i18n/translations/nb.json b/kirby/i18n/translations/nb.json index 7f50aa6..1041a86 100644 --- a/kirby/i18n/translations/nb.json +++ b/kirby/i18n/translations/nb.json @@ -1,730 +1,574 @@ { - "account.changeName": "Endre navnet ditt", - "account.delete": "Slett kontoen din", - "account.delete.confirm": "Er du sikker på at du vil slette kontoen din? Du vil bli logget ut umiddelbart. Kontoen din kan ikke gjenopprettes.", - - "activate": "Aktiver", - "add": "Legg til", - "alpha": "Alfa", - "author": "Forfatter", - "avatar": "Profilbilde", - "back": "Tilbake", - "cancel": "Avbryt", - "change": "Endre", - "close": "Lukk", - "changes": "Endringer", - "confirm": "Lagre", - "collapse": "Skjul", - "collapse.all": "Skjule alle", - "color": "Farge", - "coordinates": "Koordinater", - "copy": "Kopier", - "copy.all": "Kopier alle", - "copy.success": "{count} kopiert!", - "create": "Opprett", - "custom": "Egendefinert", - - "date": "Dato", - "date.select": "Velg dato", - - "day": "Dag", - "days.fri": "Fre", - "days.mon": "Man", - "days.sat": "L\u00f8r", - "days.sun": "S\u00f8n", - "days.thu": "Tor", - "days.tue": "Tir", - "days.wed": "Ons", - - "debugging": "Feilsøker", - - "delete": "Slett", - "delete.all": "Slett alle", - - "dialog.fields.empty": "Denne dialogen har ingen felter", - "dialog.files.empty": "Ingen filer å velge", - "dialog.pages.empty": "Ingen sider å velge", - "dialog.text.empty": "Denne dialogen definerer ingen tekst", - "dialog.users.empty": "Ingen brukere å velge", - - "dimensions": "Dimensjoner", - "disable": "Deaktivere", - "disabled": "Deaktivert", - "discard": "Forkast", - - "drawer.fields.empty": "Denne skuffen har ingen felt", - - "domain": "Domene", - "download": "Last ned", - "duplicate": "Dupliser", - - "edit": "Rediger", - - "email": "Epost", - "email.placeholder": "epost@eksempel.no", - - "enter": "Enter", - "entries": "Artikler", - "entry": "Artikkel", - - "environment": "Miljø", - - "error": "Feil", - "error.access.code": "Ugyldig kode", - "error.access.login": "Ugyldig innlogging", - "error.access.panel": "Du har ikke tilgang til panelet", - "error.access.view": "Du har ikke tilgang til denne delen av panelet", - - "error.avatar.create.fail": "Profilbildet kunne ikke lastes opp", - "error.avatar.delete.fail": "Profilbildet kunne ikke slettes", - "error.avatar.dimensions.invalid": "Vennligst hold profilbildets bredde og høyde under 3000 piksler", - "error.avatar.mime.forbidden": "Ugyldig MIME-type", - - "error.blueprint.notFound": "Blueprint \"{name}\" kunne ikke lastes inn", - - "error.blocks.max.plural": "Du kan ikke legge til flere enn {max} blokker", - "error.blocks.max.singular": "Du kan ikke legge til mer enn en blokk", - "error.blocks.min.plural": "Du må legge til minst {min} blokker", - "error.blocks.min.singular": "Du må legge til minst en blokk", - "error.blocks.validation": "Det er en feil med feltet \"{field}\" i blokk {index} hvor blokktypen \"{fieldset}\" brukes", - - "error.cache.type.invalid": "Ugyldig type cache \"{type}\"", - - "error.email.preset.notFound": "E-postinnstillingen \"{name}\" ble ikke funnet", - - "error.field.converter.invalid": "Ugyldig omformer \"{converter}\"", - "error.field.type.missing": "Felt \"{ name }\": Felttypen \"{ type }\" finnes ikke", - - "error.file.changeName.empty": "Navnet kan ikke være tomt", - "error.file.changeName.permission": "Du har ikke rettighet til å endre navnet til \"{filename}\"", - "error.file.changeTemplate.invalid": "Malen for filen \"{id}\" Kan ikke endres til \"{template}\" (gyldig: \"{blueprints}\")", - "error.file.changeTemplate.permission": "Du har ikke rettigheter til å endre malen for filen \"{id}\"", - - "error.file.duplicate": "En fil med navnet \"{filename}\" eksisterer allerede", - "error.file.extension.forbidden": "Ugyldig filtype", - "error.file.extension.invalid": "Ugyldig utvidelse: {extension}", - "error.file.extension.missing": "Du kan ikke laste opp filer uten filtype", - "error.file.maxheight": "Høyden til bildet kan ikke overgå {height} piksler", - "error.file.maxsize": "Filen er for stor", - "error.file.maxwidth": "Bredden til bildet kan ikke overgå {width} piksler", - "error.file.mime.differs": "Den opplastede filen må være av samme MIME-type \"{mime}\"", - "error.file.mime.forbidden": "Mediatypen \"{mime}\" er ikke tillatt", - "error.file.mime.invalid": "Ugyldig mediatype: {mime}", - "error.file.mime.missing": "Mediatypen for \"{filename}\" kan ikke gjenkjennes", - "error.file.minheight": "Høyden til bildet må være minst {height} piksler", - "error.file.minsize": "Filen er for liten", - "error.file.minwidth": "Bredden til bildet må være minst {width} piksler", - "error.file.name.unique": "The filename must be unique", - "error.file.name.missing": "Filnavnet kan ikke være tomt", - "error.file.notFound": "Filen \"{filename}\" kan ikke bli funnet", - "error.file.orientation": "Bilderetningen må være \"{orientation}\"", - "error.file.type.forbidden": "Du har ikke lov til å laste opp filer av typen {type}", - "error.file.type.invalid": "Ugyldig filtype: {type}", - "error.file.undefined": "Finner ikke filen", - - "error.form.incomplete": "Vennligst fiks alle feil…", - "error.form.notSaved": "Skjemaet kunne ikke lagres", - - "error.language.code": "Vennligst skriv inn gyldig språkkode", - "error.language.duplicate": "Språket eksisterer allerede", - "error.language.name": "Vennligst skriv inn et gyldig navn for språket", - "error.language.notFound": "Finner ikke språket", - - "error.layout.validation.block": "Det er en feilmelding på \"{field}\" feltet i blokk {blockIndex} med bruk av \"{fieldset}\" blokktypen i layout {layoutIndex}", - "error.layout.validation.settings": "Det er en feil i layout {index} innstillinger", - - "error.license.domain": "Domenen for lisensen mangler", - "error.license.email": "Vennligst skriv inn en gyldig e-postadresse", - "error.license.format": "Please enter a valid license code", - "error.license.verification": "Lisensen kunne ikke verifiseres", - - "error.login.totp.confirm.invalid": "Ugyldig kode", - "error.login.totp.confirm.missing": "Vennligst skriv inn nåværende koden", - - "error.object.validation": "Det er en feilmelding i \"{label}\" feltet:\n{message}", - - "error.offline": "Panelet er i øyeblikket offline", - - "error.page.changeSlug.permission": "Du kan ikke endre URLen for denne siden", - "error.page.changeSlug.reserved": "Stien til toppnivåsider kan ikke starte med \"{path}\"", - "error.page.changeStatus.incomplete": "Siden har feil og kan ikke publiseres", - "error.page.changeStatus.permission": "Sidens status kan ikke endres", - "error.page.changeStatus.toDraft.invalid": "Siden \"{slug}\" kan ikke konverteres til et utkast", - "error.page.changeTemplate.invalid": "Malen for siden \"{slug}\" kan ikke endres", - "error.page.changeTemplate.permission": "Du har ikke tillatelse til å endre malen for \"{slug}\"", - "error.page.changeTitle.empty": "Tittelen kan ikke være tom", - "error.page.changeTitle.permission": "Du har ikke tillatelse til å endre tittelen for \"{slug}\"", - "error.page.create.permission": "Du har ikke tillatelse til å opprette \"{slug}\"", - "error.page.delete": "Siden \"{slug}\" kan ikke slettes", - "error.page.delete.confirm": "Vennligst skriv inn sidens tittel for å bekrefte", - "error.page.delete.hasChildren": "Siden har undersider og kan derfor ikke slettes", - "error.page.delete.permission": "Du har ikke til å slette \"{slug}\"", - "error.page.draft.duplicate": "Et sideutkast med URL-tillegget \"{slug}\" eksisterer allerede", - "error.page.duplicate": "En side med URL-tillegget \"{slug}\" eksisterer allerede", - "error.page.duplicate.permission": "Du har ikke tillatelse til å duplisere \"{slug}\"", - "error.page.move.ancestor": "Siden kan ikke flyttes inn i seg selv", - "error.page.move.directory": "Sidestrukturen kan ikke flyttes", - "error.page.move.duplicate": "En underside med url banen \"{slug}\" finnes allerede", - "error.page.move.notFound": "Den flyttede siden kan ikke bli funnet", - "error.page.move.permission": "You are not allowed to move \"{slug}\"", - "error.page.move.template": "\"{template}\" malen er ikke akseptert som underside av \"{parent}\"", - "error.page.notFound": "Siden \"{slug}\" ble ikke funnet", - "error.page.num.invalid": "Vennligst skriv inn et gyldig sorteringsnummer. Tallet må ikke være negativt.", - "error.page.slug.invalid": "Vennligst skriv inn en gyldig URL endelse", - "error.page.slug.maxlength": "Slug lengden må være mindre enn \"{length}\" karakterer", - "error.page.sort.permission": "Siden \"{slug}\" kan ikke sorteres", - "error.page.status.invalid": "Vennligst angi en gyldig sidestatus", - "error.page.undefined": "Siden kunne ikke bli funnet", - "error.page.update.permission": "Du har ikke tillatelse til å oppdatere \"{slug}\"", - - "error.section.files.max.plural": "Det er ikke mulig å legge til mer enn {max} filer i seksjonen \"{section}\"", - "error.section.files.max.singular": "Det er ikke mulig å legge til mer enn én fil i seksjonen \"{section}\"", - "error.section.files.min.plural": "Seksjonen \"{section}\" krever minst {min} filer", - "error.section.files.min.singular": "Seksjonen \"{section}\" krever minst en fil", - - "error.section.pages.max.plural": "Det er ikke mulig å legge til mer enn {max} sider i \"{section}\" seksjonen", - "error.section.pages.max.singular": "Det er ikke mulig å legge til mer enn én side i \"{section}\" seksjonen", - "error.section.pages.min.plural": "Seksjonen \"{section}\" krever minst {min} sider", - "error.section.pages.min.singular": "Seksjonen \"{section}\" krever minst en side", - - "error.section.notLoaded": "Seksjonen \"{name}\" kunne ikke lastes inn", - "error.section.type.invalid": "Seksjonstypen \"{type}\" er ikke gyldig", - - "error.site.changeTitle.empty": "Tittelen kan ikke være tom", - "error.site.changeTitle.permission": "Du har ikke tillatelse til å endre tittel på siden", - "error.site.update.permission": "Du har ikke tillatelse til å oppdatere denne siden", - - "error.structure.validation": "Det er en feilmelding på felt \"{field}\" i rad {index}", - - "error.template.default.notFound": "Standardmalen eksisterer ikke", - - "error.unexpected": "En uventet feil oppstod! Aktiver feilsøkmodus for mer info: https://getkirby.com/docs/reference/system/options/debug", - - "error.user.changeEmail.permission": "Du har ikke tillatelse til å endre e-post for brukeren \"{name}\"", - "error.user.changeLanguage.permission": "Du har ikke tillatelse til å endre språk for brukeren \"{name}\"", - "error.user.changeName.permission": "Du har ikke tillatelse til å endre navn for brukeren \"{name}\"", - "error.user.changePassword.permission": "Du har ikke tillatelse til å endre passord for brukeren \"{name}\"", - "error.user.changeRole.lastAdmin": "Rollen for den siste administratoren kan ikke endres", - "error.user.changeRole.permission": "Du har ikke tillatelse til å endre rollen for brukeren \"{name}\"", - "error.user.changeRole.toAdmin": "Du har ikke tillatelse til å endre noen til adminrolle", - "error.user.create.permission": "Du har ikke tillatelse til å opprette denne brukeren", - "error.user.delete": "Denne brukeren kunne ikke bli slettet", - "error.user.delete.lastAdmin": "Siste administrator kan ikke slettes", - "error.user.delete.lastUser": "Den siste brukeren kan ikke slettes", - "error.user.delete.permission": "Du er ikke tillat \u00e5 slette denne brukeren", - "error.user.duplicate": "En bruker med e-postadresse \"{email}\" eksisterer allerede", - "error.user.email.invalid": "Vennligst skriv inn en gyldig e-postadresse", - "error.user.language.invalid": "Vennligst skriv inn et gyldig språk", - "error.user.notFound": "Brukeren kunne ikke bli funnet", - "error.user.password.excessive": "Please enter a valid password. Passwords must not be longer than 1000 characters.", - "error.user.password.invalid": "Vennligst skriv inn et gyldig passord. Passordet må minst være 8 tegn langt.", - "error.user.password.notSame": "Vennligst bekreft passordet", - "error.user.password.undefined": "Brukeren har ikke et passord", - "error.user.password.wrong": "Feil passord", - "error.user.role.invalid": "Vennligst skriv inn en gyldig rolle", - "error.user.undefined": "Brukeren kunne ikke bli funnet", - "error.user.update.permission": "Du har ikke tillatelse til å oppdatere brukeren \"{name}\"", - - "error.validation.accepted": "Vennligst bekreft", - "error.validation.alpha": "Vennligst skriv kun tegn mellom a-z", - "error.validation.alphanum": "Vennligst skriv kun tegn mellom a-z eller tall mellom 0-9", - "error.validation.anchor": "Vennligst skriv inn en riktig link-ankertekst", - "error.validation.between": "Vennligst angi en verdi mellom \"{min}\" og \"{max}\"", - "error.validation.boolean": "Vennligst bekreft eller avslå", - "error.validation.color": "Please enter a valid color in the {format} format", - "error.validation.contains": "Vennligst skriv inn en verdi som inneholder \"{needle}\"", - "error.validation.date": "Vennligst skriv inn en gyldig dato", - "error.validation.date.after": "Vennligst angi en dato etter {date}", - "error.validation.date.before": "Vennligst angi en dato før {date}", - "error.validation.date.between": "Vennligst angi en dato mellom {min} og {max}", - "error.validation.denied": "Vennligst avslå", - "error.validation.different": "Verdien kan ikke være \"{other}\"", - "error.validation.email": "Vennligst skriv inn en gyldig e-postadresse", - "error.validation.endswith": "Verdien må ende med \"{end}\"", - "error.validation.filename": "Vennligst skriv inn et gyldig filnavn", - "error.validation.in": "Vennligst skriv inn en av følgende: ({in})", - "error.validation.integer": "Vennligst skriv inn et gyldig tall", - "error.validation.ip": "Vennligst skriv inn en gyldig IP-adresse", - "error.validation.less": "Vennligst angi en verdi lavere enn {max}", - "error.validation.linkType": "The link type is not allowed", - "error.validation.match": "Verdien samsvarer ikke med det forventede mønsteret", - "error.validation.max": "Vennligst angi en verdi lik eller lavere enn {max}", - "error.validation.maxlength": "Vennligst angi en kortere verdi. (maks. {max} tegn)", - "error.validation.maxwords": "Vennligst ikke skriv inn mer enn {max} ord", - "error.validation.min": "Vennligst angi en verdi lik eller større enn {min}", - "error.validation.minlength": "Vennligst angi en lengre verdi. (minimum. {min} tegn)", - "error.validation.minwords": "Vennligst skriv inn minst {min} ord", - "error.validation.more": "Vennligst angi en verdi større enn {min}", - "error.validation.notcontains": "Vennligst angi en verdi som ikke inneholder \"{needle}\"", - "error.validation.notin": "Vennligst ikke angi noen av følgende:({notIn})", - "error.validation.option": "Vennligst velg et gyldig alternativ", - "error.validation.num": "Vennligst angi et gyldig nummer", - "error.validation.required": "Vennligst skriv inn noe", - "error.validation.same": "Vennligst angi \"{other}\"", - "error.validation.size": "Størrelsen på verdien må være \"{size}\"", - "error.validation.startswith": "Verdien må starte med \"{start}\"", - "error.validation.tel": "Please enter an unformatted phone number", - "error.validation.time": "Vennligst angi et gyldig tidspunkt", - "error.validation.time.after": "Vennligst angi et tidspunkt etter {time}", - "error.validation.time.before": "Vennligst angi et tidspunkt før {time}", - "error.validation.time.between": "Vennligst angi et tidspunkt mellom {min} og {max}", - "error.validation.uuid": "Please enter a valid UUID", - "error.validation.url": "Vennligst skriv inn en gyldig URL", - - "expand": "Utvid", - "expand.all": "Utvid alle", - - "field.invalid": "The field is invalid", - "field.required": "Feltet er påkrevd", - "field.blocks.changeType": "Endre type", - "field.blocks.code.name": "Kode", - "field.blocks.code.language": "Språk", - "field.blocks.code.placeholder": "Din kode…", - "field.blocks.delete.confirm": "Er du sikker på at du vil slette denne blokken?", - "field.blocks.delete.confirm.all": "Er du sikker på at du vil slette alle blokkene?", - "field.blocks.delete.confirm.selected": "Er du sikker på at du vil slette de valgte blokkene?", - "field.blocks.empty": "Ingen blokker enda", - "field.blocks.fieldsets.empty": "Ingen feltsett enda", - "field.blocks.fieldsets.label": "Vennligst velg en blokktype…", - "field.blocks.fieldsets.paste": "Trykk {{ shortcut }} for å importere layout/blokker fra utklippsverktøyet Bare de som er tillat i nåværende felt vil bli limt inn.", - "field.blocks.gallery.name": "Galleri", - "field.blocks.gallery.images.empty": "Ingen bilder enda", - "field.blocks.gallery.images.label": "Bilder", - "field.blocks.heading.level": "Nivå", - "field.blocks.heading.name": "Overskrift", - "field.blocks.heading.text": "Tekst", - "field.blocks.heading.placeholder": "Overskrift…", - "field.blocks.image.alt": "Alternativ tekst", - "field.blocks.image.caption": "Caption", - "field.blocks.image.crop": "Beskjær", - "field.blocks.image.link": "Adresse", - "field.blocks.image.location": "Plassering", - "field.blocks.image.location.internal": "Denne nettsiden", - "field.blocks.image.location.external": "Ekstern kilde", - "field.blocks.image.name": "Bilde", - "field.blocks.image.placeholder": "Velg et bilde", - "field.blocks.image.ratio": "Ratio", - "field.blocks.image.url": "Bilde URL", - "field.blocks.line.name": "Linje", - "field.blocks.list.name": "Liste", - "field.blocks.markdown.name": "Markdown", - "field.blocks.markdown.label": "Tekst", - "field.blocks.markdown.placeholder": "Markdown…", - "field.blocks.quote.name": "Sitat", - "field.blocks.quote.text.label": "Tekst", - "field.blocks.quote.text.placeholder": "Sitat…", - "field.blocks.quote.citation.label": "Kildehenvisning", - "field.blocks.quote.citation.placeholder": "av…", - "field.blocks.text.name": "Tekst", - "field.blocks.text.placeholder": "Tekst…", - "field.blocks.video.autoplay": "Autoplay", - "field.blocks.video.caption": "Caption", - "field.blocks.video.controls": "Controls", - "field.blocks.video.location": "Plassering", - "field.blocks.video.loop": "Loop", - "field.blocks.video.muted": "Muted", - "field.blocks.video.name": "Video", - "field.blocks.video.placeholder": "Legg til en video URL", - "field.blocks.video.poster": "Poster", - "field.blocks.video.preload": "Preload", - "field.blocks.video.url.label": "Video-URL", - "field.blocks.video.url.placeholder": "https://youtube.com/?v=", - - "field.files.empty": "Ingen filer har blitt valgt", - - "field.layout.change": "Endre layout", - "field.layout.delete": "Slett layout", - "field.layout.delete.confirm": "Er du sikker på at du vil slette denne layouten?", - "field.layout.delete.confirm.all": "Vil du virkelig slette alle layout?", - "field.layout.empty": "Ingen rader enda", - "field.layout.select": "Velg en layout", - - "field.object.empty": "Ingen informasjon enda", - - "field.pages.empty": "Ingen side har blitt valgt", - - "field.structure.delete.confirm": "\u00d8nsker du virkelig \u00e5 slette denne oppf\u00f8ringen?", - "field.structure.delete.confirm.all": "Vil du virkelig slette alle oppføringer?", - "field.structure.empty": "Ingen oppf\u00f8ringer enda", - - "field.users.empty": "Ingen bruker har blitt valgt", - - "fields.empty": "Ingen felt enda", - - "file": "Fil", - "file.blueprint": "Denne filen har ikke en blueprint enda. Du kan definere oppsettet i /site/blueprints/files/{blueprint}.yml", - "file.changeTemplate": "Endre mal", - "file.changeTemplate.notice": "Endring av denne filens mal kommer til å fjerne innhold for felter som ikke korresponderer med typen. Dersom den nye malen inneholder gitte regler, f.eks bildedimensjoner, vil også disse bli påført irreversibelt. Bruk varsomt.", - "file.delete.confirm": "Vil du virkelig slette denne filen?", - "file.focus.placeholder": "Sett fokuspunkt", - "file.focus.reset": "Fjern fokuspunkt", - "file.focus.title": "Focus", - "file.sort": "Endre plassering", - - "files": "Filer", - "files.empty": "Ingen filer ennå", - - "filter": "Filter", - - "hide": "Skjul", - "hour": "Tid", - "hue": "Hue", - "import": "Importer", - "info": "Info", - "insert": "Sett Inn", - "insert.after": "Sett inn etter", - "insert.before": "Sett inn før", - "install": "Installer", - - "installation": "Installasjon", - "installation.completed": "Panelet har blitt installert", - "installation.disabled": "Installasjonsprogrammet for Panelet er deaktivert på offentlige servere som standard. Vennligst kjør installasjonsprogrammet på en lokal maskin eller aktiver den med panel.install innstillingen.", - "installation.issues.accounts": "\/site\/accounts er ikke skrivbar", - "installation.issues.content": "Mappen content og alt av innhold m\u00e5 v\u00e6re skrivbar.", - "installation.issues.curl": "Utvidelsen CURL er nødvendig", - "installation.issues.headline": "Panelet kan ikke installeres", - "installation.issues.mbstring": "Utvidelsen MB String er nødvendig", - "installation.issues.media": "Mappen /media eksisterer ikke eller er ikke skrivbar", - "installation.issues.php": "Pass på at du bruker PHP 8+", - "installation.issues.sessions": "Mappen /site/sessions eksisterer ikke eller er ikke skrivbar", - - "language": "Spr\u00e5k", - "language.code": "Kode", - "language.convert": "Gjør til standard", - "language.convert.confirm": "

Vil du virkelig konvertere {name} til standardspråk? Dette kan ikke angres.

Dersom {name} har innhold som ikke er oversatt, vil nettstedet mangle innhold å falle tilbake på. Dette kan resultere i at deler av nettstedet fremstår som tomt.

", - "language.create": "Legg til språk", - "language.default": "Standardspråk", - "language.delete.confirm": "Vil du virkelig slette språket {name} inkludert alle oversettelser? Dette kan ikke angres!", - "language.deleted": "Språket har blitt slettet", - "language.direction": "Leseretning", - "language.direction.ltr": "Venstre til høyre", - "language.direction.rtl": "Høyre til venstre", - "language.locale": "PHP locale streng", - "language.locale.warning": "Du bruker et egendefinert lokalt oppsett. Vennligst endre det i språkfilen i /site/languages", - "language.name": "Navn", - "language.secondary": "Sekundærspråk", - "language.settings": "Språkinstillinger", - "language.updated": "Språk har blitt oppdatert", - "language.variables": "Språkvariabler", - "language.variables.empty": "Ingen oversettelse enda", - - "language.variable.delete.confirm": "Ønsker du virkelig å slette variablen for {key}?", - "language.variable.key": "Key", - "language.variable.notFound": "Variablen kan ikke bli funnet", - "language.variable.value": "Verdi", - - "languages": "Språk", - "languages.default": "Standardspråk", - "languages.empty": "Det er ingen språk ennå", - "languages.secondary": "Sekundære språk", - "languages.secondary.empty": "Det er ingen andre språk ennå", - - "license": "Kirby lisens", - "license.activate": "Aktiver den nå", - "license.activate.label": "Vennligst skriv inn din lisenskode", - "license.activate.domain": "Lisenses skal bli aktivert for {host}.", - "license.activate.local": "Du er i ferd med å aktivere Kirby lisensen din til lokale domenen din {host}. Hvis nettsiden skal plasseres til en offentlig domene, vennligst aktivere den der isteden. Hvis {host} er domenen du vil bruke med din lisens, vennligst fortsett.", - "license.activated": "Aktivert", - "license.buy": "Kjøp lisens", - "license.code": "Kode", - "license.code.help": "Du har mottatt din lisenskoden via e-post etter kjøpet. Vennligst kopier og lim den inn her.", - "license.code.label": "Vennligst skriv inn din lisenskode", - "license.status.active.info": "Inkluderer nye hovedversjoner til {date}", - "license.status.active.label": "Gyldig lisens", - "license.status.demo.info": "This is a demo installation", - "license.status.demo.label": "Demo", - "license.status.inactive.info": "Forny lisens for å oppdatere til nye hovedversjoner", - "license.status.inactive.label": "Ingen nye hovedversjoner", - "license.status.legacy.bubble": "Klar til å fornye lisensen?", - "license.status.legacy.info": "Lisensen din omfatter ikke denne versjonen", - "license.status.legacy.label": "Vennligst fornye lisensen din", - "license.status.missing.bubble": "Klar til å lansere din nettside?", - "license.status.missing.info": "Ingen gyldig lisens", - "license.status.missing.label": "Vennligst skriv inn din lisenskode", - "license.manage": "Håndter dine lisenser", - "license.purchased": "Kjøpt", - "license.success": "Takk for at du støtter Kirby", - "license.unregistered.label": "Ikke registrert", - - "link": "Adresse", - "link.text": "Koblingstekst", - - "loading": "Laster inn", - - "lock.unsaved": "Ulagrede endringer", - "lock.unsaved.empty": "Det er ingen flere ulagrede endringer", - "lock.isLocked": "Ulagrede endringer av {email}", - "lock.unlock": "Lås opp", - "lock.unlock.submit": "Lås opp og overskriv ulagrede endringer fra {email}", - "lock.isUnlocked": "Ble låst opp av en annen bruker", - - "login": "Logg Inn", - "login.code.label.login": "Login-kode", - "login.code.label.password-reset": "Passord tilbakestillingskode", - "login.code.placeholder.email": "000 000", - "login.code.placeholder.totp": "000000", - "login.code.text.email": "Dersom din e-post er registrert vil den forespurte koden bli sendt via e-post.", - "login.code.text.totp": "Vennligst skriv inn engangskoden fra authenticator appen din.", - "login.email.login.body": "Hei {user.nameOrEmail},\n\nDu ba nylig om en innloggingskode til panelet til {site}.\nFølgende innloggingskode vil være gyldig i {timeout} minutter:\n\n{code}\n\nDersom du ikke ba om en innloggingskode, vennligst ignorer denne e-posten eller kontakt din administrator hvis du har spørsmål.\nFor sikkerhets skyld, vennligst IKKE videresend denne e-posten.", - "login.email.login.subject": "Din innloggingskode", - "login.email.password-reset.body": "Hei {user.nameOrEmail},\n\nDu ba nylig om en tilbakestilling av passord til panelet til {site}.\nFølgende tilbakestillingskode vil være gyldig i {timeout} minutter:\n\n{code}\n\nDersom du ikke ba om en tilbakestillingskode, vennligst ignorer denne e-posten eller kontakt din administrator hvis du har spørsmål.\nFor sikkerhets skyld, vennligst IKKE videresend denne e-posten.", - "login.email.password-reset.subject": "Din kode for tilbakestilling av passord", - "login.remember": "Hold meg innlogget", - "login.reset": "Tilbakestill passord", - "login.toggleText.code.email": "Logg inn via e-post", - "login.toggleText.code.email-password": "Logg inn med passord", - "login.toggleText.password-reset.email": "Glemt passord?", - "login.toggleText.password-reset.email-password": "← Tilbake til innlogging", - "login.totp.enable.option": "Sett opp engangskoder", - "login.totp.enable.intro": "Autentiseringsapper kan generere engangskoder til bruk for totrinnspålogging når du logger inn på din konto.", - "login.totp.enable.qr.label": "1. Scan denne QR-koden", - "login.totp.enable.qr.help": "Kan du ikke scanne? Legg til installasjonsnøkkelen {secret} manuelt i din autentiseringsapp.", - "login.totp.enable.confirm.headline": "2. Bekreft med den genererte koden", - "login.totp.enable.confirm.text": "Din app genererer en engangskode hvert 30ende sekund. Skriv inn koden som vises nå for å ferdigstille oppsettet:", - "login.totp.enable.confirm.label": "Nærværende kode", - "login.totp.enable.confirm.help": "Etter dette er satt opp, vil vi spørre etter en engangskode hver gang du logger inn.", - "login.totp.enable.success": "Engangskoder er aktivert", - "login.totp.disable.option": "Deaktiver engangskoder", - "login.totp.disable.label": "Skriv inn ditt passord for å deaktivere bruk av engangskoder", - "login.totp.disable.help": "I fremtiden vil en annen tofaktorløsning – som en loginkode sendt via epost – bli etterspurt når du logger inn. Du kan alltid sette opp tofaktorkoder igjen på senere tidspunkt.", - "login.totp.disable.admin": "

Dette kommer til å deaktivere engangskoder for {user}.

I fremtiden vil en annen tofaktorløsning – som en loginkode sendt via epost – bli etterspurt når de logger inn. {user} kan alltid sette opp tofaktorkoder igjen på senere tidspunkt.", - "login.totp.disable.success": "Engangskoder deaktivert", - - "logout": "Logg ut", - - "merge": "Slå sammen", - "menu": "Meny", - "meridiem": "AM/PM", - "mime": "Mediatype", - "minutes": "Minutter", - - "month": "Måned", - "months.april": "April", - "months.august": "August", - "months.december": "Desember", - "months.february": "Februar", - "months.january": "Januar", - "months.july": "July", - "months.june": "Juni", - "months.march": "Mars", - "months.may": "Mai", - "months.november": "November", - "months.october": "Oktober", - "months.september": "September", - - "more": "Mer", - "move": "Flytt", - "name": "Navn", - "next": "Neste", - "night": "Natt", - "no": "nei", - "off": "av", - "on": "på", - "open": "Åpne", - "open.newWindow": "Åpne i nytt vindu", - "option": "Alternativ", - "options": "Alternativer", - "options.none": "Ingen alternativer", - "options.all": "Vis alle {count} alternativ", - - "orientation": "Orientering", - "orientation.landscape": "Landskap", - "orientation.portrait": "Portrett", - "orientation.square": "Kvadrat", - - "page": "Side", - "page.blueprint": "Denne siden har ikke en blueprint enda. Du kan definere oppsettet i /site/blueprints/pages/{blueprint}.yml", - "page.changeSlug": "Endre URL", - "page.changeSlug.fromTitle": "Opprett fra tittel", - "page.changeStatus": "Endre status", - "page.changeStatus.position": "Vennligst velg en posisjon", - "page.changeStatus.select": "Velg ny status", - "page.changeTemplate": "Endre mal", - "page.changeTemplate.notice": "Changing the page's template will remove content for fields that don't match in type. Use with caution.", - "page.create": "Lag som {status}", - "page.delete.confirm": "Vil du virkelig slette denne siden?", - "page.delete.confirm.subpages": "Denne siden har undersider.
Alle undersider vil også bli slettet.", - "page.delete.confirm.title": "Skriv inn sidetittel for å bekrefte", - "page.duplicate.appendix": "Kopier", - "page.duplicate.files": "Kopier filer", - "page.duplicate.pages": "Kopier sider", - "page.move": "Flytt side", - "page.sort": "Endre plassering", - "page.status": "Status", - "page.status.draft": "Utkast", - "page.status.draft.description": "Denne siden er i kladdmodus og er kun synlig for innloggede brukere eller via en hemmelig lenke.", - "page.status.listed": "Offentlig", - "page.status.listed.description": "Siden er offentlig og synlig for alle", - "page.status.unlisted": "Unotert", - "page.status.unlisted.description": "Siden er ikke er oppført og er kun tilgjengelig via URL", - - "pages": "Sider", - "pages.empty": "Ingen sider ennå", - "pages.status.draft": "Utkast", - "pages.status.listed": "Publisert", - "pages.status.unlisted": "Unotert", - - "pagination.page": "Side", - - "password": "Passord", - "paste": "Lim inn", - "paste.after": "Lim inn etter", - "paste.success": "{count} limt inn!", - "pixel": "Piksel", - "plugin": "Utvidelse", - "plugins": "Plugins", - "prev": "Forrige", - "preview": "Forhåndsvisning", - "remove": "Fjern", - "rename": "Endre navn", - "renew": "Fornye", - "replace": "Erstatt", - "replace.with": "Erstatt med", - "retry": "Pr\u00f8v p\u00e5 nytt", - "revert": "Forkast", - "revert.confirm": "Er du sikker på at vil slette alle ulagrede endringer?", - - "role": "Rolle", - "role.admin.description": "Administrator har alle rettigheter", - "role.admin.title": "Admin", - "role.all": "Alle", - "role.empty": "Det er ingen brukere med denne rollen", - "role.description.placeholder": "Ingen beskrivelse", - "role.nobody.description": "Dette er en fallback rolle uten noen rettigheter.", - "role.nobody.title": "Ingen", - - "save": "Lagre", - "search": "Søk", - "search.min": "Skriv inn {min} tegn for å søke", - "search.all": "Vis alle {count} resultat", - "search.results.none": "Ingen resultater", - - "section.invalid": "The section is invalid", - "section.required": "Denne seksjonen er påkrevd", - - "security": "Sikkerhet", - "select": "Velg", - "server": "Server", - "settings": "Innstillinger", - "show": "Vis", - "site.blueprint": "Denne siden har ikke en blueprint enda. Du kan definere oppsettet i /site/blueprints/site.yml", - "size": "Størrelse", - "slug": "URL-appendiks", - "sort": "Sortere", - "sort.drag": "Drag to sort …", - "split": "Del", - - "stats.empty": "Ingen rapporter", - "status": "Status", - - "system.info.copy": "Copy info", - "system.info.copied": "System info copied", - "system.issues.content": "content-mappen ser ut til å være eksponert", - "system.issues.eol.kirby": "Din installerte Kirby versjon har nådd sitt end-of-life, og vil ikke lenger motta sikkerhetsoppdateringer", - "system.issues.eol.plugin": "Din installerte plugin { plugin } har nådd sitt end-of-life og vil ikke lenger motta sikkerhetsoppdateringer", - "system.issues.eol.php": "Din installerte PHP versjon { release } har nådd sitt end-of-life og vil ikke lenger motta sikkerhetsoppdateringer", - "system.issues.debug": "Debugging må bli skrudd av i production", - "system.issues.git": ".git mappen ser ut til å være eksponert", - "system.issues.https": "Vi anbefaler HTTPS for alle dine sider", - "system.issues.kirby": "kirby-mappen ser ut til å være eksponert", - "system.issues.site": "site-mappen ser ut til å være eksponert", - "system.issues.vulnerability.kirby": "Din installasjon er muligens påvirket av følgende sikkerhetshull ({ severity } severity): { description }", - "system.issues.vulnerability.plugin": "Din installasjon er muligens påvirket av følgende sikkerhetshull i pluginen { plugin } ({ severity } severity): { description }", - "system.updateStatus": "Oppdater status", - "system.updateStatus.error": "Klarte ikke å lete etter oppdateringer", - "system.updateStatus.not-vulnerable": "Ingen kjente sikkerhetshull", - "system.updateStatus.security-update": "Gratis sikkerhetsoppdatering { version } tilgjengelig", - "system.updateStatus.security-upgrade": "Oppdatering { version } med sikkerhetsoppdateringer tilgjengelig", - "system.updateStatus.unreleased": "Ulansert versjon", - "system.updateStatus.up-to-date": "Oppdatert", - "system.updateStatus.update": "Gratis oppdatering { version } tilgjengelig", - "system.updateStatus.upgrade": "Oppdatering { version } tilgjengelig", - - "tel": "Telefon", - "tel.placeholder": "+49123456789", - "template": "Mal", - "title": "Tittel", - "today": "I dag", - - "toolbar.button.clear": "Fjern formattering", - "toolbar.button.code": "Kode", - "toolbar.button.bold": "Fet tekst", - "toolbar.button.email": "Epost", - "toolbar.button.headings": "Overskrifter", - "toolbar.button.heading.1": "Overskrift 1", - "toolbar.button.heading.2": "Overskrift 2", - "toolbar.button.heading.3": "Overskrift 3", - "toolbar.button.heading.4": "Overskrift 4", - "toolbar.button.heading.5": "Overskrift 5", - "toolbar.button.heading.6": "Overskrift 6", - "toolbar.button.italic": "Kursiv tekst", - "toolbar.button.file": "Fil", - "toolbar.button.file.select": "Velg en fil", - "toolbar.button.file.upload": "Last opp en fil", - "toolbar.button.link": "Adresse", - "toolbar.button.paragraph": "Avsnitt", - "toolbar.button.strike": "Gjennomstreking", - "toolbar.button.sub": "Subscript", - "toolbar.button.sup": "Superscript", - "toolbar.button.ol": "Ordnet liste", - "toolbar.button.underline": "Understrek", - "toolbar.button.ul": "Punktliste", - - "translation.author": "Kirby Team", - "translation.direction": "ltr", - "translation.name": "Norsk Bokm\u00e5l", - "translation.locale": "nb_NO", - - "type": "Type", - - "upload": "Last opp", - "upload.error.cantMove": "Den opplastede filen kunne ikke flyttes", - "upload.error.cantWrite": "Kunne ikke skrive fil til disk", - "upload.error.default": "Kunne ikke laste opp fil", - "upload.error.extension": "Filopplasting stoppet av en utvidelse", - "upload.error.formSize": "Den opplastede filen overskrider MAX_FILE_SIZE direktivet som er spesifisert i skjemaet", - "upload.error.iniPostSize": "Den opplastede filen overskrider post_max_size direktivet i php.ini", - "upload.error.iniSize": "Den opplastede filen overskrider upload_max_filesize direktivet i php.ini", - "upload.error.noFile": "Ingen fil ble lastet opp", - "upload.error.noFiles": "Ingen filer ble lastet opp", - "upload.error.partial": "Den opplastede filen ble bare delvis lastet opp", - "upload.error.tmpDir": "Mangler en midlertidig mappe", - "upload.errors": "Feil", - "upload.progress": "Laster opp…", - - "url": "Nettadresse", - "url.placeholder": "https://eksempel.no", - - "user": "Bruker", - "user.blueprint": "Du kan definere flere seksjoner og skjemafelter for denne brukerrollen i /site/blueprints/users/{blueprint}.yml", - "user.changeEmail": "Endre e-post", - "user.changeLanguage": "Endre språk", - "user.changeName": "Angi nytt navn for denne brukeren", - "user.changePassword": "Bytt passord", - "user.changePassword.new": "Nytt passord", - "user.changePassword.new.confirm": "Bekreft nytt passord…", - "user.changeRole": "Bytt rolle", - "user.changeRole.select": "Velg en ny rolle", - "user.create": "Legg til ny bruker", - "user.delete": "Slett denne brukeren", - "user.delete.confirm": "Vil du virkelig slette denne konten?", - - "users": "Brukere", - - "version": "Kirby versjon", - "version.current": "Nåværende versjon", - "version.latest": "Siste versjon", - "versionInformation": "Versjonsinformasjon", - - "view.account": "Din konto", - "view.installation": "Installasjon", - "view.languages": "Språk", - "view.resetPassword": "Tilbakestill passord", - "view.site": "Side", - "view.system": "System", - "view.users": "Brukere", - - "welcome": "Velkommen", - "year": "År", - "yes": "ja" + "account.changeName": "Endre navnet ditt", + "account.delete": "Slett kontoen din", + "account.delete.confirm": "Er du sikker på at du vil slette kontoen din? Du vil bli logget ut umiddelbart. Kontoen din kan ikke gjenopprettes.", + + "add": "Legg til", + "author": "Forfatter", + "avatar": "Profilbilde", + "back": "Tilbake", + "cancel": "Avbryt", + "change": "Endre", + "close": "Lukk", + "confirm": "Lagre", + "collapse": "Skjul", + "collapse.all": "Skjule alle", + "copy": "Kopier", + "copy.all": "Kopier alle", + "create": "Opprett", + + "date": "Dato", + "date.select": "Velg dato", + + "day": "Dag", + "days.fri": "Fre", + "days.mon": "Man", + "days.sat": "L\u00f8r", + "days.sun": "S\u00f8n", + "days.thu": "Tor", + "days.tue": "Tir", + "days.wed": "Ons", + + "debugging": "Feilsøker", + + "delete": "Slett", + "delete.all": "Slett alle", + + "dialog.files.empty": "Ingen filer å velge", + "dialog.pages.empty": "Ingen sider å velge", + "dialog.users.empty": "Ingen brukere å velge", + + "dimensions": "Dimensjoner", + "disabled": "Deaktivert", + "discard": "Forkast", + "download": "Last ned", + "duplicate": "Dupliser", + + "edit": "Rediger", + + "email": "Epost", + "email.placeholder": "epost@eksempel.no", + + "entries": "Entries", + "entry": "Entry", + + "environment": "Miljø", + + "error.access.code": "Ugyldig kode", + "error.access.login": "Ugyldig innlogging", + "error.access.panel": "Du har ikke tilgang til panelet", + "error.access.view": "Du har ikke tilgang til denne delen av panelet", + + "error.avatar.create.fail": "Profilbildet kunne ikke lastes opp", + "error.avatar.delete.fail": "Profilbildet kunne ikke slettes", + "error.avatar.dimensions.invalid": "Vennligst hold profilbildets bredde og høyde under 3000 piksler", + "error.avatar.mime.forbidden": "Ugyldig MIME-type", + + "error.blueprint.notFound": "Blueprint \"{name}\" kunne ikke lastes inn", + + "error.blocks.max.plural": "Du kan ikke legge til flere enn {max} blokker", + "error.blocks.max.singular": "Du kan ikke legge til mer enn en blokk", + "error.blocks.min.plural": "Du må legge til minst {min} blokker", + "error.blocks.min.singular": "Du må legge til minst en blokk", + "error.blocks.validation": "Det er en feil i blokken {index}", + + "error.email.preset.notFound": "E-postinnstillingen \"{name}\" ble ikke funnet", + + "error.field.converter.invalid": "Ugyldig omformer \"{converter}\"", + + "error.file.changeName.empty": "Navnet kan ikke være tomt", + "error.file.changeName.permission": "Du har ikke rettighet til å endre navnet til \"{filename}\"", + "error.file.duplicate": "En fil med navnet \"{filename}\" eksisterer allerede", + "error.file.extension.forbidden": "Ugyldig filtype", + "error.file.extension.invalid": "Ugyldig utvidelse: {extension}", + "error.file.extension.missing": "Du kan ikke laste opp filer uten filtype", + "error.file.maxheight": "Høyden til bildet kan ikke overgå {height} piksler", + "error.file.maxsize": "Filen er for stor", + "error.file.maxwidth": "Bredden til bildet kan ikke overgå {width} piksler", + "error.file.mime.differs": "Den opplastede filen må være av samme MIME-type \"{mime}\"", + "error.file.mime.forbidden": "Mediatypen \"{mime}\" er ikke tillatt", + "error.file.mime.invalid": "Ugyldig mediatype: {mime}", + "error.file.mime.missing": "Mediatypen for \"{filename}\" kan ikke gjenkjennes", + "error.file.minheight": "Høyden til bildet må være minst {height} piksler", + "error.file.minsize": "Filen er for liten", + "error.file.minwidth": "Bredden til bildet må være minst {width} piksler", + "error.file.name.missing": "Filnavnet kan ikke være tomt", + "error.file.notFound": "Finner ikke filen", + "error.file.orientation": "Bilderetningen må være \"{orientation}\"", + "error.file.type.forbidden": "Du har ikke lov til å laste opp filer av typen {type}", + "error.file.type.invalid": "Ugyldig filtype: {type}", + "error.file.undefined": "Finner ikke filen", + + "error.form.incomplete": "Vennligst fiks alle feil…", + "error.form.notSaved": "Skjemaet kunne ikke lagres", + + "error.language.code": "Vennligst skriv inn gyldig språkkode", + "error.language.duplicate": "Språket eksisterer allerede", + "error.language.name": "Vennligst skriv inn et gyldig navn for språket", + "error.language.notFound": "Finner ikke språket", + + "error.layout.validation.block": "Det er en feil i blokk {blockIndex} i layout {layoutIndex}", + "error.layout.validation.settings": "Det er en feil i layout {index} innstillinger", + + "error.license.format": "Vennligst skriv inn gyldig lisensnøkkel", + "error.license.email": "Vennligst skriv inn en gyldig e-postadresse", + "error.license.verification": "Lisensen kunne ikke verifiseres", + + "error.offline": "Panelet er i øyeblikket offline", + + "error.page.changeSlug.permission": "Du kan ikke endre URLen for denne siden", + "error.page.changeStatus.incomplete": "Siden har feil og kan ikke publiseres", + "error.page.changeStatus.permission": "Sidens status kan ikke endres", + "error.page.changeStatus.toDraft.invalid": "Siden \"{slug}\" kan ikke konverteres til et utkast", + "error.page.changeTemplate.invalid": "Malen for siden \"{slug}\" kan ikke endres", + "error.page.changeTemplate.permission": "Du har ikke tillatelse til å endre malen for \"{slug}\"", + "error.page.changeTitle.empty": "Tittelen kan ikke være tom", + "error.page.changeTitle.permission": "Du har ikke tillatelse til å endre tittelen for \"{slug}\"", + "error.page.create.permission": "Du har ikke tillatelse til å opprette \"{slug}\"", + "error.page.delete": "Siden \"{slug}\" kan ikke slettes", + "error.page.delete.confirm": "Vennligst skriv inn sidens tittel for å bekrefte", + "error.page.delete.hasChildren": "Siden har undersider og kan derfor ikke slettes", + "error.page.delete.permission": "Du har ikke til å slette \"{slug}\"", + "error.page.draft.duplicate": "Et sideutkast med URL-tillegget \"{slug}\" eksisterer allerede", + "error.page.duplicate": "En side med URL-tillegget \"{slug}\" eksisterer allerede", + "error.page.duplicate.permission": "Du har ikke tillatelse til å duplisere \"{slug}\"", + "error.page.notFound": "Siden \"{slug}\" ble ikke funnet", + "error.page.num.invalid": "Vennligst skriv inn et gyldig sorteringsnummer. Tallet må ikke være negativt.", + "error.page.slug.invalid": "Vennligst skriv inn en gyldig URL endelse", + "error.page.slug.maxlength": "Slug lengden må være mindre enn \"{length}\" karakterer", + "error.page.sort.permission": "Siden \"{slug}\" kan ikke sorteres", + "error.page.status.invalid": "Vennligst angi en gyldig sidestatus", + "error.page.undefined": "Siden kunne ikke bli funnet", + "error.page.update.permission": "Du har ikke tillatelse til å oppdatere \"{slug}\"", + + "error.section.files.max.plural": "Det er ikke mulig å legge til mer enn {max} filer i seksjonen \"{section}\"", + "error.section.files.max.singular": "Det er ikke mulig å legge til mer enn én fil i seksjonen \"{section}\"", + "error.section.files.min.plural": "Seksjonen \"{section}\" krever minst {min} filer", + "error.section.files.min.singular": "Seksjonen \"{section}\" krever minst en fil", + + "error.section.pages.max.plural": "Det er ikke mulig å legge til mer enn {max} sider i \"{section}\" seksjonen", + "error.section.pages.max.singular": "Det er ikke mulig å legge til mer enn én side i \"{section}\" seksjonen", + "error.section.pages.min.plural": "Seksjonen \"{section}\" krever minst {min} sider", + "error.section.pages.min.singular": "Seksjonen \"{section}\" krever minst en side", + + "error.section.notLoaded": "Seksjonen \"{name}\" kunne ikke lastes inn", + "error.section.type.invalid": "Seksjonstypen \"{type}\" er ikke gyldig", + + "error.site.changeTitle.empty": "Tittelen kan ikke være tom", + "error.site.changeTitle.permission": "Du har ikke tillatelse til å endre tittel på siden", + "error.site.update.permission": "Du har ikke tillatelse til å oppdatere denne siden", + + "error.template.default.notFound": "Standardmalen eksisterer ikke", + + "error.unexpected": "En uventet feil oppstod! Aktiver feilsøkmodus for mer info: https://getkirby.com/docs/reference/system/options/debug", + + "error.user.changeEmail.permission": "Du har ikke tillatelse til å endre e-post for brukeren \"{name}\"", + "error.user.changeLanguage.permission": "Du har ikke tillatelse til å endre språk for brukeren \"{name}\"", + "error.user.changeName.permission": "Du har ikke tillatelse til å endre navn for brukeren \"{name}\"", + "error.user.changePassword.permission": "Du har ikke tillatelse til å endre passord for brukeren \"{name}\"", + "error.user.changeRole.lastAdmin": "Rollen for den siste administratoren kan ikke endres", + "error.user.changeRole.permission": "Du har ikke tillatelse til å endre rollen for brukeren \"{name}\"", + "error.user.changeRole.toAdmin": "Du har ikke tillatelse til å endre noen til adminrolle", + "error.user.create.permission": "Du har ikke tillatelse til å opprette denne brukeren", + "error.user.delete": "Denne brukeren kunne ikke bli slettet", + "error.user.delete.lastAdmin": "Siste administrator kan ikke slettes", + "error.user.delete.lastUser": "Den siste brukeren kan ikke slettes", + "error.user.delete.permission": "Du er ikke tillat \u00e5 slette denne brukeren", + "error.user.duplicate": "En bruker med e-postadresse \"{email}\" eksisterer allerede", + "error.user.email.invalid": "Vennligst skriv inn en gyldig e-postadresse", + "error.user.language.invalid": "Vennligst skriv inn et gyldig språk", + "error.user.notFound": "Brukeren kunne ikke bli funnet", + "error.user.password.excessive": "Please enter a valid password. Passwords must not be longer than 1000 characters.", + "error.user.password.invalid": "Vennligst skriv inn et gyldig passord. Passordet må minst være 8 tegn langt.", + "error.user.password.notSame": "Vennligst bekreft passordet", + "error.user.password.undefined": "Brukeren har ikke et passord", + "error.user.password.wrong": "Feil passord", + "error.user.role.invalid": "Vennligst skriv inn en gyldig rolle", + "error.user.undefined": "Brukeren kunne ikke bli funnet", + "error.user.update.permission": "Du har ikke tillatelse til å oppdatere brukeren \"{name}\"", + + "error.validation.accepted": "Vennligst bekreft", + "error.validation.alpha": "Vennligst skriv kun tegn mellom a-z", + "error.validation.alphanum": "Vennligst skriv kun tegn mellom a-z eller tall mellom 0-9", + "error.validation.between": "Vennligst angi en verdi mellom \"{min}\" og \"{max}\"", + "error.validation.boolean": "Vennligst bekreft eller avslå", + "error.validation.contains": "Vennligst skriv inn en verdi som inneholder \"{needle}\"", + "error.validation.date": "Vennligst skriv inn en gyldig dato", + "error.validation.date.after": "Vennligst angi en dato etter {date}", + "error.validation.date.before": "Vennligst angi en dato før {date}", + "error.validation.date.between": "Vennligst angi en dato mellom {min} og {max}", + "error.validation.denied": "Vennligst avslå", + "error.validation.different": "Verdien kan ikke være \"{other}\"", + "error.validation.email": "Vennligst skriv inn en gyldig e-postadresse", + "error.validation.endswith": "Verdien må ende med \"{end}\"", + "error.validation.filename": "Vennligst skriv inn et gyldig filnavn", + "error.validation.in": "Vennligst skriv inn en av følgende: ({in})", + "error.validation.integer": "Vennligst skriv inn et gyldig tall", + "error.validation.ip": "Vennligst skriv inn en gyldig IP-adresse", + "error.validation.less": "Vennligst angi en verdi lavere enn {max}", + "error.validation.match": "Verdien samsvarer ikke med det forventede mønsteret", + "error.validation.max": "Vennligst angi en verdi lik eller lavere enn {max}", + "error.validation.maxlength": "Vennligst angi en kortere verdi. (maks. {max} tegn)", + "error.validation.maxwords": "Vennligst ikke skriv inn mer enn {max} ord", + "error.validation.min": "Vennligst angi en verdi lik eller større enn {min}", + "error.validation.minlength": "Vennligst angi en lengre verdi. (minimum. {min} tegn)", + "error.validation.minwords": "Vennligst skriv inn minst {min} ord", + "error.validation.more": "Vennligst angi en verdi større enn {min}", + "error.validation.notcontains": "Vennligst angi en verdi som ikke inneholder \"{needle}\"", + "error.validation.notin": "Vennligst ikke angi noen av følgende:({notIn})", + "error.validation.option": "Vennligst velg et gyldig alternativ", + "error.validation.num": "Vennligst angi et gyldig nummer", + "error.validation.required": "Vennligst skriv inn noe", + "error.validation.same": "Vennligst angi \"{other}\"", + "error.validation.size": "Størrelsen på verdien må være \"{size}\"", + "error.validation.startswith": "Verdien må starte med \"{start}\"", + "error.validation.time": "Vennligst angi et gyldig tidspunkt", + "error.validation.time.after": "Vennligst angi et tidspunkt etter {time}", + "error.validation.time.before": "Vennligst angi et tidspunkt før {time}", + "error.validation.time.between": "Vennligst angi et tidspunkt mellom {min} og {max}", + "error.validation.url": "Vennligst skriv inn en gyldig URL", + + "expand": "Utvid", + "expand.all": "Utvid alle", + + "field.required": "Feltet er påkrevd", + "field.blocks.changeType": "Endre type", + "field.blocks.code.name": "Kode", + "field.blocks.code.language": "Språk", + "field.blocks.code.placeholder": "Din kode…", + "field.blocks.delete.confirm": "Er du sikker på at du vil slette denne blokken?", + "field.blocks.delete.confirm.all": "Er du sikker på at du vil slette alle blokkene?", + "field.blocks.delete.confirm.selected": "Er du sikker på at du vil slette de valgte blokkene?", + "field.blocks.empty": "Ingen blokker enda", + "field.blocks.fieldsets.label": "Vennligst velg en blokktype…", + "field.blocks.fieldsets.paste": "Trykk {{ shortcut }} for å lime/importere blokker fra din utklippstavle", + "field.blocks.gallery.name": "Galleri", + "field.blocks.gallery.images.empty": "Ingen bilder enda", + "field.blocks.gallery.images.label": "Bilder", + "field.blocks.heading.level": "Nivå", + "field.blocks.heading.name": "Overskrift", + "field.blocks.heading.text": "Tekst", + "field.blocks.heading.placeholder": "Overskrift…", + "field.blocks.image.alt": "Alternativ tekst", + "field.blocks.image.caption": "Caption", + "field.blocks.image.crop": "Beskjær", + "field.blocks.image.link": "Adresse", + "field.blocks.image.location": "Plassering", + "field.blocks.image.name": "Bilde", + "field.blocks.image.placeholder": "Velg et bilde", + "field.blocks.image.ratio": "Ratio", + "field.blocks.image.url": "Bilde URL", + "field.blocks.line.name": "Linje", + "field.blocks.list.name": "Liste", + "field.blocks.markdown.name": "Markdown", + "field.blocks.markdown.label": "Tekst", + "field.blocks.markdown.placeholder": "Markdown…", + "field.blocks.quote.name": "Sitat", + "field.blocks.quote.text.label": "Tekst", + "field.blocks.quote.text.placeholder": "Sitat…", + "field.blocks.quote.citation.label": "Kildehenvisning", + "field.blocks.quote.citation.placeholder": "av…", + "field.blocks.text.name": "Tekst", + "field.blocks.text.placeholder": "Tekst…", + "field.blocks.video.caption": "Caption", + "field.blocks.video.name": "Video", + "field.blocks.video.placeholder": "Legg til en video URL", + "field.blocks.video.url.label": "Video-URL", + "field.blocks.video.url.placeholder": "https://youtube.com/?v=", + + "field.files.empty": "Ingen filer har blitt valgt", + + "field.layout.delete": "Slett layout", + "field.layout.delete.confirm": "Er du sikker på at du vil slette denne layouten?", + "field.layout.empty": "Ingen rader enda", + "field.layout.select": "Velg en layout", + + "field.pages.empty": "Ingen side har blitt valgt", + "field.structure.delete.confirm": "\u00d8nsker du virkelig \u00e5 slette denne oppf\u00f8ringen?", + "field.structure.empty": "Ingen oppf\u00f8ringer enda", + "field.users.empty": "Ingen bruker har blitt valgt", + + "file.blueprint": "Denne filen har ikke en blueprint enda. Du kan definere oppsettet i /site/blueprints/files/{blueprint}.yml", + "file.delete.confirm": "Vil du virkelig slette denne filen?", + "file.sort": "Endre plassering", + + "files": "Filer", + "files.empty": "Ingen filer ennå", + + "hide": "Skjul", + "hour": "Tid", + "import": "Importer", + "info": "Info", + "insert": "Sett Inn", + "insert.after": "Sett inn etter", + "insert.before": "Sett inn før", + "install": "Installer", + + "installation": "Installasjon", + "installation.completed": "Panelet har blitt installert", + "installation.disabled": "Installasjonsprogrammet for Panelet er deaktivert på offentlige servere som standard. Vennligst kjør installasjonsprogrammet på en lokal maskin eller aktiver den med panel.install innstillingen.", + "installation.issues.accounts": "\/site\/accounts er ikke skrivbar", + "installation.issues.content": "Mappen content og alt av innhold m\u00e5 v\u00e6re skrivbar.", + "installation.issues.curl": "Utvidelsen CURL er nødvendig", + "installation.issues.headline": "Panelet kan ikke installeres", + "installation.issues.mbstring": "Utvidelsen MB String er nødvendig", + "installation.issues.media": "Mappen /media eksisterer ikke eller er ikke skrivbar", + "installation.issues.php": "Pass på at du bruker PHP 7+", + "installation.issues.server": "Kirby krever Apache, Nginx eller Caddy", + "installation.issues.sessions": "Mappen /site/sessions eksisterer ikke eller er ikke skrivbar", + + "language": "Spr\u00e5k", + "language.code": "Kode", + "language.convert": "Gjør til standard", + "language.convert.confirm": "

Vil du virkelig konvertere {name} til standardspråk? Dette kan ikke angres.

Dersom {name} har innhold som ikke er oversatt, vil nettstedet mangle innhold å falle tilbake på. Dette kan resultere i at deler av nettstedet fremstår som tomt.

", + "language.create": "Legg til språk", + "language.delete.confirm": "Vil du virkelig slette språket {name} inkludert alle oversettelser? Dette kan ikke angres!", + "language.deleted": "Språket har blitt slettet", + "language.direction": "Leseretning", + "language.direction.ltr": "Venstre til høyre", + "language.direction.rtl": "Høyre til venstre", + "language.locale": "PHP locale streng", + "language.locale.warning": "Du bruker et egendefinert lokalt oppsett. Vennligst endre det i språkfilen i /site/languages", + "language.name": "Navn", + "language.updated": "Språk har blitt oppdatert", + + "languages": "Språk", + "languages.default": "Standardspråk", + "languages.empty": "Det er ingen språk ennå", + "languages.secondary": "Sekundære språk", + "languages.secondary.empty": "Det er ingen andre språk ennå", + + "license": "Kirby lisens", + "license.buy": "Kjøp lisens", + "license.register": "Registrer", + "license.manage": "Manage your licenses", + "license.register.help": "Du skal ha mottatt din lisenskode for kjøpet via e-post. Vennligst kopier og lim inn denne for å registrere deg.", + "license.register.label": "Vennligst skriv inn din lisenskode", + "license.register.success": "Takk for at du støtter Kirby", + "license.unregistered": "Dette er en uregistrert demo av Kirby", + "license.unregistered.label": "Unregistered", + + "link": "Adresse", + "link.text": "Koblingstekst", + + "loading": "Laster inn", + + "lock.unsaved": "Ulagrede endringer", + "lock.unsaved.empty": "Det er ingen flere ulagrede endringer", + "lock.isLocked": "Ulagrede endringer av {email}", + "lock.file.isLocked": "Filen redigeres for øyeblikket av {email} og kan ikke endres.", + "lock.page.isLocked": "Siden redigeres for øyeblikket av {email} og kan ikke endres.", + "lock.unlock": "Lås opp", + "lock.isUnlocked": "Dine ulagrede endringer har blitt overskrevet av en annen bruker. Du kan laste ned dine endringer for å sammenslå dem manuelt", + + "login": "Logg Inn", + "login.code.label.login": "Login kode", + "login.code.label.password-reset": "Passord tilbakestillingskode", + "login.code.placeholder.email": "000 000", + "login.code.text.email": "Dersom din e-post er registrert vil den forespurte koden bli sendt via e-post.", + "login.email.login.body": "Hei {user.nameOrEmail},\n\nDu ba nylig om en innloggingskode til panelet til {site}.\nFølgende innloggingskode vil være gyldig i {timeout} minutter:\n\n{code}\n\nDersom du ikke ba om en innloggingskode, vennligst ignorer denne e-posten eller kontakt din administrator hvis du har spørsmål.\nFor sikkerhets skyld, vennligst IKKE videresend denne e-posten.", + "login.email.login.subject": "Din innloggingskode", + "login.email.password-reset.body": "Hei {user.nameOrEmail},\n\nDu ba nylig om en tilbakestilling av passord til panelet til {site}.\nFølgende tilbakestillingskode vil være gyldig i {timeout} minutter:\n\n{code}\n\nDersom du ikke ba om en tilbakestillingskode, vennligst ignorer denne e-posten eller kontakt din administrator hvis du har spørsmål.\nFor sikkerhets skyld, vennligst IKKE videresend denne e-posten.", + "login.email.password-reset.subject": "Din kode for tilbakestilling av passord", + "login.remember": "Hold meg innlogget", + "login.reset": "Tilbakestill passord", + "login.toggleText.code.email": "Logg inn via e-post", + "login.toggleText.code.email-password": "Logg inn med passord", + "login.toggleText.password-reset.email": "Glemt passord?", + "login.toggleText.password-reset.email-password": "← Tilbake til innlogging", + + "logout": "Logg ut", + + "menu": "Meny", + "meridiem": "AM/PM", + "mime": "Mediatype", + "minutes": "Minutter", + + "month": "Måned", + "months.april": "April", + "months.august": "August", + "months.december": "Desember", + "months.february": "Februar", + "months.january": "Januar", + "months.july": "July", + "months.june": "Juni", + "months.march": "Mars", + "months.may": "Mai", + "months.november": "November", + "months.october": "Oktober", + "months.september": "September", + + "more": "Mer", + "name": "Navn", + "next": "Neste", + "no": "nei", + "off": "av", + "on": "på", + "open": "Åpne", + "open.newWindow": "Åpne i nytt vindu", + "options": "Alternativer", + "options.none": "Ingen alternativer", + + "orientation": "Orientering", + "orientation.landscape": "Landskap", + "orientation.portrait": "Portrett", + "orientation.square": "Kvadrat", + + "page.blueprint": "Denne siden har ikke en blueprint enda. Du kan definere oppsettet i /site/blueprints/pages/{blueprint}.yml", + "page.changeSlug": "Endre URL", + "page.changeSlug.fromTitle": "Opprett fra tittel", + "page.changeStatus": "Endre status", + "page.changeStatus.position": "Vennligst velg en posisjon", + "page.changeStatus.select": "Velg ny status", + "page.changeTemplate": "Endre mal", + "page.delete.confirm": "Vil du virkelig slette denne siden?", + "page.delete.confirm.subpages": "Denne siden har undersider.
Alle undersider vil også bli slettet.", + "page.delete.confirm.title": "Skriv inn sidetittel for å bekrefte", + "page.draft.create": "Lag utkast", + "page.duplicate.appendix": "Kopier", + "page.duplicate.files": "Kopier filer", + "page.duplicate.pages": "Kopier sider", + "page.sort": "Endre plassering", + "page.status": "Status", + "page.status.draft": "Utkast", + "page.status.draft.description": "Denne siden er i kladdmodus og er kun synlig for innloggede brukere eller via en hemmelig lenke.", + "page.status.listed": "Offentlig", + "page.status.listed.description": "Siden er offentlig og synlig for alle", + "page.status.unlisted": "Unotert", + "page.status.unlisted.description": "Siden er ikke er oppført og er kun tilgjengelig via URL", + + "pages": "Sider", + "pages.empty": "Ingen sider ennå", + "pages.status.draft": "Utkast", + "pages.status.listed": "Publisert", + "pages.status.unlisted": "Unotert", + + "pagination.page": "Side", + + "password": "Passord", + "paste": "Lim inn", + "paste.after": "Lim inn etter", + "pixel": "Piksel", + "plugins": "Plugins", + "prev": "Forrige", + "preview": "Forhåndsvisning", + "remove": "Fjern", + "rename": "Endre navn", + "replace": "Erstatt", + "retry": "Pr\u00f8v p\u00e5 nytt", + "revert": "Forkast", + "revert.confirm": "Er du sikker på at vil slette alle ulagrede endringer?", + + "role": "Rolle", + "role.admin.description": "Administrator har alle rettigheter", + "role.admin.title": "Admin", + "role.all": "Alle", + "role.empty": "Det er ingen brukere med denne rollen", + "role.description.placeholder": "Ingen beskrivelse", + "role.nobody.description": "Dette er en fallback rolle uten noen rettigheter.", + "role.nobody.title": "Ingen", + + "save": "Lagre", + "search": "Søk", + "search.min": "Skriv inn {min} tegn for å søke", + "search.all": "Vis alle", + "search.results.none": "Ingen resultater", + + "section.required": "Denne seksjonen er påkrevd", + + "security": "Security", + "select": "Velg", + "server": "Server", + "settings": "Innstillinger", + "show": "Vis", + "site.blueprint": "Denne siden har ikke en blueprint enda. Du kan definere oppsettet i /site/blueprints/site.yml", + "size": "Størrelse", + "slug": "URL-appendiks", + "sort": "Sortere", + + "stats.empty": "No reports", + "system.issues.content": "The content folder seems to be exposed", + "system.issues.debug": "Debugging must be turned off in production", + "system.issues.git": "The .git folder seems to be exposed", + "system.issues.https": "We recommend HTTPS for all your sites", + "system.issues.kirby": "The kirby folder seems to be exposed", + "system.issues.site": "The site folder seems to be exposed", + + "title": "Tittel", + "template": "Mal", + "today": "I dag", + + "toolbar.button.code": "Kode", + "toolbar.button.bold": "Fet tekst", + "toolbar.button.email": "Epost", + "toolbar.button.headings": "Overskrifter", + "toolbar.button.heading.1": "Overskrift 1", + "toolbar.button.heading.2": "Overskrift 2", + "toolbar.button.heading.3": "Overskrift 3", + "toolbar.button.heading.4": "Overskrift 4", + "toolbar.button.heading.5": "Overskrift 5", + "toolbar.button.heading.6": "Overskrift 6", + "toolbar.button.italic": "Kursiv tekst", + "toolbar.button.file": "Fil", + "toolbar.button.file.select": "Velg en fil", + "toolbar.button.file.upload": "Last opp en fil", + "toolbar.button.link": "Adresse", + "toolbar.button.paragraph": "Avsnitt", + "toolbar.button.strike": "Gjennomstreking", + "toolbar.button.ol": "Ordnet liste", + "toolbar.button.underline": "Understrek", + "toolbar.button.ul": "Punktliste", + + "translation.author": "Kirby Team", + "translation.direction": "ltr", + "translation.name": "Norsk Bokm\u00e5l", + "translation.locale": "nb_NO", + + "upload": "Last opp", + "upload.error.cantMove": "Den opplastede filen kunne ikke flyttes", + "upload.error.cantWrite": "Kunne ikke skrive fil til disk", + "upload.error.default": "Kunne ikke laste opp fil", + "upload.error.extension": "Filopplasting stoppet av en utvidelse", + "upload.error.formSize": "Den opplastede filen overskrider MAX_FILE_SIZE direktivet som er spesifisert i skjemaet", + "upload.error.iniPostSize": "Den opplastede filen overskrider post_max_size direktivet i php.ini", + "upload.error.iniSize": "Den opplastede filen overskrider upload_max_filesize direktivet i php.ini", + "upload.error.noFile": "Ingen fil ble lastet opp", + "upload.error.noFiles": "Ingen filer ble lastet opp", + "upload.error.partial": "Den opplastede filen ble bare delvis lastet opp", + "upload.error.tmpDir": "Mangler en midlertidig mappe", + "upload.errors": "Feil", + "upload.progress": "Laster opp…", + + "url": "Nettadresse", + "url.placeholder": "https://example.com", + + "user": "Bruker", + "user.blueprint": "Du kan definere flere seksjoner og skjemafelter for denne brukerrollen i /site/blueprints/users/{blueprint}.yml", + "user.changeEmail": "Endre e-post", + "user.changeLanguage": "Endre språk", + "user.changeName": "Angi nytt navn for denne brukeren", + "user.changePassword": "Bytt passord", + "user.changePassword.new": "Nytt passord", + "user.changePassword.new.confirm": "Bekreft nytt passord…", + "user.changeRole": "Bytt rolle", + "user.changeRole.select": "Velg en ny rolle", + "user.create": "Legg til ny bruker", + "user.delete": "Slett denne brukeren", + "user.delete.confirm": "Vil du virkelig slette denne konten?", + + "users": "Brukere", + + "version": "Kirby versjon", + + "view.account": "Din konto", + "view.installation": "Installasjon", + "view.languages": "Språk", + "view.resetPassword": "Tilbakestill passord", + "view.site": "Side", + "view.system": "System", + "view.users": "Brukere", + + "welcome": "Velkommen", + "year": "År", + "yes": "ja" } diff --git a/kirby/i18n/translations/nl.json b/kirby/i18n/translations/nl.json index 1677160..b78ec60 100644 --- a/kirby/i18n/translations/nl.json +++ b/kirby/i18n/translations/nl.json @@ -1,730 +1,574 @@ { - "account.changeName": "Wijzig je naam", - "account.delete": "Verwijder je account", - "account.delete.confirm": "Wil je echt je account verwijderen? Je wordt direct uitgelogd. Je account kan niet worden hersteld.", - - "activate": "Activeren", - "add": "Voeg toe", - "alpha": "Alpha", - "author": "Auteur", - "avatar": "Avatar", - "back": "Terug", - "cancel": "Annuleren", - "change": "Wijzigen", - "close": "Sluiten", - "changes": "Wijzigingen", - "confirm": "Oke", - "collapse": "Sluit", - "collapse.all": "Sluit alles", - "color": "Kleur", - "coordinates": "Coördinaten ", - "copy": "Kopiëren", - "copy.all": "Kopieer alles", - "copy.success": "{count} gekopieerd!", - "create": "Aanmaken", - "custom": "Custom", - - "date": "Datum", - "date.select": "Selecteer een datum", - - "day": "Dag", - "days.fri": "Vr", - "days.mon": "Ma", - "days.sat": "Za", - "days.sun": "Zo", - "days.thu": "Do", - "days.tue": "Di", - "days.wed": "Wo", - - "debugging": "Foutopsporing", - - "delete": "Verwijderen", - "delete.all": "Verwijder alles", - - "dialog.fields.empty": "Dit venster heeft geen velden", - "dialog.files.empty": "Geen bestanden om te selecteren", - "dialog.pages.empty": "Geen pagina's om te selecteren", - "dialog.text.empty": "Dit venster bevat geen tekst", - "dialog.users.empty": "Geen gebruikers om te selecteren", - - "dimensions": "Dimensies", - "disable": "Uitschakelen", - "disabled": "Uitgeschakeld", - "discard": "Annuleren", - - "drawer.fields.empty": "Deze drawer heeft geen velden", - - "domain": "Domein", - "download": "Download", - "duplicate": "Dupliceren", - - "edit": "Wijzig", - - "email": "E-mailadres", - "email.placeholder": "mail@voorbeeld.nl", - - "enter": "Enter", - "entries": "Items", - "entry": "Item", - - "environment": "Omgeving", - - "error": "Foutmelding", - "error.access.code": "Ongeldige code", - "error.access.login": "Ongeldige login", - "error.access.panel": "Je hebt geen toegang tot het Panel", - "error.access.view": "Je hebt geen toegangsrechten voor dit gedeelte van het Panel", - - "error.avatar.create.fail": "De avatar kon niet worden geupload", - "error.avatar.delete.fail": "De avatar kan niet worden verwijderd", - "error.avatar.dimensions.invalid": "Houd de breedte en hoogte van de avatar onder 3000 pixels", - "error.avatar.mime.forbidden": "De avatar moet een JPEG of PNG bestand zijn", - - "error.blueprint.notFound": "De blueprint \"{name}\" kon niet geladen worden", - - "error.blocks.max.plural": "Je kunt niet meer dan {max} blokken toevoegen", - "error.blocks.max.singular": "Je kunt niet meer dan één blok toevoegen", - "error.blocks.min.plural": "Je moet ten minste {min} blok toevoegen", - "error.blocks.min.singular": "Je moet ten minste één blok toevoegen", - "error.blocks.validation": "Er is een fout opgetreden bij het \"{field}\" veld in blok {index} in het \"{fieldset}\" bloktype", - - "error.cache.type.invalid": "Ongeldig cache type \"{type}\"", - - "error.email.preset.notFound": "De e-mailvoorinstelling \"{name}\" kan niet worden gevonden", - - "error.field.converter.invalid": "Ongeldige converter \"{converter}\"", - "error.field.type.missing": "Veld \"{ name }\": Het veldtype \"{ type }\" bestaat niet", - - "error.file.changeName.empty": "De naam mag niet leeg zijn", - "error.file.changeName.permission": "Je hebt geen rechten om de naam te wijzigen van \"{filename}\"", - "error.file.changeTemplate.invalid": "Het template voor het bestand \"{id}\" kan niet worden gewijzigd in \"{template}\" (geldig: \"{blueprints}\")", - "error.file.changeTemplate.permission": "Je hebt geen rechten om het template te wijzigen voor bestand \"{id}\"", - - "error.file.duplicate": "Er bestaat al een bestand met de naam \"{filename}\"", - "error.file.extension.forbidden": "Bestandsextensie \"{extension}\" is niet toegestaan", - "error.file.extension.invalid": "Ongeldige extensie: {extension}", - "error.file.extension.missing": "Je kunt geen bestanden uploaden zonder bestandsextensie", - "error.file.maxheight": "De hoogte van de afbeelding mag niet groter zijn dan {height} pixels", - "error.file.maxsize": "Het bestand is te groot", - "error.file.maxwidth": "De breedte van de afbeelding mag niet groter zijn dan {width} pixels", - "error.file.mime.differs": "Het geüploade bestand moet van hetzelfde mime-type zijn: \"{mime}\"", - "error.file.mime.forbidden": "Het type \"{mime}\" is niet toegestaan", - "error.file.mime.invalid": "Ongeldig media type: {mine}", - "error.file.mime.missing": "Het mediatype voor \"{filename}\" kan niet worden gedecteerd", - "error.file.minheight": "De hoogte van de afbeelding moet minimaal {height} pixels zijn", - "error.file.minsize": "Het bestand is te klein", - "error.file.minwidth": "De breedte van de afbeelding moet minimaal {width} pixels zijn", - "error.file.name.unique": "De bestandsnaam moet uniek zijn", - "error.file.name.missing": "De bestandsnaam mag niet leeg zijn", - "error.file.notFound": "Het bestand kan niet worden gevonden", - "error.file.orientation": "De oriëntatie van de afbeelding moet \"{orientation}\" zijn", - "error.file.type.forbidden": "Je hebt geen rechten om {type} bestanden up te loaden", - "error.file.type.invalid": "Ongeldig bestands type: {type}", - "error.file.undefined": "Het bestand kan niet worden gevonden", - - "error.form.incomplete": "Verbeter alle fouten in het formulier", - "error.form.notSaved": "Het formulier kon niet worden opgeslagen", - - "error.language.code": "Vul een geldige code voor deze taal in", - "error.language.duplicate": "De taal bestaat al", - "error.language.name": "Vul een geldige naam voor deze taal in", - "error.language.notFound": "De taal kan niet worden gevonden", - - "error.layout.validation.block": "Er is een fout opgetreden bij het \"{field}\" veld in blok {blockIndex} in het \"{fieldset}\" bloktype in layout {layoutIndex}", - "error.layout.validation.settings": "Er is een fout gevonden in de instellingen van ontwerp {index} ", - - "error.license.domain": "Het domein voor de licentie ontbreekt", - "error.license.email": "Gelieve een geldig emailadres in te voeren", - "error.license.format": "Vul een geldige licentie in", - "error.license.verification": "De licentie kon niet worden geverifieerd. ", - - "error.login.totp.confirm.invalid": "Ongeldige code", - "error.login.totp.confirm.missing": "Vul de code in", - - "error.object.validation": "Er is een fout opgetreden in het veld \"{label}\":\n{message}", - - "error.offline": "Het Panel is momenteel offline", - - "error.page.changeSlug.permission": "Je kunt de URL van deze pagina niet wijzigen", - "error.page.changeSlug.reserved": "Het pad van hoofdpagina's mogen niet beginnen met \"{path}\".", - "error.page.changeStatus.incomplete": "Deze pagina bevat fouten en kan niet worden gepubliceerd", - "error.page.changeStatus.permission": "De status van deze pagina kan niet worden gewijzigd", - "error.page.changeStatus.toDraft.invalid": "De pagina \"{slug}\" kan niet worden aangepast naar 'concept'", - "error.page.changeTemplate.invalid": "De template van deze pagina \"{slug}\" kan niet worden gewijzigd", - "error.page.changeTemplate.permission": "Je hebt geen rechten om het template te wijzigen van \"{slug}\"", - "error.page.changeTitle.empty": "De titel mag niet leeg zijn", - "error.page.changeTitle.permission": "Je hebt geen rechten om de titel te wijzigen van \"{slug}\"", - "error.page.create.permission": "Je hebt geen rechten om \"{slug}\" aan te maken", - "error.page.delete": "De pagina \"{slug}\" kan niet worden verwijderd", - "error.page.delete.confirm": "Voer de paginatitel in om te bevestigen", - "error.page.delete.hasChildren": "Deze pagina heeft subpagina's en kan niet worden verwijderd", - "error.page.delete.permission": "Je hebt geen rechten om \"{slug}\" te verwijderen", - "error.page.draft.duplicate": "Er bestaat al een conceptpagina met de URL-appendix \"{slug}\"", - "error.page.duplicate": "Er bestaat al een pagina met de URL-appendix \"{slug}\"", - "error.page.duplicate.permission": "Je bent niet gemachtigd om \"{slug}\" te dupliceren", - "error.page.move.ancestor": "De pagina kan niet in zichzelf worden verplaatst", - "error.page.move.directory": "De page map kan niet worden verplaatst", - "error.page.move.duplicate": "Er bestaat al een subpagina met de URL-appendix \"{slug}\"", - "error.page.move.notFound": "De verplaatste pagina kan niet gevonden worden", - "error.page.move.permission": "Je hebt geen rechten om \"{slug}\" te verplaatsen", - "error.page.move.template": "De \"{template}\" template is niet toegestaan als een subpagina van \"{parent}\"", - "error.page.notFound": "De pagina \"{slug}\" kan niet worden gevonden", - "error.page.num.invalid": "Vul een geldig sorteer-cijfer in. Het cijfer mag niet negatief zijn", - "error.page.slug.invalid": "Vul een geldig URL-achtervoegsel in", - "error.page.slug.maxlength": "Slug lengte moet minder dan \"{length}\" tekens bevatten", - "error.page.sort.permission": "De pagina \"{slug}\" kan niet worden gesorteerd", - "error.page.status.invalid": "Zorg voor een geldige paginastatus", - "error.page.undefined": "De pagina kan niet worden gevonden", - "error.page.update.permission": "Je hebt geen rechten om \"{slug}\" te updaten", - - "error.section.files.max.plural": "Voeg niet meer dan {max} bestanden toe aan de zone \"{section}\"", - "error.section.files.max.singular": "Je kunt niet meer dan 1 bestand toevoegen aan de zone \"{section}\"", - "error.section.files.min.plural": "De \"{section}\" sectie moet minimaal {min} bestanden bevatten.", - "error.section.files.min.singular": "De \"{section}\" sectie moet minimaal 1 bestand bevatten.", - - "error.section.pages.max.plural": "Je kunt niet meer dan {max} pagina's toevoegen aan de zone \"{section}\"", - "error.section.pages.max.singular": "Je kunt niet meer dan 1 pagina toevoegen aan de zone \"{section}\"", - "error.section.pages.min.plural": "De \"{section}\" sectie moet minimaal {min} pagina's bevatten.", - "error.section.pages.min.singular": "De \"{section}\" sectie moet minimaal 1 pagina bevatten.", - - "error.section.notLoaded": "De zone \"{name}\" kan niet worden geladen", - "error.section.type.invalid": "Zone-type \"{type}\" is niet geldig", - - "error.site.changeTitle.empty": "De titel mag niet leeg zijn", - "error.site.changeTitle.permission": "Je hebt geen rechten om de titel van de site te wijzigen", - "error.site.update.permission": "Je hebt geen rechten om de site te updaten", - - "error.structure.validation": "Er is een fout opgetreden in veld \"{field}\" in rij {index}", - - "error.template.default.notFound": "Het standaard template bestaat niet", - - "error.unexpected": "Een onverwacht fout heeft plaats gevonden! Schakel debug-modus in voor meer informatie: https://getkirby.com/docs/reference/system/options/debug", - - "error.user.changeEmail.permission": "Je hebt geen rechten om het e-mailadres van gebruiker \"{name}\" te wijzigen", - "error.user.changeLanguage.permission": "Je hebt geen rechten om de taal voor gebruiker \"{name}\" te wijzigen", - "error.user.changeName.permission": "Je hebt geen rechten om de naam van gebruiker \"{name}\" te wijzigen", - "error.user.changePassword.permission": "Je hebt geen rechten om het wachtwoord van gebruiker \"{name}\" te wijzigen", - "error.user.changeRole.lastAdmin": "De rol van de laatste beheerder kan niet worden gewijzigd", - "error.user.changeRole.permission": "Je hebt geen rechten om de rol van gebruiker \"{name}\" te wijzigen", - "error.user.changeRole.toAdmin": "Je hebt geen rechten om de rol van iemand te wijzigen naar admin", - "error.user.create.permission": "Je hebt geen rechten om deze gebruiker aan te maken", - "error.user.delete": "De gebruiker \"{name}\" kan niet worden verwijderd", - "error.user.delete.lastAdmin": "Je kan de laatste admin niet verwijderen", - "error.user.delete.lastUser": "De laatste gebruiker kan niet worden verwijderd", - "error.user.delete.permission": "Je hebt geen rechten om gebruiker \"{name}\" te verwijderen", - "error.user.duplicate": "Er bestaat al een gebruiker met e-mailadres \"{email}\"", - "error.user.email.invalid": "Vul een geldig e-mailadres in", - "error.user.language.invalid": "Vul een geldige taal in", - "error.user.notFound": "De gebruiker \"{name}\" kan niet worden gevonden", - "error.user.password.excessive": "Voer een geldig wachtwoord in. Wachtwoorden mogen niet langer zijn dan 1000 tekens.", - "error.user.password.invalid": "Voer een geldig wachtwoord in. Wachtwoorden moeten minstens 8 tekens lang zijn.", - "error.user.password.notSame": "De wachtwoorden komen niet overeen", - "error.user.password.undefined": "De gebruiker heeft geen wachtwoord", - "error.user.password.wrong": "Fout wachtwoord", - "error.user.role.invalid": "Vul een geldige rol in", - "error.user.undefined": "De gebruiker kan niet worden gevonden", - "error.user.update.permission": "Je hebt geen rechten om gebruiker \"{name}\" te updaten", - - "error.validation.accepted": "Ga akkoord", - "error.validation.alpha": "Vul alleen a-z karakters in", - "error.validation.alphanum": "Vul alleen tekens in tussen a-z of cijfers 0-9", - "error.validation.anchor": "Vul een juiste link in", - "error.validation.between": "Vul een waarde tussen \"{min}\" en \"{max}\"", - "error.validation.boolean": "Ga akkoord of weiger", - "error.validation.color": "Vul een geldige kleur in {format} in", - "error.validation.contains": "Vul een waarde in die \"{needle}\" bevat", - "error.validation.date": "Vul een geldige datum in", - "error.validation.date.after": "Vul een datum in na {date}", - "error.validation.date.before": "Vul een datum in voor {date}", - "error.validation.date.between": "Vul een datum in tussen {min} en {max}", - "error.validation.denied": "Weiger", - "error.validation.different": "De invoer mag niet \"{other}\" zijn", - "error.validation.email": "Vul een geldig e-mailadres in", - "error.validation.endswith": "De invoer moet eindigen met \"{end}\"", - "error.validation.filename": "Vul een geldige bestandsnaam in", - "error.validation.in": "Vul één van de volgende dingen in: ({in})", - "error.validation.integer": "Vul een geldig geheel getal in", - "error.validation.ip": "Vul een geldig IP-adres in", - "error.validation.less": "Vul een waarde in lager dan {max}", - "error.validation.linkType": "Het type link is niet toegestaan", - "error.validation.match": "De invoer klopt niet met het verwachte patroon", - "error.validation.max": "Vul een waarde in die gelijk is aan of lager dan {max}", - "error.validation.maxlength": "Gebruik minder karakters (maximaal {max} karakters)", - "error.validation.maxwords": "Vul minder dan {max} woord(en) in", - "error.validation.min": "Vul een waarde in die gelijk is aan of groter dan {min}", - "error.validation.minlength": "Gebruik meer karakters (minimaal {min} karakters)", - "error.validation.minwords": "Vul minimaal {min} woord(en) in", - "error.validation.more": "Vul een grotere waarde in dan {min}", - "error.validation.notcontains": "Zorg dat de invoer niet \"{needle}\" bevat", - "error.validation.notin": "Vul de volgende dingen niet in: ({notIn})", - "error.validation.option": "Selecteer een geldige optie", - "error.validation.num": "Vul een geldig cijfer in", - "error.validation.required": "Vul iets in", - "error.validation.same": "Vul \"{other}\" in", - "error.validation.size": "De lengte van de invoer moet \"{size}\" zijn", - "error.validation.startswith": "De invoer moet beginnen met \"{start}\"", - "error.validation.tel": "Vul een niet-geformatteerd telefoonnummer in", - "error.validation.time": "Vul een geldige tijd in", - "error.validation.time.after": "Vul een tijd in na {time}", - "error.validation.time.before": "Vul een tijd in voor {time}", - "error.validation.time.between": "Vul een tijd in tussen {min} en {max}", - "error.validation.uuid": "Vul een geldige UUID in", - "error.validation.url": "Vul een geldige URL in", - - "expand": "Open", - "expand.all": "Open alles", - - "field.invalid": "Dit veld is niet geldig", - "field.required": "Dit veld is verplicht", - "field.blocks.changeType": "Wijzig type", - "field.blocks.code.name": "Code", - "field.blocks.code.language": "Taal", - "field.blocks.code.placeholder": "Jouw code ...", - "field.blocks.delete.confirm": "Wil je echt dit blok wilt verwijderen?", - "field.blocks.delete.confirm.all": "Wil je echt alle blokken verwijderen?", - "field.blocks.delete.confirm.selected": "Wil je de geselecteerde blokken echt verwijderen?", - "field.blocks.empty": "Nog geen blokken", - "field.blocks.fieldsets.empty": "Nog geen veldsets", - "field.blocks.fieldsets.label": "Selecteer een bloktype ...", - "field.blocks.fieldsets.paste": "Druk op {{ shortcut }} om layouts/blokken van je klembord te importeren Alleen de toegestane layouts/blokken in het huidige veld worden ingevoegd.", - "field.blocks.gallery.name": "Galerij", - "field.blocks.gallery.images.empty": "Nog geen afbeeldingen", - "field.blocks.gallery.images.label": "Afbeeldingen", - "field.blocks.heading.level": "Niveau", - "field.blocks.heading.name": "Koptekst", - "field.blocks.heading.text": "Tekst", - "field.blocks.heading.placeholder": "Koptekst ...", - "field.blocks.image.alt": "Alternatieve tekst", - "field.blocks.image.caption": "Beschrijving", - "field.blocks.image.crop": "Uitsnede", - "field.blocks.image.link": "Link", - "field.blocks.image.location": "Locatie", - "field.blocks.image.location.internal": "Deze website", - "field.blocks.image.location.external": "Externe bron", - "field.blocks.image.name": "Afbeelding", - "field.blocks.image.placeholder": "Selecteer een afbeelding", - "field.blocks.image.ratio": "Verhouding", - "field.blocks.image.url": "Afbeeldings-URL", - "field.blocks.line.name": "Lijn", - "field.blocks.list.name": "Lijst", - "field.blocks.markdown.name": "Markdown", - "field.blocks.markdown.label": "Tekst", - "field.blocks.markdown.placeholder": "Markdown ...", - "field.blocks.quote.name": "Citaat", - "field.blocks.quote.text.label": "Tekst", - "field.blocks.quote.text.placeholder": "Citaat ...", - "field.blocks.quote.citation.label": "Bron", - "field.blocks.quote.citation.placeholder": "door ...", - "field.blocks.text.name": "Tekst", - "field.blocks.text.placeholder": "Tekst ...", - "field.blocks.video.autoplay": "Automatisch afspelen", - "field.blocks.video.caption": "Beschrijving", - "field.blocks.video.controls": "Besturingselementen", - "field.blocks.video.location": "Locatie", - "field.blocks.video.loop": "Herhalen", - "field.blocks.video.muted": "Gedempt", - "field.blocks.video.name": "Video", - "field.blocks.video.placeholder": "Voer een video link in", - "field.blocks.video.poster": "Afbeelding", - "field.blocks.video.preload": "Vooral laden", - "field.blocks.video.url.label": "Video link", - "field.blocks.video.url.placeholder": "https://youtube.com/?v=", - - "field.files.empty": "Nog geen bestanden geselecteerd", - - "field.layout.change": "Verander layout", - "field.layout.delete": "Verwijder indeling", - "field.layout.delete.confirm": "Weet je zeker dat je deze layout wilt verwijderen?", - "field.layout.delete.confirm.all": "Weet je zeker dat je alle layouts wilt verwijderen?", - "field.layout.empty": "Er zijn nog geen rijen", - "field.layout.select": "Selecteer een indeling", - - "field.object.empty": "Nog geen informatie", - - "field.pages.empty": "Nog geen pagina's geselecteerd", - - "field.structure.delete.confirm": "Wil je deze rij verwijderen?", - "field.structure.delete.confirm.all": "Weet je zeker dat je alle items wil verwijderen?", - "field.structure.empty": "Nog geen items", - - "field.users.empty": "Nog geen gebruikers geselecteerd", - - "fields.empty": "Nog geen velden", - - "file": "Bestand", - "file.blueprint": "Dit bestand heeft nog geen blauwdruk. U kunt de instellingen definiëren in /site/blueprints/files/{blueprint}.yml", - "file.changeTemplate": "Verander template", - "file.changeTemplate.notice": "Door het template van het bestand te wijzigen, wordt inhoud verwijderd voor velden waarvan het type niet overeenkomt. Als het nieuwe template bepaalde regels definieert, bv. afmetingen van afbeeldingen, dan worden die ook onomkeerbaar toegepast. Wees hier voorzichtig mee.", - "file.delete.confirm": "Wil je dit bestand
{filename} verwijderen?", - "file.focus.placeholder": "Set focal point", - "file.focus.reset": "Remove focal point", - "file.focus.title": "Focus", - "file.sort": "Verander positie", - - "files": "Bestanden", - "files.empty": "Nog geen bestanden", - - "filter": "Filter", - - "hide": "Verberg", - "hour": "Uur", - "hue": "Hue", - "import": "Importeer", - "info": "Info", - "insert": "Toevoegen", - "insert.after": "Voeg toe na", - "insert.before": "Voeg toe voor", - "install": "Installeren", - - "installation": "Installatie", - "installation.completed": "Het Panel is geïnstalleerd", - "installation.disabled": "Je kan geen Panel installatie uitvoeren op een openbare server. Voer het installatieprogramma uit op een lokale computer of schakel het in met de panel.install optie.", - "installation.issues.accounts": "De map /site/accounts heeft geen schrijfrechten", - "installation.issues.content": "De map /content bestaat niet of heeft geen schrijfrechten", - "installation.issues.curl": "De CURL-extensie is vereist", - "installation.issues.headline": "Het Panel kan niet worden geïnstalleerd", - "installation.issues.mbstring": "De MB String extensie is verplicht", - "installation.issues.media": "De map /mediabestaat niet of heeft geen schrijfrechten", - "installation.issues.php": "Gebruik PHP8+", - "installation.issues.sessions": "De map /site/sessions bestaat niet of heeft geen schrijfrechten", - - "language": "Taal", - "language.code": "Code", - "language.convert": "Maak standaard", - "language.convert.confirm": "

Weet je zeker dat je {name} wilt aanpassen naar de standaard taal? Dit kan niet ongedaan worden gemaakt

Als {name} nog niet vertaalde content heeft, is er geen content meer om op terug te vallen en zouden delen van je site leeg kunnen zijn.

", - "language.create": "Nieuwe taal toevoegen", - "language.default": "Standaard taal", - "language.delete.confirm": "Weet je zeker dat je de taal {name} inclusief alle vertalingen wilt verwijderen? Je kunt dit niet ongedaan maken!", - "language.deleted": "De taal is verwijderd", - "language.direction": "Leesrichting", - "language.direction.ltr": "Links naar rechts", - "language.direction.rtl": "Rechts naar links", - "language.locale": "PHP-locale regel", - "language.locale.warning": "Je gebruikt een aangepaste landinstelling. Wijzig het het taalbestand in /site/languages", - "language.name": "Naam", - "language.secondary": "Tweede taal", - "language.settings": "Taal instellingen", - "language.updated": "De taal is geüpdatet", - "language.variables": "Taal variabelen", - "language.variables.empty": "Nog geen vertalingen", - - "language.variable.delete.confirm": "Weet je zeker dat je de variabele voor {key} wil verwijderen?", - "language.variable.key": "Key", - "language.variable.notFound": "De variabele kan niet gevonden worden", - "language.variable.value": "Waarde", - - "languages": "Talen", - "languages.default": "Standaard taal", - "languages.empty": "Er zijn nog geen talen", - "languages.secondary": "Andere talen", - "languages.secondary.empty": "Er zijn nog geen andere talen beschikbaar", - - "license": "Licentie", - "license.activate": "Activeer nu", - "license.activate.label": "Activeer je licentie", - "license.activate.domain": "Je licentie wordt geactiveerd voor {host}.", - "license.activate.local": "Je staat op het punt om je Kirby licentie voor je lokale domein {host} te activeren. Als deze site op een publiek domein geplaatst wordt, activeer deze licentie dan daar. Als het domein {host} wel degene is die je voor deze licentie wil gebruiken, ga dan door.", - "license.activated": "Geactiveerd", - "license.buy": "Koop een licentie", - "license.code": "Code", - "license.code.help": "Je hebt de licentiecode via e-mail gekregen nadat je de aankoop hebt gedaan. Kopieer en plak de licentiecode hier.", - "license.code.label": "Vul je licentie in", - "license.status.active.info": "Inclusief nieuwe major versies tot {date}", - "license.status.active.label": "Geldige licentie", - "license.status.demo.info": "Dit is een demo installatie", - "license.status.demo.label": "Demo", - "license.status.inactive.info": "Verleng licentie om bij te werken naar nieuwe versies", - "license.status.inactive.label": "Geen nieuwe major versies", - "license.status.legacy.bubble": "Klaar om je licentie te vernieuwen?", - "license.status.legacy.info": "Je licentie dekt deze versie niet", - "license.status.legacy.label": "Verleng je licentie", - "license.status.missing.bubble": "Klaar om je website te lanceren?", - "license.status.missing.info": "Geen geldige licentie", - "license.status.missing.label": "Activeer je licentie", - "license.manage": "Beheer je licenties", - "license.purchased": "Gekocht", - "license.success": "Bedankt dat je Kirby ondersteunt", - "license.unregistered.label": "Niet geregistreerd", - - "link": "Link", - "link.text": "Linktekst", - - "loading": "Laden", - - "lock.unsaved": "Niet opgeslagen wijzigingen", - "lock.unsaved.empty": "Er zijn geen niet opgeslagen wijzigingen meer", - "lock.isLocked": "Niet opgeslagen wijzigingen door {email}", - "lock.unlock": "Ontgrendelen", - "lock.unlock.submit": "Niet-opgeslagen wijzigingen ontgrendelen en overschrijven met {email}", - "lock.isUnlocked": "Is ontgrendeld door een andere gebruiker", - - "login": "Inloggen", - "login.code.label.login": "Log in code", - "login.code.label.password-reset": "Wachtwoord herstel code", - "login.code.placeholder.email": "000 000", - "login.code.placeholder.totp": "000000", - "login.code.text.email": "Als je e-mailadres is geregistreerd, is de aangevraagde code per e-mail verzonden.", - "login.code.text.totp": "Vul de eenmalige code in vanuit je Authenticator-app. ", - "login.email.login.body": "Hallo {user.nameOrEmail},\n\nJe hebt onlangs een inlogcode aangevraagd voor het panel van {site}.\nDe volgende inlogcode is geldig voor {timeout} minuten:\n\n{code}\n\nAls je geen inlogcode hebt aangevraagd, negeer deze e-mail dan of neem contact op met de beheerder als je vragen hebt.\nStuur deze e-mail voor de zekerheid NIET door.", - "login.email.login.subject": "Jouw log in code", - "login.email.password-reset.body": "Hallo {user.nameOrEmail},\n\nJe hebt onlangs een wachtwoord reset code aangevraagd voor het panel van {site}.\nDe volgende wachtwoord reset code is geldig voor {timeout} minuten:\n\n{code}\n\nAls je geen wachtwoord reset code hebt aangevraagd, negeer dan deze e-mail of neem contact op met de beheerder als je vragen hebt.\nStuur deze e-mail voor de zekerheid NIET door.", - "login.email.password-reset.subject": "Jouw wachtwoord herstel code", - "login.remember": "Houd mij ingelogd", - "login.reset": "Wachtwoord herstellen", - "login.toggleText.code.email": "Log in via email", - "login.toggleText.code.email-password": "Log in met je wachtwoord", - "login.toggleText.password-reset.email": "Wachtwoord vergeten?", - "login.toggleText.password-reset.email-password": "← Terug naar log in", - "login.totp.enable.option": "Stel eenmalige codes in.", - "login.totp.enable.intro": "Authenticator-apps kunnen eenmalige codes genereren die dienen als een tweede factor als jij inlogt in je account.", - "login.totp.enable.qr.label": "1. Scan deze QR code", - "login.totp.enable.qr.help": "Problemen met scannen? Voeg de setup key {secret} handmatig toe aan je Authenticator-app.", - "login.totp.enable.confirm.headline": "2. Bevestig met een gegenereerde code", - "login.totp.enable.confirm.text": "De app genereert elke 30 seconden een nieuwe eenmalige code. Voer de huidige code in om de setup af te ronden:", - "login.totp.enable.confirm.label": "Huidige code", - "login.totp.enable.confirm.help": "Na het instellen zullen we elke keer om een eenmalige code vragen bij het inloggen.", - "login.totp.enable.success": "Eenmalige codes geactiveerd", - "login.totp.disable.option": "Schakel eenmalige codes uit", - "login.totp.disable.label": "Voer je wachtwoord in om eenmalige codes uit te schakelen", - "login.totp.disable.help": "In de toekomst zal een andere tweede factor, zoals een inlogcode die via e-mail wordt verzonden, worden gevraagd wanneer je inlogt. Je kunt later altijd weer eenmalige codes instellen.", - "login.totp.disable.admin": "

Dit schakelt eenmalige codes uit voor {user}.

In de toekomst zal bij het inloggen om een andere tweede factor worden gevraagd, zoals een inlogcode die via e-mail wordt verzonden. {user} kan na zijn volgende aanmelding opnieuw eenmalige codes instellen.

", - "login.totp.disable.success": "Eenmalige codes uitgeschakeld", - - "logout": "Uitloggen", - - "merge": "Merge", - "menu": "Menu", - "meridiem": "AM/PM", - "mime": "Mime-type", - "minutes": "Minuten", - - "month": "Maand", - "months.april": "april", - "months.august": "augustus", - "months.december": "december", - "months.february": "februari", - "months.january": "januari", - "months.july": "juli", - "months.june": "juni", - "months.march": "maart", - "months.may": "mei", - "months.november": "november", - "months.october": "oktober", - "months.september": "september", - - "more": "Meer", - "move": "Verplaatsen", - "name": "Naam", - "next": "Volgende", - "night": "Nacht", - "no": "nee", - "off": "uit", - "on": "aan", - "open": "Open", - "open.newWindow": "Openen in een nieuw scherm", - "option": "Option", - "options": "Opties", - "options.none": "Geen opties beschikbaar", - "options.all": "Laat alle {count} opties zien", - - "orientation": "Oriëntatie", - "orientation.landscape": "Liggend", - "orientation.portrait": "Staand", - "orientation.square": "Vierkant", - - "page": "Pagina", - "page.blueprint": "Deze pagina heeft nog geen blauwdruk. Je kan de instellingen definiëren in /site/blueprints/pages/{blueprint}.yml", - "page.changeSlug": "Verander URL", - "page.changeSlug.fromTitle": "Aanmaken op basis van titel", - "page.changeStatus": "Wijzig status", - "page.changeStatus.position": "Selecteer een positie", - "page.changeStatus.select": "Selecteer een nieuwe status", - "page.changeTemplate": "Verander template", - "page.changeTemplate.notice": "Door de template te wijzigen, wordt inhoud verwijderd voor velden waarvan het type niet overeenkomt. Gebruik dit voorzichtig.", - "page.create": "Maak aan als {status}", - "page.delete.confirm": "Weet je zeker dat je pagina {title} wilt verwijderen?", - "page.delete.confirm.subpages": "Deze pagina heeft subpagina's.
Alle subpagina's zullen ook worden verwijderd.", - "page.delete.confirm.title": "Voeg een paginatitel in om te bevestigen", - "page.duplicate.appendix": "Kopiëren", - "page.duplicate.files": "Kopieer bestanden", - "page.duplicate.pages": "Kopieer pagina's", - "page.move": "Move page", - "page.sort": "Verander positie", - "page.status": "Status", - "page.status.draft": "Concept", - "page.status.draft.description": "De pagina is in concept-modus en alleen zichtbaar voor ingelogde redacteuren of via een geheime link", - "page.status.listed": "Openbaar", - "page.status.listed.description": "Deze pagina is toegankelijk voor iedereen", - "page.status.unlisted": "Niet gepubliceerd", - "page.status.unlisted.description": "Deze pagina is alleen bereikbaar via URL", - - "pages": "Pagina’s", - "pages.empty": "Nog geen pagina's", - "pages.status.draft": "Concepten", - "pages.status.listed": "Gepubliceerd", - "pages.status.unlisted": "Niet gepubliceerd", - - "pagination.page": "Pagina", - - "password": "Wachtwoord", - "paste": "Plak", - "paste.after": "Plak achter", - "paste.success": "{count} geplakt!", - "pixel": "Pixel", - "plugin": "Plugin", - "plugins": "Plugins", - "prev": "Vorige", - "preview": "Voorbeeld", - "remove": "Verwijder", - "rename": "Hernoem", - "renew": "Verlengen", - "replace": "Vervang", - "replace.with": "Vervangen met", - "retry": "Probeer opnieuw", - "revert": "Annuleren", - "revert.confirm": "Weet je zeker dat je alle niet-opgeslagen veranderingen wilt verwijderen?", - - "role": "Rol", - "role.admin.description": "De admin heeft alle rechten", - "role.admin.title": "Admin", - "role.all": "Alle", - "role.empty": "Er zijn geen gebruikers met deze rol", - "role.description.placeholder": "Geen beschrijving", - "role.nobody.description": "Dit is een fallback-rol zonder rechten", - "role.nobody.title": "Niemand", - - "save": "Opslaan", - "search": "Zoeken", - "search.min": "Voer {min} tekens in om te zoeken", - "search.all": "Laat alle {count} resultaten zien", - "search.results.none": "Geen resultaten", - - "section.invalid": "De sectie is ongeldig", - "section.required": "De sectie is verplicht", - - "security": "Beveiliging", - "select": "Selecteren", - "server": "Server", - "settings": "Opties", - "show": "Toon", - "site.blueprint": "Deze website heeft nog geen ontwerp. Je kan het ontwerp hier plaatsen/site/blueprints/site.yml", - "size": "Grootte", - "slug": "URL-toevoeging", - "sort": "Sorteren", - "sort.drag": "Sleep om te sorteren ...", - "split": "Splitsen", - - "stats.empty": "Geen rapporten", - "status": "Status", - - "system.info.copy": "Copy info", - "system.info.copied": "System info copied", - "system.issues.content": "De content map lijkt zichtbaar te zijn", - "system.issues.eol.kirby": "De geïnstalleerde Kirby versie is niet meer actueel en zal geen verdere beveiligingsupdates meer ontvangen.", - "system.issues.eol.plugin": "De geïnstalleerde versie van plugin { plugin } is niet meer actueel en zal geen verdere beveiligingsupdates meer ontvangen.", - "system.issues.eol.php": "De geïnstalleerde PHP versie { release } is niet meer actueel en zal geen verdere beveiligingsupdates meer ontvangen.", - "system.issues.debug": "De debug modus moet uitgeschakeld zijn in productie", - "system.issues.git": "De .git map lijkt zichtbaar te zijn", - "system.issues.https": "We raden HTTPS aan voor al je sites", - "system.issues.kirby": "De kirby map lijkt zichtbaar te zijn", - "system.issues.site": "De site map lijkt zichtbaar te zijn", - "system.issues.vulnerability.kirby": "De installatie is mogelijk getroffen door de volgende kwetsbaarheid ({ severity } ernst): { description }", - "system.issues.vulnerability.plugin": "De installatie is mogelijk getroffen door de volgende kwetsbaarheid in plugin { plugin } ({ severity } ernst): { description }", - "system.updateStatus": "Update status", - "system.updateStatus.error": "Kan niet checken voor updates", - "system.updateStatus.not-vulnerable": "Geen bekende kwetsbaarheden", - "system.updateStatus.security-update": "Gratis veiligheids update { version } beschikbaar", - "system.updateStatus.security-upgrade": "Upgrade { version } met veiligheid aanpassingen beschikbaar", - "system.updateStatus.unreleased": "Niet vrijgegeven versie", - "system.updateStatus.up-to-date": "Up to date", - "system.updateStatus.update": "Gratis update { version } beschikbaar", - "system.updateStatus.upgrade": "Upgrade { version } beschikbaar", - - "tel": "Telefoon", - "tel.placeholder": "+49123456789", - "template": "Template", - "title": "Titel", - "today": "Vandaag", - - "toolbar.button.clear": "Verwijder formattering", - "toolbar.button.code": "Code", - "toolbar.button.bold": "Dikgedrukte tekst", - "toolbar.button.email": "E-mailadres", - "toolbar.button.headings": "Kopteksten", - "toolbar.button.heading.1": "Koptekst 1", - "toolbar.button.heading.2": "Koptekst 2", - "toolbar.button.heading.3": "Koptekst 3", - "toolbar.button.heading.4": "Hoofding 4", - "toolbar.button.heading.5": "Hoofding 5", - "toolbar.button.heading.6": "Hoofding 6", - "toolbar.button.italic": "Cursieve tekst", - "toolbar.button.file": "Bestand", - "toolbar.button.file.select": "Selecteer een bestand", - "toolbar.button.file.upload": "Upload bestand", - "toolbar.button.link": "Link", - "toolbar.button.paragraph": "Paragraaf", - "toolbar.button.strike": "Doorstreept", - "toolbar.button.sub": "Subscript", - "toolbar.button.sup": "Superscript", - "toolbar.button.ol": "Genummerde lijst", - "toolbar.button.underline": "Onderlijn", - "toolbar.button.ul": "Opsomming", - - "translation.author": "Het team van Kirby", - "translation.direction": "ltr", - "translation.name": "Nederlands", - "translation.locale": "nl_NL", - - "type": "Type", - - "upload": "Upload", - "upload.error.cantMove": "Het geüploadde bestand kon niet worden verplaatst", - "upload.error.cantWrite": "Fout bij het schrijven van het bestand naar de schijf", - "upload.error.default": "Het bestand kan niet worden geüpload", - "upload.error.extension": "Kan bestand niet uploaden vanwege de extensie", - "upload.error.formSize": "Het geüploadde bestand is groter dan de MAX_FILE_SIZE die is aangegeven in het formulier", - "upload.error.iniPostSize": "Het geüploadde bestand is groter dan de post_max_size in php.ini", - "upload.error.iniSize": "Het geüploadde bestand is groter dan de upload_max_filesize in php.ini", - "upload.error.noFile": "Er is geen bestand geüpload", - "upload.error.noFiles": "Er zijn geen bestanden geüpload", - "upload.error.partial": "Het geüploadde bestand is slechts gedeeltelijk geüpload", - "upload.error.tmpDir": "Er mist een tijdelijke map", - "upload.errors": "Foutmelding", - "upload.progress": "Uploaden...", - - "url": "Url", - "url.placeholder": "https://voorbeeld.nl", - - "user": "Gebruiker", - "user.blueprint": "Je kan aanvullende secties en formuliervelden voor deze gebruikersrol definiëren in /site/blueprints/users/{blueprint}.yml", - "user.changeEmail": "Email veranderen", - "user.changeLanguage": "Taal veranderen", - "user.changeName": "Gebruiker hernoemen", - "user.changePassword": "Wachtwoord wijzigen", - "user.changePassword.new": "Nieuw wachtwoord", - "user.changePassword.new.confirm": "Bevestig het nieuwe wachtwoord...", - "user.changeRole": "Verander rol", - "user.changeRole.select": "Kies een nieuwe rol", - "user.create": "Voeg een nieuwe gebruiker toe", - "user.delete": "Verwijder deze gebruiker", - "user.delete.confirm": "Weet je zeker dat je
{email} wil verwijderen?", - - "users": "Gebruikers", - - "version": "Kirby-versie", - "version.current": "Huidige versie", - "version.latest": "Laatste versie", - "versionInformation": "Versie informatie", - - "view.account": "Jouw account", - "view.installation": "Installatie", - "view.languages": "Talen", - "view.resetPassword": "Wachtwoord herstellen", - "view.site": "Site", - "view.system": "Systeem", - "view.users": "Gebruikers", - - "welcome": "Welkom", - "year": "Jaar", - "yes": "ja" + "account.changeName": "Wijzig je naam", + "account.delete": "Verwijder je account", + "account.delete.confirm": "Wil je echt je account verwijderen? Je wordt direct uitgelogd. Uw account kan niet worden hersteld.", + + "add": "Voeg toe", + "author": "Auteur", + "avatar": "Avatar", + "back": "Terug", + "cancel": "Annuleren", + "change": "Wijzigen", + "close": "Sluiten", + "confirm": "OK", + "collapse": "Sluit", + "collapse.all": "Sluit alles", + "copy": "Kopiëren", + "copy.all": "Kopieer alles", + "create": "Aanmaken", + + "date": "Datum", + "date.select": "Selecteer een datum", + + "day": "Dag", + "days.fri": "Vr", + "days.mon": "Ma", + "days.sat": "Za", + "days.sun": "Zo", + "days.thu": "Do", + "days.tue": "Di", + "days.wed": "Wo", + + "debugging": "Foutopsporing", + + "delete": "Verwijderen", + "delete.all": "Verwijder alles", + + "dialog.files.empty": "Geen bestanden om te selecteren", + "dialog.pages.empty": "Geen pagina's om te selecteren", + "dialog.users.empty": "Geen gebruikers om te selecteren", + + "dimensions": "Dimensies", + "disabled": "Uitgeschakeld", + "discard": "Annuleren", + "download": "Download", + "duplicate": "Dupliceren", + + "edit": "Wijzig", + + "email": "E-mailadres", + "email.placeholder": "mail@voorbeeld.nl", + + "entries": "Entries", + "entry": "Entry", + + "environment": "Omgeving", + + "error.access.code": "Ongeldige code", + "error.access.login": "Ongeldige login", + "error.access.panel": "Je hebt geen toegang tot het Panel", + "error.access.view": "Je hebt geen toegangsrechten voor deze zone van het Panel", + + "error.avatar.create.fail": "De avatar kon niet worden geupload", + "error.avatar.delete.fail": "De avatar kan niet worden verwijderd", + "error.avatar.dimensions.invalid": "Houd de breedte en hoogte van de avatar onder 3000 pixels", + "error.avatar.mime.forbidden": "De avatar moet een JPEG of PNG bestand zijn", + + "error.blueprint.notFound": "De blueprint \"{name}\" kon niet geladen worden", + + "error.blocks.max.plural": "Je kunt niet meer dan {max} blokken toevoegen", + "error.blocks.max.singular": "Je kunt niet meer dan één blok toevoegen", + "error.blocks.min.plural": "Je moet ten minste {min} blok toevoegen", + "error.blocks.min.singular": "Je moet ten minste één blok toevoegen", + "error.blocks.validation": "Er is een fout gevonden in blok {index}", + + "error.email.preset.notFound": "De e-mailvoorinstelling \"{name}\" kan niet worden gevonden", + + "error.field.converter.invalid": "Ongeldige converter \"{converter}\"", + + "error.file.changeName.empty": "De naam mag niet leeg zijn", + "error.file.changeName.permission": "Je hebt geen rechten om de naam te wijzigen van \"{filename}\"", + "error.file.duplicate": "Er bestaat al een bestand met de naam \"{filename}\"", + "error.file.extension.forbidden": "Bestandsextensie \"{extension}\" is niet toegestaan", + "error.file.extension.invalid": "Ongeldige extensie: {extension}", + "error.file.extension.missing": "Je kunt geen bestanden uploaden zonder bestandsextensie", + "error.file.maxheight": "De hoogte van de afbeelding mag niet groter zijn dan {height} pixels", + "error.file.maxsize": "Het bestand is te groot", + "error.file.maxwidth": "De breedte van de afbeelding mag niet groter zijn dan {width} pixels", + "error.file.mime.differs": "Het geüploade bestand moet van hetzelfde mime-type zijn: \"{mime}\"", + "error.file.mime.forbidden": "Het type \"{mime}\" is niet toegestaan", + "error.file.mime.invalid": "Ongeldig media type: {mine}", + "error.file.mime.missing": "Het mediatype voor \"{filename}\" kan niet worden gedecteerd", + "error.file.minheight": "De hoogte van de afbeelding moet minimaal {height} pixels zijn", + "error.file.minsize": "Het bestand is te klein", + "error.file.minwidth": "De breedte van de afbeelding moet minimaal {width} pixels zijn", + "error.file.name.missing": "De bestandsnaam mag niet leeg zijn", + "error.file.notFound": "Het bestand kan niet worden gevonden", + "error.file.orientation": "De oriëntatie van de afbeelding moet \"{orientation}\" zijn", + "error.file.type.forbidden": "Je hebt geen rechten om {type} bestanden up te loaden", + "error.file.type.invalid": "Ongeldig bestands type: {type}", + "error.file.undefined": "Het bestand kan niet worden gevonden", + + "error.form.incomplete": "Verbeter alle fouten in het formulier", + "error.form.notSaved": "Het formulier kon niet worden opgeslagen", + + "error.language.code": "Vul een geldige code voor deze taal in", + "error.language.duplicate": "De taal bestaat al", + "error.language.name": "Vul een geldige naam voor deze taal in", + "error.language.notFound": "De taal kan niet worden gevonden", + + "error.layout.validation.block": "Er is een fout gevonden in blok {blockIndex} in ontwerp {layoutIndex}", + "error.layout.validation.settings": "Er is een fout gevonden in de instellingen van ontwerp {index} ", + + "error.license.format": "Vul een gelidge licentie-key in", + "error.license.email": "Gelieve een geldig emailadres in te voeren", + "error.license.verification": "De licentie kon niet worden geverifieerd. ", + + "error.offline": "Het Panel is momenteel offline", + + "error.page.changeSlug.permission": "Je kunt de URL van deze pagina niet wijzigen", + "error.page.changeStatus.incomplete": "Deze pagina bevat fouten en kan niet worden gepubliceerd", + "error.page.changeStatus.permission": "De status van deze pagina kan niet worden gewijzigd", + "error.page.changeStatus.toDraft.invalid": "De pagina \"{slug}\" kan niet worden aangepast naar 'concept'", + "error.page.changeTemplate.invalid": "De template van deze pagina \"{slug}\" kan niet worden gewijzigd", + "error.page.changeTemplate.permission": "Je hebt geen rechten om het template te wijzigen van \"{slug}\"", + "error.page.changeTitle.empty": "De titel mag niet leeg zijn", + "error.page.changeTitle.permission": "Je hebt geen rechten om de titel te wijzigen van \"{slug}\"", + "error.page.create.permission": "Je hebt geen rechten om \"{slug}\" aan te maken", + "error.page.delete": "De pagina \"{slug}\" kan niet worden verwijderd", + "error.page.delete.confirm": "Voer de paginatitel in om te bevestigen", + "error.page.delete.hasChildren": "Deze pagina heeft subpagina's en kan niet worden verwijderd", + "error.page.delete.permission": "Je hebt geen rechten om \"{slug}\" te verwijderen", + "error.page.draft.duplicate": "Er bestaat al een conceptpagina met de URL-appendix \"{slug}\"", + "error.page.duplicate": "Er bestaat al een pagina met de URL-appendix \"{slug}\"", + "error.page.duplicate.permission": "Je bent niet gemachtigd om \"{slug}\" te dupliceren", + "error.page.notFound": "De pagina \"{slug}\" kan niet worden gevonden", + "error.page.num.invalid": "Vul een geldig sorteer-cijfer in. Het cijfer mag niet negatief zijn", + "error.page.slug.invalid": "Vul een geldig URL-achtervoegsel in", + "error.page.slug.maxlength": "Slug lengte moet minder dan \"{length}\" tekens bevatten", + "error.page.sort.permission": "De pagina \"{slug}\" kan niet worden gesorteerd", + "error.page.status.invalid": "Zorg voor een geldige paginastatus", + "error.page.undefined": "De pagina kan niet worden gevonden", + "error.page.update.permission": "Je hebt geen rechten om \"{slug}\" te updaten", + + "error.section.files.max.plural": "Voeg niet meer dan {max} bestanden toe aan de zone \"{section}\"", + "error.section.files.max.singular": "Je kunt niet meer dan 1 bestand toevoegen aan de zone \"{section}\"", + "error.section.files.min.plural": "De \"{section}\" sectie moet minimaal {min} bestanden bevatten.", + "error.section.files.min.singular": "De \"{section}\" sectie moet minimaal 1 bestand bevatten.", + + "error.section.pages.max.plural": "Je kunt niet meer dan {max} pagina's toevoegen aan de zone \"{section}\"", + "error.section.pages.max.singular": "Je kunt niet meer dan 1 pagina toevoegen aan de zone \"{section}\"", + "error.section.pages.min.plural": "De \"{section}\" sectie moet minimaal {min} pagina's bevatten.", + "error.section.pages.min.singular": "De \"{section}\" sectie moet minimaal 1 pagina bevatten.", + + "error.section.notLoaded": "De zone \"{name}\" kan niet worden geladen", + "error.section.type.invalid": "Zone-type \"{type}\" is niet geldig", + + "error.site.changeTitle.empty": "De titel mag niet leeg zijn", + "error.site.changeTitle.permission": "Je hebt geen rechten om de titel van de site te wijzigen", + "error.site.update.permission": "Je hebt geen rechten om de site te updaten", + + "error.template.default.notFound": "Het standaard template bestaat niet", + + "error.unexpected": "Een onverwacht fout heeft plaats gevonden! Schakel debug-modus in voor meer informatie: https://getkirby.com/docs/reference/system/options/debug", + + "error.user.changeEmail.permission": "Je hebt geen rechten om het e-mailadres van gebruiker \"{name}\" te wijzigen", + "error.user.changeLanguage.permission": "Je hebt geen rechten om de taal voor gebruiker \"{name}\" te wijzigen", + "error.user.changeName.permission": "Je hebt geen rechten om de naam van gebruiker \"{name}\" te wijzigen", + "error.user.changePassword.permission": "Je hebt geen rechten om het wachtwoord van gebruiker \"{name}\" te wijzigen", + "error.user.changeRole.lastAdmin": "De rol van de laatste beheerder kan niet worden gewijzigd", + "error.user.changeRole.permission": "Je hebt geen rechten om de rol van gebruiker \"{name}\" te wijzigen", + "error.user.changeRole.toAdmin": "Je hebt geen rechten om de rol van iemand te wijzigen naar admin", + "error.user.create.permission": "Je hebt geen rechten om deze gebruiker aan te maken", + "error.user.delete": "De gebruiker \"{name}\" kan niet worden verwijderd", + "error.user.delete.lastAdmin": "Je kan de laatste admin niet verwijderen", + "error.user.delete.lastUser": "De laatste gebruiker kan niet worden verwijderd", + "error.user.delete.permission": "Je hebt geen rechten om gebruiker \"{name}\" te verwijderen", + "error.user.duplicate": "Er bestaat al een gebruiker met e-mailadres \"{email}\"", + "error.user.email.invalid": "Gelieve een geldig emailadres in te voeren", + "error.user.language.invalid": "Gelieve een geldige taal in te voeren", + "error.user.notFound": "De gebruiker \"{name}\" kan niet worden gevonden", + "error.user.password.excessive": "Please enter a valid password. Passwords must not be longer than 1000 characters.", + "error.user.password.invalid": "Gelieve een geldig wachtwoord in te voeren. Wachtwoorden moeten minstens 8 karakters lang zijn.", + "error.user.password.notSame": "De wachtwoorden komen niet overeen", + "error.user.password.undefined": "De gebruiker heeft geen wachtwoord", + "error.user.password.wrong": "Fout wachtwoord", + "error.user.role.invalid": "Gelieve een geldige rol in te voeren", + "error.user.undefined": "De gebruiker kan niet worden gevonden", + "error.user.update.permission": "Je hebt geen rechten om gebruiker \"{name}\" te updaten", + + "error.validation.accepted": "Gelieve te bevestigen", + "error.validation.alpha": "Vul alleen a-z karakters in", + "error.validation.alphanum": "Vul alleen a-z karakters of cijfers (0-9) in", + "error.validation.between": "Vul een waarde tussen \"{min}\" en \"{max}\"", + "error.validation.boolean": "Ga akkoord of weiger", + "error.validation.contains": "Vul een waarde in die \"{needle}\" bevat", + "error.validation.date": "Vul een geldige datum in", + "error.validation.date.after": "Vul een datum in na {date}", + "error.validation.date.before": "Vul een datum in voor {date}", + "error.validation.date.between": "Vul een datum in tussen {min} en {max}", + "error.validation.denied": "Weiger", + "error.validation.different": "De invoer mag niet \"{other}\" zijn", + "error.validation.email": "Gelieve een geldig emailadres in te voeren", + "error.validation.endswith": "De invoer moet eindigen met \"{end}\"", + "error.validation.filename": "Vul een geldige bestandsnaam in", + "error.validation.in": "Vul één van de volgende dingen in: ({in})", + "error.validation.integer": "Vul een geldig geheel getal in", + "error.validation.ip": "Vul een geldig IP-adres in", + "error.validation.less": "Vul een waarde in lager dan {max}", + "error.validation.match": "De invoer klopt niet met het verwachte patroon", + "error.validation.max": "Vul een waarde in die gelijk is aan of lager dan {max}", + "error.validation.maxlength": "Gebruik minder karakters (maximaal {max} karakters)", + "error.validation.maxwords": "Vul minder dan {max} woord(en) in", + "error.validation.min": "Vul een waarde in die gelijk is aan of groter dan {min}", + "error.validation.minlength": "Gebruik meer karakters (minimaal {min} karakters)", + "error.validation.minwords": "Vul minimaal {min} woord(en) in", + "error.validation.more": "Vul een grotere waarde in dan {min}", + "error.validation.notcontains": "Zorg dat de invoer niet \"{needle}\" bevat", + "error.validation.notin": "Vul de volgende dingen niet in: ({notIn})", + "error.validation.option": "Selecteer een geldige optie", + "error.validation.num": "Vul een geldig cijfer in", + "error.validation.required": "Vul iets in", + "error.validation.same": "Vul \"{other}\" in", + "error.validation.size": "De lengte van de invoer moet \"{size}\" zijn", + "error.validation.startswith": "De invoer moet beginnen met \"{start}\"", + "error.validation.time": "Vul een geldige tijd in", + "error.validation.time.after": "Voer een tijd in na {time}", + "error.validation.time.before": "Voer een tijd in voor {time}", + "error.validation.time.between": "Voer een tijd in tussen {min} en {max}", + "error.validation.url": "Vul een geldige URL in", + + "expand": "Open", + "expand.all": "Open alles", + + "field.required": "Dit veld is verplicht", + "field.blocks.changeType": "Wijzig type", + "field.blocks.code.name": "Code", + "field.blocks.code.language": "Taal", + "field.blocks.code.placeholder": "Jouw code ...", + "field.blocks.delete.confirm": "Wil je echt dit blok wilt verwijderen?", + "field.blocks.delete.confirm.all": "Wil je echt alle blokken verwijderen?", + "field.blocks.delete.confirm.selected": "Wil je de geselecteerde blokken echt verwijderen?", + "field.blocks.empty": "Nog geen blokken", + "field.blocks.fieldsets.label": "Selecteer een bloktype ...", + "field.blocks.fieldsets.paste": "Druk op {{ shortcut }} om blokken van je klembord te plakken/importeren", + "field.blocks.gallery.name": "Galerij", + "field.blocks.gallery.images.empty": "Nog geen afbeeldingen", + "field.blocks.gallery.images.label": "Afbeeldingen", + "field.blocks.heading.level": "Niveau", + "field.blocks.heading.name": "Koptekst", + "field.blocks.heading.text": "Tekst", + "field.blocks.heading.placeholder": "Koptekst ...", + "field.blocks.image.alt": "Alternatieve tekst", + "field.blocks.image.caption": "Beschrijving", + "field.blocks.image.crop": "Uitsnede", + "field.blocks.image.link": "Link", + "field.blocks.image.location": "Locatie", + "field.blocks.image.name": "Afbeelding", + "field.blocks.image.placeholder": "Selecteer een afbeelding", + "field.blocks.image.ratio": "Verhouding", + "field.blocks.image.url": "Afbeeldings-URL", + "field.blocks.line.name": "Lijn", + "field.blocks.list.name": "Lijst", + "field.blocks.markdown.name": "Markdown", + "field.blocks.markdown.label": "Tekst", + "field.blocks.markdown.placeholder": "Markdown ...", + "field.blocks.quote.name": "Citaat", + "field.blocks.quote.text.label": "Tekst", + "field.blocks.quote.text.placeholder": "Citaat ...", + "field.blocks.quote.citation.label": "Bron", + "field.blocks.quote.citation.placeholder": "door ...", + "field.blocks.text.name": "Tekst", + "field.blocks.text.placeholder": "Tekst ...", + "field.blocks.video.caption": "Beschrijving", + "field.blocks.video.name": "Video", + "field.blocks.video.placeholder": "Voer een video link in", + "field.blocks.video.url.label": "Video link", + "field.blocks.video.url.placeholder": "https://youtube.com/?v=", + + "field.files.empty": "Nog geen bestanden geselecteerd", + + "field.layout.delete": "Verwijder indeling", + "field.layout.delete.confirm": "Weet je zeker dat je deze indeling wilt verwijderen?", + "field.layout.empty": "Er zijn nog geen rijen", + "field.layout.select": "Selecteer een indeling", + + "field.pages.empty": "Nog geen pagina's geselecteerd", + "field.structure.delete.confirm": "Wil je deze entry verwijderen?", + "field.structure.empty": "Nog geen items.", + "field.users.empty": "Nog geen gebruikers geselecteerd", + + "file.blueprint": "Dit bestand heeft nog geen blauwdruk. U kunt de instellingen definiëren in /site/blueprints/files/{blueprint}.yml", + "file.delete.confirm": "Wil je dit bestand
{filename} verwijderen?", + "file.sort": "Verander positie", + + "files": "Bestanden", + "files.empty": "Nog geen bestanden", + + "hide": "Verberg", + "hour": "Uur", + "import": "Importeer", + "info": "Info", + "insert": "Toevoegen", + "insert.after": "Voeg toe na", + "insert.before": "Voeg toe voor", + "install": "Installeren", + + "installation": "Installatie", + "installation.completed": "Het Panel is geïnstalleerd", + "installation.disabled": "Je kan geen Panel installatie uitvoeren op een openbare server. Voer het installatieprogramma uit op een lokale computer of schakel het in met de panel.install optie.", + "installation.issues.accounts": "De map /site/accounts heeft geen schrijfrechten", + "installation.issues.content": "De map /content bestaat niet of heeft geen schrijfrechten", + "installation.issues.curl": "De CURL-extensie is vereist", + "installation.issues.headline": "Het Panel kan niet worden geïnstalleerd", + "installation.issues.mbstring": "De MB String extensie is verplicht", + "installation.issues.media": "De map /mediabestaat niet of heeft geen schrijfrechten", + "installation.issues.php": "Gebruik PHP7+", + "installation.issues.server": "Kirby vereist Apache, Nginx of Caddy", + "installation.issues.sessions": "De map /site/sessions bestaat niet of heeft geen schrijfrechten", + + "language": "Taal", + "language.code": "Code", + "language.convert": "Maak standaard", + "language.convert.confirm": "

Weet je zeker dat je {name} wilt aanpassen naar de standaard taal? Dit kan niet ongedaan worden gemaakt

Als {name} nog niet vertaalde content heeft, is er geen content meer om op terug te vallen en zouden delen van je site leeg kunnen zijn.

", + "language.create": "Nieuwe taal toevoegen", + "language.delete.confirm": "Weet je zeker dat je de taal {name} inclusief alle vertalingen wilt verwijderen? Je kunt dit niet ongedaan maken!", + "language.deleted": "De taal is verwijderd", + "language.direction": "Leesrichting", + "language.direction.ltr": "Links naar rechts", + "language.direction.rtl": "Rechts naar links", + "language.locale": "PHP-locale regel", + "language.locale.warning": "Je gebruikt een aangepaste landinstelling. Wijzig het het taalbestand in /site/languages", + "language.name": "Naam", + "language.updated": "De taal is geüpdatet", + + "languages": "Talen", + "languages.default": "Standaard taal", + "languages.empty": "Er zijn nog geen talen", + "languages.secondary": "Andere talen", + "languages.secondary.empty": "Er zijn nog geen andere talen beschikbaar", + + "license": "Licentie", + "license.buy": "Koop een licentie", + "license.register": "Registreren", + "license.manage": "Manage your licenses", + "license.register.help": "Je hebt de licentie via e-mail gekregen nadat je de aankoop hebt gedaan. Kopieer en plak de licentie om te registreren. ", + "license.register.label": "Vul je licentie in", + "license.register.success": "Bedankt dat je Kirby ondersteunt", + "license.unregistered": "Dit is een niet geregistreerde demo van Kirby", + "license.unregistered.label": "Unregistered", + + "link": "Link", + "link.text": "Linktekst", + + "loading": "Laden", + + "lock.unsaved": "Niet opgeslagen wijzigingen", + "lock.unsaved.empty": "Er zijn geen niet opgeslagen wijzigingen meer", + "lock.isLocked": "Niet opgeslagen wijzigingen door {email}", + "lock.file.isLocked": "Dit bestand wordt momenteel bewerkt door {email} en kan niet worden gewijzigd.", + "lock.page.isLocked": "Deze pagina wordt momenteel bewerkt door {email} en kan niet worden gewijzigd.", + "lock.unlock": "Ontgrendelen", + "lock.isUnlocked": "Je niet opgeslagen wijzigingen zijn overschreven door een andere gebruiker. Je kunt je wijzigingen downloaden om ze handmatig samen te voegen.", + + "login": "Inloggen", + "login.code.label.login": "Log in code", + "login.code.label.password-reset": "Wachtwoord herstel code", + "login.code.placeholder.email": "000 000", + "login.code.text.email": "Als uw e-mailadres geregistreerd is, werd de gevraagde code per e-mail verzonden.", + "login.email.login.body": "Hallo {user.nameOrEmail},\n\nJe hebt onlangs een inlogcode aangevraagd voor het Panel van {site}.\nDe volgende inlogcode is {timeout} minuten geldig:\n\n{code}\n\nAls je geen inlogcode hebt aangevraagd, mag je deze mail negeren of neem je contact op met uw beheerder.\nOm veiligheidsredenen verzoeken wij deze e-mail NIET door te sturen.", + "login.email.login.subject": "Jouw log in code", + "login.email.password-reset.body": "Hallo {user.nameOrEmail},\n\nJe hebt onlangs een paswoord herstel code aangevraagd voor het Panel van {site}.\nDe volgende paswoord herstel code is {timeout} minuten geldig:\n\n{code}\n\nAls je geen paswoord herstel code hebt aangevraagd, mag je deze mail negeren of neem je contact op met uw beheerder.\nOm veiligheidsredenen verzoeken wij deze e-mail NIET door te sturen.", + "login.email.password-reset.subject": "Jouw wachtwoord herstel code", + "login.remember": "Houd mij ingelogd", + "login.reset": "Wachtwoord herstellen", + "login.toggleText.code.email": "Log in via email", + "login.toggleText.code.email-password": "Log in met je wachtwoord", + "login.toggleText.password-reset.email": "Wachtwoord vergeten?", + "login.toggleText.password-reset.email-password": "← Terug naar log in", + + "logout": "Uitloggen", + + "menu": "Menu", + "meridiem": "AM/PM", + "mime": "Mime-type", + "minutes": "Minuten", + + "month": "Maand", + "months.april": "april", + "months.august": "augustus", + "months.december": "december", + "months.february": "februari", + "months.january": "januari", + "months.july": "juli", + "months.june": "juni", + "months.march": "maart", + "months.may": "mei", + "months.november": "november", + "months.october": "oktober", + "months.september": "september", + + "more": "Meer", + "name": "Naam", + "next": "Volgende", + "no": "nee", + "off": "uit", + "on": "aan", + "open": "Open", + "open.newWindow": "Openen in een nieuw scherm", + "options": "Opties", + "options.none": "Geen opties beschikbaar", + + "orientation": "Oriëntatie", + "orientation.landscape": "Liggend", + "orientation.portrait": "Staand", + "orientation.square": "Vierkant", + + "page.blueprint": "Deze pagina heeft nog geen blauwdruk. Je kan de instellingen definiëren in /site/blueprints/pages/{blueprint}.yml", + "page.changeSlug": "Verander URL", + "page.changeSlug.fromTitle": "Aanmaken op basis van titel", + "page.changeStatus": "Wijzig status", + "page.changeStatus.position": "Selecteer een positie", + "page.changeStatus.select": "Selecteer een nieuwe status", + "page.changeTemplate": "Verander template", + "page.delete.confirm": "Weet je zeker dat je pagina {title} wilt verwijderen?", + "page.delete.confirm.subpages": "Deze pagina heeft subpagina's.
Alle subpagina's zullen ook worden verwijderd.", + "page.delete.confirm.title": "Voeg een paginatitel in om te bevestigen", + "page.draft.create": "Maak concept", + "page.duplicate.appendix": "Kopiëren", + "page.duplicate.files": "Kopieer bestanden", + "page.duplicate.pages": "Kopieer pagina's", + "page.sort": "Verander positie", + "page.status": "Status", + "page.status.draft": "Concept", + "page.status.draft.description": "De pagina is in concept-modus en alleen zichtbaar voor ingelogde redacteuren of via een geheime link", + "page.status.listed": "Openbaar", + "page.status.listed.description": "Deze pagina is toegankelijk voor iedereen", + "page.status.unlisted": "Niet gepubliceerd", + "page.status.unlisted.description": "Deze pagina is alleen bereikbaar via URL", + + "pages": "Pagina’s", + "pages.empty": "Nog geen pagina's", + "pages.status.draft": "Concepten", + "pages.status.listed": "Gepubliceerd", + "pages.status.unlisted": "Niet gepubliceerd", + + "pagination.page": "Pagina", + + "password": "Wachtwoord", + "paste": "Plak", + "paste.after": "Plak achter", + "pixel": "Pixel", + "plugins": "Plugins", + "prev": "Vorige", + "preview": "Voorbeeld", + "remove": "Verwijder", + "rename": "Hernoem", + "replace": "Vervang", + "retry": "Probeer opnieuw", + "revert": "Annuleren", + "revert.confirm": "Weet je zeker dat je alle niet-opgeslagen veranderingen wilt verwijderen?", + + "role": "Rol", + "role.admin.description": "De admin heeft alle rechten", + "role.admin.title": "Admin", + "role.all": "Alle", + "role.empty": "Er zijn geen gebruikers met deze rol", + "role.description.placeholder": "Geen beschrijving", + "role.nobody.description": "Dit is een fallback-rol zonder rechten", + "role.nobody.title": "Niemand", + + "save": "Opslaan", + "search": "Zoeken", + "search.min": "Voer {min} tekens in om te zoeken", + "search.all": "Toon alles", + "search.results.none": "Geen resultaten", + + "section.required": "De sectie is verplicht", + + "security": "Security", + "select": "Selecteren", + "server": "Server", + "settings": "Opties", + "show": "Toon", + "site.blueprint": "Deze website heeft nog geen ontwerp. Je kan het ontwerp hier plaatsen/site/blueprints/site.yml", + "size": "Grootte", + "slug": "URL-toevoeging", + "sort": "Sorteren", + + "stats.empty": "No reports", + "system.issues.content": "The content folder seems to be exposed", + "system.issues.debug": "Debugging must be turned off in production", + "system.issues.git": "The .git folder seems to be exposed", + "system.issues.https": "We recommend HTTPS for all your sites", + "system.issues.kirby": "The kirby folder seems to be exposed", + "system.issues.site": "The site folder seems to be exposed", + + "title": "Titel", + "template": "Template", + "today": "Vandaag", + + "toolbar.button.code": "Code", + "toolbar.button.bold": "Dikgedrukte tekst", + "toolbar.button.email": "E-mailadres", + "toolbar.button.headings": "Kopteksten", + "toolbar.button.heading.1": "Koptekst 1", + "toolbar.button.heading.2": "Koptekst 2", + "toolbar.button.heading.3": "Koptekst 3", + "toolbar.button.heading.4": "Hoofding 4", + "toolbar.button.heading.5": "Hoofding 5", + "toolbar.button.heading.6": "Hoofding 6", + "toolbar.button.italic": "Cursieve tekst", + "toolbar.button.file": "Bestand", + "toolbar.button.file.select": "Selecteer een bestand", + "toolbar.button.file.upload": "Upload bestand", + "toolbar.button.link": "Link", + "toolbar.button.paragraph": "Paragraaf", + "toolbar.button.strike": "Doorstreept", + "toolbar.button.ol": "Genummerde lijst", + "toolbar.button.underline": "Onderlijn", + "toolbar.button.ul": "Opsomming", + + "translation.author": "Het team van Kirby", + "translation.direction": "ltr", + "translation.name": "Nederlands", + "translation.locale": "nl_NL", + + "upload": "Upload", + "upload.error.cantMove": "Het geüploadde bestand kon niet worden verplaatst", + "upload.error.cantWrite": "Fout bij het schrijven van het bestand naar de schijf", + "upload.error.default": "Het bestand kan niet worden geüpload", + "upload.error.extension": "Kan bestand niet uploaden vanwege de extensie", + "upload.error.formSize": "Het geüploadde bestand is groter dan de MAX_FILE_SIZE die is aangegeven in het formulier", + "upload.error.iniPostSize": "Het geüploadde bestand is groter dan de post_max_size in php.ini", + "upload.error.iniSize": "Het geüploadde bestand is groter dan de upload_max_filesize in php.ini", + "upload.error.noFile": "Er is geen bestand geüpload", + "upload.error.noFiles": "Er zijn geen bestanden geüpload", + "upload.error.partial": "Het geüploadde bestand is slechts gedeeltelijk geüpload", + "upload.error.tmpDir": "Er mist een tijdelijke map", + "upload.errors": "Foutmelding", + "upload.progress": "Uploaden...", + + "url": "Url", + "url.placeholder": "https://voorbeeld.nl", + + "user": "Gebruiker", + "user.blueprint": "Je kan aanvullende secties en formuliervelden voor deze gebruikersrol definiëren in /site/blueprints/users/{blueprint}.yml", + "user.changeEmail": "Email veranderen", + "user.changeLanguage": "Taal veranderen", + "user.changeName": "Gebruiker hernoemen", + "user.changePassword": "Wachtwoord wijzigen", + "user.changePassword.new": "Nieuw wachtwoord", + "user.changePassword.new.confirm": "Bevestig het nieuwe wachtwoord...", + "user.changeRole": "Verander rol", + "user.changeRole.select": "Kies een nieuwe rol", + "user.create": "Voeg een nieuwe gebruiker toe", + "user.delete": "Verwijder deze gebruiker", + "user.delete.confirm": "Weet je zeker dat je
{email} wil verwijderen?", + + "users": "Gebruikers", + + "version": "Kirby-versie", + + "view.account": "Jouw account", + "view.installation": "Installatie", + "view.languages": "Talen", + "view.resetPassword": "Wachtwoord herstellen", + "view.site": "Site", + "view.system": "Systeem", + "view.users": "Gebruikers", + + "welcome": "Welkom", + "year": "Jaar", + "yes": "ja" } diff --git a/kirby/i18n/translations/pl.json b/kirby/i18n/translations/pl.json index 45857ee..f40e9b3 100644 --- a/kirby/i18n/translations/pl.json +++ b/kirby/i18n/translations/pl.json @@ -1,730 +1,574 @@ { - "account.changeName": "Zmień swoje imię", - "account.delete": "Usuń swoje konto", - "account.delete.confirm": "Czy na pewno chcesz usunąć swoje konto? Zostaniesz natychmiast wylogowany. Twojego konta nie da się odzyskać.", - - "activate": "Aktywuj", - "add": "Dodaj", - "alpha": "Alfa", - "author": "Autor", - "avatar": "Zdj\u0119cie profilowe", - "back": "Wróć", - "cancel": "Anuluj", - "change": "Zmie\u0144", - "close": "Zamknij", - "changes": "Zmiany", - "confirm": "Ok", - "collapse": "Zwiń", - "collapse.all": "Zwiń wszystkie", - "color": "Kolor", - "coordinates": "Współrzędne", - "copy": "Kopiuj", - "copy.all": "Skopiuj wszystko", - "copy.success": "{count} skopiowanych!", - "create": "Utwórz", - "custom": "Niestandardowe", - - "date": "Data", - "date.select": "Wybierz datę", - - "day": "Dzień", - "days.fri": "Pt", - "days.mon": "Pn", - "days.sat": "Sb", - "days.sun": "Nd", - "days.thu": "Czw", - "days.tue": "Wt", - "days.wed": "\u015ar", - - "debugging": "Debugowanie", - - "delete": "Usu\u0144", - "delete.all": "Usuń wszystkie", - - "dialog.fields.empty": "To okno dialogowe nie zawiera żadnych pól", - "dialog.files.empty": "Brak plików do wyboru", - "dialog.pages.empty": "Brak stron do wyboru", - "dialog.text.empty": "To okno dialogowe nie definiuje żadnego tekstu", - "dialog.users.empty": "Brak użytkowników do wyboru", - - "dimensions": "Wymiary", - "disable": "Wyłącz", - "disabled": "Wyłączone", - "discard": "Odrzu\u0107", - - "drawer.fields.empty": "Ten panel nie zawiera żadnych pól", - - "domain": "Domena", - "download": "Pobierz", - "duplicate": "Zduplikuj", - - "edit": "Edytuj", - - "email": "Email", - "email.placeholder": "mail@example.com", - - "enter": "Wprowadź", - "entries": "Wpisy", - "entry": "Wpis", - - "environment": "Środowisko", - - "error": "Błąd", - "error.access.code": "Nieprawidłowy kod", - "error.access.login": "Nieprawidłowy login", - "error.access.panel": "Nie masz uprawnień by dostać się do panelu", - "error.access.view": "Nie masz uprawnień, by dostać się do tej części panelu", - - "error.avatar.create.fail": "Nie udało się załadować zdjęcia profilowego", - "error.avatar.delete.fail": "Nie udało się usunąć zdjęcia profilowego", - "error.avatar.dimensions.invalid": "Proszę zachować szerokość i wysokość zdjęcia profilowego poniżej 3000 pikseli", - "error.avatar.mime.forbidden": "Zdjęcie profilowe musi być plikiem JPEG lub PNG", - - "error.blueprint.notFound": "Nie udało się załadować wzorca \"{name}\"", - - "error.blocks.max.plural": "Możesz dodać nie więcej niż {max} bloki/-ów", - "error.blocks.max.singular": "Możesz dodać tylko jeden blok", - "error.blocks.min.plural": "Musisz dodać co najmniej {min} bloki/-ów", - "error.blocks.min.singular": "Musisz dodać co najmniej jeden blok", - "error.blocks.validation": "Wystąpił błąd w polu „{field}” w bloku {index} o typie bloku „{fieldset}”", - - "error.cache.type.invalid": "Nieprawidłowy typ pamięci podręcznej „{type}”", - - "error.email.preset.notFound": "Nie udało się załadować wzorca wiadomości e-mail \"{name}\"", - - "error.field.converter.invalid": "Nieprawidłowy konwerter \"{converter}\"", - "error.field.type.missing": "Pole „{ name }”: Typ pola „{ type }” nie istnieje", - - "error.file.changeName.empty": "Imię nie może być puste", - "error.file.changeName.permission": "Nie masz uprawnień, by zmienić nazwę \"{filename}\"", - "error.file.changeTemplate.invalid": "Szablonu pliku \"{id}\" nie można zmienić na \"{template}\" (poprawne: \"{blueprints}\")", - "error.file.changeTemplate.permission": "Nie masz uprawnień, by zmieniać szablon pliku \"{id}\"", - - "error.file.duplicate": "Istnieje już plik o nazwie \"{filename}\"", - "error.file.extension.forbidden": "Rozszerzenie \"{extension}\" jest niedozwolone", - "error.file.extension.invalid": "Nieprawidłowe rozszerzenie: {extension}", - "error.file.extension.missing": "Brak rozszerzenia pliku \"{filename}\"", - "error.file.maxheight": "Wysokość obrazka nie może być większa niż {height} pikseli", - "error.file.maxsize": "Plik jest za duży", - "error.file.maxwidth": "Szerokość obrazka nie może być większa niż {width} pikseli", - "error.file.mime.differs": "Przesłany plik musi być tego samego typu mime \"{mime}\"", - "error.file.mime.forbidden": "Typ multimediów \"{mime}\" jest niedozwolony", - "error.file.mime.invalid": "Nieprawidłowy typ MIME: {mime}", - "error.file.mime.missing": "Nie można wykryć typu multimediów dla \"{filename}\"", - "error.file.minheight": "Wysokość obrazka musi wynosić co najmniej {height} pikseli", - "error.file.minsize": "Plik jest za mały", - "error.file.minwidth": "Szerokość obrazka musi wynosić co najmniej {width} pikseli", - "error.file.name.unique": "Nazwa pliku musi być unikalna", - "error.file.name.missing": "Nazwa pliku nie może być pusta", - "error.file.notFound": "Nie można znaleźć pliku \"{filename}\"", - "error.file.orientation": "Orientacja obrazka musi być \"{orientation}\"", - "error.file.type.forbidden": "Nie możesz przesyłać plików {type}", - "error.file.type.invalid": "Nieprawidłowy typ pliku: {type}", - "error.file.undefined": "Nie można znaleźć pliku", - - "error.form.incomplete": "Popraw wszystkie błędy w formularzu…", - "error.form.notSaved": "Nie udało się zapisać formularza", - - "error.language.code": "Wprowadź poprawny kod języka.", - "error.language.duplicate": "Język już istnieje.", - "error.language.name": "Wprowadź poprawną nazwę języka.", - "error.language.notFound": "Język nie został odnaleziony", - - "error.layout.validation.block": "Wystąpił błąd w polu „{field}” w bloku {blockIndex} o typie bloku „{fieldset}” w układzie {layoutIndex}", - "error.layout.validation.settings": "W ustawieniach układu {index} jest błąd", - - "error.license.domain": "Brakuje domeny dla licencji", - "error.license.email": "Wprowadź poprawny adres email", - "error.license.format": "Please enter a valid license code", - "error.license.verification": "Nie udało się zweryfikować licencji", - - "error.login.totp.confirm.invalid": "Nieprawidłowy kod", - "error.login.totp.confirm.missing": "Wpisz aktualny kod", - - "error.object.validation": "Wystąpił błąd w polu „{label}”:\n{message}", - - "error.offline": "Panel jest obecnie offline", - - "error.page.changeSlug.permission": "Nie możesz zmienić końcówki adresu URL w \"{slug}\"", - "error.page.changeSlug.reserved": "Ścieżka stron najwyższego poziomu nie może zaczynać się od \"{path}\"", - "error.page.changeStatus.incomplete": "Strona zawiera błędy i nie można jej opublikować", - "error.page.changeStatus.permission": "Status tej strony nie może zostać zmieniony", - "error.page.changeStatus.toDraft.invalid": "Strony \"{slug}\" nie można przekonwertować na szkic", - "error.page.changeTemplate.invalid": "Nie można zmienić szablonu strony \"{slug}\"", - "error.page.changeTemplate.permission": "Nie masz uprawnień, by zmienić szablon dla \"{slug}\"", - "error.page.changeTitle.empty": "Tytuł nie może być pusty", - "error.page.changeTitle.permission": "Nie masz uprawnień, by zmienić tytuł dla \"{slug}\"", - "error.page.create.permission": "Nie masz uprawnień, by utworzyć \"{slug}\"", - "error.page.delete": "Strony \"{slug}\" nie można usunąć", - "error.page.delete.confirm": "Wprowadź tytuł strony, aby potwierdzić", - "error.page.delete.hasChildren": "Strona zawiera podstrony i nie można jej usunąć", - "error.page.delete.permission": "Nie masz uprawnień, by usunąć \"{slug}\"", - "error.page.draft.duplicate": "Istnieje już szkic z końcówką URL \"{slug}\"", - "error.page.duplicate": "Istnieje już strona z końcówką URL \"{slug}\"", - "error.page.duplicate.permission": "Nie masz uprawnień, by zduplikować \"{slug}\"", - "error.page.move.ancestor": "Strony nie można przenieść do siebie samej", - "error.page.move.directory": "Nie można przenieść katalogu strony", - "error.page.move.duplicate": "Istnieje już podstrona z końcówką URL \"{slug}\"", - "error.page.move.notFound": "Przeniesiona strona nie została odnaleziona", - "error.page.move.permission": "Nie masz uprawnień, by przenieść \"{slug}\"", - "error.page.move.template": "Szablon \"{template}\" nie jest akceptowany jako podstrona \"{parent}\"", - "error.page.notFound": "Nie można znaleźć strony \"{slug}\"", - "error.page.num.invalid": "Wprowadź poprawny numer sortujący. Liczby nie mogą być ujemne.", - "error.page.slug.invalid": "Wprowadź poprawną końcówkę adresu URL", - "error.page.slug.maxlength": "Końcówka adresu musi być krótsza niż \"{length}\" znaków", - "error.page.sort.permission": "Nie można sortować strony \"{slug}\"", - "error.page.status.invalid": "Ustaw prawidłowy status strony", - "error.page.undefined": "Nie udało się znaleźć strony", - "error.page.update.permission": "Nie masz uprawnień, by zaktualizować \"{slug}\"", - - "error.section.files.max.plural": "Do sekcji \"{section}\" można dodać nie więcej niż {max} plików", - "error.section.files.max.singular": "Do sekcji \"{section}\" można dodać tylko jeden plik", - "error.section.files.min.plural": "W sekcji \"{section}\" musi być co najmniej {min} pliki/-ów", - "error.section.files.min.singular": "W sekcji \"{section}\" musi być co najmniej jeden plik", - - "error.section.pages.max.plural": "Do sekcji \"{section}\" można dodać nie więcej niż {max} stron", - "error.section.pages.max.singular": "Do sekcji \"{section}\" można dodać tylko jedną stronę", - "error.section.pages.min.plural": "W sekcji \"{section}\" musi być co najmniej {min} stron/-y", - "error.section.pages.min.singular": "W sekcji \"{section}\" musi być co najmniej jedna strona", - - "error.section.notLoaded": "Nie udało się załadować sekcji \"{name}\"", - "error.section.type.invalid": "Typ sekcji \"{type}\" jest nieprawidłowy", - - "error.site.changeTitle.empty": "Tytuł nie może być pusty", - "error.site.changeTitle.permission": "Nie masz uprawnień, by zmienić tytuł strony", - "error.site.update.permission": "Nie masz uprawnień, by zaktualizować stronę", - - "error.structure.validation": "Wystąpił błąd w polu \"{field}\" w wierszu {index}", - - "error.template.default.notFound": "Domyślny szablon nie istnieje", - - "error.unexpected": "Wystąpił nieoczekiwany błąd! Włącz tryb debugowania, aby uzyskać więcej informacji: https://getkirby.com/docs/reference/system/options/debug", - - "error.user.changeEmail.permission": "Nie masz uprawnień, by zmienić adres e-mail użytkownika \"{name}\"", - "error.user.changeLanguage.permission": "Nie masz uprawnień, by zmienić język użytkownika \"{name}\"", - "error.user.changeName.permission": "Nie masz uprawnień, by zmienić nazwę użytkownika \"{name}\"", - "error.user.changePassword.permission": "Nie masz uprawnień, by zmienić hasło użytkownika \"{name}\"", - "error.user.changeRole.lastAdmin": "Nie można zmienić roli ostatniego administratora", - "error.user.changeRole.permission": "Nie masz uprawnień, by zmienić rolę użytkownika \"{name}\"", - "error.user.changeRole.toAdmin": "Nie masz uprawnień, by awansować kogoś do roli daministratora", - "error.user.create.permission": "Nie masz uprawnień, by utworzyć tego użytkownika", - "error.user.delete": "Nie można usunąć użytkownika \"{name}\"", - "error.user.delete.lastAdmin": "Nie można usunąć ostatniego administratora", - "error.user.delete.lastUser": "Nie można usunąć ostatniego użytkownika", - "error.user.delete.permission": "Nie masz uprawnień, by usunąć użytkownika \"{name}\"", - "error.user.duplicate": "Istnieje już użytkownik z adresem email \"{email}\"", - "error.user.email.invalid": "Wprowadź poprawny adres email", - "error.user.language.invalid": "Proszę podać poprawny język", - "error.user.notFound": "Nie można znaleźć użytkownika \"{name}\"", - "error.user.password.excessive": "Wpisz prawidłowe hasło. Hasła nie mogą być dłuższe niż 1000 znaków.", - "error.user.password.invalid": "Wprowadź prawidłowe hasło. Hasła muszą mieć co najmniej 8 znaków.", - "error.user.password.notSame": "Hasła nie są takie same", - "error.user.password.undefined": "Użytkownik nie ma hasła", - "error.user.password.wrong": "Nieprawidłowe hasło", - "error.user.role.invalid": "Wprowadź poprawną rolę", - "error.user.undefined": "Nie można znaleźć użytkownika", - "error.user.update.permission": "Nie masz uprawnień, by zaktualizować użytkownika \"{name}\"", - - "error.validation.accepted": "Proszę potwierdzić", - "error.validation.alpha": "Wprowadź tylko znaki między a-z", - "error.validation.alphanum": "Wprowadź tylko znaki między a-z lub cyfry 0-9", - "error.validation.anchor": "Wprowadź poprawny odnośnik", - "error.validation.between": "Wprowadź wartość między \"{min}\" i \"{max}\"", - "error.validation.boolean": "Potwierdź lub odmów", - "error.validation.color": "Wprowadź poprawny kolor w formacie {format}", - "error.validation.contains": "Wprowadź wartość, która zawiera \"{needle}\"", - "error.validation.date": "Wprowadź poprawną datę", - "error.validation.date.after": "Wprowadź datę późniejszą niż {date}", - "error.validation.date.before": "Wprowadź datę wcześniejszą niż {date}", - "error.validation.date.between": "Wprowadź datę między {min} a {max}", - "error.validation.denied": "Proszę odmówić", - "error.validation.different": "Wartością nie może być \"{other}\"", - "error.validation.email": "Wprowadź poprawny adres email", - "error.validation.endswith": "Wartość musi kończyć się na \"{end}\"", - "error.validation.filename": "Wprowadź poprawną nazwę pliku", - "error.validation.in": "Wprowadź jedno z następujących: ({in})", - "error.validation.integer": "Wprowadź poprawną liczbę całkowitą", - "error.validation.ip": "Wprowadź poprawny adres IP", - "error.validation.less": "Wprowadź wartość mniejszą niż {max}", - "error.validation.linkType": "Typ łącza jest niedozwolony", - "error.validation.match": "Wartość nie jest zgodna z oczekiwanym wzorcem", - "error.validation.max": "Wprowadź wartość równą lub mniejszą niż {max}", - "error.validation.maxlength": "Wprowadź krótszą wartość. (maks. {max} znaków)", - "error.validation.maxwords": "Wprowadź nie więcej niż {max} słowa/słów", - "error.validation.min": "Wprowadź wartość równą lub większą niż {min}", - "error.validation.minlength": "Wprowadź dłuższą wartość. (min. {min} znaków)", - "error.validation.minwords": "Wprowadź co najmniej {min} słowa/słów", - "error.validation.more": "Wprowadź wartość większą niż {min}", - "error.validation.notcontains": "Wprowadź wartość, która nie zawiera \"{needle}\"", - "error.validation.notin": "Nie wprowadzaj żadnego z następujących ({notIn})", - "error.validation.option": "Wybierz poprawną opcję", - "error.validation.num": "Wprowadź poprawny numer", - "error.validation.required": "Wpisz coś", - "error.validation.same": "Wprowadź \"{other}\"", - "error.validation.size": "Rozmiar wartości musi wynosić \"{size}\"", - "error.validation.startswith": "Wartość musi zaczynać się od \"{start}\"", - "error.validation.tel": "Wprowadź niesformatowany numer telefonu", - "error.validation.time": "Wprowadź poprawny czas", - "error.validation.time.after": "Wprowadź czas późniejszy niż {time}", - "error.validation.time.before": "Wprowadź czas wcześniejszy niż {time}", - "error.validation.time.between": "Wprowadź czas między {min} a {max}", - "error.validation.uuid": "Wprowadź prawidłowy identyfikator UUID", - "error.validation.url": "Wprowadź poprawny adres URL", - - "expand": "Rozwiń", - "expand.all": "Rozwiń wszystkie", - - "field.invalid": "Pole jest nieprawidłowe", - "field.required": "Pole jest wymagane", - "field.blocks.changeType": "Zmień typ", - "field.blocks.code.name": "Kod", - "field.blocks.code.language": "Język", - "field.blocks.code.placeholder": "Twój kod …", - "field.blocks.delete.confirm": "Czy na pewno chcesz usunąć ten blok?", - "field.blocks.delete.confirm.all": "Czy na pewno chcesz usunąć wszystkie bloki?", - "field.blocks.delete.confirm.selected": "Czy na pewno chcesz usunąć wszystkie wybrane bloki?", - "field.blocks.empty": "Nie ma jeszcze żadnych bloków", - "field.blocks.fieldsets.empty": "Nie ma jeszcze zestawów pól", - "field.blocks.fieldsets.label": "Wybierz typ bloku …", - "field.blocks.fieldsets.paste": "Naciśnij {{ shortcut }}, aby zaimportować układy/bloki ze schowka. Zostaną wstawione tylko te, które są dozwolone w bieżącym polu.", - "field.blocks.gallery.name": "Galeria", - "field.blocks.gallery.images.empty": "Nie ma jeszcze żadnych obrazków", - "field.blocks.gallery.images.label": "Obrazki", - "field.blocks.heading.level": "Poziom", - "field.blocks.heading.name": "Nagłówek", - "field.blocks.heading.text": "Tekst", - "field.blocks.heading.placeholder": "Nagłówek …", - "field.blocks.image.alt": "Tekst alternatywny", - "field.blocks.image.caption": "Podpis", - "field.blocks.image.crop": "Przytnij", - "field.blocks.image.link": "Link", - "field.blocks.image.location": "Lokalizacja", - "field.blocks.image.location.internal": "Ta witryna", - "field.blocks.image.location.external": "Zewnętrzne źródło", - "field.blocks.image.name": "Obrazek", - "field.blocks.image.placeholder": "Wybierz obrazek", - "field.blocks.image.ratio": "Proporcje", - "field.blocks.image.url": "URL obrazka", - "field.blocks.line.name": "Linia", - "field.blocks.list.name": "Lista", - "field.blocks.markdown.name": "Markdown", - "field.blocks.markdown.label": "Tekst", - "field.blocks.markdown.placeholder": "Markdown …", - "field.blocks.quote.name": "Cytat", - "field.blocks.quote.text.label": "Tekst", - "field.blocks.quote.text.placeholder": "Cytat …", - "field.blocks.quote.citation.label": "Źródło", - "field.blocks.quote.citation.placeholder": "autorstwa …", - "field.blocks.text.name": "Tekst", - "field.blocks.text.placeholder": "Tekst …", - "field.blocks.video.autoplay": "Autoplay", - "field.blocks.video.caption": "Podpis", - "field.blocks.video.controls": "Controls", - "field.blocks.video.location": "Lokalizacja", - "field.blocks.video.loop": "Loop", - "field.blocks.video.muted": "Muted", - "field.blocks.video.name": "Video", - "field.blocks.video.placeholder": "Wprowadź URL video", - "field.blocks.video.poster": "Poster", - "field.blocks.video.preload": "Preload", - "field.blocks.video.url.label": "URL video", - "field.blocks.video.url.placeholder": "https://youtube.com/?v=", - - "field.files.empty": "Nie wybrano jeszcze żadnych plików", - - "field.layout.change": "Zmień układ", - "field.layout.delete": "Usuń układ", - "field.layout.delete.confirm": "Czy na pewno chcesz usunąć ten układ?", - "field.layout.delete.confirm.all": "Czy na pewno chcesz usunąć wszystkie układy?", - "field.layout.empty": "Nie ma jeszcze żadnych rzędów", - "field.layout.select": "Wybierz układ", - - "field.object.empty": "Brak informacji", - - "field.pages.empty": "Nie wybrano jeszcze żadnych stron", - - "field.structure.delete.confirm": "Czy na pewno chcesz usunąć ten wiersz?", - "field.structure.delete.confirm.all": "Czy na pewno chcesz usunąć wszystkie wpisy?", - "field.structure.empty": "Nie ma jeszcze \u017cadnych wpis\u00f3w.", - - "field.users.empty": "Nie wybrano jeszcze żadnych użytkowników", - - "fields.empty": "Nie ma jeszcze żadnych pól", - - "file": "Plik", - "file.blueprint": "Ten plik nie ma jeszcze wzorca. Możesz go zdefiniować w /site/blueprints/files/{blueprint}.yml", - "file.changeTemplate": "Zmień szablon", - "file.changeTemplate.notice": "Zmiana szablonu pliku spowoduje usunięcie zawartości pól, które nie pasują pod względem typu. Jeżeli nowy szablon określa pewne zasady, np. wymiarów obrazu, one również zostaną zastosowane nieodwracalnie. Używaj ostrożnie.", - "file.delete.confirm": "Czy na pewno chcesz usunąć
{filename}?", - "file.focus.placeholder": "Ustaw punkt centralny", - "file.focus.reset": "Usuń punkt centralny", - "file.focus.title": "Punkt centralny", - "file.sort": "Zmień pozycję", - - "files": "Pliki", - "files.empty": "Nie ma jeszcze żadnych plików", - - "filter": "Filtr", - - "hide": "Ukryj", - "hour": "Godzina", - "hue": "Odcień", - "import": "Importuj", - "info": "Informacje", - "insert": "Wstaw", - "insert.after": "Wstaw po", - "insert.before": "Wstaw przed", - "install": "Zainstaluj", - - "installation": "Instalacja", - "installation.completed": "Panel został zainstalowany", - "installation.disabled": "Instalator panelu jest domyślnie wyłączony na serwerach publicznych. Uruchom instalator na komputerze lokalnym lub włącz go za pomocą opcji panel.install.", - "installation.issues.accounts": "Folder /site/accounts nie istnieje lub nie ma uprawnień do zapisu", - "installation.issues.content": "Folder /content nie istnieje lub nie ma uprawnień do zapisu", - "installation.issues.curl": "Wymagane jest rozszerzenie CURL", - "installation.issues.headline": "Nie można zainstalować panelu", - "installation.issues.mbstring": "Wymagane jest rozszerzenie MB String", - "installation.issues.media": "Folder /media nie istnieje lub nie ma uprawnień do zapisu", - "installation.issues.php": "Upewnij się, że używasz PHP 8+", - "installation.issues.sessions": "Folder /site/sessions nie istnieje lub nie ma uprawnień do zapisu", - - "language": "J\u0119zyk", - "language.code": "Kod", - "language.convert": "Ustaw jako domyślny", - "language.convert.confirm": "

Czy na pewno chcesz zmienić domyślny język na {name}? Nie można tego cofnąć.

Jeżeli brakuje tłumaczenia jakichś treści na {name}, nie będzie ich czym zastąpić i części witryny mogą być puste.

", - "language.create": "Dodaj nowy język", - "language.default": "Domyślny język", - "language.delete.confirm": "Czy na pewno chcesz usunąć język {name} i wszystkie tłumaczenia? Tego nie da się cofnąć!", - "language.deleted": "Język został usunięty", - "language.direction": "Kierunek czytania", - "language.direction.ltr": "Od lewej do prawej", - "language.direction.rtl": "Od prawej do lewej", - "language.locale": "PHP locale string", - "language.locale.warning": "Używasz niestandardowej konfiguracji ustawień regionalnych. Zmodyfikuj to w pliku języka w /site/langugaes", - "language.name": "Nazwa", - "language.secondary": "Drugorzędny język", - "language.settings": "Ustawienia języków", - "language.updated": "Język został zaktualizowany", - "language.variables": "Zmienne językowe", - "language.variables.empty": "Nie ma jeszcze żadnych tłumaczeń", - - "language.variable.delete.confirm": "Czy na pewno chcesz usunąć zmienną przypisaną do klucza {key}?", - "language.variable.key": "Klucz", - "language.variable.notFound": "Nie udało się odnaleźć zmiennej", - "language.variable.value": "Wartość", - - "languages": "Języki", - "languages.default": "Domyślny język", - "languages.empty": "Nie ma jeszcze żadnych języków", - "languages.secondary": "Dodatkowe języki", - "languages.secondary.empty": "Nie ma jeszcze dodatkowych języków", - - "license": "Licencja", - "license.activate": "Aktywuj teraz", - "license.activate.label": "Aktywuj swoją licencję", - "license.activate.domain": "Twoja licencja zostanie aktywowana na {host}.", - "license.activate.local": "Zamierzasz aktywować licencję Kirby dla domeny lokalnej {host}. Jeżeli ta strona będzie uruchamiana w publicznie dostępnej domenie, należy ją aktywować tam. Jeśli {host} jest domeną, dla której chcesz używać licencji, kontynuuj.", - "license.activated": "Aktywowana", - "license.buy": "Kup licencję", - "license.code": "Kod", - "license.code.help": "Po zakupie otrzymałeś emailem kod licencyjny. Skopiuj go i wklej tutaj.", - "license.code.label": "Wprowadź swój kod licencji", - "license.status.active.info": "Zawiera nowe główne wersje do {date}", - "license.status.active.label": "Ważna licencja", - "license.status.demo.info": "This is a demo installation", - "license.status.demo.label": "Demo", - "license.status.inactive.info": "Odnów licencję, by zaktualizować do nowych wersji głównych", - "license.status.inactive.label": "Brak nowych wersji głównych", - "license.status.legacy.bubble": "Gotowy/-a do odnowienia swojej licencji?", - "license.status.legacy.info": "Twoja licencja nie obejmuje tej wersji", - "license.status.legacy.label": "Odnów swoją licencję", - "license.status.missing.bubble": "Gotowy/-a do uruchomienia strony?", - "license.status.missing.info": "Brak ważnej licencji", - "license.status.missing.label": "Aktywuj swoją licencję", - "license.manage": "Zarządzaj swoimi licencjami", - "license.purchased": "Zakupiona", - "license.success": "Dziękujemy za wspieranie Kirby", - "license.unregistered.label": "Niezarejestrowane", - - "link": "Link", - "link.text": "Tekst linku", - - "loading": "Ładuję", - - "lock.unsaved": "Niezapisane zmiany", - "lock.unsaved.empty": "Nie ma już żadnych niezapisanych zmian", - "lock.isLocked": "Niezapisane zmiany autorstwa {email}", - "lock.unlock": "Odblokuj", - "lock.unlock.submit": "Odblokuj i nadpisz niezapisane zmiany autorstwa {email}", - "lock.isUnlocked": "Zostało odblokowane przez innego użytkownika", - - "login": "Zaloguj się", - "login.code.label.login": "Kod logowania się", - "login.code.label.password-reset": "Kod resetowania hasła", - "login.code.placeholder.email": "000 000", - "login.code.placeholder.totp": "000000", - "login.code.text.email": "Jeśli Twój adres email jest zarejestrowany, żądany kod został wysłany na Twoją skrzynkę.", - "login.code.text.totp": "Wprowadź jednorazowy kod z aplikacji uwierzytelniającej.", - "login.email.login.body": "Cześć {user.nameOrEmail},\n\nNiedawno poprosiłaś/-eś o kod do zalogowania się do panelu strony {site}.\nPoniższy kod do zalogowania się będzie ważny przez {timeout} minut:\n\n{code}\n\nJeżeli nie zażądałaś/-eś kodu do logowania się, zignoruj tę wiadomość e-mail lub skontaktuj się z administratorem, jeśli masz pytania.\nZe względów bezpieczeństwa NIE przesyłaj dalej tego e-maila.", - "login.email.login.subject": "Twój kod logowania się", - "login.email.password-reset.body": "Cześć {user.nameOrEmail},\n\nNiedawno poprosiłaś/-eś o kod resetowania hasła do panelu strony {site}.\nPoniższy kod resetowania hasła będzie ważny przez {timeout} minut:\n\n{code}\n\nJeżeli nie zażądałaś/-eś kodu resetowania hasła, zignoruj tę wiadomość e-mail lub skontaktuj się z administratorem, jeśli masz pytania. \nZe względów bezpieczeństwa NIE przesyłaj dalej tego e-maila. ", - "login.email.password-reset.subject": "Twój kod resetujący hasło", - "login.remember": "Nie wylogowuj mnie", - "login.reset": "Zresetuj hasło", - "login.toggleText.code.email": "Zaloguj się za pomocą adresu email", - "login.toggleText.code.email-password": "Zaloguj się za pomocą hasła", - "login.toggleText.password-reset.email": "Zapomniałeś/-aś hasła?", - "login.toggleText.password-reset.email-password": "← Powrót do logowania", - "login.totp.enable.option": "Ustaw kody jednorazowe", - "login.totp.enable.intro": "Aplikacje uwierzytelniające mogą generować jednorazowe kody, które są używane jako drugi czynnik podczas logowania się na konto.", - "login.totp.enable.qr.label": "1. Zeskanuj ten kod QR", - "login.totp.enable.qr.help": "Nie możesz zeskanować? Dodaj ręcznie klucz instalacyjny {secret} do aplikacji uwierzytelniającej.", - "login.totp.enable.confirm.headline": "2. Potwierdź wygenerowanym kodem", - "login.totp.enable.confirm.text": "Aplikacja generuje nowy kod jednorazowy co 30 sekund. Wprowadź aktualny kod, aby dokończyć konfigurację:", - "login.totp.enable.confirm.label": "Aktualny kod", - "login.totp.enable.confirm.help": "Po tej konfiguracji będziemy prosić o jednorazowy kod przy każdym logowaniu.", - "login.totp.enable.success": "Kody jednorazowe włączone", - "login.totp.disable.option": "Wyłącz kody jednorazowe", - "login.totp.disable.label": "Wprowadź swoje hasło, aby wyłączyć kody jednorazowe", - "login.totp.disable.help": "W przyszłości podczas logowania wymagany będzie inny drugi czynnik, taki jak kod logowania wysłany emailem. Kody jednorazowe możesz zawsze skonfigurować później.", - "login.totp.disable.admin": "

Spowoduje to wyłączenie kodów jednorazowych dla użytkownika {user}.

W przyszłości podczas logowania wymagany będzie inny drugi czynnik, taki jak kod logowania wysłany emailem. {user} może ponownie skonfigurować kody jednorazowe po następnym zalogowaniu.

", - "login.totp.disable.success": "Kody jednorazowe wyłączone", - - "logout": "Wyloguj się", - - "merge": "Połącz", - "menu": "Menu", - "meridiem": "AM/PM", - "mime": "Typ multimediów", - "minutes": "Minuty", - - "month": "Miesiąc", - "months.april": "Kwiecie\u0144", - "months.august": "Sierpie\u0144", - "months.december": "Grudzie\u0144", - "months.february": "Luty", - "months.january": "Stycze\u0144", - "months.july": "Lipiec", - "months.june": "Czerwiec", - "months.march": "Marzec", - "months.may": "Maj", - "months.november": "Listopad", - "months.october": "Pa\u017adziernik", - "months.september": "Wrzesie\u0144", - - "more": "Więcej", - "move": "Przenieś", - "name": "Nazwa", - "next": "Następne", - "night": "Noc", - "no": "nie", - "off": "wyłączone", - "on": "włączone", - "open": "Otwórz", - "open.newWindow": "Otwórz w nowym oknie", - "option": "Opcja", - "options": "Opcje", - "options.none": "Brak opcji", - "options.all": "Pokaż wszystkie {count} opcje/-i", - - "orientation": "Orientacja", - "orientation.landscape": "Pozioma", - "orientation.portrait": "Pionowa", - "orientation.square": "Kwadrat", - - "page": "Strona", - "page.blueprint": "Ta strona nie ma jeszcze wzorca. Możesz go zdefiniować w /site/blueprints/pages/{blueprint}.yml", - "page.changeSlug": "Zmie\u0144 URL", - "page.changeSlug.fromTitle": "Utw\u00f3rz na podstawie tytu\u0142u", - "page.changeStatus": "Zmień status", - "page.changeStatus.position": "Wybierz pozycję", - "page.changeStatus.select": "Wybierz nowy status", - "page.changeTemplate": "Zmień szablon", - "page.changeTemplate.notice": "Zmiana szablonu strony spowoduje usunięcie treści z pól, które nie pasują pod względem typu. Używaj ostrożnie.", - "page.create": "Utwórz jako {status}", - "page.delete.confirm": "Czy na pewno chcesz usunąć {title}?", - "page.delete.confirm.subpages": "Ta strona zawiera podstrony.
Wszystkie podstrony również zostaną usunięte.", - "page.delete.confirm.title": "Wprowadź tytuł strony, aby potwierdzić", - "page.duplicate.appendix": "Kopiuj", - "page.duplicate.files": "Kopiuj pliki", - "page.duplicate.pages": "Kopiuj strony", - "page.move": "Przenieś stronę", - "page.sort": "Zmień pozycję", - "page.status": "Status", - "page.status.draft": "Szkic", - "page.status.draft.description": "Strona jest w trybie roboczym i widoczna tylko dla zalogowanych redaktorów lub pod sekretnym linkiem", - "page.status.listed": "Opublikowana", - "page.status.listed.description": "Strona jest opublikowana i widoczna dla każdego", - "page.status.unlisted": "Nie katalogowana", - "page.status.unlisted.description": "Strona jest dostępna tylko za pośrednictwem adresu URL", - - "pages": "Strony", - "pages.empty": "Nie ma jeszcze żadnych stron", - "pages.status.draft": "Szkice", - "pages.status.listed": "Opublikowane", - "pages.status.unlisted": "Nie katalogowana", - - "pagination.page": "Strona", - - "password": "Has\u0142o", - "paste": "Wklej", - "paste.after": "Wklej po", - "paste.success": "{count} wklejonych!", - "pixel": "Piksel", - "plugin": "Wtyczka", - "plugins": "Wtyczki", - "prev": "Poprzednie", - "preview": "Podgląd", - "remove": "Usuń", - "rename": "Zmień nazwę", - "renew": "Odnów", - "replace": "Zamie\u0144", - "replace.with": "Zamień z", - "retry": "Pon\u00f3w pr\u00f3b\u0119", - "revert": "Odrzu\u0107", - "revert.confirm": "Czy na pewno chcesz usunąć wszystkie niezapisane zmiany?", - - "role": "Rola", - "role.admin.description": "Administrator posiada wszystkie uprawnienia", - "role.admin.title": "Administrator", - "role.all": "Wszystkie", - "role.empty": "Nie ma użytkowników z tą rolą", - "role.description.placeholder": "Brak opisu", - "role.nobody.description": "To jest rola zastępcza bez żadnych uprawnień", - "role.nobody.title": "Nikt", - - "save": "Zapisz", - "search": "Szukaj", - "search.min": "Aby wyszukać, wprowadź co najmniej {min} znaków", - "search.all": "Pokaż wszystkie {count} wyniki/-ów", - "search.results.none": "Brak wyników", - - "section.invalid": "Sekcja jest nieprawidłowa", - "section.required": "Sekcja jest wymagana", - - "security": "Bezpieczeństwo", - "select": "Wybierz", - "server": "Serwer", - "settings": "Ustawienia", - "show": "Pokaż", - "site.blueprint": "Ta strona nie ma jeszcze wzorca. Możesz go zdefiniować w /site/blueprints/site.yml", - "size": "Rozmiar", - "slug": "Końcówka URL", - "sort": "Sortuj", - "sort.drag": "Przeciągnij, aby posortować…", - "split": "Podziel", - - "stats.empty": "Brak raportów", - "status": "Status", - - "system.info.copy": "Copy info", - "system.info.copied": "System info copied", - "system.issues.content": "Zdaje się, że folder „content” jest wystawiony na publiczny dostęp", - "system.issues.eol.kirby": "Twoja zainstalowana wersja Kirby osiągnęła koniec okresu wsparcia i nie będzie otrzymywać dalszych aktualizacji zabezpieczeń", - "system.issues.eol.plugin": "Twoja zainstalowana wersja wtyczki { plugin } osiągnęła koniec okresu wsparcia i nie będzie otrzymywać dalszych aktualizacji zabezpieczeń", - "system.issues.eol.php": "Zainstalowana wersja PHP { release } osiągnęła koniec okresu eksploatacji i nie będzie otrzymywać dalszych aktualizacji zabezpieczeń.", - "system.issues.debug": "Debugowanie musi być wyłączone w środowisku produkcyjnym", - "system.issues.git": "Zdaje się, że folder „.git” jest wystawiony na publiczny dostęp", - "system.issues.https": "Zalecamy HTTPS dla wszystkich Twoich witryn", - "system.issues.kirby": "Zdaje się, że folder „kirby” jest wystawiony na publiczny dostęp", - "system.issues.site": "Zdaje się, że folder „site” jest wystawiony na publiczny dostęp", - "system.issues.vulnerability.kirby": "Twojej instalacji może zagrażać następująca luka w zabezpieczeniach ({ severity } stopień): { description }", - "system.issues.vulnerability.plugin": "Twojej instalacji może zagrażać następująca luka w zabezpieczeniach we wtyczce { plugin } ({ severity } poziom): { description }", - "system.updateStatus": "Stan aktualizacji", - "system.updateStatus.error": "Nie udało się sprawdzić dostępności aktualizacji", - "system.updateStatus.not-vulnerable": "Brak znanych luk bezpieczeństwa", - "system.updateStatus.security-update": "Dostępna darmowa aktualizacja { version } z poprawkami bezpieczeństwa", - "system.updateStatus.security-upgrade": "Dostępna aktualizacja { version } z poprawkami bezpieczeństwa", - "system.updateStatus.unreleased": "Niepublikowana wersja", - "system.updateStatus.up-to-date": "Aktualna", - "system.updateStatus.update": "Dostępna darmowa aktualizacja { version }", - "system.updateStatus.upgrade": "Dostępna aktualizacja { version }", - - "tel": "Telefon", - "tel.placeholder": "+48123456789", - "template": "Szablon", - "title": "Tytuł", - "today": "Dzisiaj", - - "toolbar.button.clear": "Wyczyść formatowanie", - "toolbar.button.code": "Kod", - "toolbar.button.bold": "Pogrubienie", - "toolbar.button.email": "Email", - "toolbar.button.headings": "Nagłówki", - "toolbar.button.heading.1": "Nagłówek 1", - "toolbar.button.heading.2": "Nagłówek 2", - "toolbar.button.heading.3": "Nagłówek 3", - "toolbar.button.heading.4": "Nagłówek 4", - "toolbar.button.heading.5": "Nagłówek 5", - "toolbar.button.heading.6": "Nagłówek 6", - "toolbar.button.italic": "Kursywa", - "toolbar.button.file": "Plik", - "toolbar.button.file.select": "Wybierz plik", - "toolbar.button.file.upload": "Prześlij plik", - "toolbar.button.link": "Link", - "toolbar.button.paragraph": "Akapit", - "toolbar.button.strike": "Przekreślenie", - "toolbar.button.sub": "Indeks dolny", - "toolbar.button.sup": "Indeks górny", - "toolbar.button.ol": "Lista numerowana", - "toolbar.button.underline": "Podkreślenie", - "toolbar.button.ul": "Lista wypunktowana", - - "translation.author": "Zespół Kirby", - "translation.direction": "ltr", - "translation.name": "Polski", - "translation.locale": "pl_PL", - - "type": "Typ", - - "upload": "Prześlij", - "upload.error.cantMove": "Przesłany plik nie mógł być przeniesiony", - "upload.error.cantWrite": "Nie udało się zapisać pliku na dysku", - "upload.error.default": "Nie udało się przesłać pliku", - "upload.error.extension": "Przesyłanie pliku zostało zastopowane przez rozszerzenie", - "upload.error.formSize": "Przesłany plik przekracza dyrektywę MAX_FILE_SIZE określoną w formularzu", - "upload.error.iniPostSize": "Przesłany plik przekracza dyrektywę post_max_size określoną w php.ini", - "upload.error.iniSize": "Przesłany plik przekracza dyrektywę upload_max_filesize określoną w php.ini", - "upload.error.noFile": "Nie został przesłany żaden plik", - "upload.error.noFiles": "Nie zostały przesłane żadne pliki", - "upload.error.partial": "Została przesłana tylko część przesyłanego pliku", - "upload.error.tmpDir": "Brak tymczasowego folderu", - "upload.errors": "Błąd", - "upload.progress": "Przesyłanie…", - - "url": "Url", - "url.placeholder": "https://example.com", - - "user": "Użytkownik", - "user.blueprint": "Możesz zdefiniować dodatkowe sekcje i pola dla użytkownika o takiej roli w /site/blueprints/users/{blueprint}.yml", - "user.changeEmail": "Zmień email", - "user.changeLanguage": "Zmień język", - "user.changeName": "Zmień nazwę tego użytkownika", - "user.changePassword": "Zmień hasło", - "user.changePassword.new": "Nowe hasło", - "user.changePassword.new.confirm": "Potwierdź nowe hasło…", - "user.changeRole": "Zmień rolę", - "user.changeRole.select": "Wybierz nową rolę", - "user.create": "Dodaj nowego użytkownika", - "user.delete": "Usuń tego użytkownika", - "user.delete.confirm": "Czy na pewno chcesz usunąć
{email}?", - - "users": "Użytkownicy", - - "version": "Wersja", - "version.current": "Obecna wersja", - "version.latest": "Ostatnia wersja", - "versionInformation": "Informacje o wersji", - - "view.account": "Twoje konto", - "view.installation": "Instalacja", - "view.languages": "Języki", - "view.resetPassword": "Zresetuj hasło", - "view.site": "Strona", - "view.system": "System", - "view.users": "U\u017cytkownicy", - - "welcome": "Witaj", - "year": "Rok", - "yes": "tak" + "account.changeName": "Zmień swoje imię", + "account.delete": "Usuń swoje konto", + "account.delete.confirm": "Czy na pewno chcesz usunąć swoje konto? Zostaniesz natychmiast wylogowany. Twojego konta nie da się odzyskać.", + + "add": "Dodaj", + "author": "Autor", + "avatar": "Zdj\u0119cie profilowe", + "back": "Wróć", + "cancel": "Anuluj", + "change": "Zmie\u0144", + "close": "Zamknij", + "confirm": "Ok", + "collapse": "Zwiń", + "collapse.all": "Zwiń wszystkie", + "copy": "Kopiuj", + "copy.all": "Skopiuj wszystko", + "create": "Utwórz", + + "date": "Data", + "date.select": "Wybierz datę", + + "day": "Dzień", + "days.fri": "Pt", + "days.mon": "Pn", + "days.sat": "Sb", + "days.sun": "Nd", + "days.thu": "Czw", + "days.tue": "Wt", + "days.wed": "\u015ar", + + "debugging": "Debugowanie", + + "delete": "Usu\u0144", + "delete.all": "Usuń wszystkie", + + "dialog.files.empty": "Brak plików do wyboru", + "dialog.pages.empty": "Brak stron do wyboru", + "dialog.users.empty": "Brak użytkowników do wyboru", + + "dimensions": "Wymiary", + "disabled": "Wyłączone", + "discard": "Odrzu\u0107", + "download": "Pobierz", + "duplicate": "Zduplikuj", + + "edit": "Edytuj", + + "email": "Email", + "email.placeholder": "mail@example.com", + + "entries": "Wpisy", + "entry": "Wpis", + + "environment": "Środowisko", + + "error.access.code": "Nieprawidłowy kod", + "error.access.login": "Nieprawidłowy login", + "error.access.panel": "Nie masz uprawnień by dostać się do panelu", + "error.access.view": "Nie masz uprawnień, by dostać się do tej części panelu", + + "error.avatar.create.fail": "Nie udało się załadować zdjęcia profilowego", + "error.avatar.delete.fail": "Nie udało się usunąć zdjęcia profilowego", + "error.avatar.dimensions.invalid": "Proszę zachować szerokość i wysokość zdjęcia profilowego poniżej 3000 pikseli", + "error.avatar.mime.forbidden": "Zdjęcie profilowe musi być plikiem JPEG lub PNG", + + "error.blueprint.notFound": "Nie udało się załadować wzorca \"{name}\"", + + "error.blocks.max.plural": "Możesz dodać nie więcej niż {max} bloki/-ów", + "error.blocks.max.singular": "Możesz dodać tylko jeden blok", + "error.blocks.min.plural": "Musisz dodać co najmniej {min} bloki/-ów", + "error.blocks.min.singular": "Musisz dodać co najmniej jeden blok", + "error.blocks.validation": "W bloku {index} jest błąd", + + "error.email.preset.notFound": "Nie udało się załadować wzorca wiadomości e-mail \"{name}\"", + + "error.field.converter.invalid": "Nieprawidłowy konwerter \"{converter}\"", + + "error.file.changeName.empty": "Imię nie może być puste", + "error.file.changeName.permission": "Nie masz uprawnień, by zmienić nazwę \"{filename}\"", + "error.file.duplicate": "Istnieje już plik o nazwie \"{filename}\"", + "error.file.extension.forbidden": "Rozszerzenie \"{extension}\" jest niedozwolone", + "error.file.extension.invalid": "Nieprawidłowe rozszerzenie: {extension}", + "error.file.extension.missing": "Brak rozszerzenia pliku \"{filename}\"", + "error.file.maxheight": "Wysokość obrazka nie może być większa niż {height} pikseli", + "error.file.maxsize": "Plik jest za duży", + "error.file.maxwidth": "Szerokość obrazka nie może być większa niż {width} pikseli", + "error.file.mime.differs": "Przesłany plik musi być tego samego typu mime \"{mime}\"", + "error.file.mime.forbidden": "Typ multimediów \"{mime}\" jest niedozwolony", + "error.file.mime.invalid": "Nieprawidłowy typ MIME: {mime}", + "error.file.mime.missing": "Nie można wykryć typu multimediów dla \"{filename}\"", + "error.file.minheight": "Wysokość obrazka musi wynosić co najmniej {height} pikseli", + "error.file.minsize": "Plik jest za mały", + "error.file.minwidth": "Szerokość obrazka musi wynosić co najmniej {width} pikseli", + "error.file.name.missing": "Nazwa pliku nie może być pusta", + "error.file.notFound": "Nie można znaleźć pliku \"{filename}\"", + "error.file.orientation": "Orientacja obrazka musi być \"{orientation}\"", + "error.file.type.forbidden": "Nie możesz przesyłać plików {type}", + "error.file.type.invalid": "Nieprawidłowy typ pliku: {type}", + "error.file.undefined": "Nie można znaleźć pliku", + + "error.form.incomplete": "Popraw wszystkie błędy w formularzu…", + "error.form.notSaved": "Nie udało się zapisać formularza", + + "error.language.code": "Wprowadź poprawny kod języka.", + "error.language.duplicate": "Język już istnieje.", + "error.language.name": "Wprowadź poprawną nazwę języka.", + "error.language.notFound": "Język nie został odnaleziony", + + "error.layout.validation.block": "W bloku {blockIndex} w układzie {layoutIndex} jest błąd", + "error.layout.validation.settings": "W ustawieniach układu {index} jest błąd", + + "error.license.format": "Wprowadź poprawny klucz licencyjny", + "error.license.email": "Wprowadź poprawny adres email", + "error.license.verification": "Nie udało się zweryfikować licencji", + + "error.offline": "Panel jest obecnie offline", + + "error.page.changeSlug.permission": "Nie możesz zmienić końcówki adresu URL w \"{slug}\"", + "error.page.changeStatus.incomplete": "Strona zawiera błędy i nie można jej opublikować", + "error.page.changeStatus.permission": "Status tej strony nie może zostać zmieniony", + "error.page.changeStatus.toDraft.invalid": "Strony \"{slug}\" nie można przekonwertować na szkic", + "error.page.changeTemplate.invalid": "Nie można zmienić szablonu strony \"{slug}\"", + "error.page.changeTemplate.permission": "Nie masz uprawnień, by zmienić szablon dla \"{slug}\"", + "error.page.changeTitle.empty": "Tytuł nie może być pusty", + "error.page.changeTitle.permission": "Nie masz uprawnień, by zmienić tytuł dla \"{slug}\"", + "error.page.create.permission": "Nie masz uprawnień, by utworzyć \"{slug}\"", + "error.page.delete": "Strony \"{slug}\" nie można usunąć", + "error.page.delete.confirm": "Wprowadź tytuł strony, aby potwierdzić", + "error.page.delete.hasChildren": "Strona zawiera podstrony i nie można jej usunąć", + "error.page.delete.permission": "Nie masz uprawnień, by usunąć \"{slug}\"", + "error.page.draft.duplicate": "Istnieje już szkic z końcówką URL \"{slug}\"", + "error.page.duplicate": "Istnieje już strona z końcówką URL \"{slug}\"", + "error.page.duplicate.permission": "Nie masz uprawnień, by zduplikować \"{slug}\"", + "error.page.notFound": "Nie można znaleźć strony \"{slug}\"", + "error.page.num.invalid": "Wprowadź poprawny numer sortujący. Liczby nie mogą być ujemne.", + "error.page.slug.invalid": "Wprowadź poprawną końcówkę adresu URL", + "error.page.slug.maxlength": "Końcówka adresu musi być krótsza niż \"{length}\" znaków", + "error.page.sort.permission": "Nie można sortować strony \"{slug}\"", + "error.page.status.invalid": "Ustaw prawidłowy status strony", + "error.page.undefined": "Nie udało się znaleźć strony", + "error.page.update.permission": "Nie masz uprawnień, by zaktualizować \"{slug}\"", + + "error.section.files.max.plural": "Do sekcji \"{section}\" można dodać nie więcej niż {max} plików", + "error.section.files.max.singular": "Do sekcji \"{section}\" można dodać tylko jeden plik", + "error.section.files.min.plural": "W sekcji \"{section}\" musi być co najmniej {min} pliki/-ów", + "error.section.files.min.singular": "W sekcji \"{section}\" musi być co najmniej jeden plik", + + "error.section.pages.max.plural": "Do sekcji \"{section}\" można dodać nie więcej niż {max} stron", + "error.section.pages.max.singular": "Do sekcji \"{section}\" można dodać tylko jedną stronę", + "error.section.pages.min.plural": "W sekcji \"{section}\" musi być co najmniej {min} stron/-y", + "error.section.pages.min.singular": "W sekcji \"{section}\" musi być co najmniej jedna strona", + + "error.section.notLoaded": "Nie udało się załadować sekcji \"{name}\"", + "error.section.type.invalid": "Typ sekcji \"{type}\" jest nieprawidłowy", + + "error.site.changeTitle.empty": "Tytuł nie może być pusty", + "error.site.changeTitle.permission": "Nie masz uprawnień, by zmienić tytuł strony", + "error.site.update.permission": "Nie masz uprawnień, by zaktualizować stronę", + + "error.template.default.notFound": "Domyślny szablon nie istnieje", + + "error.unexpected": "Wystąpił nieoczekiwany błąd! Włącz tryb debugowania, aby uzyskać więcej informacji: https://getkirby.com/docs/reference/system/options/debug", + + "error.user.changeEmail.permission": "Nie masz uprawnień, by zmienić adres e-mail użytkownika \"{name}\"", + "error.user.changeLanguage.permission": "Nie masz uprawnień, by zmienić język użytkownika \"{name}\"", + "error.user.changeName.permission": "Nie masz uprawnień, by zmienić nazwę użytkownika \"{name}\"", + "error.user.changePassword.permission": "Nie masz uprawnień, by zmienić hasło użytkownika \"{name}\"", + "error.user.changeRole.lastAdmin": "Nie można zmienić roli ostatniego administratora", + "error.user.changeRole.permission": "Nie masz uprawnień, by zmienić rolę użytkownika \"{name}\"", + "error.user.changeRole.toAdmin": "Nie masz uprawnień, by awansować kogoś do roli daministratora", + "error.user.create.permission": "Nie masz uprawnień, by utworzyć tego użytkownika", + "error.user.delete": "Nie można usunąć użytkownika \"{name}\"", + "error.user.delete.lastAdmin": "Nie można usunąć ostatniego administratora", + "error.user.delete.lastUser": "Nie można usunąć ostatniego użytkownika", + "error.user.delete.permission": "Nie masz uprawnień, by usunąć użytkownika \"{name}\"", + "error.user.duplicate": "Istnieje już użytkownik z adresem email \"{email}\"", + "error.user.email.invalid": "Wprowadź poprawny adres email", + "error.user.language.invalid": "Proszę podać poprawny język", + "error.user.notFound": "Nie można znaleźć użytkownika \"{name}\"", + "error.user.password.excessive": "Please enter a valid password. Passwords must not be longer than 1000 characters.", + "error.user.password.invalid": "Wprowadź prawidłowe hasło. Hasła muszą mieć co najmniej 8 znaków.", + "error.user.password.notSame": "Hasła nie są takie same", + "error.user.password.undefined": "Użytkownik nie ma hasła", + "error.user.password.wrong": "Nieprawidłowe hasło", + "error.user.role.invalid": "Wprowadź poprawną rolę", + "error.user.undefined": "Nie można znaleźć użytkownika", + "error.user.update.permission": "Nie masz uprawnień, by zaktualizować użytkownika \"{name}\"", + + "error.validation.accepted": "Proszę potwierdzić", + "error.validation.alpha": "Wprowadź tylko znaki między a-z", + "error.validation.alphanum": "Wprowadź tylko znaki między a-z lub cyfry 0-9", + "error.validation.between": "Wprowadź wartość między \"{min}\" i \"{max}\"", + "error.validation.boolean": "Potwierdź lub odmów", + "error.validation.contains": "Wprowadź wartość, która zawiera \"{needle}\"", + "error.validation.date": "Wprowadź poprawną datę", + "error.validation.date.after": "Wprowadź datę późniejszą niż {date}", + "error.validation.date.before": "Wprowadź datę wcześniejszą niż {date}", + "error.validation.date.between": "Wprowadź datę między {min} a {max}", + "error.validation.denied": "Proszę odmówić", + "error.validation.different": "Wartością nie może być \"{other}\"", + "error.validation.email": "Wprowadź poprawny adres email", + "error.validation.endswith": "Wartość musi kończyć się na \"{end}\"", + "error.validation.filename": "Wprowadź poprawną nazwę pliku", + "error.validation.in": "Wprowadź jedno z następujących: ({in})", + "error.validation.integer": "Wprowadź poprawną liczbę całkowitą", + "error.validation.ip": "Wprowadź poprawny adres IP", + "error.validation.less": "Wprowadź wartość mniejszą niż {max}", + "error.validation.match": "Wartość nie jest zgodna z oczekiwanym wzorcem", + "error.validation.max": "Wprowadź wartość równą lub mniejszą niż {max}", + "error.validation.maxlength": "Wprowadź krótszą wartość. (maks. {max} znaków)", + "error.validation.maxwords": "Wprowadź nie więcej niż {max} słowa/słów", + "error.validation.min": "Wprowadź wartość równą lub większą niż {min}", + "error.validation.minlength": "Wprowadź dłuższą wartość. (min. {min} znaków)", + "error.validation.minwords": "Wprowadź co najmniej {min} słowa/słów", + "error.validation.more": "Wprowadź wartość większą niż {min}", + "error.validation.notcontains": "Wprowadź wartość, która nie zawiera \"{needle}\"", + "error.validation.notin": "Nie wprowadzaj żadnego z następujących ({notIn})", + "error.validation.option": "Wybierz poprawną opcję", + "error.validation.num": "Wprowadź poprawny numer", + "error.validation.required": "Wpisz coś", + "error.validation.same": "Wprowadź \"{other}\"", + "error.validation.size": "Rozmiar wartości musi wynosić \"{size}\"", + "error.validation.startswith": "Wartość musi zaczynać się od \"{start}\"", + "error.validation.time": "Wprowadź poprawny czas", + "error.validation.time.after": "Wprowadź czas późniejszy niż {time}", + "error.validation.time.before": "Wprowadź czas wcześniejszy niż {time}", + "error.validation.time.between": "Wprowadź czas między {min} a {max}", + "error.validation.url": "Wprowadź poprawny adres URL", + + "expand": "Rozwiń", + "expand.all": "Rozwiń wszystkie", + + "field.required": "Pole jest wymagane", + "field.blocks.changeType": "Zmień typ", + "field.blocks.code.name": "Kod", + "field.blocks.code.language": "Język", + "field.blocks.code.placeholder": "Twój kod …", + "field.blocks.delete.confirm": "Czy na pewno chcesz usunąć ten blok?", + "field.blocks.delete.confirm.all": "Czy na pewno chcesz usunąć wszystkie bloki?", + "field.blocks.delete.confirm.selected": "Czy na pewno chcesz usunąć wszystkie wybrane bloki?", + "field.blocks.empty": "Nie ma jeszcze żadnych bloków", + "field.blocks.fieldsets.label": "Wybierz typ bloku …", + "field.blocks.fieldsets.paste": "Wciśnij {{ shortcut }} by wkleić/zaimportować bloki ze schowka", + "field.blocks.gallery.name": "Galeria", + "field.blocks.gallery.images.empty": "Nie ma jeszcze żadnych obrazków", + "field.blocks.gallery.images.label": "Obrazki", + "field.blocks.heading.level": "Poziom", + "field.blocks.heading.name": "Nagłówek", + "field.blocks.heading.text": "Tekst", + "field.blocks.heading.placeholder": "Nagłówek …", + "field.blocks.image.alt": "Tekst alternatywny", + "field.blocks.image.caption": "Podpis", + "field.blocks.image.crop": "Przytnij", + "field.blocks.image.link": "Link", + "field.blocks.image.location": "Lokalizacja", + "field.blocks.image.name": "Obrazek", + "field.blocks.image.placeholder": "Wybierz obrazek", + "field.blocks.image.ratio": "Proporcje", + "field.blocks.image.url": "URL obrazka", + "field.blocks.line.name": "Linijka", + "field.blocks.list.name": "Lista", + "field.blocks.markdown.name": "Markdown", + "field.blocks.markdown.label": "Tekst", + "field.blocks.markdown.placeholder": "Markdown …", + "field.blocks.quote.name": "Cytat", + "field.blocks.quote.text.label": "Tekst", + "field.blocks.quote.text.placeholder": "Cytat …", + "field.blocks.quote.citation.label": "Źródło", + "field.blocks.quote.citation.placeholder": "autorstwa …", + "field.blocks.text.name": "Tekst", + "field.blocks.text.placeholder": "Tekst …", + "field.blocks.video.caption": "Podpis", + "field.blocks.video.name": "Video", + "field.blocks.video.placeholder": "Wprowadź URL video", + "field.blocks.video.url.label": "URL video", + "field.blocks.video.url.placeholder": "https://youtube.com/?v=", + + "field.files.empty": "Nie wybrano jeszcze żadnych plików", + + "field.layout.delete": "Usuń układ", + "field.layout.delete.confirm": "Czy na pewno chcesz usunąć ten układ?", + "field.layout.empty": "Nie ma jeszcze żadnych rzędów", + "field.layout.select": "Wybierz układ", + + "field.pages.empty": "Nie wybrano jeszcze żadnych stron", + "field.structure.delete.confirm": "Czy na pewno chcesz usunąć ten wiersz?", + "field.structure.empty": "Nie ma jeszcze \u017cadnych wpis\u00f3w.", + "field.users.empty": "Nie wybrano jeszcze żadnych użytkowników", + + "file.blueprint": "Ten plik nie ma jeszcze wzorca. Możesz go zdefiniować w /site/blueprints/files/{blueprint}.yml", + "file.delete.confirm": "Czy na pewno chcesz usunąć
{filename}?", + "file.sort": "Zmień pozycję", + + "files": "Pliki", + "files.empty": "Nie ma jeszcze żadnych plików", + + "hide": "Ukryj", + "hour": "Godzina", + "import": "Importuj", + "info": "Informacje", + "insert": "Wstaw", + "insert.after": "Wstaw po", + "insert.before": "Wstaw przed", + "install": "Zainstaluj", + + "installation": "Instalacja", + "installation.completed": "Panel został zainstalowany", + "installation.disabled": "Instalator panelu jest domyślnie wyłączony na serwerach publicznych. Uruchom instalator na komputerze lokalnym lub włącz go za pomocą opcji panel.install.", + "installation.issues.accounts": "Folder /site/accounts nie istnieje lub nie ma uprawnień do zapisu", + "installation.issues.content": "Folder /content nie istnieje lub nie ma uprawnień do zapisu", + "installation.issues.curl": "Wymagane jest rozszerzenie CURL", + "installation.issues.headline": "Nie można zainstalować panelu", + "installation.issues.mbstring": "Wymagane jest rozszerzenie MB String", + "installation.issues.media": "Folder /media nie istnieje lub nie ma uprawnień do zapisu", + "installation.issues.php": "Upewnij się, że używasz PHP 7+", + "installation.issues.server": "Kirby wymaga Apache, Nginx lub Caddy", + "installation.issues.sessions": "Folder /site/sessions nie istnieje lub nie ma uprawnień do zapisu", + + "language": "J\u0119zyk", + "language.code": "Kod", + "language.convert": "Ustaw jako domyślny", + "language.convert.confirm": "

Czy na pewno chcesz zmienić domyślny język na {name}? Nie można tego cofnąć.

Jeżeli brakuje tłumaczenia jakichś treści na {name}, nie będzie ich czym zastąpić i części witryny mogą być puste.

", + "language.create": "Dodaj nowy język", + "language.delete.confirm": "Czy na pewno chcesz usunąć język {name} i wszystkie tłumaczenia? Tego nie da się cofnąć!", + "language.deleted": "Język został usunięty", + "language.direction": "Kierunek czytania", + "language.direction.ltr": "Od lewej do prawej", + "language.direction.rtl": "Od prawej do lewej", + "language.locale": "PHP locale string", + "language.locale.warning": "Używasz niestandardowej konfiguracji ustawień regionalnych. Zmodyfikuj to w pliku języka w /site/langugaes", + "language.name": "Nazwa", + "language.updated": "Język został zaktualizowany", + + "languages": "Języki", + "languages.default": "Domyślny język", + "languages.empty": "Nie ma jeszcze żadnych języków", + "languages.secondary": "Dodatkowe języki", + "languages.secondary.empty": "Nie ma jeszcze dodatkowych języków", + + "license": "Licencja", + "license.buy": "Kup licencję", + "license.register": "Zarejestruj", + "license.manage": "Zarządzaj swoimi licencjami", + "license.register.help": "Po zakupieniu licencji otrzymałaś/-eś mailem klucz. Skopiuj go i wklej tutaj, aby dokonać rejestracji.", + "license.register.label": "Wprowadź swój kod licencji", + "license.register.success": "Dziękujemy za wspieranie Kirby", + "license.unregistered": "To jest niezarejestrowana wersja demonstracyjna Kirby", + "license.unregistered.label": "Niezarejestrowane", + + "link": "Link", + "link.text": "Tekst linku", + + "loading": "Ładuję", + + "lock.unsaved": "Niezapisane zmiany", + "lock.unsaved.empty": "Nie ma już żadnych niezapisanych zmian", + "lock.isLocked": "Niezapisane zmiany autorstwa {email}", + "lock.file.isLocked": "Plik jest aktualnie edytowany przez {email} i nie może zostać zmieniony.", + "lock.page.isLocked": "Strona jest aktualnie edytowana przez {email} i nie może zostać zmieniona.", + "lock.unlock": "Odblokuj", + "lock.isUnlocked": "Twoje niezapisane zmiany zostały nadpisane przez innego użytkownika. Możesz pobrać swoje zmiany, by scalić je ręcznie.", + + "login": "Zaloguj się", + "login.code.label.login": "Kod logowania się", + "login.code.label.password-reset": "Kod resetowania hasła", + "login.code.placeholder.email": "000 000", + "login.code.text.email": "Jeśli Twój adres email jest zarejestrowany, żądany kod został wysłany na Twoją skrzynkę.", + "login.email.login.body": "Cześć {user.nameOrEmail},\n\nNiedawno poprosiłaś/-eś o kod do zalogowania się do panelu strony {site}.\nPoniższy kod do zalogowania się będzie ważny przez {timeout} minut:\n\n{code}\n\nJeżeli nie zażądałaś/-eś kodu do logowania się, zignoruj tę wiadomość e-mail lub skontaktuj się z administratorem, jeśli masz pytania.\nZe względów bezpieczeństwa NIE przesyłaj dalej tego e-maila.", + "login.email.login.subject": "Twój kod logowania się", + "login.email.password-reset.body": "Cześć {user.nameOrEmail},\n\nNiedawno poprosiłaś/-eś o kod resetowania hasła do panelu strony {site}.\nPoniższy kod resetowania hasła będzie ważny przez {timeout} minut:\n\n{code}\n\nJeżeli nie zażądałaś/-eś kodu resetowania hasła, zignoruj tę wiadomość e-mail lub skontaktuj się z administratorem, jeśli masz pytania. \nZe względów bezpieczeństwa NIE przesyłaj dalej tego e-maila. ", + "login.email.password-reset.subject": "Twój kod resetujący hasło", + "login.remember": "Nie wylogowuj mnie", + "login.reset": "Zresetuj hasło", + "login.toggleText.code.email": "Zaloguj się za pomocą adresu email", + "login.toggleText.code.email-password": "Zaloguj się za pomocą hasła", + "login.toggleText.password-reset.email": "Zapomniałeś/-aś hasła?", + "login.toggleText.password-reset.email-password": "← Powrót do logowania", + + "logout": "Wyloguj", + + "menu": "Menu", + "meridiem": "AM/PM", + "mime": "Typ multimediów", + "minutes": "Minuty", + + "month": "Miesiąc", + "months.april": "Kwiecie\u0144", + "months.august": "Sierpie\u0144", + "months.december": "Grudzie\u0144", + "months.february": "Luty", + "months.january": "Stycze\u0144", + "months.july": "Lipiec", + "months.june": "Czerwiec", + "months.march": "Marzec", + "months.may": "Maj", + "months.november": "Listopad", + "months.october": "Pa\u017adziernik", + "months.september": "Wrzesie\u0144", + + "more": "Więcej", + "name": "Nazwa", + "next": "Następne", + "no": "nie", + "off": "wyłączone", + "on": "włączone", + "open": "Otwórz", + "open.newWindow": "Otwórz w nowym oknie", + "options": "Opcje", + "options.none": "Brak opcji", + + "orientation": "Orientacja", + "orientation.landscape": "Pozioma", + "orientation.portrait": "Pionowa", + "orientation.square": "Kwadrat", + + "page.blueprint": "Ta strona nie ma jeszcze wzorca. Możesz go zdefiniować w /site/blueprints/pages/{blueprint}.yml", + "page.changeSlug": "Zmie\u0144 URL", + "page.changeSlug.fromTitle": "Utw\u00f3rz na podstawie tytu\u0142u", + "page.changeStatus": "Zmień status", + "page.changeStatus.position": "Wybierz pozycję", + "page.changeStatus.select": "Wybierz nowy status", + "page.changeTemplate": "Zmień szablon", + "page.delete.confirm": "Czy na pewno chcesz usunąć {title}?", + "page.delete.confirm.subpages": "Ta strona zawiera podstrony.
Wszystkie podstrony również zostaną usunięte.", + "page.delete.confirm.title": "Wprowadź tytuł strony, aby potwierdzić", + "page.draft.create": "Utwórz szkic", + "page.duplicate.appendix": "Kopiuj", + "page.duplicate.files": "Kopiuj pliki", + "page.duplicate.pages": "Kopiuj strony", + "page.sort": "Zmień pozycję", + "page.status": "Status", + "page.status.draft": "Szkic", + "page.status.draft.description": "Strona jest w trybie roboczym i widoczna tylko dla zalogowanych redaktorów lub pod sekretnym linkiem", + "page.status.listed": "Opublikowana", + "page.status.listed.description": "Strona jest opublikowana i widoczna dla każdego", + "page.status.unlisted": "Nie katalogowana", + "page.status.unlisted.description": "Strona jest dostępna tylko za pośrednictwem adresu URL", + + "pages": "Strony", + "pages.empty": "Nie ma jeszcze żadnych stron", + "pages.status.draft": "Szkice", + "pages.status.listed": "Opublikowane", + "pages.status.unlisted": "Nie katalogowana", + + "pagination.page": "Strona", + + "password": "Has\u0142o", + "paste": "Wklej", + "paste.after": "Wklej po", + "pixel": "Piksel", + "plugins": "Wtyczki", + "prev": "Poprzednie", + "preview": "Podgląd", + "remove": "Usuń", + "rename": "Zmień nazwę", + "replace": "Zamie\u0144", + "retry": "Pon\u00f3w pr\u00f3b\u0119", + "revert": "Odrzu\u0107", + "revert.confirm": "Czy na pewno chcesz usunąć wszystkie niezapisane zmiany?", + + "role": "Rola", + "role.admin.description": "Administrator posiada wszystkie uprawnienia", + "role.admin.title": "Administrator", + "role.all": "Wszystkie", + "role.empty": "Nie ma użytkowników z tą rolą", + "role.description.placeholder": "Brak opisu", + "role.nobody.description": "To jest rola zastępcza bez żadnych uprawnień", + "role.nobody.title": "Nikt", + + "save": "Zapisz", + "search": "Szukaj", + "search.min": "Aby wyszukać, wprowadź co najmniej {min} znaków", + "search.all": "Pokaż wzystkie", + "search.results.none": "Brak wyników", + + "section.required": "Sekcja jest wymagana", + + "security": "Bezpieczeństwo", + "select": "Wybierz", + "server": "Serwer", + "settings": "Ustawienia", + "show": "Pokaż", + "site.blueprint": "Ta strona nie ma jeszcze wzorca. Możesz go zdefiniować w /site/blueprints/site.yml", + "size": "Rozmiar", + "slug": "Końcówka URL", + "sort": "Sortuj", + + "stats.empty": "Brak raportów", + "system.issues.content": "Zdaje się, że folder „content” jest wystawiony na publiczny dostęp", + "system.issues.debug": "Debugowanie musi być wyłączone w środowisku produkcyjnym", + "system.issues.git": "Zdaje się, że folder „.git” jest wystawiony na publiczny dostęp", + "system.issues.https": "Zalecamy HTTPS dla wszystkich Twoich witryn", + "system.issues.kirby": "Zdaje się, że folder „kirby” jest wystawiony na publiczny dostęp", + "system.issues.site": "Zdaje się, że folder „site” jest wystawiony na publiczny dostęp", + + "title": "Tytuł", + "template": "Szablon", + "today": "Dzisiaj", + + "toolbar.button.code": "Kod", + "toolbar.button.bold": "Pogrubienie", + "toolbar.button.email": "Email", + "toolbar.button.headings": "Nagłówki", + "toolbar.button.heading.1": "Nagłówek 1", + "toolbar.button.heading.2": "Nagłówek 2", + "toolbar.button.heading.3": "Nagłówek 3", + "toolbar.button.heading.4": "Nagłówek 4", + "toolbar.button.heading.5": "Nagłówek 5", + "toolbar.button.heading.6": "Nagłówek 6", + "toolbar.button.italic": "Kursywa", + "toolbar.button.file": "Plik", + "toolbar.button.file.select": "Wybierz plik", + "toolbar.button.file.upload": "Prześlij plik", + "toolbar.button.link": "Link", + "toolbar.button.paragraph": "Akapit", + "toolbar.button.strike": "Przekreślenie", + "toolbar.button.ol": "Lista numerowana", + "toolbar.button.underline": "Podkreślenie", + "toolbar.button.ul": "Lista wypunktowana", + + "translation.author": "Zespół Kirby", + "translation.direction": "ltr", + "translation.name": "Polski", + "translation.locale": "pl_PL", + + "upload": "Prześlij", + "upload.error.cantMove": "Przesłany plik nie mógł być przeniesiony", + "upload.error.cantWrite": "Nie udało się zapisać pliku na dysku", + "upload.error.default": "Nie udało się przesłać pliku", + "upload.error.extension": "Przesyłanie pliku zostało zastopowane przez rozszerzenie", + "upload.error.formSize": "Przesłany plik przekracza dyrektywę MAX_FILE_SIZE określoną w formularzu", + "upload.error.iniPostSize": "Przesłany plik przekracza dyrektywę post_max_size określoną w php.ini", + "upload.error.iniSize": "Przesłany plik przekracza dyrektywę upload_max_filesize określoną w php.ini", + "upload.error.noFile": "Nie został przesłany żaden plik", + "upload.error.noFiles": "Nie zostały przesłane żadne pliki", + "upload.error.partial": "Została przesłana tylko część przesyłanego pliku", + "upload.error.tmpDir": "Brak tymczasowego folderu", + "upload.errors": "Błąd", + "upload.progress": "Przesyłanie…", + + "url": "Url", + "url.placeholder": "https://example.com", + + "user": "Użytkownik", + "user.blueprint": "Możesz zdefiniować dodatkowe sekcje i pola dla użytkownika o takiej roli w /site/blueprints/users/{blueprint}.yml", + "user.changeEmail": "Zmień email", + "user.changeLanguage": "Zmień język", + "user.changeName": "Zmień nazwę tego użytkownika", + "user.changePassword": "Zmień hasło", + "user.changePassword.new": "Nowe hasło", + "user.changePassword.new.confirm": "Potwierdź nowe hasło…", + "user.changeRole": "Zmień rolę", + "user.changeRole.select": "Wybierz nową rolę", + "user.create": "Dodaj nowego użytkownika", + "user.delete": "Usuń tego użytkownika", + "user.delete.confirm": "Czy na pewno chcesz usunąć
{email}?", + + "users": "Użytkownicy", + + "version": "Wersja", + + "view.account": "Twoje konto", + "view.installation": "Instalacja", + "view.languages": "Języki", + "view.resetPassword": "Zresetuj hasło", + "view.site": "Strona", + "view.system": "System", + "view.users": "U\u017cytkownicy", + + "welcome": "Witaj", + "year": "Rok", + "yes": "tak" } diff --git a/kirby/i18n/translations/pt_BR.json b/kirby/i18n/translations/pt_BR.json index b851dab..26c89a1 100644 --- a/kirby/i18n/translations/pt_BR.json +++ b/kirby/i18n/translations/pt_BR.json @@ -1,730 +1,574 @@ { - "account.changeName": "Mudar seu nome", - "account.delete": "Deletar sua conta", - "account.delete.confirm": "Deseja realmente deletar sua conta? Você sairá do site imediatamente. Sua conta não poderá ser recuperada. ", - - "activate": "Ativar", - "add": "Adicionar", - "alpha": "Alpha", - "author": "Autor", - "avatar": "Foto do perfil", - "back": "Voltar", - "cancel": "Cancelar", - "change": "Alterar", - "close": "Fechar", - "changes": "Alterações", - "confirm": "Salvar", - "collapse": "Colapsar", - "collapse.all": "Colapsar todos", - "color": "Cor", - "coordinates": "Coordenadas", - "copy": "Copiar", - "copy.all": "Copiar todos", - "copy.success": "{count} copiados!", - "create": "Criar", - "custom": "Personalizado", - - "date": "Data", - "date.select": "Selecione uma data", - - "day": "Dia", - "days.fri": "Sex", - "days.mon": "Seg", - "days.sat": "S\u00e1b", - "days.sun": "Dom", - "days.thu": "Qui", - "days.tue": "Ter", - "days.wed": "Qua", - - "debugging": "Depuração ", - - "delete": "Deletar", - "delete.all": "Deletar todos", - - "dialog.fields.empty": "Esta caixa de diálogo não tem campos", - "dialog.files.empty": "Nenhum arquivo para selecionar", - "dialog.pages.empty": "Nenhuma página para selecionar", - "dialog.text.empty": "Esta caixa de diálogo não define nenhum texto", - "dialog.users.empty": "Nenhum usuário para selecionar", - - "dimensions": "Dimensões", - "disable": "Desativar", - "disabled": "Desativado", - "discard": "Descartar", - - "drawer.fields.empty": "Esta janela não tem campos", - - "domain": "Domínio", - "download": "Baixar", - "duplicate": "Duplicar", - - "edit": "Editar", - - "email": "Email", - "email.placeholder": "mail@exemplo.com", - - "enter": "Insira", - "entries": "Registos", - "entry": "Registo", - - "environment": "Ambiente", - - "error": "Erro", - "error.access.code": "Código inválido", - "error.access.login": "Código de acesso inválido", - "error.access.panel": "Você não tem permissão para acessar o painel", - "error.access.view": "Você não tem permissão para acessar esta parte do painel", - - "error.avatar.create.fail": "A foto de perfil não pôde ser enviada", - "error.avatar.delete.fail": "A foto de perfil não pôde ser deletada", - "error.avatar.dimensions.invalid": "Por favor, use uma foto de perfil com largura e altura menores que 3000 pixels", - "error.avatar.mime.forbidden": "A foto de perfil deve ser um arquivo JPEG ou PNG", - - "error.blueprint.notFound": "A planta \"{name}\" não pôde ser carregada", - - "error.blocks.max.plural": "Você não deve adicionar mais do que {max} blocos", - "error.blocks.max.singular": "Você não deve adicionar mais do que um bloco", - "error.blocks.min.plural": "Você deve adicionar pelo menos {min} blocos", - "error.blocks.min.singular": "Você deve adicionar pelo menos um bloco", - "error.blocks.validation": "Há um erro no campo \"{field}\" no bloco {index} a usar o tipo de bloco \"{fieldset}\"", - - "error.cache.type.invalid": "Tipo de cache \"{type}\" inválido", - - "error.email.preset.notFound": "Pré-configuração de email \"{name}\" não foi encontrada", - - "error.field.converter.invalid": "Conversor \"{converter}\" inválido", - "error.field.type.missing": "Campo \"{name}\": O tipo de campo \"{type}\" não existe", - - "error.file.changeName.empty": "O nome não deve ficar em branco", - "error.file.changeName.permission": "Você não tem permissão para alterar o nome de \"{filename}\"", - "error.file.changeTemplate.invalid": "O template para o ficheiro \"{id}\" não pode ser alterado para \"{template}\" (válido: \"{blueprints}\")", - "error.file.changeTemplate.permission": "Não tem permissão para alterar o template do ficheiro \"{id}\"", - - "error.file.duplicate": "Um arquivo com o nome \"{filename}\" já existe", - "error.file.extension.forbidden": "Extensão \"{extension}\" não permitida", - "error.file.extension.invalid": "Extensão inválida: {extension}", - "error.file.extension.missing": "Extensão de \"{filename}\" em falta", - "error.file.maxheight": "A altura da imagem não pode exceder {height} pixels", - "error.file.maxsize": "O arquivo é grande demais", - "error.file.maxwidth": "A largura da imagem não pode exceder {width} pixels", - "error.file.mime.differs": "O arquivo enviado precisa ser do tipo \"{mime}\"", - "error.file.mime.forbidden": "Tipo de mídia \"{mime}\" não permitido", - "error.file.mime.invalid": "Tipo mime inválido: {mime}", - "error.file.mime.missing": "Tipo de mídia de \"{filename}\" não detectado", - "error.file.minheight": "A altura da imagem deve ser pelo menos {height} pixels", - "error.file.minsize": "O arquivo é pequeno demais", - "error.file.minwidth": "A largura da imagem deve ser pelo menos {width} pixels", - "error.file.name.unique": "O nome do ficheiro deve ser único", - "error.file.name.missing": "O nome do arquivo não pode ficar em branco", - "error.file.notFound": "Arquivo \"{filename}\" não encontrado", - "error.file.orientation": "A orientação da imagem deve ser “{orientation}”", - "error.file.type.forbidden": "Você não tem permissão para enviar arquivos {type}", - "error.file.type.invalid": "Tipo inválido de arquivo: {type}", - "error.file.undefined": "Arquivo n\u00e3o encontrado", - - "error.form.incomplete": "Por favor, corrija os erros do formulário…", - "error.form.notSaved": "O formulário não pôde ser salvo", - - "error.language.code": "Por favor entre um código válido para o idioma", - "error.language.duplicate": "O idioma já existe", - "error.language.name": "Por favor entre um nome válido para o idioma", - "error.language.notFound": "O idioma não foi encontrado", - - "error.layout.validation.block": "Há um erro no campo \"{field}\" no bloco {blockIndex} a usar o tipo de bloco \"{fieldset}\" no layout {layoutIndex}", - "error.layout.validation.settings": "Há um erro na configuração do layout {index}", - - "error.license.domain": "O domínio da licença está em falta", - "error.license.email": "Digite um endereço de email válido", - "error.license.format": "Por favor insira um código de licença válido", - "error.license.verification": "A licensa não pôde ser verificada", - - "error.login.totp.confirm.invalid": "Código inválido", - "error.login.totp.confirm.missing": "Por favor insira o código atual", - - "error.object.validation": "Há um erro no campo \"{label}\":\n{message}", - - "error.offline": "O painel está offline no momento", - - "error.page.changeSlug.permission": "Você não tem permissão para alterar o anexo de URL de \"{slug}\"", - "error.page.changeSlug.reserved": "O caminho das páginas de nível superior não deve começar com \"{path}\"", - "error.page.changeStatus.incomplete": "A página possui erros e não pode ser salva", - "error.page.changeStatus.permission": "O estado desta página não pode ser alterado", - "error.page.changeStatus.toDraft.invalid": "A página \"{slug}\" não pode ser convertida para rascunho", - "error.page.changeTemplate.invalid": "O tema da página \"{slug}\" não pode ser alterado", - "error.page.changeTemplate.permission": "Você não tem permissão para alterar o tema de \"{slug}\"", - "error.page.changeTitle.empty": "O título não pode ficar em branco", - "error.page.changeTitle.permission": "Você não tem permissão para alterar o título de \"{slug}\"", - "error.page.create.permission": "Você não tem permissão para criar \"{slug}\"", - "error.page.delete": "A página \"{slug}\" não pode ser deletada", - "error.page.delete.confirm": "Por favor, digite o título da página para confirmar", - "error.page.delete.hasChildren": "A página possui subpáginas e não pode ser deletada", - "error.page.delete.permission": "Você não tem permissão para deletar \"{slug}\"", - "error.page.draft.duplicate": "Uma página rascunho com um anexo de URL \"{slug}\" já existe", - "error.page.duplicate": "Uma página com o anexo de URL \"{slug}\" já existe", - "error.page.duplicate.permission": "Você não tem permissão para duplicar “{slug}”", - "error.page.move.ancestor": "A página não pode ser movida para dentro dela mesma", - "error.page.move.directory": "A pasta da página não pode ser movida", - "error.page.move.duplicate": "Uma subpágina com o segmento de URL \"{slug}\" já existe", - "error.page.move.notFound": "A página movida não foi encontrada", - "error.page.move.permission": "Não tem permissão para mover \"{slug}\"", - "error.page.move.template": "O template \"{template}\" não é aceite como subpágina de \"{parent}\"", - "error.page.notFound": "Página \"{slug}\" não encontrada", - "error.page.num.invalid": "Digite um número de ordenação válido. Este número não pode ser negativo.", - "error.page.slug.invalid": "Por favor entre um anexo de URL válido ", - "error.page.slug.maxlength": "O slug deve ter menos de “{length}” caracteres", - "error.page.sort.permission": "A página \"{slug}\" não pode ser ordenada", - "error.page.status.invalid": "Por favor, defina um estado de página válido", - "error.page.undefined": "P\u00e1gina n\u00e3o encontrada", - "error.page.update.permission": "Você não tem permissão para atualizar \"{slug}\"", - - "error.section.files.max.plural": "Você não pode adicionar mais do que {max} arquivos à seção \"{section}\"", - "error.section.files.max.singular": "Você não pode adicionar mais do que um arquivo à seção \"{section}\"", - "error.section.files.min.plural": "A seção “{section}” precisa ter pelo menos {min} arquivos", - "error.section.files.min.singular": "A seção “{section}” precisa ter pelo menos um arquivo", - - "error.section.pages.max.plural": "Você não pode adicionar mais do que {max} páginas à seção \"{section}\"", - "error.section.pages.max.singular": "Você não pode adicionar mais do que uma página à seção \"{section}\"", - "error.section.pages.min.plural": "A seção “{section}” precisa ter pelo menos {min} páginas ", - "error.section.pages.min.singular": "A seção “{section}” precisa ter pelo menos uma página ", - - "error.section.notLoaded": "A seção \"{name}\" não pôde ser carregada", - "error.section.type.invalid": "O tipo da seção \"{type}\" não é válido", - - "error.site.changeTitle.empty": "O título não pode ficar em branco", - "error.site.changeTitle.permission": "Você não tem permissão para alterar o título do site", - "error.site.update.permission": "Você não tem permissão para atualizar o site", - - "error.structure.validation": "Existe um erro no campo \"{field}\" na linha {index}", - - "error.template.default.notFound": "O tema padrão não existe", - - "error.unexpected": "Ocorreu um erro inesperado! Ative o modo de debug para obter mais informações: https://getkirby.com/docs/reference/system/options/debug", - - "error.user.changeEmail.permission": "Você não tem permissão para alterar o email do usuário \"{name}\"", - "error.user.changeLanguage.permission": "Você não tem permissão para alterar o idioma do usuário \"{name}\"", - "error.user.changeName.permission": "Você não tem permissão para alterar o nome do usuário \"{name}\"", - "error.user.changePassword.permission": "Você não tem permissão para alterar a senha do usuário \"{name}\"", - "error.user.changeRole.lastAdmin": "O papel do último administrador não pode ser alterado", - "error.user.changeRole.permission": "Você não tem permissão para alterar o papel do usuário \"{name}\"", - "error.user.changeRole.toAdmin": "Você não tem permissão para promover usuários ao papel de administrador ", - "error.user.create.permission": "Você não tem permissão para criar este usuário", - "error.user.delete": "O usuário \"{name}\" não pode ser deletado", - "error.user.delete.lastAdmin": "O último administrador não pode ser deletado", - "error.user.delete.lastUser": "O último usuário não pode ser deletado", - "error.user.delete.permission": "Você não tem permissão para deletar o usuário \"{name}\"", - "error.user.duplicate": "Um usuário com o email \"{email}\" já existe", - "error.user.email.invalid": "Digite um endereço de email válido", - "error.user.language.invalid": "Digite um idioma válido", - "error.user.notFound": "Usuário \"{name}\" não encontrado", - "error.user.password.excessive": "Por favor insira uma palavra-passe válida. As palavras-passe não devem ter mais do que 1000 caracteres.", - "error.user.password.invalid": "Digite uma senha válida. Sua senha deve ter pelo menos 8 caracteres.", - "error.user.password.notSame": "As senhas não combinam", - "error.user.password.undefined": "O usuário não possui uma senha", - "error.user.password.wrong": "Senha errada", - "error.user.role.invalid": "Digite um papel válido", - "error.user.undefined": "Usuário não encontrado", - "error.user.update.permission": "Você não tem permissão para atualizar o usuário \"{name}\"", - - "error.validation.accepted": "Por favor, confirme", - "error.validation.alpha": "Por favor, use apenas caracteres entre a-z", - "error.validation.alphanum": "Por favor, use apenas caracteres entre a-z ou 0-9", - "error.validation.anchor": "Por favor insira uma âncora de link correta", - "error.validation.between": "Digite um valor entre \"{min}\" e \"{max}\"", - "error.validation.boolean": "Por favor, confirme ou rejeite", - "error.validation.color": "Por favor, insira uma cor válida no formato {format}", - "error.validation.contains": "Digite um valor que contenha \"{needle}\"", - "error.validation.date": "Escolha uma data válida", - "error.validation.date.after": "Por favor entre uma data depois de {date}", - "error.validation.date.before": "Por favor entre uma data antes de {date}", - "error.validation.date.between": "Por favor entre uma data entre {min} e {max}", - "error.validation.denied": "Por favor, cancele", - "error.validation.different": "O valor deve ser diferente de \"{other}\"", - "error.validation.email": "Digite um endereço de email válido", - "error.validation.endswith": "O valor deve terminar com \"{end}\"", - "error.validation.filename": "Digite um nome de arquivo válido", - "error.validation.in": "Digite um destes valores: ({in})", - "error.validation.integer": "Digite um número inteiro válido", - "error.validation.ip": "Digite um endereço de IP válido", - "error.validation.less": "Digite um valor menor que {max}", - "error.validation.linkType": "O tipo de link não é permitido", - "error.validation.match": "O valor não combina com o padrão esperado", - "error.validation.max": "Digite um valor igual ou menor que {max}", - "error.validation.maxlength": "Digite um valor curto. (no máximo {max} caracteres)", - "error.validation.maxwords": "Digite menos que {max} palavra(s)", - "error.validation.min": "Digite um valor igual ou maior que {min}", - "error.validation.minlength": "Digite um valor maior. (no mínimo {min} caracteres)", - "error.validation.minwords": "Digite ao menos {min} palavra(s)", - "error.validation.more": "Digite um valor maior que {min}", - "error.validation.notcontains": "Digite um valor que não contenha \"{needle}\"", - "error.validation.notin": "Não digite nenhum destes valores: ({notIn})", - "error.validation.option": "Escolha uma opção válida", - "error.validation.num": "Digite um número válido", - "error.validation.required": "Digite algo", - "error.validation.same": "Por favor, digite \"{other}\"", - "error.validation.size": "O tamanho do valor deve ser \"{size}\"", - "error.validation.startswith": "O valor deve começar com \"{start}\"", - "error.validation.tel": "Por favor, insira um número de telefone não formatado", - "error.validation.time": "Digite um horário válido", - "error.validation.time.after": "Por favor entre um horário depois de {time}", - "error.validation.time.before": "Por favor entre um horário antes de {time}", - "error.validation.time.between": "Por favor entre um horário entre {min} e {max}", - "error.validation.uuid": "Por favor, insira um UUID válido", - "error.validation.url": "Digite uma URL válida", - - "expand": "Expandir", - "expand.all": "Expandir todos", - - "field.invalid": "O campo é inválido", - "field.required": "Este campo é obrigatório ", - "field.blocks.changeType": "Mudar tipo", - "field.blocks.code.name": "Código", - "field.blocks.code.language": "Idioma", - "field.blocks.code.placeholder": "Seu código …", - "field.blocks.delete.confirm": "Deseja realmente deletar este bloco?", - "field.blocks.delete.confirm.all": "Deseja realmente deletar todos os blocos?", - "field.blocks.delete.confirm.selected": "Deseja realmente deletar os blocos selecionados?", - "field.blocks.empty": "Nenhum bloco", - "field.blocks.fieldsets.empty": "Ainda não há tipos de blocos", - "field.blocks.fieldsets.label": "Por favor selecione um tipo de bloco …", - "field.blocks.fieldsets.paste": "Pressione {{ shortcut }} para importar layouts/blocks da sua área de transferência Só serão inseridos aqueles permitidos no campo atual.", - "field.blocks.gallery.name": "Galeria", - "field.blocks.gallery.images.empty": "Nenhuma imagem", - "field.blocks.gallery.images.label": "Imagens", - "field.blocks.heading.level": "Nível ", - "field.blocks.heading.name": "Título ", - "field.blocks.heading.text": "Texto", - "field.blocks.heading.placeholder": "Título …", - "field.blocks.image.alt": "Texto alternativo", - "field.blocks.image.caption": "Legenda", - "field.blocks.image.crop": "Cortar", - "field.blocks.image.link": "Link", - "field.blocks.image.location": "Localização ", - "field.blocks.image.location.internal": "Este website", - "field.blocks.image.location.external": "Fonte externa", - "field.blocks.image.name": "Imagem", - "field.blocks.image.placeholder": "Selecionar uma imagem", - "field.blocks.image.ratio": "Proporção ", - "field.blocks.image.url": "URL da imagem", - "field.blocks.line.name": "Linha", - "field.blocks.list.name": "Lista", - "field.blocks.markdown.name": "Markdown", - "field.blocks.markdown.label": "Texto", - "field.blocks.markdown.placeholder": "Markdown …", - "field.blocks.quote.name": "Citação ", - "field.blocks.quote.text.label": "Texto", - "field.blocks.quote.text.placeholder": "Citação …", - "field.blocks.quote.citation.label": "Citação ", - "field.blocks.quote.citation.placeholder": "de …", - "field.blocks.text.name": "Texto", - "field.blocks.text.placeholder": "Texto …", - "field.blocks.video.autoplay": "Reprodução automática", - "field.blocks.video.caption": "Legenda", - "field.blocks.video.controls": "Controlos", - "field.blocks.video.location": "Localização ", - "field.blocks.video.loop": "Repetir", - "field.blocks.video.muted": "Sem som", - "field.blocks.video.name": "Vídeo ", - "field.blocks.video.placeholder": "Entre uma URL de vídeo ", - "field.blocks.video.poster": "Poster", - "field.blocks.video.preload": "Pré-carregamento", - "field.blocks.video.url.label": "URL-Vídeo", - "field.blocks.video.url.placeholder": "https://youtube.com/?v=", - - "field.files.empty": "Nenhum arquivo selecionado", - - "field.layout.change": "Alterar layout", - "field.layout.delete": "Deletar layout", - "field.layout.delete.confirm": "Deseja realmente deletar este layout?", - "field.layout.delete.confirm.all": "Tem a certeza que pretende remover todos os layouts?", - "field.layout.empty": "Nenhuma linha", - "field.layout.select": "Selecionar um layout", - - "field.object.empty": "Nenhuma informação ainda", - - "field.pages.empty": "Nenhuma página selecionada", - - "field.structure.delete.confirm": "Deseja realmente deletar esta linha?", - "field.structure.delete.confirm.all": "Tem a certeza que pretende eliminar todos os registos?", - "field.structure.empty": "Nenhum registro", - - "field.users.empty": "Nenhum usuário selecionado", - - "fields.empty": "Nenhum campo ainda", - - "file": "Ficheiro", - "file.blueprint": "Este arquivo não tem planta. Você pode definir sua planta em /site/blueprints/files/{blueprint}.yml", - "file.changeTemplate": "Alterar tema", - "file.changeTemplate.notice": "Alterar o template do ficheiro irá remover o conteúdo dos campos que não correspondem ao mesmo tipo. Se o novo template definir certas regras, por exemplo dimensões de imagem, estas também serão aplicadas irreversivelmente. Use com cuidado.", - "file.delete.confirm": "Deseja realmente deletar
{filename}?", - "file.focus.placeholder": "Definir ponto de foco", - "file.focus.reset": "Remover ponto de foco", - "file.focus.title": "Foco", - "file.sort": "Mudar posição", - - "files": "Arquivos", - "files.empty": "Nenhum arquivo", - - "filter": "Filtro", - - "hide": "Ocultar", - "hour": "Hora", - "hue": "Tonalidade", - "import": "Importar", - "info": "Info", - "insert": "Inserir", - "insert.after": "Inserir após", - "insert.before": "Inserir antes", - "install": "Instalar", - - "installation": "Instalação", - "installation.completed": "Painel instalado com sucesso", - "installation.disabled": "O instalador do painel está desabilitado em servidores públicos por padrão. Por favor, execute o instalador em uma máquina local ou habilite a opção panel.install.", - "installation.issues.accounts": "A pasta /site/accounts não existe ou não possui permissão de escrita", - "installation.issues.content": "A pasta /content não existe ou não possui permissão de escrita", - "installation.issues.curl": "A extensão CURL é necessária", - "installation.issues.headline": "O painel não pôde ser instalado", - "installation.issues.mbstring": "A extensão MB String é necessária", - "installation.issues.media": "A pasta /media não existe ou não possui permissão de escrita", - "installation.issues.php": "Certifique-se que você está usando o PHP 8+", - "installation.issues.sessions": "A pasta /site/sessions não existe ou não possui permissão de escrita", - - "language": "Idioma", - "language.code": "Código", - "language.convert": "Tornar padrão", - "language.convert.confirm": "

Deseja realmente converter {name} para o idioma padrão? Esta ação não poderá ser revertida.

Se {name} tiver conteúdo não traduzido, partes do seu site poderão ficar sem conteúdo.

", - "language.create": "Adicionar novo idioma", - "language.default": "Idioma padrão", - "language.delete.confirm": "Deseja realmente deletar o idioma {name} incluíndo todas as traduções. Esta ação não poderá ser revertida!", - "language.deleted": "Idioma deletado", - "language.direction": "Direção de leitura", - "language.direction.ltr": "Esquerda para direita", - "language.direction.rtl": "Direita para esquerda", - "language.locale": "String de localização do PHP", - "language.locale.warning": "Você está usando uma configuração de local customizada. Por favor modifique a configuração no arquivo do idioma em /site/languages", - "language.name": "Nome", - "language.secondary": "Idioma secundário", - "language.settings": "Configurações de idioma", - "language.updated": "Idioma atualizado", - "language.variables": "Variáveis de idioma", - "language.variables.empty": "Nenhuma tradução ainda", - - "language.variable.delete.confirm": "Tem a certeza que pretende eliminar a variável {key}?", - "language.variable.key": "Chave", - "language.variable.notFound": "A variável não foi encontrada", - "language.variable.value": "Valor", - - "languages": "Idiomas", - "languages.default": "Idioma padrão", - "languages.empty": "Nenhum idioma", - "languages.secondary": "Idiomas secundários", - "languages.secondary.empty": "Nenhum idioma secundário", - - "license": "Licen\u00e7a do Kirby ", - "license.activate": "Ativar agora", - "license.activate.label": "Por favor, ative a sua licença", - "license.activate.domain": "A sua licença será irá ser ativada para {host}.", - "license.activate.local": "Está prestes a ativar a sua licença Kirby no domínio local {host}. Se este site vai ser alojado num domínio público, por favor ative-o lá. Se o domínio {host} é o o que deseja para usar a sua licença, por favor continue.", - "license.activated": "Ativado", - "license.buy": "Comprar licença", - "license.code": "Código", - "license.code.help": "Recebeu o seu código de licença por e-mail após a compra. Por favor, copie e cole aqui.", - "license.code.label": "Por favor, digite o código da sua licença", - "license.status.active.info": "Inclui novas versões principais até {date}", - "license.status.active.label": "Licença válida", - "license.status.demo.info": "Esta é uma instalação de demonstração", - "license.status.demo.label": "Demonstração", - "license.status.inactive.info": "Renove a licença para atualizar para novas versões principais", - "license.status.inactive.label": "Nenhuma versão principal nova", - "license.status.legacy.bubble": "Pronto para renovar a sua licença?", - "license.status.legacy.info": "A sua licença não abrange esta versão", - "license.status.legacy.label": "Por favor, renove a sua licença", - "license.status.missing.bubble": "Pronto para lançar o seu site?", - "license.status.missing.info": "Nenhuma licença válida", - "license.status.missing.label": "Por favor, ative a sua licença", - "license.manage": "Gerir as suas licenças", - "license.purchased": "Compradas", - "license.success": "Obrigado por apoiar o Kirby", - "license.unregistered.label": "Não registadas", - - "link": "Link", - "link.text": "Texto do link", - - "loading": "Carregando", - - "lock.unsaved": "Mudanças não salvas", - "lock.unsaved.empty": "Não há mais mudanças não salvas", - "lock.isLocked": "Alterações não guardadas de {email}", - "lock.unlock": "Destrancar", - "lock.unlock.submit": "Desbloqueie e substitua alterações não guardadas de {email}", - "lock.isUnlocked": "Foi desbloqueado por outro utilizador", - - "login": "Entrar", - "login.code.label.login": "Código de acesso", - "login.code.label.password-reset": "Código de redefinição de senha", - "login.code.placeholder.email": "000 0000", - "login.code.placeholder.totp": "000000", - "login.code.text.email": "Se seu endereço de email está registrado, o código requisitado será mandado por email.", - "login.code.text.totp": "Por favor, insira o código único da sua aplicação de autenticação.", - "login.email.login.body": "Oi, {user.nameOrEmail},\n\nVocê recentemente pediu um código de acesso ao painel administrativo do site {site}.\nO seguinte código será válido por {timeout} minutos:\n\n{code}\n\nSe você não pediu este código de acesso, por favor ignore esta mensagem, ou contate seu Administrador de Sistemas se você tiver dúvidas.\nPor questões de segurança, por favor NÃO compartilhe esta mensagem.", - "login.email.login.subject": "Seu código de acesso", - "login.email.password-reset.body": "Oi, {user.nameOrEmail},\n\nVocê recentemente pediu um código de redefinição de senha, para o painel administrativo do site {site}.\nO seguinte código de redefinição de senha será válido por {timeout} minutos:\n\n{code}\n\nSe você não pediu este código, por favor ignore esta mensagem, ou contate seu Administrador de Sistemas se você tiver dúvidas.\nPor questões de segurança, por favor NÃO compartilhe esta mensagem.", - "login.email.password-reset.subject": "Seu código de redefinição de senha", - "login.remember": "Manter-me conectado", - "login.reset": "Redefinir senha", - "login.toggleText.code.email": "Entrar com email", - "login.toggleText.code.email-password": "Entrar com senha", - "login.toggleText.password-reset.email": "Esqueceu sua senha?", - "login.toggleText.password-reset.email-password": "← Voltar à entrada", - "login.totp.enable.option": "Configurar códigos únicos", - "login.totp.enable.intro": "As aplicações de autenticação podem gerar códigos únicos que são utilizados como um segundo fator ao iniciar a sessão na sua conta.", - "login.totp.enable.qr.label": "1. Leia este código QR", - "login.totp.enable.qr.help": "Não consegue ler o código? Adicione a chave de configuração {secret} manualmente à sua aplicação de autenticação.", - "login.totp.enable.confirm.headline": "2. Confirme com o código gerado", - "login.totp.enable.confirm.text": "A sua aplicação gera um novo código único a cada 30 segundos. Insira o código atual para concluir a configuração:", - "login.totp.enable.confirm.label": "Código atual", - "login.totp.enable.confirm.help": "Após esta configuração, iremos solicitar um código único sempre que iniciar a sessão.", - "login.totp.enable.success": "Códigos únicos ativados", - "login.totp.disable.option": "Desativar códigos únicos", - "login.totp.disable.label": "Insira a sua palavra-passe para desativar códigos únicos", - "login.totp.disable.help": "No futuro, um segundo fator diferente, como um código de início de sessão enviado por e-mail, será solicitado quando iniciar a sessão. Poderá configurar códigos únicos novamente mais tarde.", - "login.totp.disable.admin": "Isto irá desactivar os códigos únicos para {user}. No futuro, um segundo fator diferente, como um código de início de sessão enviado por e-mail, será solicitado quando eles iniciarem a sessão. {user} poderá configurar códigos únicos novamente após o próximo início de sessão.", - "login.totp.disable.success": "Códigos únicos desativados", - - "logout": "Sair", - - "merge": "Unir", - "menu": "Menu", - "meridiem": "AM/PM", - "mime": "Tipo de mídia", - "minutes": "Minutos", - - "month": "Mês", - "months.april": "Abril", - "months.august": "Agosto", - "months.december": "Dezembro", - "months.february": "Fevereiro", - "months.january": "Janeiro", - "months.july": "Julho", - "months.june": "Junho", - "months.march": "Mar\u00e7o", - "months.may": "Maio", - "months.november": "Novembro", - "months.october": "Outubro", - "months.september": "Setembro", - - "more": "Mais", - "move": "Mover", - "name": "Nome", - "next": "Próximo", - "night": "Noite", - "no": "não", - "off": "não", - "on": "sim", - "open": "Abrir", - "open.newWindow": "Abrir em nova janela", - "option": "Opção", - "options": "Opções", - "options.none": "Nenhuma opção", - "options.all": "Mostrar todas as {count} opções", - - "orientation": "Orientação", - "orientation.landscape": "Paisagem", - "orientation.portrait": "Retrato", - "orientation.square": "Quadrado", - - "page": "Página", - "page.blueprint": "Esta página não tem planta. Você pode definir sua planta em /site/blueprints/pages/{blueprint}.yml", - "page.changeSlug": "Alterar URL", - "page.changeSlug.fromTitle": "Criar a partir do t\u00edtulo", - "page.changeStatus": "Alterar estado", - "page.changeStatus.position": "Selecione uma posição", - "page.changeStatus.select": "Selecione um novo estado", - "page.changeTemplate": "Alterar tema", - "page.changeTemplate.notice": "Alterar o template da página irá remover o conteúdo dos campos que não correspondem ao mesmo tipo. Use com cuidado.", - "page.create": "Criar como {status}", - "page.delete.confirm": "Deseja realmente deletar {title}?", - "page.delete.confirm.subpages": "Esta página possui subpáginas.
Todas as subpáginas serão excluídas também.", - "page.delete.confirm.title": "Digite o título da página para confirmar", - "page.duplicate.appendix": "Copiar", - "page.duplicate.files": "Copiar arquivos", - "page.duplicate.pages": "Copiar páginas", - "page.move": "Mover página", - "page.sort": "Mudar posição", - "page.status": "Estado", - "page.status.draft": "Rascunho", - "page.status.draft.description": "A página é um rascunho, e visível somente por editores logados, ou através de um link secreto.", - "page.status.listed": "Pública", - "page.status.listed.description": "A página pública é visível para todos", - "page.status.unlisted": "Não listadas", - "page.status.unlisted.description": "Esta página é acessível somente através da URL", - - "pages": "Páginas", - "pages.empty": "Nenhuma página", - "pages.status.draft": "Rascunhos", - "pages.status.listed": "Publicadas", - "pages.status.unlisted": "Não listadas", - - "pagination.page": "Página", - - "password": "Senha", - "paste": "Colar", - "paste.after": "Colar após", - "paste.success": "{count} colados!", - "pixel": "Pixel", - "plugin": "Plugin", - "plugins": "Plugins", - "prev": "Anterior", - "preview": "Visualizar", - "remove": "Remover", - "rename": "Renomear", - "renew": "Renovar", - "replace": "Substituir", - "replace.with": "Substituir por", - "retry": "Tentar novamente", - "revert": "Descartar", - "revert.confirm": "Deseja realmente deletar todas as mudanças não salvas?", - - "role": "Papel", - "role.admin.description": "O administrador tem todos os direitos", - "role.admin.title": "Administrador", - "role.all": "Todos", - "role.empty": "Não há usuários com este papel", - "role.description.placeholder": "Sem descrição", - "role.nobody.description": "Este é um papel atribuído por padrão, sem nenhuma permissão", - "role.nobody.title": "Ninguém", - - "save": "Salvar", - "search": "Buscar", - "search.min": "Digite {min} caracteres para fazer uma busca", - "search.all": "Mostrar todos os {count} resultados", - "search.results.none": "Nenhum resultado", - - "section.invalid": "A secção é inválida", - "section.required": "Esta seção é obrigatória", - - "security": "Segurança", - "select": "Selecionar", - "server": "Servidor", - "settings": "Configurações", - "show": "Mostrar", - "site.blueprint": "Este site não tem planta. Você pode definir sua planta em /site/blueprints/site.yml", - "size": "Tamanho", - "slug": "Anexo de URL", - "sort": "Ordenar", - "sort.drag": "Arraste para ordenar ...", - "split": "Dividir", - - "stats.empty": "Nenhum relatório", - "status": "Estado", - - "system.info.copy": "Copy info", - "system.info.copied": "System info copied", - "system.issues.content": "A pasta \"content\" parece não estar protegida", - "system.issues.eol.kirby": "A versão instalada do Kirby chegou ao fim da sua vida útil e não irá receber mais atualizações de segurança", - "system.issues.eol.plugin": "A versão instalada do plugin {plugin} chegou ao fim da sua vida útil e não irá receber mais atualizações de segurança", - "system.issues.eol.php": "A versão instalada {release} de PHP chegou ao fim da sua vida útil e não irá receber mais atualizações de segurança", - "system.issues.debug": "O modo debug deve ser desativado em produção", - "system.issues.git": "A pasta \".git\" parece não estar protegida", - "system.issues.https": "Nós recomendamos HTTPS para todos os seus sites", - "system.issues.kirby": "A pasta \"kirby\" parece não estar protegida", - "system.issues.site": "A pasta \"site\" parece não estar protegida", - "system.issues.vulnerability.kirby": "A sua instalação poderá ser afetada pela seguinte vulnerabilidade ({ severity } gravidade): { description }", - "system.issues.vulnerability.plugin": "A sua instalação poderá ser afetada pela seguinte vulnerabilidade no plugin { plugin } ({ severity } gravidade): { description }", - "system.updateStatus": "Atualizar estado", - "system.updateStatus.error": "Não foi possível verificar se havia atualizações", - "system.updateStatus.not-vulnerable": "Nenhuma vulnerabilidade conhecida", - "system.updateStatus.security-update": "Atualização de segurança gratuita { version } disponível", - "system.updateStatus.security-upgrade": "Atualização { version } com correções de segurança disponível", - "system.updateStatus.unreleased": "Versão não lançada", - "system.updateStatus.up-to-date": "Atualizado", - "system.updateStatus.update": "Atualização gratuita { version } disponível", - "system.updateStatus.upgrade": "Atualização { version } disponível", - - "tel": "Telefone", - "tel.placeholder": "+351 123456789", - "template": "Tema", - "title": "Título", - "today": "Hoje", - - "toolbar.button.clear": "Limpar formatação", - "toolbar.button.code": "Código", - "toolbar.button.bold": "Negrito", - "toolbar.button.email": "Email", - "toolbar.button.headings": "Títulos", - "toolbar.button.heading.1": "Título 1", - "toolbar.button.heading.2": "Título 2", - "toolbar.button.heading.3": "Título 3", - "toolbar.button.heading.4": "Título 4", - "toolbar.button.heading.5": "Título 5", - "toolbar.button.heading.6": "Título 6", - "toolbar.button.italic": "Itálico", - "toolbar.button.file": "Arquivo", - "toolbar.button.file.select": "Selecionar arquivo", - "toolbar.button.file.upload": "Carregar arquivo", - "toolbar.button.link": "Link", - "toolbar.button.paragraph": "Parágrafo", - "toolbar.button.strike": "Riscado", - "toolbar.button.sub": "Subscrito", - "toolbar.button.sup": "Sobrescrito", - "toolbar.button.ol": "Lista ordenada", - "toolbar.button.underline": "Sublinhado", - "toolbar.button.ul": "Lista não-ordenada", - - "translation.author": "Time Kirby", - "translation.direction": "ltr", - "translation.name": "Português do Brasil", - "translation.locale": "pt_BR", - - "type": "Tipo", - - "upload": "Enviar", - "upload.error.cantMove": "O arquivo carregado não pôde ser movido", - "upload.error.cantWrite": "Falha ao escrever o arquivo no disco", - "upload.error.default": "O arquivo não pode ser carregado", - "upload.error.extension": "O carregamento do arquivo foi interrompido por causa da extensão", - "upload.error.formSize": "O arquivo carregado excede a diretiva de MAX_FILE_SIZE especificada no formulário", - "upload.error.iniPostSize": "O arquivo carregado excede a diretiva post_max_size do php.ini", - "upload.error.iniSize": "O arquivo carregado excede a diretiva upload_max_size do php.ini", - "upload.error.noFile": "Nenhum arquivo foi carregado", - "upload.error.noFiles": "Nenhum arquivo foi carregado", - "upload.error.partial": "O arquivo foi só parcialmente carregado", - "upload.error.tmpDir": "Falta uma pasta temporária", - "upload.errors": "Erro", - "upload.progress": "Enviando…", - - "url": "Url", - "url.placeholder": "https://example.com", - - "user": "Usuário", - "user.blueprint": "Você pode definir seções e campos de formulário adicionais para este papel de usuário em /site/blueprints/users/{blueprint}.yml", - "user.changeEmail": "Alterar email", - "user.changeLanguage": "Alterar idioma", - "user.changeName": "Renomear usuário", - "user.changePassword": "Alterar senha", - "user.changePassword.new": "Nova senha", - "user.changePassword.new.confirm": "Confirme a nova senha…", - "user.changeRole": "Alterar papel", - "user.changeRole.select": "Selecione um novo papel", - "user.create": "Adicionar novo usuário", - "user.delete": "Deletar este usuário", - "user.delete.confirm": "Deseja realmente deletar
{email}?", - - "users": "Usuários", - - "version": "Vers\u00e3o do Kirby", - "version.current": "Versão atual", - "version.latest": "Versão mais recente", - "versionInformation": "Informação da versão", - - "view.account": "Sua conta", - "view.installation": "Instala\u00e7\u00e3o", - "view.languages": "Idiomas", - "view.resetPassword": "Redefinir senha", - "view.site": "Site", - "view.system": "Sistema", - "view.users": "Usu\u00e1rios", - - "welcome": "Bem-vindo", - "year": "Ano", - "yes": "sim" + "account.changeName": "Mudar seu nome", + "account.delete": "Deletar sua conta", + "account.delete.confirm": "Deseja realmente deletar sua conta? Você sairá do site imediatamente. Sua conta não poderá ser recuperada. ", + + "add": "Adicionar", + "author": "Autor", + "avatar": "Foto do perfil", + "back": "Voltar", + "cancel": "Cancelar", + "change": "Alterar", + "close": "Fechar", + "confirm": "Salvar", + "collapse": "Colapsar", + "collapse.all": "Colapsar todos", + "copy": "Copiar", + "copy.all": "Copiar todos", + "create": "Criar", + + "date": "Data", + "date.select": "Selecione uma data", + + "day": "Dia", + "days.fri": "Sex", + "days.mon": "Seg", + "days.sat": "S\u00e1b", + "days.sun": "Dom", + "days.thu": "Qui", + "days.tue": "Ter", + "days.wed": "Qua", + + "debugging": "Depuração ", + + "delete": "Deletar", + "delete.all": "Deletar todos", + + "dialog.files.empty": "Nenhum arquivo para selecionar", + "dialog.pages.empty": "Nenhuma página para selecionar", + "dialog.users.empty": "Nenhum usuário para selecionar", + + "dimensions": "Dimensões", + "disabled": "Desativado", + "discard": "Descartar", + "download": "Baixar", + "duplicate": "Duplicar", + + "edit": "Editar", + + "email": "Email", + "email.placeholder": "mail@exemplo.com", + + "entries": "Entries", + "entry": "Entry", + + "environment": "Ambiente", + + "error.access.code": "Código inválido", + "error.access.login": "Código de acesso inválido", + "error.access.panel": "Você não tem permissão para acessar o painel", + "error.access.view": "Você não tem permissão para acessar esta parte do painel", + + "error.avatar.create.fail": "A foto de perfil não pôde ser enviada", + "error.avatar.delete.fail": "A foto de perfil não pôde ser deletada", + "error.avatar.dimensions.invalid": "Por favor, use uma foto de perfil com largura e altura menores que 3000 pixels", + "error.avatar.mime.forbidden": "A foto de perfil deve ser um arquivo JPEG ou PNG", + + "error.blueprint.notFound": "A planta \"{name}\" não pôde ser carregada", + + "error.blocks.max.plural": "Você não deve adicionar mais do que {max} blocos", + "error.blocks.max.singular": "Você não deve adicionar mais do que um bloco", + "error.blocks.min.plural": "Você deve adicionar pelo menos {min} blocos", + "error.blocks.min.singular": "Você deve adicionar pelo menos um bloco", + "error.blocks.validation": "Há um erro no bloco {index}", + + "error.email.preset.notFound": "Pré-configuração de email \"{name}\" não foi encontrada", + + "error.field.converter.invalid": "Conversor \"{converter}\" inválido", + + "error.file.changeName.empty": "O nome não deve ficar em branco", + "error.file.changeName.permission": "Você não tem permissão para alterar o nome de \"{filename}\"", + "error.file.duplicate": "Um arquivo com o nome \"{filename}\" já existe", + "error.file.extension.forbidden": "Extensão \"{extension}\" não permitida", + "error.file.extension.invalid": "Extensão inválida: {extension}", + "error.file.extension.missing": "Extensão de \"{filename}\" em falta", + "error.file.maxheight": "A altura da imagem não pode exceder {height} pixels", + "error.file.maxsize": "O arquivo é grande demais", + "error.file.maxwidth": "A largura da imagem não pode exceder {width} pixels", + "error.file.mime.differs": "O arquivo enviado precisa ser do tipo \"{mime}\"", + "error.file.mime.forbidden": "Tipo de mídia \"{mime}\" não permitido", + "error.file.mime.invalid": "Tipo mime inválido: {mime}", + "error.file.mime.missing": "Tipo de mídia de \"{filename}\" não detectado", + "error.file.minheight": "A altura da imagem deve ser pelo menos {height} pixels", + "error.file.minsize": "O arquivo é pequeno demais", + "error.file.minwidth": "A largura da imagem deve ser pelo menos {width} pixels", + "error.file.name.missing": "O nome do arquivo não pode ficar em branco", + "error.file.notFound": "Arquivo \"{filename}\" não encontrado", + "error.file.orientation": "A orientação da imagem deve ser “{orientation}”", + "error.file.type.forbidden": "Você não tem permissão para enviar arquivos {type}", + "error.file.type.invalid": "Tipo inválido de arquivo: {type}", + "error.file.undefined": "Arquivo n\u00e3o encontrado", + + "error.form.incomplete": "Por favor, corrija os erros do formulário…", + "error.form.notSaved": "O formulário não pôde ser salvo", + + "error.language.code": "Por favor entre um código válido para o idioma", + "error.language.duplicate": "O idioma já existe", + "error.language.name": "Por favor entre um nome válido para o idioma", + "error.language.notFound": "O idioma não foi encontrado", + + "error.layout.validation.block": "Há um erro no bloco {blockIndex} no layout {layoutIndex}", + "error.layout.validation.settings": "Há um erro na configuração do layout {index}", + + "error.license.format": "Por favor entre uma chave de licensa válida ", + "error.license.email": "Digite um endereço de email válido", + "error.license.verification": "A licensa não pôde ser verificada", + + "error.offline": "O painel está offline no momento", + + "error.page.changeSlug.permission": "Você não tem permissão para alterar o anexo de URL de \"{slug}\"", + "error.page.changeStatus.incomplete": "A página possui erros e não pode ser salva", + "error.page.changeStatus.permission": "O estado desta página não pode ser alterado", + "error.page.changeStatus.toDraft.invalid": "A página \"{slug}\" não pode ser convertida para rascunho", + "error.page.changeTemplate.invalid": "O tema da página \"{slug}\" não pode ser alterado", + "error.page.changeTemplate.permission": "Você não tem permissão para alterar o tema de \"{slug}\"", + "error.page.changeTitle.empty": "O título não pode ficar em branco", + "error.page.changeTitle.permission": "Você não tem permissão para alterar o título de \"{slug}\"", + "error.page.create.permission": "Você não tem permissão para criar \"{slug}\"", + "error.page.delete": "A página \"{slug}\" não pode ser deletada", + "error.page.delete.confirm": "Por favor, digite o título da página para confirmar", + "error.page.delete.hasChildren": "A página possui subpáginas e não pode ser deletada", + "error.page.delete.permission": "Você não tem permissão para deletar \"{slug}\"", + "error.page.draft.duplicate": "Uma página rascunho com um anexo de URL \"{slug}\" já existe", + "error.page.duplicate": "Uma página com o anexo de URL \"{slug}\" já existe", + "error.page.duplicate.permission": "Você não tem permissão para duplicar “{slug}”", + "error.page.notFound": "Página \"{slug}\" não encontrada", + "error.page.num.invalid": "Digite um número de ordenação válido. Este número não pode ser negativo.", + "error.page.slug.invalid": "Por favor entre um anexo de URL válido ", + "error.page.slug.maxlength": "O slug deve ter menos de “{length}” caracteres", + "error.page.sort.permission": "A página \"{slug}\" não pode ser ordenada", + "error.page.status.invalid": "Por favor, defina um estado de página válido", + "error.page.undefined": "P\u00e1gina n\u00e3o encontrada", + "error.page.update.permission": "Você não tem permissão para atualizar \"{slug}\"", + + "error.section.files.max.plural": "Você não pode adicionar mais do que {max} arquivos à seção \"{section}\"", + "error.section.files.max.singular": "Você não pode adicionar mais do que um arquivo à seção \"{section}\"", + "error.section.files.min.plural": "A seção “{section}” precisa ter pelo menos {min} arquivos", + "error.section.files.min.singular": "A seção “{section}” precisa ter pelo menos um arquivo", + + "error.section.pages.max.plural": "Você não pode adicionar mais do que {max} páginas à seção \"{section}\"", + "error.section.pages.max.singular": "Você não pode adicionar mais do que uma página à seção \"{section}\"", + "error.section.pages.min.plural": "A seção “{section}” precisa ter pelo menos {min} páginas ", + "error.section.pages.min.singular": "A seção “{section}” precisa ter pelo menos uma página ", + + "error.section.notLoaded": "A seção \"{name}\" não pôde ser carregada", + "error.section.type.invalid": "O tipo da seção \"{type}\" não é válido", + + "error.site.changeTitle.empty": "O título não pode ficar em branco", + "error.site.changeTitle.permission": "Você não tem permissão para alterar o título do site", + "error.site.update.permission": "Você não tem permissão para atualizar o site", + + "error.template.default.notFound": "O tema padrão não existe", + + "error.unexpected": "An unexpected error occurred! Enable debug mode for more info: https://getkirby.com/docs/reference/system/options/debug", + + "error.user.changeEmail.permission": "Você não tem permissão para alterar o email do usuário \"{name}\"", + "error.user.changeLanguage.permission": "Você não tem permissão para alterar o idioma do usuário \"{name}\"", + "error.user.changeName.permission": "Você não tem permissão para alterar o nome do usuário \"{name}\"", + "error.user.changePassword.permission": "Você não tem permissão para alterar a senha do usuário \"{name}\"", + "error.user.changeRole.lastAdmin": "O papel do último administrador não pode ser alterado", + "error.user.changeRole.permission": "Você não tem permissão para alterar o papel do usuário \"{name}\"", + "error.user.changeRole.toAdmin": "Você não tem permissão para promover usuários ao papel de administrador ", + "error.user.create.permission": "Você não tem permissão para criar este usuário", + "error.user.delete": "O usuário \"{name}\" não pode ser deletado", + "error.user.delete.lastAdmin": "O último administrador não pode ser deletado", + "error.user.delete.lastUser": "O último usuário não pode ser deletado", + "error.user.delete.permission": "Você não tem permissão para deletar o usuário \"{name}\"", + "error.user.duplicate": "Um usuário com o email \"{email}\" já existe", + "error.user.email.invalid": "Digite um endereço de email válido", + "error.user.language.invalid": "Digite um idioma válido", + "error.user.notFound": "Usuário \"{name}\" não encontrado", + "error.user.password.excessive": "Please enter a valid password. Passwords must not be longer than 1000 characters.", + "error.user.password.invalid": "Digite uma senha válida. Sua senha deve ter pelo menos 8 caracteres.", + "error.user.password.notSame": "As senhas não combinam", + "error.user.password.undefined": "O usuário não possui uma senha", + "error.user.password.wrong": "Senha errada", + "error.user.role.invalid": "Digite um papel válido", + "error.user.undefined": "Usuário não encontrado", + "error.user.update.permission": "Você não tem permissão para atualizar o usuário \"{name}\"", + + "error.validation.accepted": "Por favor, confirme", + "error.validation.alpha": "Por favor, use apenas caracteres entre a-z", + "error.validation.alphanum": "Por favor, use apenas caracteres entre a-z ou 0-9", + "error.validation.between": "Digite um valor entre \"{min}\" e \"{max}\"", + "error.validation.boolean": "Por favor, confirme ou rejeite", + "error.validation.contains": "Digite um valor que contenha \"{needle}\"", + "error.validation.date": "Escolha uma data válida", + "error.validation.date.after": "Por favor entre uma data depois de {date}", + "error.validation.date.before": "Por favor entre uma data antes de {date}", + "error.validation.date.between": "Por favor entre uma data entre {min} e {max}", + "error.validation.denied": "Por favor, cancele", + "error.validation.different": "O valor deve ser diferente de \"{other}\"", + "error.validation.email": "Digite um endereço de email válido", + "error.validation.endswith": "O valor deve terminar com \"{end}\"", + "error.validation.filename": "Digite um nome de arquivo válido", + "error.validation.in": "Digite um destes valores: ({in})", + "error.validation.integer": "Digite um número inteiro válido", + "error.validation.ip": "Digite um endereço de IP válido", + "error.validation.less": "Digite um valor menor que {max}", + "error.validation.match": "O valor não combina com o padrão esperado", + "error.validation.max": "Digite um valor igual ou menor que {max}", + "error.validation.maxlength": "Digite um valor curto. (no máximo {max} caracteres)", + "error.validation.maxwords": "Digite menos que {max} palavra(s)", + "error.validation.min": "Digite um valor igual ou maior que {min}", + "error.validation.minlength": "Digite um valor maior. (no mínimo {min} caracteres)", + "error.validation.minwords": "Digite ao menos {min} palavra(s)", + "error.validation.more": "Digite um valor maior que {min}", + "error.validation.notcontains": "Digite um valor que não contenha \"{needle}\"", + "error.validation.notin": "Não digite nenhum destes valores: ({notIn})", + "error.validation.option": "Escolha uma opção válida", + "error.validation.num": "Digite um número válido", + "error.validation.required": "Digite algo", + "error.validation.same": "Por favor, digite \"{other}\"", + "error.validation.size": "O tamanho do valor deve ser \"{size}\"", + "error.validation.startswith": "O valor deve começar com \"{start}\"", + "error.validation.time": "Digite um horário válido", + "error.validation.time.after": "Por favor entre um horário depois de {time}", + "error.validation.time.before": "Por favor entre um horário antes de {time}", + "error.validation.time.between": "Por favor entre um horário entre {min} e {max}", + "error.validation.url": "Digite uma URL válida", + + "expand": "Expandir", + "expand.all": "Expandir todos", + + "field.required": "Este campo é obrigatório ", + "field.blocks.changeType": "Mudar tipo", + "field.blocks.code.name": "Código", + "field.blocks.code.language": "Idioma", + "field.blocks.code.placeholder": "Seu código …", + "field.blocks.delete.confirm": "Deseja realmente deletar este bloco?", + "field.blocks.delete.confirm.all": "Deseja realmente deletar todos os blocos?", + "field.blocks.delete.confirm.selected": "Deseja realmente deletar os blocos selecionados?", + "field.blocks.empty": "Nenhum bloco", + "field.blocks.fieldsets.label": "Por favor selecione um tipo de bloco …", + "field.blocks.fieldsets.paste": "Digite {{ shortcut }} para colar/importar blocos da sua área de transferência ", + "field.blocks.gallery.name": "Galeria", + "field.blocks.gallery.images.empty": "Nenhuma imagem", + "field.blocks.gallery.images.label": "Imagens", + "field.blocks.heading.level": "Nível ", + "field.blocks.heading.name": "Título ", + "field.blocks.heading.text": "Texto", + "field.blocks.heading.placeholder": "Título …", + "field.blocks.image.alt": "Texto alternativo", + "field.blocks.image.caption": "Legenda", + "field.blocks.image.crop": "Cortar", + "field.blocks.image.link": "Link", + "field.blocks.image.location": "Localização ", + "field.blocks.image.name": "Imagem", + "field.blocks.image.placeholder": "Selecionar uma imagem", + "field.blocks.image.ratio": "Proporção ", + "field.blocks.image.url": "URL da imagem", + "field.blocks.line.name": "Linha", + "field.blocks.list.name": "Lista", + "field.blocks.markdown.name": "Markdown", + "field.blocks.markdown.label": "Texto", + "field.blocks.markdown.placeholder": "Markdown …", + "field.blocks.quote.name": "Citação ", + "field.blocks.quote.text.label": "Texto", + "field.blocks.quote.text.placeholder": "Citação …", + "field.blocks.quote.citation.label": "Citação ", + "field.blocks.quote.citation.placeholder": "de …", + "field.blocks.text.name": "Texto", + "field.blocks.text.placeholder": "Texto …", + "field.blocks.video.caption": "Legenda", + "field.blocks.video.name": "Vídeo ", + "field.blocks.video.placeholder": "Entre uma URL de vídeo ", + "field.blocks.video.url.label": "URL-Vídeo", + "field.blocks.video.url.placeholder": "https://youtube.com/?v=", + + "field.files.empty": "Nenhum arquivo selecionado", + + "field.layout.delete": "Deletar layout", + "field.layout.delete.confirm": "Deseja realmente deletar este layout?", + "field.layout.empty": "Nenhuma linha", + "field.layout.select": "Selecionar um layout", + + "field.pages.empty": "Nenhuma página selecionada", + "field.structure.delete.confirm": "Deseja realmente deletar esta linha?", + "field.structure.empty": "Nenhum registro", + "field.users.empty": "Nenhum usuário selecionado", + + "file.blueprint": "Este arquivo não tem planta. Você pode definir sua planta em /site/blueprints/files/{blueprint}.yml", + "file.delete.confirm": "Deseja realmente deletar
{filename}?", + "file.sort": "Mudar posição", + + "files": "Arquivos", + "files.empty": "Nenhum arquivo", + + "hide": "Ocultar", + "hour": "Hora", + "import": "Importar", + "info": "Info", + "insert": "Inserir", + "insert.after": "Inserir após", + "insert.before": "Inserir antes", + "install": "Instalar", + + "installation": "Instalação", + "installation.completed": "Painel instalado com sucesso", + "installation.disabled": "O instalador do painel está desabilitado em servidores públicos por padrão. Por favor, execute o instalador em uma máquina local ou habilite a opção panel.install.", + "installation.issues.accounts": "A pasta /site/accounts não existe ou não possui permissão de escrita", + "installation.issues.content": "A pasta /content não existe ou não possui permissão de escrita", + "installation.issues.curl": "A extensão CURL é necessária", + "installation.issues.headline": "O painel não pôde ser instalado", + "installation.issues.mbstring": "A extensão MB String é necessária", + "installation.issues.media": "A pasta /media não existe ou não possui permissão de escrita", + "installation.issues.php": "Certifique-se que você está usando o PHP 7+", + "installation.issues.server": "Kirby necessita do Apache, Nginx ou Caddy", + "installation.issues.sessions": "A pasta /site/sessions não existe ou não possui permissão de escrita", + + "language": "Idioma", + "language.code": "Código", + "language.convert": "Tornar padrão", + "language.convert.confirm": "

Deseja realmente converter {name} para o idioma padrão? Esta ação não poderá ser revertida.

Se {name} tiver conteúdo não traduzido, partes do seu site poderão ficar sem conteúdo.

", + "language.create": "Adicionar novo idioma", + "language.delete.confirm": "Deseja realmente deletar o idioma {name} incluíndo todas as traduções. Esta ação não poderá ser revertida!", + "language.deleted": "Idioma deletado", + "language.direction": "Direção de leitura", + "language.direction.ltr": "Esquerda para direita", + "language.direction.rtl": "Direita para esquerda", + "language.locale": "String de localização do PHP", + "language.locale.warning": "Você está usando uma configuração de local customizada. Por favor modifique a configuração no arquivo do idioma em /site/languages", + "language.name": "Nome", + "language.updated": "Idioma atualizado", + + "languages": "Idiomas", + "languages.default": "Idioma padrão", + "languages.empty": "Nenhum idioma", + "languages.secondary": "Idiomas secundários", + "languages.secondary.empty": "Nenhum idioma secundário", + + "license": "Licen\u00e7a do Kirby ", + "license.buy": "Comprar licença", + "license.register": "Registrar", + "license.manage": "Manage your licenses", + "license.register.help": "Você recebeu o código da sua licença por email ao efetuar sua compra. Por favor, copie e cole o código para completar seu registro.", + "license.register.label": "Por favor, digite o código da sua licença", + "license.register.success": "Obrigado por apoiar o Kirby", + "license.unregistered": "Esta é uma cópia de demonstração não registrada do Kirby", + "license.unregistered.label": "Unregistered", + + "link": "Link", + "link.text": "Texto do link", + + "loading": "Carregando", + + "lock.unsaved": "Mudanças não salvas", + "lock.unsaved.empty": "Não há mais mudanças não salvas", + "lock.isLocked": "Mudanças não salvas por {email}", + "lock.file.isLocked": "Este arquivo está sendo editado no momento por {email}, e não pode ser mudado", + "lock.page.isLocked": "Esta página está sendo editada no momento por {email}, e não pode ser mudada", + "lock.unlock": "Destrancar", + "lock.isUnlocked": "Suas mudanças não salvas foram alteradas por outro usuário, e serão perdidas. Você pode baixar um arquivo com suas mudanças, para depois fundi-las manualmente. ", + + "login": "Entrar", + "login.code.label.login": "Código de acesso", + "login.code.label.password-reset": "Código de redefinição de senha", + "login.code.placeholder.email": "000 0000", + "login.code.text.email": "Se seu endereço de email está registrado, o código requisitado será mandado por email.", + "login.email.login.body": "Oi, {user.nameOrEmail},\n\nVocê recentemente pediu um código de acesso ao painel administrativo do site {site}.\nO seguinte código será válido por {timeout} minutos:\n\n{code}\n\nSe você não pediu este código de acesso, por favor ignore esta mensagem, ou contate seu Administrador de Sistemas se você tiver dúvidas.\nPor questões de segurança, por favor NÃO compartilhe esta mensagem.", + "login.email.login.subject": "Seu código de acesso", + "login.email.password-reset.body": "Oi, {user.nameOrEmail},\n\nVocê recentemente pediu um código de redefinição de senha, para o painel administrativo do site {site}.\nO seguinte código de redefinição de senha será válido por {timeout} minutos:\n\n{code}\n\nSe você não pediu este código, por favor ignore esta mensagem, ou contate seu Administrador de Sistemas se você tiver dúvidas.\nPor questões de segurança, por favor NÃO compartilhe esta mensagem.", + "login.email.password-reset.subject": "Seu código de redefinição de senha", + "login.remember": "Manter-me conectado", + "login.reset": "Redefinir senha", + "login.toggleText.code.email": "Entrar com email", + "login.toggleText.code.email-password": "Entrar com senha", + "login.toggleText.password-reset.email": "Esqueceu sua senha?", + "login.toggleText.password-reset.email-password": "← Voltar à entrada", + + "logout": "Sair", + + "menu": "Menu", + "meridiem": "AM/PM", + "mime": "Tipo de mídia", + "minutes": "Minutos", + + "month": "Mês", + "months.april": "Abril", + "months.august": "Agosto", + "months.december": "Dezembro", + "months.february": "Fevereiro", + "months.january": "Janeiro", + "months.july": "Julho", + "months.june": "Junho", + "months.march": "Mar\u00e7o", + "months.may": "Maio", + "months.november": "Novembro", + "months.october": "Outubro", + "months.september": "Setembro", + + "more": "Mais", + "name": "Nome", + "next": "Próximo", + "no": "não", + "off": "não", + "on": "sim", + "open": "Abrir", + "open.newWindow": "Abrir em nova janela", + "options": "Opções", + "options.none": "Nenhuma opção", + + "orientation": "Orientação", + "orientation.landscape": "Paisagem", + "orientation.portrait": "Retrato", + "orientation.square": "Quadrado", + + "page.blueprint": "Esta página não tem planta. Você pode definir sua planta em /site/blueprints/pages/{blueprint}.yml", + "page.changeSlug": "Alterar URL", + "page.changeSlug.fromTitle": "Criar a partir do t\u00edtulo", + "page.changeStatus": "Alterar estado", + "page.changeStatus.position": "Selecione uma posição", + "page.changeStatus.select": "Selecione um novo estado", + "page.changeTemplate": "Alterar tema", + "page.delete.confirm": "Deseja realmente deletar {title}?", + "page.delete.confirm.subpages": "Esta página possui subpáginas.
Todas as subpáginas serão excluídas também.", + "page.delete.confirm.title": "Digite o título da página para confirmar", + "page.draft.create": "Criar rascunho", + "page.duplicate.appendix": "Copiar", + "page.duplicate.files": "Copiar arquivos", + "page.duplicate.pages": "Copiar páginas", + "page.sort": "Mudar posição", + "page.status": "Estado", + "page.status.draft": "Rascunho", + "page.status.draft.description": "A página é um rascunho, e visível somente por editores logados, ou através de um link secreto.", + "page.status.listed": "Pública", + "page.status.listed.description": "A página pública é visível para todos", + "page.status.unlisted": "Não listadas", + "page.status.unlisted.description": "Esta página é acessível somente através da URL", + + "pages": "Páginas", + "pages.empty": "Nenhuma página", + "pages.status.draft": "Rascunhos", + "pages.status.listed": "Publicadas", + "pages.status.unlisted": "Não listadas", + + "pagination.page": "Página", + + "password": "Senha", + "paste": "Colar", + "paste.after": "Colar após", + "pixel": "Pixel", + "plugins": "Plugins", + "prev": "Anterior", + "preview": "Visualizar", + "remove": "Remover", + "rename": "Renomear", + "replace": "Substituir", + "retry": "Tentar novamente", + "revert": "Descartar", + "revert.confirm": "Deseja realmente deletar todas as mudanças não salvas?", + + "role": "Papel", + "role.admin.description": "O administrador tem todos os direitos", + "role.admin.title": "Administrador", + "role.all": "Todos", + "role.empty": "Não há usuários com este papel", + "role.description.placeholder": "Sem descrição", + "role.nobody.description": "Este é um papel atribuído por padrão, sem nenhuma permissão", + "role.nobody.title": "Ninguém", + + "save": "Salvar", + "search": "Buscar", + "search.min": "Digite {min} caracteres para fazer uma busca", + "search.all": "Mostrar todos", + "search.results.none": "Nenhum resultado", + + "section.required": "Esta seção é obrigatória", + + "security": "Security", + "select": "Selecionar", + "server": "Servidor", + "settings": "Configurações", + "show": "Mostrar", + "site.blueprint": "Este site não tem planta. Você pode definir sua planta em /site/blueprints/site.yml", + "size": "Tamanho", + "slug": "Anexo de URL", + "sort": "Ordenar", + + "stats.empty": "No reports", + "system.issues.content": "The content folder seems to be exposed", + "system.issues.debug": "Debugging must be turned off in production", + "system.issues.git": "The .git folder seems to be exposed", + "system.issues.https": "We recommend HTTPS for all your sites", + "system.issues.kirby": "The kirby folder seems to be exposed", + "system.issues.site": "The site folder seems to be exposed", + + "title": "Título", + "template": "Tema", + "today": "Hoje", + + "toolbar.button.code": "Código", + "toolbar.button.bold": "Negrito", + "toolbar.button.email": "Email", + "toolbar.button.headings": "Títulos", + "toolbar.button.heading.1": "Título 1", + "toolbar.button.heading.2": "Título 2", + "toolbar.button.heading.3": "Título 3", + "toolbar.button.heading.4": "Título 4", + "toolbar.button.heading.5": "Título 5", + "toolbar.button.heading.6": "Título 6", + "toolbar.button.italic": "Itálico", + "toolbar.button.file": "Arquivo", + "toolbar.button.file.select": "Selecionar arquivo", + "toolbar.button.file.upload": "Carregar arquivo", + "toolbar.button.link": "Link", + "toolbar.button.paragraph": "Parágrafo", + "toolbar.button.strike": "Riscado", + "toolbar.button.ol": "Lista ordenada", + "toolbar.button.underline": "Sublinhado", + "toolbar.button.ul": "Lista não-ordenada", + + "translation.author": "Time Kirby", + "translation.direction": "ltr", + "translation.name": "Português do Brasil", + "translation.locale": "pt_BR", + + "upload": "Enviar", + "upload.error.cantMove": "O arquivo carregado não pôde ser movido", + "upload.error.cantWrite": "Falha ao escrever o arquivo no disco", + "upload.error.default": "O arquivo não pode ser carregado", + "upload.error.extension": "O carregamento do arquivo foi interrompido por causa da extensão", + "upload.error.formSize": "O arquivo carregado excede a diretiva de MAX_FILE_SIZE especificada no formulário", + "upload.error.iniPostSize": "O arquivo carregado excede a diretiva post_max_size do php.ini", + "upload.error.iniSize": "O arquivo carregado excede a diretiva upload_max_size do php.ini", + "upload.error.noFile": "Nenhum arquivo foi carregado", + "upload.error.noFiles": "Nenhum arquivo foi carregado", + "upload.error.partial": "O arquivo foi só parcialmente carregado", + "upload.error.tmpDir": "Falta uma pasta temporária", + "upload.errors": "Erro", + "upload.progress": "Enviando…", + + "url": "Url", + "url.placeholder": "https://example.com", + + "user": "Usuário", + "user.blueprint": "Você pode definir seções e campos de formulário adicionais para este papel de usuário em /site/blueprints/users/{blueprint}.yml", + "user.changeEmail": "Alterar email", + "user.changeLanguage": "Alterar idioma", + "user.changeName": "Renomear usuário", + "user.changePassword": "Alterar senha", + "user.changePassword.new": "Nova senha", + "user.changePassword.new.confirm": "Confirme a nova senha…", + "user.changeRole": "Alterar papel", + "user.changeRole.select": "Selecione um novo papel", + "user.create": "Adicionar novo usuário", + "user.delete": "Deletar este usuário", + "user.delete.confirm": "Deseja realmente deletar
{email}?", + + "users": "Usuários", + + "version": "Vers\u00e3o do Kirby", + + "view.account": "Sua conta", + "view.installation": "Instala\u00e7\u00e3o", + "view.languages": "Idiomas", + "view.resetPassword": "Redefinir senha", + "view.site": "Site", + "view.system": "Sistema", + "view.users": "Usu\u00e1rios", + + "welcome": "Bem-vindo", + "year": "Ano", + "yes": "sim" } diff --git a/kirby/i18n/translations/pt_PT.json b/kirby/i18n/translations/pt_PT.json index 437e127..dadf3ef 100644 --- a/kirby/i18n/translations/pt_PT.json +++ b/kirby/i18n/translations/pt_PT.json @@ -1,730 +1,574 @@ { - "account.changeName": "Altere o seu nome", - "account.delete": "Elimine a sua conta", - "account.delete.confirm": "Tem a certeza que pretende eliminar a sua conta? A sessão será terminada imediatamente. A sua conta não poderá ser recuperada. ", - - "activate": "Ativar", - "add": "Adicionar", - "alpha": "Alpha", - "author": "Autor", - "avatar": "Foto de perfil", - "back": "Voltar", - "cancel": "Cancelar", - "change": "Alterar", - "close": "Fechar", - "changes": "Alterações", - "confirm": "Ok", - "collapse": "Colapsar", - "collapse.all": "Colapsar todos", - "color": "Cor", - "coordinates": "Coordenadas", - "copy": "Copiar", - "copy.all": "Copiar todos", - "copy.success": "{count} copiados!", - "create": "Criar", - "custom": "Personalizado", - - "date": "Data", - "date.select": "Selecione uma data", - - "day": "Dia", - "days.fri": "Sex", - "days.mon": "Seg", - "days.sat": "S\u00e1b", - "days.sun": "Dom", - "days.thu": "Qui", - "days.tue": "Ter", - "days.wed": "Qua", - - "debugging": "Depuração ", - - "delete": "Eliminar", - "delete.all": "Eliminar todos", - - "dialog.fields.empty": "Esta caixa de diálogo não tem campos", - "dialog.files.empty": "Sem ficheiros para selecionar", - "dialog.pages.empty": "Sem páginas para selecionar", - "dialog.text.empty": "Esta caixa de diálogo não define nenhum texto", - "dialog.users.empty": "Sem utilizadores para selecionar", - - "dimensions": "Dimensões", - "disable": "Desativar", - "disabled": "Desativado", - "discard": "Descartar", - - "drawer.fields.empty": "Esta janela não tem campos", - - "domain": "Domínio", - "download": "Descarregar", - "duplicate": "Duplicar", - - "edit": "Editar", - - "email": "Email", - "email.placeholder": "mail@exemplo.pt", - - "enter": "Insira", - "entries": "Registos", - "entry": "Registo", - - "environment": "Ambiente", - - "error": "Erro", - "error.access.code": "Código inválido", - "error.access.login": "Dados de acesso inválidos", - "error.access.panel": "Não tem permissões para aceder ao painel", - "error.access.view": "Não tem permissões para aceder a esta área do painel", - - "error.avatar.create.fail": "Não foi possível enviar a foto de perfil", - "error.avatar.delete.fail": "Não foi possível eliminar a foto de perfil", - "error.avatar.dimensions.invalid": "Por favor, use uma foto de perfil com largura e altura menores que 3000 pixels", - "error.avatar.mime.forbidden": "A foto de perfil deve ser um ficheiro JPEG ou PNG", - - "error.blueprint.notFound": "Não foi possível carregar o blueprint \"{name}\"", - - "error.blocks.max.plural": "Não pode adicionar mais do que {max} blocos", - "error.blocks.max.singular": "Não pode adicionar mais do que um bloco", - "error.blocks.min.plural": "Tem de adicionar pelo menos {min} blocos", - "error.blocks.min.singular": "Tem de adicionar pelo menos um bloco", - "error.blocks.validation": "Há um erro no campo \"{field}\" no bloco {index} a usar o tipo de bloco \"{fieldset}\"", - - "error.cache.type.invalid": "Tipo de cache \"{type}\" inválido", - - "error.email.preset.notFound": "A predefinição de email \"{name}\" não foi encontrada", - - "error.field.converter.invalid": "Conversor \"{converter}\" inválido", - "error.field.type.missing": "Campo \"{name}\": O tipo de campo \"{type}\" não existe", - - "error.file.changeName.empty": "O nome não pode ficar em branco", - "error.file.changeName.permission": "Não tem permissões para alterar o nome de \"{filename}\"", - "error.file.changeTemplate.invalid": "O template para o ficheiro \"{id}\" não pode ser alterado para \"{template}\" (válido: \"{blueprints}\")", - "error.file.changeTemplate.permission": "Não tem permissão para alterar o template do ficheiro \"{id}\"", - - "error.file.duplicate": "Um ficheiro com o nome \"{filename}\" já existe", - "error.file.extension.forbidden": "A extensão \"{extension}\" não é permitida", - "error.file.extension.invalid": "Extensão inválida: {extension}", - "error.file.extension.missing": "As extensões de \"{filename}\" estão em falta", - "error.file.maxheight": "A altura da imagem não deve exceder {height} pixels", - "error.file.maxsize": "O ficheiro é demasiado grande", - "error.file.maxwidth": "A largura da imagem não deve exceder {width} pixels", - "error.file.mime.differs": "O ficheiro enviado precisa de ser do tipo \"{mime}\"", - "error.file.mime.forbidden": "O tipo de mídia \"{mime}\" não é permitido", - "error.file.mime.invalid": "Tipo de mídia inválido: {mime}", - "error.file.mime.missing": "Não foi possível detectar o tipo de mídia de \"{filename}\"", - "error.file.minheight": "A altura da imagem deve ter pelo menos {height} pixels", - "error.file.minsize": "O ficheiro é demasiado pequeno", - "error.file.minwidth": "A largura da imagem deve ter pelo menos {width} pixels", - "error.file.name.unique": "O nome do ficheiro deve ser único", - "error.file.name.missing": "O nome do ficheiro não pode ficar em branco", - "error.file.notFound": "Não foi possível encontrar o ficheiro \"{filename}\"", - "error.file.orientation": "A orientação da imagem deve ser \"{orientation}\"", - "error.file.type.forbidden": "Não tem permissões para enviar ficheiros {type}", - "error.file.type.invalid": "Tipo de ficheiro inválido: {type}", - "error.file.undefined": "Não foi possível encontrar o ficheiro", - - "error.form.incomplete": "Por favor, corrija todos os erros do formulário…", - "error.form.notSaved": "Não foi possível guardar o formulário", - - "error.language.code": "Por favor, insira um código válido para o idioma", - "error.language.duplicate": "O idioma já existe", - "error.language.name": "Por favor, insira um nome válido para o idioma", - "error.language.notFound": "Não foi possível encontrar o idioma", - - "error.layout.validation.block": "Há um erro no campo \"{field}\" no bloco {blockIndex} a usar o tipo de bloco \"{fieldset}\" no layout {layoutIndex}", - "error.layout.validation.settings": "Há um erro na configuração do layout {index}", - - "error.license.domain": "O domínio da licença está em falta", - "error.license.email": "Por favor, insira um endereço de email válido", - "error.license.format": "Por favor, insira um código de licença válido", - "error.license.verification": "Não foi possível verificar a licença", - - "error.login.totp.confirm.invalid": "Código inválido", - "error.login.totp.confirm.missing": "Por favor, insira o código atual", - - "error.object.validation": "Há um erro no campo \"{label}\":\n{message}", - - "error.offline": "O painel encontra-se offline de momento", - - "error.page.changeSlug.permission": "Não tem permissões para alterar o URL de \"{slug}\"", - "error.page.changeSlug.reserved": "O caminho das páginas de nível superior não deve começar com \"{path}\"", - "error.page.changeStatus.incomplete": "A página tem erros e não pode ser publicada", - "error.page.changeStatus.permission": "O estado desta página não pode ser alterado", - "error.page.changeStatus.toDraft.invalid": "A página \"{slug}\" não pode ser convertida para rascunho", - "error.page.changeTemplate.invalid": "O template da página \"{slug}\" não pode ser alterado", - "error.page.changeTemplate.permission": "Não tem permissões para alterar o template de \"{slug}\"", - "error.page.changeTitle.empty": "O título não pode ficar em branco", - "error.page.changeTitle.permission": "Não tem permissões para alterar o título de \"{slug}\"", - "error.page.create.permission": "Não tem permissões para criar \"{slug}\"", - "error.page.delete": "A página \"{slug}\" não pode ser eliminada", - "error.page.delete.confirm": "Por favor, insira o título da página para confirmar", - "error.page.delete.hasChildren": "A página tem subpáginas e não pode ser eliminada", - "error.page.delete.permission": "Não tem permissões para eliminar \"{slug}\"", - "error.page.draft.duplicate": "Uma página de rascunho com o URL \"{slug}\" já existe", - "error.page.duplicate": "Uma página com o URL \"{slug}\" já existe", - "error.page.duplicate.permission": "Não tem permissões para duplicar \"{slug}\"", - "error.page.move.ancestor": "A página não pode ser movida para dentro dela mesma", - "error.page.move.directory": "A pasta da página não pode ser movida", - "error.page.move.duplicate": "Já existe uma subpágina com o URL \"{slug}\"", - "error.page.move.notFound": "A página movida não foi encontrada", - "error.page.move.permission": "Não tem permissões para mover \"{slug}\"", - "error.page.move.template": "O template \"{template}\" não é aceite como subpágina de \"{parent}\"", - "error.page.notFound": "Não foi possível encontrar a página \"{slug}\"", - "error.page.num.invalid": "Por favor, insira um número de ordenação válido. Este número não pode ser negativo.", - "error.page.slug.invalid": "Por favor, insira um caminho de URL válido ", - "error.page.slug.maxlength": "O URL não pode conter mais do que \"{length}\" caracteres", - "error.page.sort.permission": "Não é possível ordenar a página \"{slug}\"", - "error.page.status.invalid": "Por favor, defina um estado de página válido", - "error.page.undefined": "Não foi possível encontrar a página", - "error.page.update.permission": "Não tem permissões para atualizar \"{slug}\"", - - "error.section.files.max.plural": "Não pode adicionar mais do que {max} ficheiros à secção \"{section}\"", - "error.section.files.max.singular": "Não pode adicionar mais do que um ficheiro à secção \"{section}\"", - "error.section.files.min.plural": "A secção \"{section}\" requer no mínimo {min} ficheiros", - "error.section.files.min.singular": "A secção \"{section}\" requer no mínimo um ficheiro", - - "error.section.pages.max.plural": "Não pode adicionar mais do que {max} páginas à secção \"{section}\"", - "error.section.pages.max.singular": "Não pode adicionar mais do que uma página à secção \"{section}\"", - "error.section.pages.min.plural": "A secção \"{section}\" requer no mínimo {min} páginas", - "error.section.pages.min.singular": "A secção \"{section}\" requer no mínimo uma página", - - "error.section.notLoaded": "Não foi possível carregar a secção \"{name}\"", - "error.section.type.invalid": "O tipo de secção \"{type}\" não é válido", - - "error.site.changeTitle.empty": "O título não pode ficar em branco", - "error.site.changeTitle.permission": "Não tem permissões para alterar o título do site", - "error.site.update.permission": "Não tem permissões para atualizar o site", - - "error.structure.validation": "Existe um erro no campo \"{field}\" na linha {index}", - - "error.template.default.notFound": "O template \"default\" não existe", - - "error.unexpected": "Ocorreu um erro inesperado! Ative o modo de debug para obter mais informações: https://getkirby.com/docs/reference/system/options/debug", - - "error.user.changeEmail.permission": "Não tem permissões para alterar o email do utilizador \"{name}\"", - "error.user.changeLanguage.permission": "Não tem permissões para alterar o idioma do utilizador \"{name}\"", - "error.user.changeName.permission": "Não tem permissões para alterar o nome do utilizador \"{name}\"", - "error.user.changePassword.permission": "Não tem permissões para alterar a palavra-passe do utilizador \"{name}\"", - "error.user.changeRole.lastAdmin": "A função do último administrador não pode ser alterada", - "error.user.changeRole.permission": "Não tem permissões para alterar a função do utilizador \"{name}\"", - "error.user.changeRole.toAdmin": "Não tem permissões para promover utilizadores à função de administrador", - "error.user.create.permission": "Não tem permissões para criar este utilizador", - "error.user.delete": "Não é possível eliminar o utilizador \"{name}\"", - "error.user.delete.lastAdmin": "Não é possível eliminar o último administrador", - "error.user.delete.lastUser": "Não é possível eliminar o último utilizador", - "error.user.delete.permission": "Não tem permissões para eliminar o utilizador \"{name}\"", - "error.user.duplicate": "Já existe um utilizador com o email \"{email}\"", - "error.user.email.invalid": "Por favor, insira um endereço de email válido", - "error.user.language.invalid": "Por favor, insira um idioma válido", - "error.user.notFound": "Não foi possível encontrar o utilizador \"{name}\"", - "error.user.password.excessive": "Por favor, insira uma palavra-passe válida. As palavras-passe não devem ter mais do que 1000 caracteres.", - "error.user.password.invalid": "Por favor, insira uma palavra-passe válida. As palavras-passe devem ter pelo menos 8 caracteres.", - "error.user.password.notSame": "As palavras-passe não coincidem", - "error.user.password.undefined": "O utilizador não tem uma palavra-passe", - "error.user.password.wrong": "Palavra-passe errada", - "error.user.role.invalid": "Por favor, insira uma função válida", - "error.user.undefined": "Não foi possível encontrar o utilizador", - "error.user.update.permission": "Não tem permissões para atualizar o utilizador \"{name}\"", - - "error.validation.accepted": "Por favor, confirme", - "error.validation.alpha": "Por favor, insira apenas caracteres entre a-z", - "error.validation.alphanum": "Por favor, insira apenas caracteres entre a-z ou 0-9", - "error.validation.anchor": "Por favor, insira uma âncora de link correta", - "error.validation.between": "Por favor, insira um valor entre \"{min}\" e \"{max}\"", - "error.validation.boolean": "Por favor, confirme ou rejeite", - "error.validation.color": "Por favor, insira uma cor válida no formato {format}", - "error.validation.contains": "Por favor, insira um valor que contenha \"{needle}\"", - "error.validation.date": "Por favor, insira uma data válida", - "error.validation.date.after": "Por favor, insira uma data posterior a {date}", - "error.validation.date.before": "Por favor, insira uma data anterior a {date}", - "error.validation.date.between": "Por favor, insira uma data entre {min} e {max}", - "error.validation.denied": "Por favor, rejeite", - "error.validation.different": "O valor tem de ser diferente de \"{other}\"", - "error.validation.email": "Por favor, insira um endereço de email válido", - "error.validation.endswith": "O valor tem de terminar com \"{end}\"", - "error.validation.filename": "Por favor, insira um nome de ficheiro válido", - "error.validation.in": "Por favor, insira um dos seguintes valores: ({in})", - "error.validation.integer": "Por favor, insira um número inteiro válido", - "error.validation.ip": "Por favor, insira um endereço de IP válido", - "error.validation.less": "Por favor, insira um valor menor que {max}", - "error.validation.linkType": "O tipo de link não é permitido", - "error.validation.match": "O valor não corresponde ao padrão esperado", - "error.validation.max": "Por favor, insira um valor igual ou menor que {max}", - "error.validation.maxlength": "Por favor, insira um valor mais curto. (máximo {max} caracteres)", - "error.validation.maxwords": "Por favor, não insira mais que {max} palavra(s)", - "error.validation.min": "Por favor, insira um valor igual ou maior que {min}", - "error.validation.minlength": "Por favor, insira um valor mais longo. (mínimo {min} caracteres)", - "error.validation.minwords": "Por favor, insira pelo menos {min} palavra(s)", - "error.validation.more": "Por favor, insira um valor maior que {min}", - "error.validation.notcontains": "Por favor, insira um valor que não contenha \"{needle}\"", - "error.validation.notin": "Por favor, não insira nenhum destes valores: ({notIn})", - "error.validation.option": "Por favor, selecione uma opção válida", - "error.validation.num": "Por favor, insira um número válido", - "error.validation.required": "Por favor, insira algo", - "error.validation.same": "Por favor, insira \"{other}\"", - "error.validation.size": "O tamanho do valor tem de ser \"{size}\"", - "error.validation.startswith": "O valor tem de começar com \"{start}\"", - "error.validation.tel": "Por favor, insira um número de telefone não formatado", - "error.validation.time": "Por favor, insira uma hora válida", - "error.validation.time.after": "Por favor, insira uma hora posterior a {time}", - "error.validation.time.before": "Por favor, insira uma hora anterior a {time}", - "error.validation.time.between": "Por favor, insira uma hora entre {min} e {max}", - "error.validation.uuid": "Por favor, insira um UUID válido", - "error.validation.url": "Por favor, insira um URL válido", - - "expand": "Expandir", - "expand.all": "Expandir todos", - - "field.invalid": "O campo é inválido", - "field.required": "O campo é obrigatório", - "field.blocks.changeType": "Alterar tipo", - "field.blocks.code.name": "Código", - "field.blocks.code.language": "Idioma", - "field.blocks.code.placeholder": "O seu código …", - "field.blocks.delete.confirm": "Tem a certeza que pretende eliminar este bloco?", - "field.blocks.delete.confirm.all": "Tem a certeza que pretende eliminar todos os blocos?", - "field.blocks.delete.confirm.selected": "Tem a certeza que pretende eliminar os blocos selecionados?", - "field.blocks.empty": "Nenhum bloco ainda", - "field.blocks.fieldsets.empty": "Nenhum tipo de bloco ainda", - "field.blocks.fieldsets.label": "Por favor, selecione um tipo de bloco …", - "field.blocks.fieldsets.paste": "Pressione {{ shortcut }} para importar layouts/blocks da sua área de transferência Só serão inseridos aqueles permitidos no campo atual.", - "field.blocks.gallery.name": "Galeria", - "field.blocks.gallery.images.empty": "Nenhuma imagem ainda", - "field.blocks.gallery.images.label": "Imagens", - "field.blocks.heading.level": "Nível ", - "field.blocks.heading.name": "Título ", - "field.blocks.heading.text": "Texto", - "field.blocks.heading.placeholder": "Título …", - "field.blocks.image.alt": "Texto alternativo", - "field.blocks.image.caption": "Legenda", - "field.blocks.image.crop": "Cortar", - "field.blocks.image.link": "Link", - "field.blocks.image.location": "Localização ", - "field.blocks.image.location.internal": "Este website", - "field.blocks.image.location.external": "Fonte externa", - "field.blocks.image.name": "Imagem", - "field.blocks.image.placeholder": "Selecionar uma imagem", - "field.blocks.image.ratio": "Proporção ", - "field.blocks.image.url": "URL da imagem", - "field.blocks.line.name": "Linha", - "field.blocks.list.name": "Lista", - "field.blocks.markdown.name": "Markdown", - "field.blocks.markdown.label": "Texto", - "field.blocks.markdown.placeholder": "Markdown …", - "field.blocks.quote.name": "Citação ", - "field.blocks.quote.text.label": "Texto", - "field.blocks.quote.text.placeholder": "Citação …", - "field.blocks.quote.citation.label": "Citação ", - "field.blocks.quote.citation.placeholder": "de …", - "field.blocks.text.name": "Texto", - "field.blocks.text.placeholder": "Texto …", - "field.blocks.video.autoplay": "Reprodução automática", - "field.blocks.video.caption": "Legenda", - "field.blocks.video.controls": "Controlos", - "field.blocks.video.location": "Localização ", - "field.blocks.video.loop": "Repetir", - "field.blocks.video.muted": "Sem som", - "field.blocks.video.name": "Vídeo ", - "field.blocks.video.placeholder": "Insira um URL de vídeo ", - "field.blocks.video.poster": "Poster", - "field.blocks.video.preload": "Pré-carregamento", - "field.blocks.video.url.label": "URL-Vídeo", - "field.blocks.video.url.placeholder": "https://youtube.com/?v=", - - "field.files.empty": "Nenhum ficheiro selecionado ainda", - - "field.layout.change": "Alterar layout", - "field.layout.delete": "Eliminar layout", - "field.layout.delete.confirm": "Tem a certeza que pretende eliminar este layout?", - "field.layout.delete.confirm.all": "Tem a certeza que pretende eliminar todos os layouts?", - "field.layout.empty": "Nenhuma linha ainda", - "field.layout.select": "Selecionar um layout", - - "field.object.empty": "Nenhuma informação ainda", - - "field.pages.empty": "Nenhuma página selecionada ainda", - - "field.structure.delete.confirm": "Tem a certeza que pretende eliminar esta linha?", - "field.structure.delete.confirm.all": "Tem a certeza que pretende eliminar todos os registos?", - "field.structure.empty": "Nenhum registo ainda", - - "field.users.empty": "Nenhum utilizador selecionado ainda", - - "fields.empty": "Nenhum campo ainda", - - "file": "Ficheiro", - "file.blueprint": "Este ficheiro ainda não tem blueprint. Pode configurar o blueprint em /site/blueprints/files/{blueprint}.yml", - "file.changeTemplate": "Alterar template", - "file.changeTemplate.notice": "Alterar o template do ficheiro irá remover o conteúdo dos campos que não correspondem ao mesmo tipo. Se o novo template definir certas regras, por exemplo dimensões de imagem, estas também serão aplicadas irreversivelmente. Use com cuidado.", - "file.delete.confirm": "Tem a certeza que pretende eliminar
{filename}?", - "file.focus.placeholder": "Definir ponto de foco", - "file.focus.reset": "Remover ponto de foco", - "file.focus.title": "Foco", - "file.sort": "Alterar posição", - - "files": "Ficheiros", - "files.empty": "Nenhum ficheiro ainda", - - "filter": "Filtro", - - "hide": "Ocultar", - "hour": "Hora", - "hue": "Tonalidade", - "import": "Importar", - "info": "Info", - "insert": "Inserir", - "insert.after": "Inserir após", - "insert.before": "Inserir antes", - "install": "Instalar", - - "installation": "Instalação", - "installation.completed": "O painel foi instalado com sucesso", - "installation.disabled": "A instalação do painel está desativada em servidores públicos por defeito. Execute a instalação numa máquina local ou ative-a com a opção panel.install.", - "installation.issues.accounts": "A pasta /site/accounts não existe ou não tem permissão de escrita", - "installation.issues.content": "A pasta /content não existe ou não tem permissão de escrita", - "installation.issues.curl": "A extensão CURL é necessária", - "installation.issues.headline": "Não foi possível instalar o painel", - "installation.issues.mbstring": "A extensão MB String é necessária", - "installation.issues.media": "A pasta /media não existe ou não tem permissão de escrita", - "installation.issues.php": "Certifique-se que está a usar o PHP 8+", - "installation.issues.sessions": "A pasta /site/sessions não existe ou não tem permissão de escrita", - - "language": "Idioma", - "language.code": "Código", - "language.convert": "Definir como por defeito", - "language.convert.confirm": "

Tem a certeza que pretende converter {name} para o idioma por defeito? Esta ação não pode ser revertida.

Se {name} tiver conteúdo não traduzido, partes do site podem ficar sem conteúdo.

", - "language.create": "Adicionar um novo idioma", - "language.default": "Idioma por defeito", - "language.delete.confirm": "Tem a certeza que pretende eliminar o idioma {name} incluindo todas as traduções? Esta ação não pode ser revertida!", - "language.deleted": "O idioma foi eliminado", - "language.direction": "Direção de leitura", - "language.direction.ltr": "Esquerda para direita", - "language.direction.rtl": "Direita para esquerda", - "language.locale": "String de localização do PHP", - "language.locale.warning": "Está a usar configurações de localização personalizadas. Corrija as mesmas no ficheiro /site/languages", - "language.name": "Nome", - "language.secondary": "Idioma secundário", - "language.settings": "Configurações de idioma", - "language.updated": "O idioma foi atualizado", - "language.variables": "Variáveis de idioma", - "language.variables.empty": "Nenhuma tradução ainda", - - "language.variable.delete.confirm": "Tem a certeza que pretende eliminar a variável {key}?", - "language.variable.key": "Chave", - "language.variable.notFound": "Não foi possível encontrar a variável", - "language.variable.value": "Valor", - - "languages": "Idiomas", - "languages.default": "Idioma por defeito", - "languages.empty": "Nenhum idioma ainda", - "languages.secondary": "Idiomas secundários", - "languages.secondary.empty": "Nenhum idioma secundário ainda", - - "license": "Licença ", - "license.activate": "Ative-a agora", - "license.activate.label": "Por favor, ative a sua licença", - "license.activate.domain": "A sua licença será ativada para {host}.", - "license.activate.local": "Está prestes a ativar a sua licença Kirby no domínio local {host}. Se este site vai ser alojado num domínio público, por favor ative-o lá. Se o domínio {host} é o que deseja para usar a sua licença, por favor continue.", - "license.activated": "Ativada", - "license.buy": "Compre uma licença", - "license.code": "Código", - "license.code.help": "Recebeu o seu código de licença por email após a compra. Por favor, copie e cole aqui.", - "license.code.label": "Por favor, insira o código da sua licença", - "license.status.active.info": "Inclui novas versões principais até {date}", - "license.status.active.label": "Licença válida", - "license.status.demo.info": "Esta é uma instalação de demonstração", - "license.status.demo.label": "Demonstração", - "license.status.inactive.info": "Renove a licença para atualizar para novas versões principais", - "license.status.inactive.label": "Nenhuma versão principal nova", - "license.status.legacy.bubble": "Pronto para renovar a sua licença?", - "license.status.legacy.info": "A sua licença não abrange esta versão", - "license.status.legacy.label": "Por favor, renove a sua licença", - "license.status.missing.bubble": "Pronto para lançar o seu site?", - "license.status.missing.info": "Sem licença válida", - "license.status.missing.label": "Por favor, ative a sua licença", - "license.manage": "Gerir as suas licenças", - "license.purchased": "Comprada", - "license.success": "Obrigado por apoiar o Kirby", - "license.unregistered.label": "Não registada", - - "link": "Link", - "link.text": "Texto do link", - - "loading": "A carregar", - - "lock.unsaved": "Alterações não guardadas", - "lock.unsaved.empty": "Não existem mais alterações não guardadas", - "lock.isLocked": "Alterações não guardadas de {email}", - "lock.unlock": "Desbloquear", - "lock.unlock.submit": "Desbloqueie e substitua alterações não guardadas de {email}", - "lock.isUnlocked": "Foi desbloqueado por outro utilizador", - - "login": "Entrar", - "login.code.label.login": "Código de início de sessão", - "login.code.label.password-reset": "Código de redefinição de palavra-passe", - "login.code.placeholder.email": "000 0000", - "login.code.placeholder.totp": "000000", - "login.code.text.email": "Se o seu endereço de email está registado, o código solicitado foi enviado por email.", - "login.code.text.totp": "Por favor, insira o código de segurança da sua aplicação de autenticação.", - "login.email.login.body": "Olá {user.nameOrEmail},\n\nRecentemente solicitou um código de início de sessão para o painel de {site}.\nO seguinte código de início de sessão será válido por {timeout} minutos:\n\n{code}\n\nSe não solicitou um código de início de sessão, por favor ignore este e-mail ou entre em contacto com o administrador se tiver dúvidas.\nPor motivos de segurança, por favor NÃO reencaminhe este e-mail.", - "login.email.login.subject": "O seu código de início de sessão", - "login.email.password-reset.body": "Olá {user.nameOrEmail},\n\nRecentemente solicitou um código de redefinição de palavra-passe para o painel de {site}.\nO seguinte código de redefinição de palavra-passe será válido por {timeout} minutos:\n\n{code}\n\nSe não solicitou um código de redefinição de palavra-passe, por favor ignore este e-mail ou entre em contacto com o administrador se tiver dúvidas.\nPor motivos de segurança, por favor NÃO reencaminhe este e-mail.", - "login.email.password-reset.subject": "O seu código de redefinição de palavra-passe", - "login.remember": "Manter sessão iniciada", - "login.reset": "Redefinir palavra-passe", - "login.toggleText.code.email": "Iniciar sessão com email", - "login.toggleText.code.email-password": "Iniciar sessão com palavra-passe", - "login.toggleText.password-reset.email": "Esqueceu a sua palavra-passe?", - "login.toggleText.password-reset.email-password": "← Voltar ao início de sessão", - "login.totp.enable.option": "Configurar códigos de segurança", - "login.totp.enable.intro": "As aplicações de autenticação podem gerar códigos de segurança que são usados como um segundo fator ao iniciar a sessão na sua conta.", - "login.totp.enable.qr.label": "1. Leia este código QR", - "login.totp.enable.qr.help": "Não consegue ler o código? Adicione a chave de configuração {secret} manualmente à sua aplicação de autenticação.", - "login.totp.enable.confirm.headline": "2. Confirme com o código gerado", - "login.totp.enable.confirm.text": "A sua aplicação gera um novo código de segurança a cada 30 segundos. Insira o código atual para concluir a configuração:", - "login.totp.enable.confirm.label": "Código atual", - "login.totp.enable.confirm.help": "Após esta configuração, iremos solicitar um código de segurança sempre que iniciar a sessão.", - "login.totp.enable.success": "Códigos de segurança ativados", - "login.totp.disable.option": "Desativar códigos de segurança", - "login.totp.disable.label": "Insira a sua palavra-passe para desativar códigos de segurança", - "login.totp.disable.help": "No futuro, um segundo fator diferente, como um código de início de sessão enviado por e-mail, será solicitado quando iniciar a sessão. Poderá configurar códigos de segurança novamente mais tarde.", - "login.totp.disable.admin": "

Isto irá desactivar os códigos de segurança para {user}.

No futuro, um segundo fator diferente, como um código de início de sessão enviado por e-mail, será solicitado quando eles iniciarem a sessão. {user} poderá configurar códigos de segurança novamente após o próximo início de sessão.

", - "login.totp.disable.success": "Códigos de segurança desativados", - - "logout": "Sair", - - "merge": "Unir", - "menu": "Menu", - "meridiem": "AM/PM", - "mime": "Tipo de Mídia", - "minutes": "Minutos", - - "month": "Mês", - "months.april": "Abril", - "months.august": "Agosto", - "months.december": "Dezembro", - "months.february": "Fevereiro", - "months.january": "Janeiro", - "months.july": "Julho", - "months.june": "Junho", - "months.march": "Mar\u00e7o", - "months.may": "Maio", - "months.november": "Novembro", - "months.october": "Outubro", - "months.september": "Setembro", - - "more": "Mais", - "move": "Mover", - "name": "Nome", - "next": "Próximo", - "night": "Noite", - "no": "não", - "off": "off", - "on": "on", - "open": "Abrir", - "open.newWindow": "Abrir numa nova janela", - "option": "Opção", - "options": "Opções", - "options.none": "Sem opções", - "options.all": "Mostrar todas as {count} opções", - - "orientation": "Orientação", - "orientation.landscape": "Paisagem", - "orientation.portrait": "Retrato", - "orientation.square": "Quadrado", - - "page": "Página", - "page.blueprint": "Esta página não tem blueprint ainda. Pode configurar o blueprint em /site/blueprints/pages/{blueprint}.yml", - "page.changeSlug": "Alterar URL", - "page.changeSlug.fromTitle": "Criar a partir do t\u00edtulo", - "page.changeStatus": "Alterar estado", - "page.changeStatus.position": "Selecione uma posição", - "page.changeStatus.select": "Selecione um novo estado", - "page.changeTemplate": "Alterar template", - "page.changeTemplate.notice": "Alterar o template da página irá remover o conteúdo dos campos que não correspondem ao mesmo tipo. Use com cuidado.", - "page.create": "Criar como {status}", - "page.delete.confirm": "Tem a certeza que pretende eliminar {title}?", - "page.delete.confirm.subpages": "Esta página tem subpáginas.
Todas as subpáginas serão eliminadas também.", - "page.delete.confirm.title": "Por favor, insira o título da página para confirmar", - "page.duplicate.appendix": "Copiar", - "page.duplicate.files": "Copiar ficheiros", - "page.duplicate.pages": "Copiar páginas", - "page.move": "Mover página", - "page.sort": "Alterar posição", - "page.status": "Estado", - "page.status.draft": "Rascunho", - "page.status.draft.description": "A página está em modo de rascunho e é visível apenas para editores com sessão iniciada ou através de um link secreto", - "page.status.listed": "Pública", - "page.status.listed.description": "A página é pública para todos", - "page.status.unlisted": "Não listada", - "page.status.unlisted.description": "Esta página é acessível apenas através de URL", - - "pages": "Páginas", - "pages.empty": "Nenhuma página ainda", - "pages.status.draft": "Rascunhos", - "pages.status.listed": "Publicadas", - "pages.status.unlisted": "Não listadas", - - "pagination.page": "Página", - - "password": "Palavra-passe", - "paste": "Colar", - "paste.after": "Colar após", - "paste.success": "{count} colados!", - "pixel": "Pixel", - "plugin": "Plugin", - "plugins": "Plugins", - "prev": "Anterior", - "preview": "Pré-visualizar", - "remove": "Remover", - "rename": "Alterar nome", - "renew": "Renovar", - "replace": "Substituir", - "replace.with": "Substituir por", - "retry": "Tentar novamente", - "revert": "Reverter", - "revert.confirm": "Tem a certeza que pretende eliminar todas as alterações não guardadas?", - - "role": "Função", - "role.admin.description": "O administrador tem todas as permissões", - "role.admin.title": "Administrador", - "role.all": "Todos", - "role.empty": "Não há utilizadores com esta função", - "role.description.placeholder": "Sem descrição", - "role.nobody.description": "Esta é uma função de recurso sem permissões", - "role.nobody.title": "Ninguém", - - "save": "Guardar", - "search": "Pesquisar", - "search.min": "Insira {min} caracteres para pesquisar", - "search.all": "Mostrar todos os {count} resultados", - "search.results.none": "Sem resultados", - - "section.invalid": "A secção é inválida", - "section.required": "A secção é obrigatória", - - "security": "Segurança", - "select": "Selecionar", - "server": "Servidor", - "settings": "Configurações", - "show": "Mostrar", - "site.blueprint": "O site não tem blueprint ainda. Pode configurar o blueprint em /site/blueprints/site.yml", - "size": "Tamanho", - "slug": "URL", - "sort": "Ordenar", - "sort.drag": "Arraste para ordenar ...", - "split": "Dividir", - - "stats.empty": "Sem relatórios", - "status": "Estado", - - "system.info.copy": "Copy info", - "system.info.copied": "System info copied", - "system.issues.content": "A pasta content parece não estar protegida", - "system.issues.eol.kirby": "A versão instalada do Kirby chegou ao fim da sua vida útil e não irá receber mais atualizações de segurança", - "system.issues.eol.plugin": "A versão instalada do plugin { plugin } chegou ao fim da sua vida útil e não irá receber mais atualizações de segurança", - "system.issues.eol.php": "A versão instalada { release } de PHP chegou ao fim da sua vida útil e não irá receber mais atualizações de segurança", - "system.issues.debug": "O modo debug deve ser desativado em produção", - "system.issues.git": "A pasta .git parece não estar protegida", - "system.issues.https": "Nós recomendamos HTTPS para todos os seus sites", - "system.issues.kirby": "A pasta kirby parece não estar protegida", - "system.issues.site": "A pasta site parece não estar protegida", - "system.issues.vulnerability.kirby": "A sua instalação poderá ser afetada pela seguinte vulnerabilidade ({ severity } gravidade): { description }", - "system.issues.vulnerability.plugin": "A sua instalação poderá ser afetada pela seguinte vulnerabilidade no plugin { plugin } ({ severity } gravidade): { description }", - "system.updateStatus": "Atualizar estado", - "system.updateStatus.error": "Não foi possível verificar se havia atualizações", - "system.updateStatus.not-vulnerable": "Nenhuma vulnerabilidade conhecida", - "system.updateStatus.security-update": "Atualização de segurança gratuita { version } disponível", - "system.updateStatus.security-upgrade": "Atualização { version } com correções de segurança disponível", - "system.updateStatus.unreleased": "Versão não lançada", - "system.updateStatus.up-to-date": "Atualizado", - "system.updateStatus.update": "Atualização gratuita { version } disponível", - "system.updateStatus.upgrade": "Atualização { version } disponível", - - "tel": "Telefone", - "tel.placeholder": "+351912345678", - "template": "Template", - "title": "Título", - "today": "Hoje", - - "toolbar.button.clear": "Limpar formatação", - "toolbar.button.code": "Código", - "toolbar.button.bold": "Negrito", - "toolbar.button.email": "Email", - "toolbar.button.headings": "Títulos", - "toolbar.button.heading.1": "Título 1", - "toolbar.button.heading.2": "Título 2", - "toolbar.button.heading.3": "Título 3", - "toolbar.button.heading.4": "Título 4", - "toolbar.button.heading.5": "Título 5", - "toolbar.button.heading.6": "Título 6", - "toolbar.button.italic": "Itálico", - "toolbar.button.file": "Ficheiro", - "toolbar.button.file.select": "Selecione um ficheiro", - "toolbar.button.file.upload": "Envie um ficheiro", - "toolbar.button.link": "Link", - "toolbar.button.paragraph": "Parágrafo", - "toolbar.button.strike": "Rasurado", - "toolbar.button.sub": "Subscrito", - "toolbar.button.sup": "Sobrescrito", - "toolbar.button.ol": "Lista ordenada", - "toolbar.button.underline": "Sublinhado", - "toolbar.button.ul": "Lista não-ordenada", - - "translation.author": "Equipa Kirby", - "translation.direction": "ltr", - "translation.name": "Português (Portugal)", - "translation.locale": "pt_PT", - - "type": "Tipo", - - "upload": "Enviar", - "upload.error.cantMove": "Não foi possível mover o ficheiro enviado", - "upload.error.cantWrite": "Não foi possível guardar o ficheiro em disco", - "upload.error.default": "Não foi possível enviar o ficheiro", - "upload.error.extension": "O envio do ficheiro foi interrompido devido à extensão", - "upload.error.formSize": "O ficheiro enviado excede a diretiva MAX_FILE_SIZE especificada no formulário", - "upload.error.iniPostSize": "O ficheiro enviado excede a diretiva post_max_size do php.ini", - "upload.error.iniSize": "O ficheiro enviado excede a diretiva upload_max_filesize do php.ini", - "upload.error.noFile": "Nenhum ficheiro foi enviado", - "upload.error.noFiles": "Nenhum ficheiro foi enviado", - "upload.error.partial": "O ficheiro foi enviado apenas parcialmente", - "upload.error.tmpDir": "Pasta temporária em falta", - "upload.errors": "Erro", - "upload.progress": "A enviar…", - - "url": "URL", - "url.placeholder": "https://exemplo.pt", - - "user": "Utilizador", - "user.blueprint": "Pode definir secções adicionais e campos de formulário para esta função de utilizador em /site/blueprints/users/{blueprint}.yml", - "user.changeEmail": "Alterar email", - "user.changeLanguage": "Alterar idioma", - "user.changeName": "Alterar o nome deste utilizador", - "user.changePassword": "Alterar palavra-passe", - "user.changePassword.new": "Nova palavra-passe", - "user.changePassword.new.confirm": "Confirme a nova palavra-passe…", - "user.changeRole": "Alterar função", - "user.changeRole.select": "Selecione uma nova função", - "user.create": "Adicionar um novo utilizador", - "user.delete": "Eliminar este utilizador", - "user.delete.confirm": "Tem a certeza que pretende eliminar
{email}?", - - "users": "Utilizadores", - - "version": "Versão", - "version.current": "Versão atual", - "version.latest": "Versão mais recente", - "versionInformation": "Informação da versão", - - "view.account": "A sua conta", - "view.installation": "Instala\u00e7\u00e3o", - "view.languages": "Idiomas", - "view.resetPassword": "Redefinir palavra-passe", - "view.site": "Site", - "view.system": "Sistema", - "view.users": "Utilizadores", - - "welcome": "Bem-vindo", - "year": "Ano", - "yes": "sim" + "account.changeName": "Mudar seu nome", + "account.delete": "Deletar sua conta", + "account.delete.confirm": "Deseja realmente deletar sua conta? Você sairá do site imediatamente. Sua conta não poderá ser recuperada. ", + + "add": "Adicionar", + "author": "Autor", + "avatar": "Foto do perfil", + "back": "Voltar", + "cancel": "Cancelar", + "change": "Alterar", + "close": "Fechar", + "confirm": "Salvar", + "collapse": "Colapsar", + "collapse.all": "Colapsar todos", + "copy": "Copiar", + "copy.all": "Copiar todos", + "create": "Criar", + + "date": "Data", + "date.select": "Selecione uma data", + + "day": "Dia", + "days.fri": "Sex", + "days.mon": "Seg", + "days.sat": "S\u00e1b", + "days.sun": "Dom", + "days.thu": "Qui", + "days.tue": "Ter", + "days.wed": "Qua", + + "debugging": "Depuração ", + + "delete": "Excluir", + "delete.all": "Deletar todos", + + "dialog.files.empty": "Sem arquivos para selecionar", + "dialog.pages.empty": "Sem páginas para selecionar", + "dialog.users.empty": "Sem utilizadores para selecionar", + + "dimensions": "Dimensões", + "disabled": "Inativo", + "discard": "Descartar", + "download": "Descarregar", + "duplicate": "Duplicar", + + "edit": "Editar", + + "email": "Email", + "email.placeholder": "mail@exemplo.pt", + + "entries": "Entries", + "entry": "Entry", + + "environment": "Ambiente", + + "error.access.code": "Código inválido", + "error.access.login": "Login inválido", + "error.access.panel": "Não tem permissões para aceder ao painel", + "error.access.view": "Não tem permissões para aceder a esta área do Painel", + + "error.avatar.create.fail": "A foto de perfil não foi enviada", + "error.avatar.delete.fail": "A foto do perfil não foi excluída", + "error.avatar.dimensions.invalid": "Por favor, use uma foto de perfil com largura e altura menores que 3000 pixels", + "error.avatar.mime.forbidden": "A foto de perfil deve ser um arquivo JPEG ou PNG", + + "error.blueprint.notFound": "O blueprint \"{name}\" não pode ser carregado", + + "error.blocks.max.plural": "Você não deve adicionar mais do que {max} blocos", + "error.blocks.max.singular": "Você não deve adicionar mais do que um bloco", + "error.blocks.min.plural": "Você deve adicionar pelo menos {min} blocos", + "error.blocks.min.singular": "Você deve adicionar pelo menos um bloco", + "error.blocks.validation": "Há um erro no bloco {index}", + + "error.email.preset.notFound": "Preset de email \"{name}\" não encontrado", + + "error.field.converter.invalid": "Conversor \"{converter}\" inválido", + + "error.file.changeName.empty": "O nome não pode ficar em branco", + "error.file.changeName.permission": "Não tem permissões para alterar o nome de \"{filename}\"", + "error.file.duplicate": "Um arquivo com o nome \"{filename}\" já existe", + "error.file.extension.forbidden": "Extensão \"{extension}\" não permitida", + "error.file.extension.invalid": "Extensão inválida: {extension}", + "error.file.extension.missing": "Extensão de \"{filename}\" em falta", + "error.file.maxheight": "A altura da imagem não deve exceder {height} pixels", + "error.file.maxsize": "O arquivo é muito grande", + "error.file.maxwidth": "A largura da imagem não deve exceder {width} pixels", + "error.file.mime.differs": "O arquivo enviado precisa ser do tipo \"{mime}\"", + "error.file.mime.forbidden": "Tipo de mídia \"{mime}\" não permitido", + "error.file.mime.invalid": "Tipo de mídia inválido: {mime}", + "error.file.mime.missing": "Tipo de mídia de \"{filename}\" não detectado", + "error.file.minheight": "A altura da imagem deve ser pelo menos {height} pixels", + "error.file.minsize": "O ficheiro é muito pequeno", + "error.file.minwidth": "A largura da imagem deve ser pelo menos {width} pixels", + "error.file.name.missing": "O nome do arquivo não pode ficar em branco", + "error.file.notFound": "Arquivo \"{filename}\" não encontrado", + "error.file.orientation": "A orientação da imagem deve ser \"{orientation}\"", + "error.file.type.forbidden": "Não tem permissões para enviar arquivos {type}", + "error.file.type.invalid": "Tipo inválido de arquivo: {type}", + "error.file.undefined": "Arquivo n\u00e3o encontrado", + + "error.form.incomplete": "Por favor, corrija os erros do formulário…", + "error.form.notSaved": "O formulário não foi guardado", + + "error.language.code": "Insira um código de idioma válido", + "error.language.duplicate": "O idioma já existe", + "error.language.name": "Insira um nome válido para o idioma", + "error.language.notFound": "O idioma não foi encontrado", + + "error.layout.validation.block": "Há um erro no bloco {blockIndex} no layout {layoutIndex}", + "error.layout.validation.settings": "Há um erro na configuração do layout {index}", + + "error.license.format": "Insira uma chave de licença válida", + "error.license.email": "Digite um endereço de email válido", + "error.license.verification": "Não foi possível verificar a licença", + + "error.offline": "O painel está offline no momento", + + "error.page.changeSlug.permission": "Não tem permissões para alterar a URL de \"{slug}\"", + "error.page.changeStatus.incomplete": "A página possui erros e não pode ser guardada", + "error.page.changeStatus.permission": "O estado desta página não pode ser alterado", + "error.page.changeStatus.toDraft.invalid": "A página \"{slug}\" não pode ser convertida para rascunho", + "error.page.changeTemplate.invalid": "O tema da página \"{slug}\" não pode ser alterado", + "error.page.changeTemplate.permission": "Não tem permissões para alterar o tema de \"{slug}\"", + "error.page.changeTitle.empty": "O título não pode ficar em branco", + "error.page.changeTitle.permission": "Não tem permissões para alterar o título de \"{slug}\"", + "error.page.create.permission": "Não tem permissões para criar \"{slug}\"", + "error.page.delete": "A página \"{slug}\" não pode ser excluída", + "error.page.delete.confirm": "Por favor, digite o título da página para confirmar", + "error.page.delete.hasChildren": "A página possui subpáginas e não pode ser excluída", + "error.page.delete.permission": "Não tem permissões para excluir \"{slug}\"", + "error.page.draft.duplicate": "Um rascunho de página com a URL \"{slug}\" já existe", + "error.page.duplicate": "Uma página com a URL \"{slug}\" já existe", + "error.page.duplicate.permission": "Não tem permissão para duplicar \"{slug}\"", + "error.page.notFound": "Página\"{slug}\" não encontrada", + "error.page.num.invalid": "Digite um número de ordenação válido. Este número não pode ser negativo.", + "error.page.slug.invalid": "Por favor entre um anexo de URL válido ", + "error.page.slug.maxlength": "O slug não pode conter mais do que \"{length}\" caracteres", + "error.page.sort.permission": "A página \"{slug}\" não pode ser ordenada", + "error.page.status.invalid": "Por favor, defina um estado de página válido", + "error.page.undefined": "P\u00e1gina n\u00e3o encontrada", + "error.page.update.permission": "Não tem permissões para atualizar \"{slug}\"", + + "error.section.files.max.plural": "Não pode adicionar mais do que {max} arquivos à seção \"{section}\"", + "error.section.files.max.singular": "Não pode adicionar mais do que um arquivo à seção \"{section}\"", + "error.section.files.min.plural": "A secção \"{section}\" requer no mínimo {min} arquivos", + "error.section.files.min.singular": "A secção \"{section}\" requer no mínimo um arquivo", + + "error.section.pages.max.plural": "Não pode adicionar mais do que {max} página à seção \"{section}\"", + "error.section.pages.max.singular": "Não pode adicionar mais do que uma página à seção \"{section}\"", + "error.section.pages.min.plural": "A secção \"{section}\" requer no mínimo {min} páginas", + "error.section.pages.min.singular": "A secção \"{section}\" requer no mínimo uma página", + + "error.section.notLoaded": "A seção \"{name}\" não pôde ser carregada", + "error.section.type.invalid": "O tipo da seção \"{type}\" não é válido", + + "error.site.changeTitle.empty": "O título não pode ficar em branco", + "error.site.changeTitle.permission": "Não tem permissões para alterar o título do site", + "error.site.update.permission": "Não tem permissões para atualizar o site", + + "error.template.default.notFound": "O tema padrão não existe", + + "error.unexpected": "An unexpected error occurred! Enable debug mode for more info: https://getkirby.com/docs/reference/system/options/debug", + + "error.user.changeEmail.permission": "Não tem permissões para alterar o email do utilizador \"{name}\"", + "error.user.changeLanguage.permission": "Não tem permissões para alterar o idioma do utilizador \"{name}\"", + "error.user.changeName.permission": "Não tem permissões para alterar o nome do utilizador \"{name}\"", + "error.user.changePassword.permission": "Não tem permissões para alterar a palavra-passe do utilizador \"{name}\"", + "error.user.changeRole.lastAdmin": "A função do último administrador não pode ser alterado", + "error.user.changeRole.permission": "Não tem permissões para alterar a função do utilizador \"{name}\"", + "error.user.changeRole.toAdmin": "Não tem permissões para promover utilizadores à função de administrador", + "error.user.create.permission": "Não tem permissões para criar este utilizador", + "error.user.delete": "O utilizador \"{name}\" não pode ser excluído", + "error.user.delete.lastAdmin": "O último administrador não pode ser excluído", + "error.user.delete.lastUser": "O último utilizador não pode ser excluído", + "error.user.delete.permission": "Não tem permissões para excluir o utilizador \"{name}\"", + "error.user.duplicate": "Um utilizador com o email \"{email}\" já existe", + "error.user.email.invalid": "Digite um endereço de email válido", + "error.user.language.invalid": "Digite um idioma válido", + "error.user.notFound": "Utilizador \"{name}\" não encontrado", + "error.user.password.excessive": "Please enter a valid password. Passwords must not be longer than 1000 characters.", + "error.user.password.invalid": "Digite uma palavra-passe válida. A sua palavra-passe deve ter pelo menos 8 caracteres.", + "error.user.password.notSame": "As palavras-passe não combinam", + "error.user.password.undefined": "O utilizador não possui uma palavra-passe", + "error.user.password.wrong": "Senha errada", + "error.user.role.invalid": "Digite uma função válida", + "error.user.undefined": "Usuário não encontrado", + "error.user.update.permission": "Não tem permissões para atualizar o utilizador \"{name}\"", + + "error.validation.accepted": "Por favor, confirme", + "error.validation.alpha": "Por favor, use apenas caracteres entre a-z", + "error.validation.alphanum": "Por favor, use apenas caracteres entre a-z ou 0-9", + "error.validation.between": "Digite um valor entre \"{min}\" e \"{max}\"", + "error.validation.boolean": "Por favor, confirme ou rejeite", + "error.validation.contains": "Digite um valor que contenha \"{needle}\"", + "error.validation.date": "Escolha uma data válida", + "error.validation.date.after": "Escolha uma data posterior a {date}", + "error.validation.date.before": "Escolha uma data anterior a {date}", + "error.validation.date.between": "Escolha uma data compreendida entre {min} e {max}", + "error.validation.denied": "Por favor, cancele", + "error.validation.different": "O valor deve ser diferente de \"{other}\"", + "error.validation.email": "Digite um endereço de email válido", + "error.validation.endswith": "O valor deve terminar com \"{end}\"", + "error.validation.filename": "Digite um nome de arquivo válido", + "error.validation.in": "Digite um destes valores: ({in})", + "error.validation.integer": "Digite um número inteiro válido", + "error.validation.ip": "Digite um endereço de IP válido", + "error.validation.less": "Digite um valor menor que {max}", + "error.validation.match": "O valor não combina com o padrão esperado", + "error.validation.max": "Digite um valor igual ou menor que {max}", + "error.validation.maxlength": "Digite um valor curto. (no máximo {max} caracteres)", + "error.validation.maxwords": "Digite menos que {max} palavra(s)", + "error.validation.min": "Digite um valor igual ou maior que {min}", + "error.validation.minlength": "Digite um valor maior. (no mínimo {min} caracteres)", + "error.validation.minwords": "Digite ao menos {min} palavra(s)", + "error.validation.more": "Digite um valor maior que {min}", + "error.validation.notcontains": "Digite um valor que não contenha \"{needle}\"", + "error.validation.notin": "Não digite nenhum destes valores: ({notIn})", + "error.validation.option": "Escolha uma opção válida", + "error.validation.num": "Digite um número válido", + "error.validation.required": "Digite algo", + "error.validation.same": "Por favor, digite \"{other}\"", + "error.validation.size": "O tamanho do valor deve ser \"{size}\"", + "error.validation.startswith": "O valor deve começar com \"{start}\"", + "error.validation.time": "Digite uma hora válida", + "error.validation.time.after": "Por favor entre um horário depois de {time}", + "error.validation.time.before": "Por favor entre um horário antes de {time}", + "error.validation.time.between": "Por favor entre um horário entre {min} e {max}", + "error.validation.url": "Digite uma URL válida", + + "expand": "Expandir", + "expand.all": "Expandir todos", + + "field.required": "Este campo é necessário", + "field.blocks.changeType": "Mudar tipo", + "field.blocks.code.name": "Código", + "field.blocks.code.language": "Idioma", + "field.blocks.code.placeholder": "Seu código …", + "field.blocks.delete.confirm": "Deseja realmente deletar este bloco?", + "field.blocks.delete.confirm.all": "Deseja realmente deletar todos os blocos?", + "field.blocks.delete.confirm.selected": "Deseja realmente deletar os blocos selecionados?", + "field.blocks.empty": "Nenhum bloco", + "field.blocks.fieldsets.label": "Por favor selecione um tipo de bloco …", + "field.blocks.fieldsets.paste": "Digite {{ shortcut }} para colar/importar blocos da sua área de transferência ", + "field.blocks.gallery.name": "Galeria", + "field.blocks.gallery.images.empty": "Nenhuma imagem", + "field.blocks.gallery.images.label": "Imagens", + "field.blocks.heading.level": "Nível ", + "field.blocks.heading.name": "Título ", + "field.blocks.heading.text": "Texto", + "field.blocks.heading.placeholder": "Título …", + "field.blocks.image.alt": "Texto alternativo", + "field.blocks.image.caption": "Legenda", + "field.blocks.image.crop": "Cortar", + "field.blocks.image.link": "Link", + "field.blocks.image.location": "Localização ", + "field.blocks.image.name": "Imagem", + "field.blocks.image.placeholder": "Selecionar uma imagem", + "field.blocks.image.ratio": "Proporção ", + "field.blocks.image.url": "URL da imagem", + "field.blocks.line.name": "Linha", + "field.blocks.list.name": "Lista", + "field.blocks.markdown.name": "Markdown", + "field.blocks.markdown.label": "Texto", + "field.blocks.markdown.placeholder": "Markdown …", + "field.blocks.quote.name": "Citação ", + "field.blocks.quote.text.label": "Texto", + "field.blocks.quote.text.placeholder": "Citação …", + "field.blocks.quote.citation.label": "Citação ", + "field.blocks.quote.citation.placeholder": "de …", + "field.blocks.text.name": "Texto", + "field.blocks.text.placeholder": "Texto …", + "field.blocks.video.caption": "Legenda", + "field.blocks.video.name": "Vídeo ", + "field.blocks.video.placeholder": "Entre uma URL de vídeo ", + "field.blocks.video.url.label": "URL-Vídeo", + "field.blocks.video.url.placeholder": "https://youtube.com/?v=", + + "field.files.empty": "Nenhum arquivo selecionado", + + "field.layout.delete": "Deletar layout", + "field.layout.delete.confirm": "Deseja realmente deletar este layout?", + "field.layout.empty": "Nenhuma linha", + "field.layout.select": "Selecionar um layout", + + "field.pages.empty": "Nenhuma página selecionada", + "field.structure.delete.confirm": "Deseja realmente excluir este registro?", + "field.structure.empty": "Nenhum registro", + "field.users.empty": "Nenhum utilizador selecionado", + + "file.blueprint": "Este arquivo não tem planta. Você pode definir sua planta em /site/blueprints/files/{blueprint}.yml", + "file.delete.confirm": "Deseja realmente excluir
{filename}?", + "file.sort": "Mudar posição", + + "files": "Arquivos", + "files.empty": "Nenhum arquivo", + + "hide": "Ocultar", + "hour": "Hora", + "import": "Importar", + "info": "Info", + "insert": "Inserir", + "insert.after": "Inserir após", + "insert.before": "Inserir antes", + "install": "Instalar", + + "installation": "Instalação", + "installation.completed": "Painel instalado com sucesso", + "installation.disabled": "Por padrão, o instalador do painel está desabilitado em servidores públicos. Por favor, execute o instalador numa máquina local ou habilite a opção panel.install.", + "installation.issues.accounts": "A pasta /site/accounts não existe ou não possui permissão de escrita", + "installation.issues.content": "A pasta /content não existe ou não possui permissão de escrita", + "installation.issues.curl": "A extensão CURL é necessária", + "installation.issues.headline": "O painel não pôde ser instalado", + "installation.issues.mbstring": "A extensão MB String é necessária", + "installation.issues.media": "A pasta /media não existe ou não possui permissão de escrita", + "installation.issues.php": "Certifique-se que está a usar o PHP 7+", + "installation.issues.server": "O Kirby necessita do Apache, Nginx ou Caddy", + "installation.issues.sessions": "A pasta /site/sessions não existe ou não possui permissão de escrita", + + "language": "Idioma", + "language.code": "Código", + "language.convert": "Tornar padrão", + "language.convert.confirm": "

Deseja realmente converter {name} para o idioma padrão? Esta ação não poderá ser revertida.

Se {name} tiver conteúdo não traduzido, partes do seu site poderão ficar sem conteúdo.

", + "language.create": "Adicionar novo idioma", + "language.delete.confirm": "Deseja realmente excluir o idioma {name} incluíndo todas as traduções? Esta ação não poderá ser revertida!", + "language.deleted": "Idioma excluído", + "language.direction": "Direção de leitura", + "language.direction.ltr": "Esquerda para direita", + "language.direction.rtl": "Direita para esquerda", + "language.locale": "String de localização do PHP", + "language.locale.warning": "Está a usar configurações de localização personalizadas. Corrija as mesmas no ficheiro /site/languages", + "language.name": "Nome", + "language.updated": "Idioma atualizado", + + "languages": "Idiomas", + "languages.default": "Idioma padrão", + "languages.empty": "Nenhum idioma", + "languages.secondary": "Idiomas secundários", + "languages.secondary.empty": "Nenhum idioma secundário", + + "license": "Licen\u00e7a do Kirby ", + "license.buy": "Comprar uma licença", + "license.register": "Registrar", + "license.manage": "Manage your licenses", + "license.register.help": "Recebeu o código da sua licença por email após a compra. Por favor, copie e cole-o para completar o registro.", + "license.register.label": "Por favor, digite o código da sua licença", + "license.register.success": "Obrigado por apoiar o Kirby", + "license.unregistered": "Esta é uma demonstração não registrada do Kirby", + "license.unregistered.label": "Unregistered", + + "link": "Link", + "link.text": "Texto do link", + + "loading": "A carregar", + + "lock.unsaved": "Alterações por guardar", + "lock.unsaved.empty": "Não existem alterações por guardar", + "lock.isLocked": "Alterações por guardar de {email}", + "lock.file.isLocked": "O arquivo está a ser editado por {email} e não pode ser alterado.", + "lock.page.isLocked": "A página está a ser editada por {email} e não pode ser alterada.", + "lock.unlock": "Desbloquear", + "lock.isUnlocked": "As suas alterações foram sobrepostas por outro utilizador. Pode descarregar as suas alterações e combiná-las manualmente.", + + "login": "Entrar", + "login.code.label.login": "Código de acesso", + "login.code.label.password-reset": "Código de redefinição de senha", + "login.code.placeholder.email": "000 0000", + "login.code.text.email": "Se seu endereço de email está registrado, o código requisitado será mandado por email.", + "login.email.login.body": "Hi {user.nameOrEmail},\n\nYou recently requested a login code for the Panel of {site}.\nThe following login code will be valid for {timeout} minutes:\n\n{code}\n\nIf you did not request a login code, please ignore this email or contact your administrator if you have questions.\nFor security, please DO NOT forward this email.", + "login.email.login.subject": "Seu código de acesso", + "login.email.password-reset.body": "Hi {user.nameOrEmail},\n\nYou recently requested a password reset code for the Panel of {site}.\nThe following password reset code will be valid for {timeout} minutes:\n\n{code}\n\nIf you did not request a password reset code, please ignore this email or contact your administrator if you have questions.\nFor security, please DO NOT forward this email.", + "login.email.password-reset.subject": "Seu código de redefinição de senha", + "login.remember": "Manter-me conectado", + "login.reset": "Redefinir senha", + "login.toggleText.code.email": "Entrar com email", + "login.toggleText.code.email-password": "Entrar com senha", + "login.toggleText.password-reset.email": "Esqueceu sua senha?", + "login.toggleText.password-reset.email-password": "← Voltar à entrada", + + "logout": "Sair", + + "menu": "Menu", + "meridiem": "AM/PM", + "mime": "Tipo de mídia", + "minutes": "Minutos", + + "month": "Mês", + "months.april": "Abril", + "months.august": "Agosto", + "months.december": "Dezembro", + "months.february": "Fevereiro", + "months.january": "Janeiro", + "months.july": "Julho", + "months.june": "Junho", + "months.march": "Mar\u00e7o", + "months.may": "Maio", + "months.november": "Novembro", + "months.october": "Outubro", + "months.september": "Setembro", + + "more": "Mais", + "name": "Nome", + "next": "Próximo", + "no": "não", + "off": "off", + "on": "on", + "open": "Abrir", + "open.newWindow": "Abrir em nova janela", + "options": "Opções", + "options.none": "Sem opções", + + "orientation": "Orientação", + "orientation.landscape": "Paisagem", + "orientation.portrait": "Retrato", + "orientation.square": "Quadrado", + + "page.blueprint": "Esta página não tem planta. Você pode definir sua planta em /site/blueprints/pages/{blueprint}.yml", + "page.changeSlug": "Alterar URL", + "page.changeSlug.fromTitle": "Criar a partir do t\u00edtulo", + "page.changeStatus": "Alterar estado", + "page.changeStatus.position": "Selecione uma posição", + "page.changeStatus.select": "Selecione um novo estado", + "page.changeTemplate": "Alterar tema", + "page.delete.confirm": "Deseja realmente excluir {title}?", + "page.delete.confirm.subpages": "Esta página possui subpáginas.
Todas as subpáginas serão excluídas também.", + "page.delete.confirm.title": "Digite o título da página para confirmar", + "page.draft.create": "Criar rascunho", + "page.duplicate.appendix": "Copiar", + "page.duplicate.files": "Copiar arquivos", + "page.duplicate.pages": "Copiar páginas", + "page.sort": "Mudar posição", + "page.status": "Estado", + "page.status.draft": "Rascunho", + "page.status.draft.description": "A página está em modo de rascunho e é visível somente para editores", + "page.status.listed": "Pública", + "page.status.listed.description": "A página é pública para todos", + "page.status.unlisted": "Não listadas", + "page.status.unlisted.description": "Esta página é acessível somente através da URL", + + "pages": "Páginas", + "pages.empty": "Nenhuma página", + "pages.status.draft": "Rascunhos", + "pages.status.listed": "Publicadas", + "pages.status.unlisted": "Não listadas", + + "pagination.page": "Página", + + "password": "Palavra-passe", + "paste": "Colar", + "paste.after": "Colar após", + "pixel": "Pixel", + "plugins": "Plugins", + "prev": "Anterior", + "preview": "Visualizar", + "remove": "Remover", + "rename": "Renomear", + "replace": "Substituir", + "retry": "Tentar novamente", + "revert": "Descartar", + "revert.confirm": "Tem a certeza que pretende eliminar todas as alterações por guardar?", + + "role": "Função", + "role.admin.description": "O administrador tem todas as permissões.", + "role.admin.title": "Administrador", + "role.all": "Todos", + "role.empty": "Não há utilizadores com esta função", + "role.description.placeholder": "Sem descrição", + "role.nobody.description": "Esta é uma função de salvaguarda sem permissões.", + "role.nobody.title": "Ninguém", + + "save": "Salvar", + "search": "Buscar", + "search.min": "Introduza {min} caracteres para pesquisar", + "search.all": "Mostrar todos", + "search.results.none": "Sem resultados", + + "section.required": "Esta seção é necessária", + + "security": "Security", + "select": "Selecionar", + "server": "Servidor", + "settings": "Configurações", + "show": "Mostrar", + "site.blueprint": "Este site não tem planta. Você pode definir sua planta em /site/blueprints/site.yml", + "size": "Tamanho", + "slug": "URL", + "sort": "Ordenar", + + "stats.empty": "No reports", + "system.issues.content": "The content folder seems to be exposed", + "system.issues.debug": "Debugging must be turned off in production", + "system.issues.git": "The .git folder seems to be exposed", + "system.issues.https": "We recommend HTTPS for all your sites", + "system.issues.kirby": "The kirby folder seems to be exposed", + "system.issues.site": "The site folder seems to be exposed", + + "title": "Título", + "template": "Tema", + "today": "Hoje", + + "toolbar.button.code": "Código", + "toolbar.button.bold": "Negrito", + "toolbar.button.email": "Email", + "toolbar.button.headings": "Títulos", + "toolbar.button.heading.1": "Título 1", + "toolbar.button.heading.2": "Título 2", + "toolbar.button.heading.3": "Título 3", + "toolbar.button.heading.4": "Título 4", + "toolbar.button.heading.5": "Título 5", + "toolbar.button.heading.6": "Título 6", + "toolbar.button.italic": "Itálico", + "toolbar.button.file": "Ficheiro", + "toolbar.button.file.select": "Selecione o arquivo", + "toolbar.button.file.upload": "Carregue o arquivo", + "toolbar.button.link": "Link", + "toolbar.button.paragraph": "Parágrafo", + "toolbar.button.strike": "Riscado", + "toolbar.button.ol": "Lista ordenada", + "toolbar.button.underline": "Sublinhado", + "toolbar.button.ul": "Lista não-ordenada", + + "translation.author": "Kirby Team", + "translation.direction": "ltr", + "translation.name": "Português (Europeu)", + "translation.locale": "pt_PT", + + "upload": "Enviar", + "upload.error.cantMove": "Não foi possível mover o arquivo carregado", + "upload.error.cantWrite": "Não foi possível guardar o arquivo no sistema de ficheiros.", + "upload.error.default": "Não foi possível carregar o arquivo", + "upload.error.extension": "A extensão do arquivo não permite o carregamento", + "upload.error.formSize": "O arquivo excede o tamanho MAX_FILE_SIZE", + "upload.error.iniPostSize": "O arquivo excede o tamanho post_max_size", + "upload.error.iniSize": "O arquivo carregado excede a definição upload_max_filesize do php.ini", + "upload.error.noFile": "Nenhum arquivo carregado", + "upload.error.noFiles": "Nenhuns arquivos carregados", + "upload.error.partial": "O arquivo foi parcialmente carregado", + "upload.error.tmpDir": "Pasta temporária em falta", + "upload.errors": "Erro", + "upload.progress": "A enviar…", + + "url": "Url", + "url.placeholder": "https://exemplo.pt", + + "user": "Utilizador", + "user.blueprint": "Você pode definir seções e campos de formulário adicionais para este papel de usuário em /site/blueprints/users/{blueprint}.yml", + "user.changeEmail": "Alterar email", + "user.changeLanguage": "Alterar idioma", + "user.changeName": "Renomear este utilizador", + "user.changePassword": "Alterar palavra-passe", + "user.changePassword.new": "Nova palavra-passe", + "user.changePassword.new.confirm": "Confirme a nova palavra-passe…", + "user.changeRole": "Alterar Função", + "user.changeRole.select": "Selecione uma nova função", + "user.create": "Adicionar novo utilizador", + "user.delete": "Excluir este utilizador", + "user.delete.confirm": "Deseja realmente excluir
{email}?", + + "users": "Utilizadores", + + "version": "Vers\u00e3o do Kirby", + + "view.account": "A sua conta", + "view.installation": "Instala\u00e7\u00e3o", + "view.languages": "Idiomas", + "view.resetPassword": "Redefinir senha", + "view.site": "Site", + "view.system": "Sistema", + "view.users": "Utilizadores", + + "welcome": "Bem-vindo", + "year": "Ano", + "yes": "sim" } diff --git a/kirby/i18n/translations/ro.json b/kirby/i18n/translations/ro.json deleted file mode 100644 index 51cd677..0000000 --- a/kirby/i18n/translations/ro.json +++ /dev/null @@ -1,730 +0,0 @@ -{ - "account.changeName": "Schimbă-ți numele", - "account.delete": "Șterge-ți contul", - "account.delete.confirm": "Chiar vrei să îți ștergi contul? Vei fi deconectat imediat. Contul nu poate fi recuperat.", - - "activate": "Activează", - "add": "Adaug\u0103", - "alpha": "Alfa", - "author": "Autor", - "avatar": "Imagine de profil", - "back": "Înapoi", - "cancel": "Anulează", - "change": "Modific\u0103", - "close": "\u00cenchide", - "changes": "Schimbări", - "confirm": "Ok", - "collapse": "Pliază", - "collapse.all": "Pliază toate", - "color": "Culoare", - "coordinates": "Coordonate", - "copy": "Copiază", - "copy.all": "Copiază toate", - "copy.success": "Copiat {count}!", - "create": "Creează", - "custom": "Personalizat", - - "date": "Data", - "date.select": "Alege o dată", - - "day": "Ziua", - "days.fri": "Vin", - "days.mon": "Lun", - "days.sat": "S\u00e2m", - "days.sun": "Dum", - "days.thu": "Joi", - "days.tue": "Mar", - "days.wed": "Mie", - - "debugging": "Depanare", - - "delete": "\u0218terge", - "delete.all": "Șterge toate", - - "dialog.fields.empty": "Acest dialog nu are niciun câmp", - "dialog.files.empty": "Nu există fișiere de selectat", - "dialog.pages.empty": "Nu există pagini de selectat", - "dialog.text.empty": "Acest dialog nu definește niciun text", - "dialog.users.empty": "Nu există utilizatori de selectat", - - "dimensions": "Dimensiuni", - "disable": "Dezactivați", - "disabled": "Dezactivat", - "discard": "Renun\u021b\u0103", - - "drawer.fields.empty": "Acest sertar nu are niciun câmp", - - "domain": "Domeniu", - "download": "Descarcă", - "duplicate": "Duplică", - - "edit": "Editeaz\u0103", - - "email": "E-mail", - "email.placeholder": "email@exemplu.com", - - "enter": "Introdu", - "entries": "Întregistrări", - "entry": "Înregistrare", - - "environment": "Mediu", - - "error": "Eroare", - "error.access.code": "Cod nevalid", - "error.access.login": "Conectare nevalidă", - "error.access.panel": "Nu ai voie să accesezi panoul", - "error.access.view": "Nu ai voie să accesezi această parte a panoului", - - "error.avatar.create.fail": "Imaginea de profil nu a putut fi încărcată", - "error.avatar.delete.fail": "Imaginea de profil nu a putut fi ștearsă", - "error.avatar.dimensions.invalid": "Păstrează te rog lățimea și înălțimea imaginii de profil sub 3000 de pixeli", - "error.avatar.mime.forbidden": "Imaginea de profil trebuie să fie un fișier JPEG sau PNG", - - "error.blueprint.notFound": "Blueprint-ul \"{name}\" nu a putut fi încărcat", - - "error.blocks.max.plural": "Nu poți adăuga mai mult de {max} blocuri", - "error.blocks.max.singular": "Nu poți adăuga mai mult de un bloc", - "error.blocks.min.plural": "Trebuie să adaugi cel puțin {min} blocuri", - "error.blocks.min.singular": "Trebuie să adaugi cel puțin un bloc", - "error.blocks.validation": "Există o eroare la câmpul \"{field}\" în blocul {index} care folosește tipul de bloc \"{fieldset}\"", - - "error.cache.type.invalid": "Tipul de cache \"{type}\" este nevalid", - - "error.email.preset.notFound": "Preset-ul de e-mail \"{name}\" nu a fost găsit", - - "error.field.converter.invalid": "Convertorul \"{converter}\" nu este valid", - "error.field.type.missing": "Câmpul \"{ name }\": Tipul de câmp \"{ type }\" nu există", - - "error.file.changeName.empty": "Numele nu trebuie să fie gol", - "error.file.changeName.permission": "Nu ai voie să schimbi numele fișierului \"{filename}\"", - "error.file.changeTemplate.invalid": "Șablonul pentru fișierul \"{id}\" nu poate fi schimbat la \"{template}\" (valide: \"{blueprints}\")", - "error.file.changeTemplate.permission": "Nu ai voie să schimbi șablonul pentru fișierul \"{id}\"", - - "error.file.duplicate": "Există deja un fișier cu numele \"{filename}\"", - "error.file.extension.forbidden": "Extensia de fișier \"{extension}\" nu este permisă", - "error.file.extension.invalid": "Extensie de fișier nevalidă: {extension}", - "error.file.extension.missing": "Extensia de fișier pentru \"{filename}\" lipsește", - "error.file.maxheight": "Înălțimea imaginii nu poate depăși {height} pixeli", - "error.file.maxsize": "Fișierul este prea mare", - "error.file.maxwidth": "Lățimea imaginii nu poate depăși {width} pixeli", - "error.file.mime.differs": "Fișierul încărcat trebuie să aibă același tip mime \"{mime}\"", - "error.file.mime.forbidden": "Tipul media \"{mime}\" nu este permis", - "error.file.mime.invalid": "Tip mime nevalid: {mime}", - "error.file.mime.missing": "Tipul media pentru \"{filename}\" nu poate fi detectat", - "error.file.minheight": "Imaginea trebuie să aibă înălțimea de minim {height} pixeli", - "error.file.minsize": "Fișierul este prea mic", - "error.file.minwidth": "Imaginea trebuie să aibă lățimea de minim {width} pixeli", - "error.file.name.unique": "Numele fișierului trebuie să fie unic", - "error.file.name.missing": "Numele fișierului nu poate fi gol", - "error.file.notFound": "Fișierul \"{filename}\" nu a fost găsit", - "error.file.orientation": "Orientarea imaginii trebuie să fie \"{orientation}\"", - "error.file.type.forbidden": "Nu ai voie să încarci fișiere {type}", - "error.file.type.invalid": "Tip nevalid de fișier: {type}", - "error.file.undefined": "Fișierul nu a fost găsit", - - "error.form.incomplete": "Te rog repară toate erorile din formular…", - "error.form.notSaved": "Formularul nu a putut fi salvat", - - "error.language.code": "Te rog introdu un cod valid pentru limbă", - "error.language.duplicate": "Limba există deja", - "error.language.name": "Te rog introdu un nume valid pentru limbă", - "error.language.notFound": "Limba nu a fost găsită", - - "error.layout.validation.block": "Există o eroare la câmpul \"{field}\" în blocul {blockIndex} care utilizează tipul de bloc \"{fieldset}\" în aranjamentul {layoutIndex}", - "error.layout.validation.settings": "Există o eroare la setările aranjamentului {index}", - - "error.license.domain": "Domeniul pentru licență lipsește", - "error.license.email": "Te rog introdu o adresă de e-mail validă", - "error.license.format": "Te rog introdu un cod de licență valid", - "error.license.verification": "Licența nu a putut fi verificată", - - "error.login.totp.confirm.invalid": "Cod nevalid", - "error.login.totp.confirm.missing": "Vă rugăm să introduceți codul curent", - - "error.object.validation": "Există o eroare la câmpul \"{label}\":\n{message}", - - "error.offline": "Panoul este momentan offline", - - "error.page.changeSlug.permission": "Nu ai voie să schimbi apendicele URL pentru \"{slug}\"", - "error.page.changeSlug.reserved": "Calea paginilor de la primul nivel nu poate să înceapă cu \"{path}\"", - "error.page.changeStatus.incomplete": "Pagina are erori și nu poate fi publicată", - "error.page.changeStatus.permission": "Starea acestei pagini nu poate fi schimbată", - "error.page.changeStatus.toDraft.invalid": "Pagina \"{slug}\" nu poate fi schimbată în ciornă", - "error.page.changeTemplate.invalid": "Șablonul paginii \"{slug}\" nu poate fi schimbat", - "error.page.changeTemplate.permission": "Nu ai voie să schimbi șablonul pentru \"{slug}\"", - "error.page.changeTitle.empty": "Titlul nu poate rămâne gol", - "error.page.changeTitle.permission": "Nu ai voie să schimbi titlul pentru \"{slug}\"", - "error.page.create.permission": "Nu ai voie să creezi \"{slug}\"", - "error.page.delete": "Pagina \"{slug}\" nu poate fi ștearsă", - "error.page.delete.confirm": "Te rog introdu titlul paginii pentru a confirma", - "error.page.delete.hasChildren": "Pagina are subpagini și nu poate fi ștearsă", - "error.page.delete.permission": "Nu ai voie să ștergi \"{slug}\"", - "error.page.draft.duplicate": "Există deja o ciornă cu apendicele URL \"{slug}\"", - "error.page.duplicate": "Există deja o pagină cu apendicele URL \"{slug}\"", - "error.page.duplicate.permission": "Nu ai voie să duplici \"{slug}\"", - "error.page.move.ancestor": "Pagina nu poate fi mutată în ea însăși", - "error.page.move.directory": "Directorul de pagini nu poate fi mutat", - "error.page.move.duplicate": "Există deja o sub-pagină cu apendicele URL \"{slug}\"", - "error.page.move.notFound": "Pagina mutată nu a fost găsită", - "error.page.move.permission": "Nu ai voie să muți \"{slug}\"", - "error.page.move.template": "Șablonul \"{template}\" nu este acceptat ca sub-pagină a \"{parent}\"", - "error.page.notFound": "Pagina \"{slug}\" nu a fost găsită", - "error.page.num.invalid": "Te rog introdu un număr de sortare valid. Numerele nu pot fi negative.", - "error.page.slug.invalid": "Te rog introdu un apendice URL valid", - "error.page.slug.maxlength": "Lungimea slug-ului nu poate depăși \"{length}\"", - "error.page.sort.permission": "Pagina \"{slug}\" nu poate fi sortată", - "error.page.status.invalid": "Te rog stabilește o stare validă pentru pagină", - "error.page.undefined": "Pagina nu a fost găsită", - "error.page.update.permission": "Nu ai voie să actualizezi \"{slug}\"", - - "error.section.files.max.plural": "Nu poți avea mai mult de {max} fișiere în secțiunea \"{section}\"", - "error.section.files.max.singular": "Nu poți avea mai mult de un fișier în secțiunea \"{section}\"", - "error.section.files.min.plural": "Secțiunea \"{section}\" are nevoie de cel puțin {min} fișiere", - "error.section.files.min.singular": "Secțiunea \"{section}\" are nevoie de cel puțin un fișier", - - "error.section.pages.max.plural": "Nu poți avea mai mult de {max} pagini în secțiunea \"{section}\"", - "error.section.pages.max.singular": "Nu poți avea mai mult de o pagină în secțiunea \"{section}\"", - "error.section.pages.min.plural": "Secțiunea \"{section}\" are nevoie de cel puțin {min} pagini", - "error.section.pages.min.singular": "Secțiunea \"{section}\" are nevoie de cel puțin o pagină", - - "error.section.notLoaded": "Secțiunea \"{name}\" nu a putut fi încărcată", - "error.section.type.invalid": "Tipul de secțiune \"{type}\" nu este valid", - - "error.site.changeTitle.empty": "Titlul nu poate să rămână gol", - "error.site.changeTitle.permission": "Nu ai voie să schimbi titlul site-ului", - "error.site.update.permission": "Nu ai voie să actualizezi site-ul", - - "error.structure.validation": "Există o eroare la câmpul \"{field}\" pe rândul {index}", - - "error.template.default.notFound": "Șablonul implicit nu există", - - "error.unexpected": "S-a produs o eroare neașteptată! Activează modul depanare pentru mai multe informații: https://getkirby.com/docs/reference/system/options/debug", - - "error.user.changeEmail.permission": "Nu ai voie să schimbi adresa de e-mail a utilizatorului \"{name}\"", - "error.user.changeLanguage.permission": "Nu ai voie să schimbi limba utilizatorului \"{name}\"", - "error.user.changeName.permission": "Nu ai voie să schimbi numele utilizatorului \"{name}\"", - "error.user.changePassword.permission": "Nu ai voie să schimbi parola utilizatorului \"{name}\"", - "error.user.changeRole.lastAdmin": "Rolul ultimului administrator nu poate fi schimbat", - "error.user.changeRole.permission": "Nu ai voie să schimbi rolul utilizatorului \"{name}\"", - "error.user.changeRole.toAdmin": "Nu ai voie să promovezi un utilizator la rolul de administrator", - "error.user.create.permission": "Nu ai voie să creezi acest utilizator", - "error.user.delete": "Utilizatorul \"{name}\" nu poate fi șters", - "error.user.delete.lastAdmin": "Ultimul administrator nu poate fi șters", - "error.user.delete.lastUser": "Ultimul utilizator nu poate fi șters", - "error.user.delete.permission": "Nu ai voie să ștergi utilizatorul \"{name}\"", - "error.user.duplicate": "Există deja un utilizator cu adresa e-mail \"{email}\"", - "error.user.email.invalid": "Te rog introdu o adresă de e-mail validă", - "error.user.language.invalid": "Te rog introdu o limbă validă", - "error.user.notFound": "Utilizatorul \"{name}\" nu a fost găsit", - "error.user.password.excessive": "Te rog introdu o parolă validă. Parolele nu pot fi mai lungi de 1000 de caractere.", - "error.user.password.invalid": "Te rog introdu o parolă validă. Parola trebuie să aibă cel puțin 8 caractere.", - "error.user.password.notSame": "Parolele nu se potrivesc", - "error.user.password.undefined": "Utilizatorul nu are parolă", - "error.user.password.wrong": "Parolă greșită", - "error.user.role.invalid": "Te rog introdu un rol valid", - "error.user.undefined": "Utilizatorul nu a fost găsit", - "error.user.update.permission": "Nu ai voie să actualizezi utilizatorul \"{name}\"", - - "error.validation.accepted": "Te rog confirmă", - "error.validation.alpha": "Te rog introdu doar caractere din intervalul a-z", - "error.validation.alphanum": "Te rog introdu doar caractere din intervalul a-z sau cifre 0-9", - "error.validation.anchor": "Te rog introdu o ancoră corectă pentru legătură", - "error.validation.between": "Te rog introdu o valoare între \"{min}\" și \"{max}\"", - "error.validation.boolean": "Te rog confirmă sau refuză", - "error.validation.color": "Te rog introdu o culoare validă în formatul {format}", - "error.validation.contains": "Te rog introdu o valoare care conține \"{needle}\"", - "error.validation.date": "Te rog introdu o dată validă", - "error.validation.date.after": "Te rog introdu o dată după {date}", - "error.validation.date.before": "Te rog introdu o dată dinainte de {date}", - "error.validation.date.between": "Te rog introdu o dată între {min} și {max}", - "error.validation.denied": "Te rog refuză", - "error.validation.different": "Valoarea nu poate fi \"{other}\"", - "error.validation.email": "Te rog introdu o adresă de e-mail validă", - "error.validation.endswith": "Valoarea nu se poate termina cu \"{end}\"", - "error.validation.filename": "Te rog introdu un nume valid de fișier", - "error.validation.in": "Te rog introdu una dintre următoarele: ({in})", - "error.validation.integer": "Te rog introdu un număr întreg valid", - "error.validation.ip": "Te rog introdu o adresă IP validă", - "error.validation.less": "Te rog introdu o valoare mai mică decât {max}", - "error.validation.linkType": "Tipul de legătură nu este permis", - "error.validation.match": "Valoarea nu se potrivește cu forma așteptată", - "error.validation.max": "Te rog introdu o valoare mai mică sau egală cu {max}", - "error.validation.maxlength": "Te rog introdu o valoare mai scurtă. (max. {max} caractere)", - "error.validation.maxwords": "Te rog nu introduce mai mult de {max} cuvinte.", - "error.validation.min": "Te rog introdu o valoare mai mare sau egală cu {min}", - "error.validation.minlength": "Te rog introdu o valoare mai lungă. (min. {min} caractere)", - "error.validation.minwords": "Te rog introdu cel puțin {min} cuvinte", - "error.validation.more": "Te rog introdu o valoare mai mare decât {min}", - "error.validation.notcontains": "Te rog introdu o valoare care să nu conțină \"{needle}\"", - "error.validation.notin": "Te rog nu introduce niciuna dintre următoarele: ({notIn})", - "error.validation.option": "Te rog alege o opțiune validă", - "error.validation.num": "Te rog introdu un număr valid", - "error.validation.required": "Te rog introdu ceva", - "error.validation.same": "Te rog introdu \"{other}\"", - "error.validation.size": "Dimensiunea valorii trebuie să fie \"{size}\"", - "error.validation.startswith": "Valoarea trebuie să înceapă cu \"{start}\"", - "error.validation.tel": "Te rog introdu un număr de telefon neformatat", - "error.validation.time": "Te rog introdu un timp valid", - "error.validation.time.after": "Te rog introdu un timp după {time}", - "error.validation.time.before": "Te rog introdu un timp înainte de {time}", - "error.validation.time.between": "Te rog introdu un timp între {min} și {max}", - "error.validation.uuid": "Te rog introdu un UUID valid", - "error.validation.url": "Te rog introdu un URL valid", - - "expand": "Extinde", - "expand.all": "Extinde toate", - - "field.invalid": "Câmpul este nevalid", - "field.required": "Acest câmp este necesar", - "field.blocks.changeType": "Schimbă tipul", - "field.blocks.code.name": "Cod", - "field.blocks.code.language": "Limba", - "field.blocks.code.placeholder": "Codul tău …", - "field.blocks.delete.confirm": "Chiar vrei să ștergi acest bloc?", - "field.blocks.delete.confirm.all": "Chiar vrei să ștergi toate blocurile?", - "field.blocks.delete.confirm.selected": "Chiar vrei să ștergi blocurile selectate?", - "field.blocks.empty": "Niciun bloc deocamdată", - "field.blocks.fieldsets.empty": "Niciun set de câmpuri încă", - "field.blocks.fieldsets.label": "Te rog alege un tip de bloc …", - "field.blocks.fieldsets.paste": "Apasă {{ shortcut }} pentru a importa aranjamente/blocuri din clipboard Doar cele permise pentru câmpul curent vor fi inserate.", - "field.blocks.gallery.name": "Galerie", - "field.blocks.gallery.images.empty": "Nicio imagine deocamdată", - "field.blocks.gallery.images.label": "Imagini", - "field.blocks.heading.level": "Nivel", - "field.blocks.heading.name": "Subtitlu", - "field.blocks.heading.text": "Text", - "field.blocks.heading.placeholder": "Subtitlu …", - "field.blocks.image.alt": "Text alternativ", - "field.blocks.image.caption": "Etichetă", - "field.blocks.image.crop": "Decupaj", - "field.blocks.image.link": "Legătură", - "field.blocks.image.location": "Localizare", - "field.blocks.image.location.internal": "Acest website", - "field.blocks.image.location.external": "Sursă externă", - "field.blocks.image.name": "Imagine", - "field.blocks.image.placeholder": "Alege o imagine", - "field.blocks.image.ratio": "Raport", - "field.blocks.image.url": "URL-ul imaginii", - "field.blocks.line.name": "Linie", - "field.blocks.list.name": "Listă", - "field.blocks.markdown.name": "Markdown", - "field.blocks.markdown.label": "Text", - "field.blocks.markdown.placeholder": "Markdown …", - "field.blocks.quote.name": "Citat", - "field.blocks.quote.text.label": "Text", - "field.blocks.quote.text.placeholder": "Citat …", - "field.blocks.quote.citation.label": "Citare", - "field.blocks.quote.citation.placeholder": "de …", - "field.blocks.text.name": "Text", - "field.blocks.text.placeholder": "Text …", - "field.blocks.video.autoplay": "Autoredare", - "field.blocks.video.caption": "Etichetă", - "field.blocks.video.controls": "Controale", - "field.blocks.video.location": "Localizare", - "field.blocks.video.loop": "În buclă", - "field.blocks.video.muted": "Fără sonor", - "field.blocks.video.name": "Video", - "field.blocks.video.placeholder": "Introdu URL-ul video-ului", - "field.blocks.video.poster": "Poster", - "field.blocks.video.preload": "Preîncarcă", - "field.blocks.video.url.label": "URL-ul video-ului", - "field.blocks.video.url.placeholder": "https://youtube.com/?v=", - - "field.files.empty": "Niciun fișier selectat deocamdată", - - "field.layout.change": "Schimbă aranjament", - "field.layout.delete": "Șterge aranjamentul", - "field.layout.delete.confirm": "Chiar vrei să ștergi acest aranjament?", - "field.layout.delete.confirm.all": "Chiar vrei să ștergi toate aranjamentele?", - "field.layout.empty": "Niciun rând deocamdată", - "field.layout.select": "Alege un aranjament", - - "field.object.empty": "Nicio informație deocamdată", - - "field.pages.empty": "Nicio pagină aleasă deocamdată", - - "field.structure.delete.confirm": "Chiar vrei să ștergi acest rând?", - "field.structure.delete.confirm.all": "Chiar vrei să ștergi toate înregistrările?", - "field.structure.empty": "Nicio înregistrare deocamdată", - - "field.users.empty": "Niciun utilizator ales deocamdată", - - "fields.empty": "Niciun câmp deocamdată", - - "file": "Fișier", - "file.blueprint": "Acest fișier nu are încă un Blueprint. Poți să-l definești în /site/blueprints/files/{blueprint}.yml", - "file.changeTemplate": "Schimbă șablonul", - "file.changeTemplate.notice": "Schimbarea șablonului fișierului va înlătura conținutul câmpurilor care nu se potrivesc ca tip. Dacă noul șablon definește anumite reguli, de ex. dimensiuni de imagini, acestea vor fi de asemenea aplicate în mod ireversibil. Folosiți cu prudență.", - "file.delete.confirm": "Chiar vrei să ștergi
{filename}?", - "file.focus.placeholder": "Stabilește punct focal", - "file.focus.reset": "Înlătură punct focal", - "file.focus.title": "Focalizare", - "file.sort": "Schimbă poziția", - - "files": "Fișiere", - "files.empty": "Niciun fișier deocamdată", - - "filter": "Filtru", - - "hide": "Ascunde", - "hour": "Ora", - "hue": "Nuanță", - "import": "Importă", - "info": "Informații", - "insert": "Inserează", - "insert.after": "Inserează după", - "insert.before": "Inserează înainte", - "install": "Instalează", - - "installation": "Instalare", - "installation.completed": "Panoul a fost instalat", - "installation.disabled": "Instalarea panoului este dezactivată în mod implicit pe servere publice. Te rog rulează instalarea pe o mașină locală sau activează-l cu opțiunea panel.install.", - "installation.issues.accounts": "Directorul /site/accounts nu există sau nu are permisiuni de scriere.", - "installation.issues.content": "Directorul /content nu există sau nu are permisiuni de scriere.", - "installation.issues.curl": "Extensia CURL este necesară", - "installation.issues.headline": "Panoul nu poate fi instalat", - "installation.issues.mbstring": "Extensia MB String este necesară", - "installation.issues.media": "Directorul /media nu există sau nu are permisiuni de scriere", - "installation.issues.php": "Asigură-te că folosești PHP 8+", - "installation.issues.sessions": "Directorul /site/sessions folder nu există sau nu are permisiuni de scriere", - - "language": "Limba", - "language.code": "Cod", - "language.convert": "Stabilește ca implicit", - "language.convert.confirm": "

Chiar vrei să transformi {name} în limba implicită? Această modificare este ireversibilă.

Dacă {name} are conținut netradus, unele părți din site s-ar putea să nu mai aibă conținut de rezervă, și vor apărea goale.

", - "language.create": "Adaugă o limbă nouă", - "language.default": "Limba implicită", - "language.delete.confirm": "Chiar vrei să ștergi limba {name}, inclusiv toate traducerile? Această operațiune este ireversibilă.", - "language.deleted": "Limba a fost ștearsă", - "language.direction": "Direcția de citire", - "language.direction.ltr": "De la stânga la dreapta", - "language.direction.rtl": "De la dreapta la stânga", - "language.locale": "String-ul PHP locale", - "language.locale.warning": "Folosești pentru localizare o formulă manuală. Modificările le poți face în fișierul de limbă în /site/languages", - "language.name": "Nume", - "language.secondary": "Limbă secundară", - "language.settings": "Reglaje limbă", - "language.updated": "Limba a fost actualizată", - "language.variables": "Variabile limbă", - "language.variables.empty": "Nicio traducere deocamdată", - - "language.variable.delete.confirm": "Chiar vrei să ștergi variabila pentru {key}?", - "language.variable.key": "Cheie", - "language.variable.notFound": "Variabila nu a fost găsită", - "language.variable.value": "Valoare", - - "languages": "Limbi", - "languages.default": "Limba implicită", - "languages.empty": "Nu există limbi deocamdată", - "languages.secondary": "Limbi secundare", - "languages.secondary.empty": "Nu există limbi secundare deocamdată.", - - "license": "Licența", - "license.activate": "Activați acum", - "license.activate.label": "Vă rugăm să activați licența", - "license.activate.domain": "Licența va fi activată pentru {host}.", - "license.activate.local": "Sunteți pe cale să activați licența Kirby pentru domeniul local {host}. Dacă acest site va fi implementat pe un domeniu public, vă rugăm să o activați acolo în schimb. Dacă {host} este domeniul pentru care doriți să utilizați licența, vă rugăm să continuați.", - "license.activated": "Activată", - "license.buy": "Cumpără o licență", - "license.code": "Cod", - "license.code.help": "Ați primit codul de licență după achiziție prin e-mail. Vă rugăm să-l copiați și să-l inserezi aici.", - "license.code.label": "Te rog introdu codul tău de licență", - "license.status.active.info": "Include noi versiuni majore până la data de {date}", - "license.status.active.label": "Licență validă", - "license.status.demo.info": "Aceasta este o instalare demo", - "license.status.demo.label": "Demo", - "license.status.inactive.info": "Reînnoiți licența pentru a actualiza la noile versiuni majore", - "license.status.inactive.label": "Fără noi versiuni majore", - "license.status.legacy.bubble": "Sunteți pregătit să reînnoiți licența?", - "license.status.legacy.info": "Licența dvs. nu acoperă această versiune", - "license.status.legacy.label": "Vă rugăm să reînnoiți licența", - "license.status.missing.bubble": "Sunteți pregătit să lansați site-ul?", - "license.status.missing.info": "Licență nevalidă", - "license.status.missing.label": "Vă rugăm să activați licența", - "license.manage": "Gestionează-ți licențele", - "license.purchased": "Achiziționat", - "license.success": "Mulțumim că susții Kirby", - "license.unregistered.label": "Neînregistrat", - - "link": "Legătură", - "link.text": "Textul legăturii", - - "loading": "Se încarcă", - - "lock.unsaved": "Schimbări nesalvate", - "lock.unsaved.empty": "Nu mai există nicio schimbare nesalvată", - "lock.isLocked": "Schimbări nesalvate de {email}", - "lock.unlock": "Deblochează", - "lock.unlock.submit": "Deblochează și suprascrie schimbările nesalvate de {email}", - "lock.isUnlocked": "A fost deblocată de alt utilizator", - - "login": "Conectează-te", - "login.code.label.login": "Cod de conectare", - "login.code.label.password-reset": "Cod de restabilire parolă", - "login.code.placeholder.email": "000 000", - "login.code.placeholder.totp": "000000", - "login.code.text.email": "Dacă adresa de e-mail este înregistrată, codul cerut a fost trimis pe adresă.", - "login.code.text.totp": "Vă rugăm să introduceți codul unic de pe aplicația dvs. de autentificare.", - "login.email.login.body": "Salut {user.nameOrEmail},\n\nAi cerut recent un cod de conectare pentru Panoul site-ului {site}.\nCodul de conectare de mai jos va fi valid pentru următoarele {timeout} minute:\n\n{code}\n\nDacă nu tu ai cerut un cod de conectare, te rog ignoră acest e-mail sau ia legătura cu administratorul site-ului dacă ai întrebări.\nDin motive de siguranță, te rog să NU trimiți acest email mai departe.", - "login.email.login.subject": "Codul tău de conectare", - "login.email.password-reset.body": "Salut {user.nameOrEmail},\n\nAi cerut recent un cod de restabilire a parolei pentru Panoul site-ului {site}.\nCodul de restabilire a parolei de mai jos este valabil pentru următoarele {timeout} minute:\n\n{code}\n\nDacă nu tu ai cerut codul de restabilire a parolei, te rog ignoră acest e-mail sau ia legătura cu administratorul site-ului dacă ai întrebări.\nDin motive de securitate, te rog să NU trimiți acest e-mail mai departe.", - "login.email.password-reset.subject": "Codul tău de restabilire a parolei", - "login.remember": "Ține-mă conectat", - "login.reset": "Restabilește parola", - "login.toggleText.code.email": "Conectare prin e-mail", - "login.toggleText.code.email-password": "Conectare cu parola", - "login.toggleText.password-reset.email": "Ți-ai uitat parola?", - "login.toggleText.password-reset.email-password": "← Înapoi la conectare", - "login.totp.enable.option": "Configurați codurile de unică folosință", - "login.totp.enable.intro": "Aplicațiile de autentificare pot genera coduri de unică folosință utilizate ca al doilea factor la autentificarea în contul dvs.", - "login.totp.enable.qr.label": "1. Scanați acest cod QR", - "login.totp.enable.qr.help": "Nu puteți scana? Adăugați manual cheia de configurare {secret} în aplicația dvs. de autentificare.", - "login.totp.enable.confirm.headline": "2. Confirmați cu codul generat", - "login.totp.enable.confirm.text": "Aplicația dvs. generează un nou cod de unică folosință la fiecare 30 de secunde. Introduceți codul curent pentru a finaliza configurarea:", - "login.totp.enable.confirm.label": "Cod curent", - "login.totp.enable.confirm.help": "După această configurare, vă vom solicita un cod de unică folosință de fiecare dată când vă autentificați.", - "login.totp.enable.success": "Codurile de unică folosință activate", - "login.totp.disable.option": "Dezactivați codurile de unică folosință", - "login.totp.disable.label": "Introduceți parola pentru a dezactiva codurile de unică folosință", - "login.totp.disable.help": "În viitor, va fi solicitat un al doilea factor diferit, cum ar fi un cod de autentificare trimis prin e-mail, atunci când vă autentificați. Puteți configura din nou codurile de unică folosință oricând mai târziu.", - "login.totp.disable.admin": "

Această acțiune va dezactiva codurile de unică folosință pentru {user}.

În viitor, se va solicita un al doilea factor diferit, cum ar fi un cod de autentificare trimis prin e-mail, atunci când se autentifică. {user} poate configura din nou codurile de unică folosință după următoarea autentificare.", - "login.totp.disable.success": "Codurile de unică folosință dezactivate", - - "logout": "Deconectare", - - "merge": "Îmbină", - "menu": "Meniu", - "meridiem": "AM/PM", - "mime": "Tipul media", - "minutes": "Minute", - - "month": "Luna", - "months.april": "Aprilie", - "months.august": "August", - "months.december": "Decembrie", - "months.february": "Februarie", - "months.january": "Ianuarie", - "months.july": "Iulie", - "months.june": "Iunie", - "months.march": "Martie", - "months.may": "Mai", - "months.november": "Noiembrie", - "months.october": "Octombrie", - "months.september": "Septembrie", - - "more": "Mai multe", - "move": "Mută", - "name": "Nume", - "next": "Următoarea", - "night": "Noapte", - "no": "nu", - "off": "oprit", - "on": "pornit", - "open": "Deschide", - "open.newWindow": "Deschide în fereastră nouă", - "option": "Opțiune", - "options": "Opțiuni", - "options.none": "Nicio opțiune", - "options.all": "Afișați toate {count} opțiunile", - - "orientation": "Orientare", - "orientation.landscape": "Landscape", - "orientation.portrait": "Portrait", - "orientation.square": "Pătrată", - - "page": "Pagină", - "page.blueprint": "Această pagină nu are încă un Blueprint. Poți să-l definești în /site/blueprints/pages/{blueprint}.yml", - "page.changeSlug": "Schimbă URL-ul", - "page.changeSlug.fromTitle": "Creează din titlu", - "page.changeStatus": "Schimbă starea", - "page.changeStatus.position": "Te rog alege o poziție", - "page.changeStatus.select": "Alege o stare nouă", - "page.changeTemplate": "Schimbă șablonul", - "page.changeTemplate.notice": "Schimbarea șablonului paginii va înlătura conținutul câmpurilor care nu se potrivesc ca tip. Folosește cu prudență.", - "page.create": "Creează ca {status}", - "page.delete.confirm": "Chiar vrei să ștergi {title}?", - "page.delete.confirm.subpages": "Această pagină are subpagini.
Subpaginile vor fi de asemenea toate șterse.", - "page.delete.confirm.title": "Introdu titlul paginii pentru a confirma", - "page.duplicate.appendix": "Copiază", - "page.duplicate.files": "Copiază fișierele", - "page.duplicate.pages": "Copiază paginile", - "page.move": "Mută pagina", - "page.sort": "Schimbă poziția", - "page.status": "Stare", - "page.status.draft": "Ciornă", - "page.status.draft.description": "Pagina este în modul ciornă și va fi vizibilă doar editorilor conectați sau printr-un link secret", - "page.status.listed": "Publică", - "page.status.listed.description": "Pagina este publică, accesibilă oricui", - "page.status.unlisted": "Nelistată", - "page.status.unlisted.description": "Pagina este accesibilă doar prin URL", - - "pages": "Pagini", - "pages.empty": "Nicio pagină deocamdată", - "pages.status.draft": "Ciorne", - "pages.status.listed": "Publicate", - "pages.status.unlisted": "Nelistate", - - "pagination.page": "Pagină", - - "password": "Parola", - "paste": "Inserează", - "paste.after": "Inserează după", - "paste.success": "inserate {count}!", - "pixel": "Pixel", - "plugin": "Plugin", - "plugins": "Plugin-uri", - "prev": "Precedenta", - "preview": "Previzualizează", - "remove": "Înlătură", - "rename": "Redenumește", - "renew": "Reînnoiți", - "replace": "\u00cenlocuie\u0219te", - "replace.with": "Înlocuiește cu", - "retry": "Încearcă din nou", - "revert": "Renunță", - "revert.confirm": "Chiar vrei să ștergi toate schimbările nesalvate?", - - "role": "Rol", - "role.admin.description": "Administratorul are toate drepturile", - "role.admin.title": "Administrator", - "role.all": "Toate", - "role.empty": "Nu există niciun utilizator cu acest rol", - "role.description.placeholder": "Nicio descriere", - "role.nobody.description": "Acesta este un rol de rezervă fără nicio permisiune.", - "role.nobody.title": "Nimeni", - - "save": "Salveaz\u0103", - "search": "Caută", - "search.min": "Introdu {min} caractere pentru a căuta", - "search.all": "Afișați toate {count} rezultatele", - "search.results.none": "Niciun rezultat", - - "section.invalid": "Secțiunea este nevalidă", - "section.required": "Această secțiune este necesară", - - "security": "Securitate", - "select": "Alege", - "server": "Server", - "settings": "Reglaje", - "show": "Arată", - "site.blueprint": "Site-ul nu are încă un Blueprint. Poți să-l definești în /site/blueprints/site.yml", - "size": "Dimensiune", - "slug": "Apendicele URL", - "sort": "Sortare", - "sort.drag": "Trage pt. a sorta …", - "split": "Împarte", - - "stats.empty": "Niciun raport", - "status": "Stare", - - "system.info.copy": "Copy info", - "system.info.copied": "System info copied", - "system.issues.content": "Directorul de conținut pare să fie expus", - "system.issues.eol.kirby": "Versiunea instalată de Kirby a ajuns la sfârșitul vieții utile și nu va mai primi actualizări de securitate.", - "system.issues.eol.plugin": "Versiunea instalată a plugin-ului { plugin } a ajuns la sfârșitul vieții utile și nu va mai primi actualizări de securitate.", - "system.issues.eol.php": "Versiunea PHP instalată { release } a ajuns la sfârșitul vieții și nu va mai primi actualizări de securitate", - "system.issues.debug": "Modul depanare trebuie să fie oprit în producție", - "system.issues.git": "Directorul .git pare să fie expus", - "system.issues.https": "Recomandăm HTTPS pentru toate site-urile.", - "system.issues.kirby": "Directorul Kirby pare să fie expus", - "system.issues.site": "Directorul site pare să fie expus", - "system.issues.vulnerability.kirby": "Instalarea ta ar putea fi afectată de următoarea vulnerabilitate ({ severity } severity): { description }", - "system.issues.vulnerability.plugin": "Instalarea ta ar putea fi afectată de următoarea vulnerabilitate în plugin-ul { plugin } ({ severity } severity): { description }", - "system.updateStatus": "Starea actualizării", - "system.updateStatus.error": "Nu am putut căuta actualizări", - "system.updateStatus.not-vulnerable": "Nicio vulnerabilitate cunoscută", - "system.updateStatus.security-update": "Actualizare gratuită de securitate { version } disponibilă", - "system.updateStatus.security-upgrade": "Actualizarea { version } cu reparații de securitate disponibilă", - "system.updateStatus.unreleased": "Versiune nelansată", - "system.updateStatus.up-to-date": "La zi", - "system.updateStatus.update": "Actualizare gratuită { version } disponibilă", - "system.updateStatus.upgrade": "Actualizare { version } disponibilă", - - "tel": "Telefon", - "tel.placeholder": "+40123456789", - "template": "Șablon", - "title": "Titlu", - "today": "Astăzi", - - "toolbar.button.clear": "Elimină formatarea", - "toolbar.button.code": "Cod", - "toolbar.button.bold": "Bold", - "toolbar.button.email": "Adresă e-mail", - "toolbar.button.headings": "Subtitluri", - "toolbar.button.heading.1": "Subtitlu 1", - "toolbar.button.heading.2": "Subtitlu 2", - "toolbar.button.heading.3": "Subtitlu 3", - "toolbar.button.heading.4": "Subtitlu 4", - "toolbar.button.heading.5": "Subtitlu 5", - "toolbar.button.heading.6": "Subtitlu 6", - "toolbar.button.italic": "Italic", - "toolbar.button.file": "Fișier", - "toolbar.button.file.select": "Alege un fișier", - "toolbar.button.file.upload": "Încarcă un fișier", - "toolbar.button.link": "Link", - "toolbar.button.paragraph": "Paragraf", - "toolbar.button.strike": "Tăiat", - "toolbar.button.sub": "Indice", - "toolbar.button.sup": "Exponent", - "toolbar.button.ol": "Listă ordonată", - "toolbar.button.underline": "Subliniat", - "toolbar.button.ul": "Listă cu puncte", - - "translation.author": "Echipa Kirby", - "translation.direction": "ltr", - "translation.name": "Rom\u00e2n\u0103", - "translation.locale": "ro_RO", - - "type": "Tip", - - "upload": "Încarcă", - "upload.error.cantMove": "Fișierul încărcat nu a putut fi mutat", - "upload.error.cantWrite": "Nu s-a putut scrie fișierul pe disc", - "upload.error.default": "Fișierul nu a putut fi încărcat", - "upload.error.extension": "Încărcarea fișierelor oprită de extensie", - "upload.error.formSize": "Fișierul încărcat depășește directiva MAX_FILE_SIZE specificată în formular", - "upload.error.iniPostSize": "Fișierul încărcat depășește directiva post_max_size din php.ini", - "upload.error.iniSize": "Fișierul încărcat depășește directiva upload_max_filesize din php.ini", - "upload.error.noFile": "Nu a fost încărcat niciun fișier", - "upload.error.noFiles": "Nu au fost încărcate fișiere", - "upload.error.partial": "Fișierul a fost încărcat doar parțial", - "upload.error.tmpDir": "Lipsește un director temporar", - "upload.errors": "Eroare", - "upload.progress": "Se încarcă...", - - "url": "Url", - "url.placeholder": "https://example.com", - - "user": "Utilizator", - "user.blueprint": "Poți defini secțiuni și câmpuri de formular suplimentare pentru acest rol de utilizator în /site/blueprints/users/{blueprint}.yml", - "user.changeEmail": "Schimbă adresa de e-mail", - "user.changeLanguage": "Schimbă limba", - "user.changeName": "Redenumește acest utilizator", - "user.changePassword": "Schimbă parola", - "user.changePassword.new": "Parola nouă", - "user.changePassword.new.confirm": "Confirmă parola nouă...", - "user.changeRole": "Schimbă rolul", - "user.changeRole.select": "Alege un rol nou", - "user.create": "Adaugă un nou utilizator", - "user.delete": "Șterge acest utilizator", - "user.delete.confirm": "Chiar vrei să ștergi
{email}?", - - "users": "Utilizatori", - - "version": "Versiune", - "version.current": "Versiunea curentă", - "version.latest": "Ultima versiune", - "versionInformation": "Informații despre versiune", - - "view.account": "Contul t\u0103u", - "view.installation": "Instalare", - "view.languages": "Limbi", - "view.resetPassword": "Restabilește parola", - "view.site": "Site", - "view.system": "Sistem", - "view.users": "Utilizatori", - - "welcome": "Bun venit", - "year": "Anul", - "yes": "da" -} diff --git a/kirby/i18n/translations/ru.json b/kirby/i18n/translations/ru.json index 4d4e859..5eb589d 100644 --- a/kirby/i18n/translations/ru.json +++ b/kirby/i18n/translations/ru.json @@ -1,730 +1,574 @@ { - "account.changeName": "Изменить имя", - "account.delete": "Удалить пользователя", - "account.delete.confirm": "Вы действительно хотите удалить свой аккаунт? Вы сразу покинете панель управления, а аккаунт нельзя будет восстановить.", - - "activate": "Активировать", - "add": "\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c", - "alpha": "Альфа", - "author": "Автор", - "avatar": "\u0410\u0432\u0430\u0442\u0430\u0440 (\u0444\u043e\u0442\u043e)", - "back": "Назад", - "cancel": "\u041e\u0442\u043c\u0435\u043d\u0438\u0442\u044c", - "change": "\u0418\u0437\u043c\u0435\u043d\u0438\u0442\u044c", - "close": "\u0417\u0430\u043a\u0440\u044b\u0442\u044c", - "changes": "Изменения", - "confirm": "Ок", - "collapse": "Свернуть", - "collapse.all": "Свернуть все", - "color": "Цвет", - "coordinates": "Координаты", - "copy": "Скопировать", - "copy.all": "Копировать все", - "copy.success": "{count} скопировано", - "create": "Создать", - "custom": "Другое", - - "date": "Дата", - "date.select": "Выберите дату", - - "day": "День", - "days.fri": "\u041f\u0442", - "days.mon": "\u041f\u043d", - "days.sat": "\u0421\u0431", - "days.sun": "\u0412\u0441", - "days.thu": "\u0427\u0442", - "days.tue": "\u0412\u0442", - "days.wed": "\u0421\u0440", - - "debugging": "Отладка", - - "delete": "\u0423\u0434\u0430\u043b\u0438\u0442\u044c", - "delete.all": "Удалить все", - - "dialog.fields.empty": "Для этого окна нет полей", - "dialog.files.empty": "Нет файлов для выбора", - "dialog.pages.empty": "Нет страниц для выбора", - "dialog.text.empty": "Окно не содержит никакого текста", - "dialog.users.empty": "Нет пользователей для выбора", - - "dimensions": "Размеры", - "disable": "Отключить", - "disabled": "Отключено", - "discard": "\u0421\u0431\u0440\u043e\u0441", - - "drawer.fields.empty": "Нет полей", - - "domain": "Домен", - "download": "Скачать", - "duplicate": "Дублировать", - - "edit": "\u041d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c", - - "email": "Email", - "email.placeholder": "mail@example.com", - - "enter": "Введите", - "entries": "Записи", - "entry": "Запись", - - "environment": "Среда", - - "error": "Ошибка", - "error.access.code": "Неверный код", - "error.access.login": "Неверный логин или пароль", - "error.access.panel": "У вас нет права доступа к панели", - "error.access.view": "У вас нет прав доступа к этой части панели", - - "error.avatar.create.fail": "Не удалось загрузить фотографию профиля", - "error.avatar.delete.fail": "\u0410\u0432\u0430\u0442\u0430\u0440 (\u0444\u043e\u0442\u043e) \u043a \u0430\u043a\u043a\u0430\u0443\u043d\u0442\u0443 \u043d\u0435 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0443\u0434\u0430\u043b\u0435\u043d", - "error.avatar.dimensions.invalid": "Пожалуйста, сделайте чтобы ширина или высота фотографии была меньше 3000 пикселей", - "error.avatar.mime.forbidden": "Фотография профиля должна быть JPEG или PNG", - - "error.blueprint.notFound": "Не удалось загрузить разметку \"{name}\"", - - "error.blocks.max.plural": "Вы не можете добавить больше {max} блоков", - "error.blocks.max.singular": "Вы не можете добавить больше одного блока", - "error.blocks.min.plural": "Вы должны добавить хотя бы {min} блоков", - "error.blocks.min.singular": "Вы должны добавить хотя бы один блок", - "error.blocks.validation": "Ошибка в поле \"{field}\" в блоке {index} типа \"{fieldset}\"", - - "error.cache.type.invalid": "Неверный тип кэша: \"{type}\"", - - "error.email.preset.notFound": "Email-шаблон \"{name}\" не найден", - - "error.field.converter.invalid": "Неверный конвертер \"{converter}\"", - "error.field.type.missing": "Поле \"{ name }\": тип поля \"{ type }\" не существует", - - "error.file.changeName.empty": "Название не может быть пустым", - "error.file.changeName.permission": "У вас нет права изменить название \"{filename}\"", - "error.file.changeTemplate.invalid": "Шаблон для файла \"{id}\" не может быть изменен на \"{template}\" (допускается: \"{blueprints}\")", - "error.file.changeTemplate.permission": "У вас нет права изменять шаблон для файла \"{id}\"", - - "error.file.duplicate": "Файл с названием \"{filename}\" уже есть", - "error.file.extension.forbidden": "Расширение файла \"{extension}\" неразрешено", - "error.file.extension.invalid": "Неверное разрешение: {extension}", - "error.file.extension.missing": "Файлу \"{filename}\" не хватает расширения", - "error.file.maxheight": "Высота изображения не должна превышать {height} px", - "error.file.maxsize": "Файл слишком большой", - "error.file.maxwidth": "Ширина изображения не должна превышать {width} px", - "error.file.mime.differs": "Загружаемый файл должен иметь такое же расширение (тип): \"{mime}\"", - "error.file.mime.forbidden": "Расширение (тип) \"{mime}\" не допускается", - "error.file.mime.invalid": "Неверное расширение (тип): {mime}", - "error.file.mime.missing": "Не удалось определить тип медиа для файла \"{filename}\"", - "error.file.minheight": "Высота файла должна быть хотя бы {height} px", - "error.file.minsize": "Файл слишком маленький", - "error.file.minwidth": "Ширина файла должна быть хотя бы {width} px", - "error.file.name.unique": "Название файла должно быть уникальным", - "error.file.name.missing": "Название файла не может быть пустым", - "error.file.notFound": "\u0424\u0430\u0439\u043b \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d", - "error.file.orientation": "Ориентация изображения должна быть \"{orientation}\"", - "error.file.type.forbidden": "У вас нет права загружать файлы {type}", - "error.file.type.invalid": "Неверный тип файла: {type}", - "error.file.undefined": "\u0424\u0430\u0439\u043b \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d", - - "error.form.incomplete": "Пожалуйста, исправьте все ошибки в форме", - "error.form.notSaved": "Форма не может быть сохранена", - - "error.language.code": "Пожалуйста, впишите правильный код языка", - "error.language.duplicate": "Язык уже есть", - "error.language.name": "Пожалуйста, впишите правильное название языка", - "error.language.notFound": "Не получилось найти этот язык", - - "error.layout.validation.block": "Ошибка в поле \"{field}\" в блоке {blockIndex} типа \"{fieldset}\" внутри разметки {layoutIndex}", - "error.layout.validation.settings": "Ошибка в настройках макета {index}", - - "error.license.domain": "Лицензия на этот домен отсутствует", - "error.license.email": "Пожалуйста, введите правильный Email", - "error.license.format": "Пожалуйста, введите правильный лицензионный код", - "error.license.verification": "Лицензия не подтверждена", - - "error.login.totp.confirm.invalid": "Неверный код", - "error.login.totp.confirm.missing": "Пожалуйста, введите текущий код", - - "error.object.validation": "Ошибка в поле \"{label}\":\n{message}", - - "error.offline": "Панель управления не в сети", - - "error.page.changeSlug.permission": "\u0412\u044b \u043d\u0435 \u043c\u043e\u0436\u0435\u0442\u0435 \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c URL \u044d\u0442\u043e\u0439 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b", - "error.page.changeSlug.reserved": "Путь к страницам верхнего уровня не должен начинаться с \"{path}\"", - "error.page.changeStatus.incomplete": "На странице есть ошибки и поэтому ее нельзя опубликовать", - "error.page.changeStatus.permission": "Невозможно изменить статус для этой страницы", - "error.page.changeStatus.toDraft.invalid": "Невозможно конвертировать в черновик страницу \"{slug}\"", - "error.page.changeTemplate.invalid": "Невозможно изменить шаблон страницы \"{slug}\"", - "error.page.changeTemplate.permission": "У вас нет права изменять шаблон для \"{slug}\"", - "error.page.changeTitle.empty": "Название не может быть пустым", - "error.page.changeTitle.permission": "у вас нет права изменять название \"{slug}\"", - "error.page.create.permission": "У вас нет права создать \"{slug}\"", - "error.page.delete": "Невозможно удалить страницу \"{slug}\"", - "error.page.delete.confirm": "Впишите название страницы чтобы подтвердить", - "error.page.delete.hasChildren": "У страницы есть внутренние страницы, поэтому ее невозможно удалить", - "error.page.delete.permission": "У вас нет права удалить \"{slug}\"", - "error.page.draft.duplicate": "Черновик страницы с URL \"{slug}\" уже есть", - "error.page.duplicate": "Страница с URL \"{slug}\" уже есть", - "error.page.duplicate.permission": "У вас нет права дублировать \"{slug}\"", - "error.page.move.ancestor": "Невозможно переместить страницу саму в себя", - "error.page.move.directory": "Невозможно перенести каталог страницы", - "error.page.move.duplicate": "Подстраница с URL \"{slug}\" уже существует", - "error.page.move.notFound": "Перемещенная страница не найдена", - "error.page.move.permission": "У вас нет права переместить \"{slug}\"", - "error.page.move.template": "Шаблон \"{template}\" не разрешен для подстраниц \"{parent}\"", - "error.page.notFound": "\u0421\u0442\u0440\u0430\u043d\u0438\u0446\u0430 \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d\u0430", - "error.page.num.invalid": "Пожалуйста, впишите правильное число сортировки. Число не может быть отрицательным.", - "error.page.slug.invalid": "Пожалуйста, введите правильный URL", - "error.page.slug.maxlength": "Длина ссылки должна быть короче \"{length}\" символов", - "error.page.sort.permission": "Невозможно сортировать страницу \"{slug}\"", - "error.page.status.invalid": "Пожалуйста, установите верный статус страницы", - "error.page.undefined": "\u0421\u0442\u0440\u0430\u043d\u0438\u0446\u0430 \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d\u0430", - "error.page.update.permission": "У вас нет права обновить \"{slug}\"", - - "error.section.files.max.plural": "Нельзя добавить больше чем {max} файлов в секции \"{section}\"", - "error.section.files.max.singular": "Можно добавить не больше 1 файла в секции \"{section}\"", - "error.section.files.min.plural": "Секция \"{section}\" требует хотя бы {min} файлов", - "error.section.files.min.singular": "Секция \"{section}\" требует хотя бы 1 файл", - - "error.section.pages.max.plural": "Можно добавить не больше {max} страниц в секции \"{section}\"", - "error.section.pages.max.singular": "Нельзя добавить больше чем 1 страницу в секции \"{section}\"", - "error.section.pages.min.plural": "Секция \"{section}\" требует хотя бы {min} страниц", - "error.section.pages.min.singular": "Секция \"{section}\" требует хотя бы одну страницу", - - "error.section.notLoaded": "Секция \"{name}\" не может быть загружена", - "error.section.type.invalid": "Тип секции {type} неверный", - - "error.site.changeTitle.empty": "Название не может быть пустым", - "error.site.changeTitle.permission": "У вас нет права изменять название сайта", - "error.site.update.permission": "У вас нет права обновить сайт", - - "error.structure.validation": "Ошибка в поле \"{field}\" в строке {index}", - - "error.template.default.notFound": "Нет шаблона по умолчанию", - - "error.unexpected": "Произошла непредвиденная ошибка! Включите режим отладки для получения дополнительной информации: https://getkirby.com/docs/reference/system/options/debug", - - "error.user.changeEmail.permission": "У вас нет права изменять Email пользователя \"{name}\"", - "error.user.changeLanguage.permission": "У вас нет права изменять язык для пользователя \"{name}\"", - "error.user.changeName.permission": "У вас нет права изменять имя пользователя \"{name}\"", - "error.user.changePassword.permission": "У вас нет права изменять пароль для пользователя \"{name}\"", - "error.user.changeRole.lastAdmin": "Роль единственного администратора нельзя изменить", - "error.user.changeRole.permission": "У вас нет права изменять роль пользователя \"{name}\"", - "error.user.changeRole.toAdmin": "У вас нет прав предоставить роль администратора", - "error.user.create.permission": "У вас нет права создать этого пользователя", - "error.user.delete": "\u0410\u043a\u043a\u0430\u0443\u043d\u0442 \u043d\u0435 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0443\u0434\u0430\u043b\u0435\u043d", - "error.user.delete.lastAdmin": "\u0412\u044b \u043d\u0435 \u043c\u043e\u0436\u0435\u0442\u0435 \u0443\u0434\u0430\u043b\u0438\u0442\u044c \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0433\u043e \u0430\u0434\u043c\u0438\u043d\u0438\u0441\u0442\u0440\u0430\u0442\u043e\u0440\u0430", - "error.user.delete.lastUser": "Нельзя удалить единственного пользователя", - "error.user.delete.permission": "У вас нет права удалить пользователя \"{name}\"", - "error.user.duplicate": "Пользователь с Email \"{email}\" уже есть", - "error.user.email.invalid": "Пожалуйста, введите правильный Email", - "error.user.language.invalid": "Введите правильный язык", - "error.user.notFound": "Пользователь \"{name}\" не найден", - "error.user.password.excessive": "Пожалуйста, введите верный пароль. Длина паролей не должна превышать 1000 символов.", - "error.user.password.invalid": "Пожалуйста, введите правильный пароль. Он должен состоять минимум из 8 символов.", - "error.user.password.notSame": "\u041f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430, \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0434\u0438\u0442\u0435 \u043f\u0430\u0440\u043e\u043b\u044c", - "error.user.password.undefined": "У пользователя нет пароля", - "error.user.password.wrong": "Неверный пароль", - "error.user.role.invalid": "Введите правильную роль", - "error.user.undefined": "Аккаунт не найден", - "error.user.update.permission": "У вас нет права обновить пользователя \"{name}\"", - - "error.validation.accepted": "Пожалуйста, подтвердите", - "error.validation.alpha": "Пожалуйста, введите только буквы a-z", - "error.validation.alphanum": "Пожалуйста, введите только буквы a-z или числа 0-9", - "error.validation.anchor": "Пожалуйста, введите правильную ссылку на якорь", - "error.validation.between": "Пожалуйста, введите значение от \"{min}\" до \"{max}\"", - "error.validation.boolean": "Пожалуйста, подтвердите или отмените", - "error.validation.color": "Пожалуйста, введите верное значение цвета в формате {format}", - "error.validation.contains": "Пожалуйста, впишите значение, которое содержит \"{needle}\"", - "error.validation.date": "Пожалуйста, укажите правильную дату", - "error.validation.date.after": "Пожалуйста, укажите дату после {date}", - "error.validation.date.before": "Пожалуйста, укажите дату до {date}", - "error.validation.date.between": "Пожалуйста, укажите дату между {min} и {max}", - "error.validation.denied": "Пожалуйста отмените", - "error.validation.different": "Значение не может быть \"{other}\"", - "error.validation.email": "Пожалуйста, введите правильный Email", - "error.validation.endswith": "Значение должно заканчиваться с \"{end}\"", - "error.validation.filename": "Пожалуйста, введите правильное название файла", - "error.validation.in": "Пожалуйста, введите одно из следующих: ({in})", - "error.validation.integer": "Пожалуйста, введите правильное целое число", - "error.validation.ip": "Пожалуйста, введите правильный IP адрес", - "error.validation.less": "Пожалуйста, введите значение меньше чем {max}", - "error.validation.linkType": "Тип ссылки не допускается", - "error.validation.match": "Значение не соответствует ожидаемому шаблону", - "error.validation.max": "Пожалуйста, введите значение равное или больше чем {max}", - "error.validation.maxlength": "Пожалуйста, введите значение короче (макс. {max} символов)", - "error.validation.maxwords": "Пожалуйста, введите не более {max} слов ", - "error.validation.min": "Пожалуйста, введите значение равное или больше чем {min}", - "error.validation.minlength": "Пожалуйста, введите значение длиннее (мин. {min} символов)", - "error.validation.minwords": "Пожалуйста, введите хотя бы {min} слов", - "error.validation.more": "Пожалуйста, введите значение больше, чем {min}", - "error.validation.notcontains": "Пожалуйста, введите значение, которое не содержит \"{needle}\"", - "error.validation.notin": "Пожалуйста, не вписывайте одно из: ({notIn})", - "error.validation.option": "Пожалуйста, выберите правильную опцию ", - "error.validation.num": "Пожалуйста, введите правильный номер", - "error.validation.required": "Пожалуйста, введите что-нибудь", - "error.validation.same": "Пожалуйста, введите \"{other}\"", - "error.validation.size": "Значение размера должно быть \"{size}\"", - "error.validation.startswith": "Значение должно начинаться с \"{start}\"", - "error.validation.tel": "Пожалуйста, введите неформатированный номер телефона", - "error.validation.time": "Пожалуйста, введите правильную дату", - "error.validation.time.after": "Пожалуйста, укажите время после {time}", - "error.validation.time.before": "Пожалуйста, укажите время до {time}", - "error.validation.time.between": "Пожалуйста, укажите время между {min} и {max}", - "error.validation.uuid": "Пожалуйста, введите правильный UUID", - "error.validation.url": "Пожалуйста, введите правильный URL", - - "expand": "Развернуть", - "expand.all": "Развернуть все", - - "field.invalid": "Неверное поле", - "field.required": "Поле обязательно", - "field.blocks.changeType": "Изменить тип", - "field.blocks.code.name": "Код", - "field.blocks.code.language": "Язык", - "field.blocks.code.placeholder": "Ваш код …", - "field.blocks.delete.confirm": "Вы действительно хотите удалить этот блок?", - "field.blocks.delete.confirm.all": "Вы действительно хотите удалить все блоки?", - "field.blocks.delete.confirm.selected": "Вы действительно хотите удалить эти блоки?", - "field.blocks.empty": "Блоков нет", - "field.blocks.fieldsets.empty": "Пока нет наборов полей", - "field.blocks.fieldsets.label": "Пожалуйста, выберите тип блока…", - "field.blocks.fieldsets.paste": "Нажмите {{ shortcut }} чтобы импортировать макеты/блоки из буфера обмена Будут вставлены только те, которые разрешены в текущем поле.", - "field.blocks.gallery.name": "Галерея", - "field.blocks.gallery.images.empty": "Изображений нет", - "field.blocks.gallery.images.label": "Изображения", - "field.blocks.heading.level": "Уровень", - "field.blocks.heading.name": "Заголовок", - "field.blocks.heading.text": "Текст", - "field.blocks.heading.placeholder": "Заголовок …", - "field.blocks.image.alt": "Альтернативный текст", - "field.blocks.image.caption": "Подпись", - "field.blocks.image.crop": "Обрезать", - "field.blocks.image.link": "Ссылка", - "field.blocks.image.location": "Расположение", - "field.blocks.image.location.internal": "Этот сайт", - "field.blocks.image.location.external": "Внешний источник", - "field.blocks.image.name": "Картинка", - "field.blocks.image.placeholder": "Выберите изображение", - "field.blocks.image.ratio": "Соотношение", - "field.blocks.image.url": "URL изображения", - "field.blocks.line.name": "Линия", - "field.blocks.list.name": "Список", - "field.blocks.markdown.name": "Markdown", - "field.blocks.markdown.label": "Текст", - "field.blocks.markdown.placeholder": "Markdown …", - "field.blocks.quote.name": "Цитата", - "field.blocks.quote.text.label": "Текст", - "field.blocks.quote.text.placeholder": "Цитата …", - "field.blocks.quote.citation.label": "Цитирование", - "field.blocks.quote.citation.placeholder": "Автор …", - "field.blocks.text.name": "Текст", - "field.blocks.text.placeholder": "Текст …", - "field.blocks.video.autoplay": "Автовоспроизведение", - "field.blocks.video.caption": "Подпись", - "field.blocks.video.controls": "Элементы управления", - "field.blocks.video.location": "Расположение", - "field.blocks.video.loop": "Зациклить", - "field.blocks.video.muted": "Без звука", - "field.blocks.video.name": "Видео", - "field.blocks.video.placeholder": "Введите ссылку на видео", - "field.blocks.video.poster": "Обложка", - "field.blocks.video.preload": "Предзагрузка", - "field.blocks.video.url.label": "Ссылка на видео", - "field.blocks.video.url.placeholder": "https://youtube.com/?v=", - - "field.files.empty": "Файлы не выбраны", - - "field.layout.change": "Изменить разметку", - "field.layout.delete": "Удалить разметку", - "field.layout.delete.confirm": "Вы действительно хотите удалить эту разметку?", - "field.layout.delete.confirm.all": "Вы действительно хотите удалить всю разметку?", - "field.layout.empty": "Строк нет", - "field.layout.select": "Выберите разметку", - - "field.object.empty": "Пока нет информации", - - "field.pages.empty": "Страницы не выбраны", - - "field.structure.delete.confirm": "Вы точно хотите удалить эту запись?", - "field.structure.delete.confirm.all": "Вы действительно хотите удалить все значения?", - "field.structure.empty": "Записей нет", - - "field.users.empty": "Пользователей нет", - - "fields.empty": "Ещё нет полей", - - "file": "Файл", - "file.blueprint": "У файла пока нет разметки. Вы можете определить новые секции и поля разметки в /site/blueprints/files/{blueprint}.yml", - "file.changeTemplate": "Изменить шаблон", - "file.changeTemplate.notice": "Изменение шаблона файла приведет к удалению содержимого полей, которые не совпадут по типу. Если у нового шаблона есть определенные условия, например размер изображения, они также будут применены. Используйте с осторожностью.", - "file.delete.confirm": "Вы точно хотите удалить файл
{filename}?", - "file.focus.placeholder": "Установить фокусную точку", - "file.focus.reset": "Удалить фокусную точку", - "file.focus.title": "Фокусная точка", - "file.sort": "Изменить позицию", - - "files": "Файлы", - "files.empty": "Еще нет файлов", - - "filter": "Фильтр", - - "hide": "Скрыть", - "hour": "Час", - "hue": "Оттенок", - "import": "Импортировать", - "info": "Информация", - "insert": "\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044c", - "insert.after": "Вставить ниже", - "insert.before": "Вставить выше", - "install": "Установить", - - "installation": "Установка", - "installation.completed": "Панель установлена", - "installation.disabled": "Установка панели по умолчанию отключена на общедоступных серверах. Пожалуйста запустите установку на локальном сервере или включите такую возможность с помощью опции panel.install", - "installation.issues.accounts": "Каталог /site/accounts не существует или не имеет прав записи", - "installation.issues.content": "Каталог /content не существует или не имеет прав записи", - "installation.issues.curl": "Расширение CURL необходимо", - "installation.issues.headline": "Не удалось установить панель", - "installation.issues.mbstring": "Расширение MB String необходимо", - "installation.issues.media": "Каталог /media не существует или нет прав записи", - "installation.issues.php": "Убедитесь, что используется PHP 8+", - "installation.issues.sessions": "Каталог /site/sessions не существует или нет прав записи", - - "language": "\u042f\u0437\u044b\u043a", - "language.code": "Код", - "language.convert": "Установить по умолчанию", - "language.convert.confirm": "

Вы точно хотите конвертировать {name} в главный язык? Это нельзя будет отменить.

Если {name} имеет непереведенный контент, то больше не будет верного каскада и части вашего сайта могут быть пустыми.

", - "language.create": "Добавить новый язык", - "language.default": "Главный язык", - "language.delete.confirm": "Вы точно хотите удалить {name} язык, включая все переводы? Это нельзя будет вернуть.", - "language.deleted": "Язык удален", - "language.direction": "Направление чтения", - "language.direction.ltr": "Слева направо", - "language.direction.rtl": "Справа налево", - "language.locale": "PHP locale string", - "language.locale.warning": "Вы используете кастомную локаль. Пожалуйста измените ее в файле языка в /site/languages", - "language.name": "Название", - "language.secondary": "Второстепенный язык", - "language.settings": "Настройки языка", - "language.updated": "Язык обновлен", - "language.variables": "Языковые переменные", - "language.variables.empty": "Пока нет переводов", - - "language.variable.delete.confirm": "Вы действительно хотите удалить переменную для {key}?", - "language.variable.key": "Ключ", - "language.variable.notFound": "Переменная не найдена", - "language.variable.value": "Значение", - - "languages": "Языки", - "languages.default": "Главный язык", - "languages.empty": "Языков нет", - "languages.secondary": "Дополнительные языки", - "languages.secondary.empty": "Дополнительных языков нет", - - "license": "Лицензия", - "license.activate": "Активировать сейчас", - "license.activate.label": "Пожалуйста, активируйте Вашу лицензию", - "license.activate.domain": "Ваша лицензия будет активирована на {host}.", - "license.activate.local": "Вы собираетесь активировать лицензию на локальный домен {host}. Если этот сайт будет размещен на общедоступном домене, то, пожалуйста, укажите его вместо {host}.", - "license.activated": "Активировано", - "license.buy": "Купить лицензию", - "license.code": "Код", - "license.code.help": "Вставьте код лицензии, который вы получили Email после покупки.", - "license.code.label": "Пожалуйста вставьте код лицензии", - "license.status.active.info": "Включает обновления до {date}", - "license.status.active.label": "Действительная лицензия", - "license.status.demo.info": "Это демонстрационная установка", - "license.status.demo.label": "Демо", - "license.status.inactive.info": "Обновите лицензию для перехода на новые версии", - "license.status.inactive.label": "Нет новых обновлений", - "license.status.legacy.bubble": "Вы готовы обновить вашу лицензию?", - "license.status.legacy.info": "Ваша лицензия не покрывает эту версию", - "license.status.legacy.label": "Пожалуйста, обновите вашу лицензию", - "license.status.missing.bubble": "Готовы запустить Ваш сайт?", - "license.status.missing.info": "Нет действительной лицензии", - "license.status.missing.label": "Пожалуйста, активируйте Вашу лицензию", - "license.manage": "Управление лицензиями", - "license.purchased": "Приобретено", - "license.success": "Спасибо за поддержку Kirby", - "license.unregistered.label": "Не зарегистрировано", - - "link": "\u0421\u0441\u044b\u043b\u043a\u0430", - "link.text": "\u0422\u0435\u043a\u0441\u0442 \u0441\u0441\u044b\u043b\u043a\u0438", - - "loading": "Загрузка", - - "lock.unsaved": "Несохраненные изменения", - "lock.unsaved.empty": "Несохраненных изменений нет", - "lock.isLocked": "Несохраненные изменения {email}", - "lock.unlock": "Разблокировать", - "lock.unlock.submit": "Разблокируйте и перезапишите несохраненные изменения {email}", - "lock.isUnlocked": "Были перезаписаны другим пользователем", - - "login": "Войти", - "login.code.label.login": "Код для входа", - "login.code.label.password-reset": "Код для сброса пароля", - "login.code.placeholder.email": "000 000", - "login.code.placeholder.totp": "000000", - "login.code.text.email": "Если ваш Email уже зарегистрирован, запрашиваемый код был отправлен на него.", - "login.code.text.totp": "Пожалуйста, введите одноразовый пароль из вашего приложения-аутентификатора.", - "login.email.login.body": "{code} — код для входа на сайт {site}. Код действителен {timeout} минут.\n\nЗдравствуйте, {user.nameOrEmail}!\n\nЕсли вы не запрашивали код для входа, проигнорируйте это письмо или обратитесь к администратору, если у вас есть вопросы.\nВ целях безопасности НЕ ПЕРЕСЫЛАЙТЕ это письмо.", - "login.email.login.subject": "Ваш код для входа", - "login.email.password-reset.body": "{code} — код для сброса пароля на сайт «{site}». Код действителен {timeout} минут.\n\nЗдравствуйте, {user.nameOrEmail}!\n\nЕсли вы не запрашивали сброс пароля, проигнорируйте это письмо или обратитесь к администратору, если у вас есть вопросы.\nВ целях безопасности НЕ ПЕРЕСЫЛАЙТЕ это письмо.", - "login.email.password-reset.subject": "Ваш код для сброса пароля", - "login.remember": "Запомнить пароль", - "login.reset": "Сбросить пароль", - "login.toggleText.code.email": "Вход с помощью Email", - "login.toggleText.code.email-password": "Вход с паролем", - "login.toggleText.password-reset.email": "Забыли ваш пароль?", - "login.toggleText.password-reset.email-password": "← Вернуться к форме входа", - "login.totp.enable.option": "Настроить одноразовые пароли", - "login.totp.enable.intro": "Приложения‑аутентификаторы могут генерировать одноразовые коды, которые используются в качестве второго фактора при входе в вашу учетную запись.", - "login.totp.enable.qr.label": "1. Отсканируйте этот QR-код", - "login.totp.enable.qr.help": "Не удается выполнить сканирование? Добавьте ключ настройки {secret} вручную в ваше приложение для проверки подлинности.", - "login.totp.enable.confirm.headline": "2. Подтвердите с помощью генерированного кода", - "login.totp.enable.confirm.text": "Ваше приложение генерирует новый одноразовый код каждые 30 секунд. Введите текущий код для завершения настройки:", - "login.totp.enable.confirm.label": "Текущий код", - "login.totp.enable.confirm.help": "После этой настройки мы будем запрашивать у вас одноразовый код при каждом входе.", - "login.totp.enable.success": "Одноразовые коды включены", - "login.totp.disable.option": "Отключить одноразовые коды", - "login.totp.disable.label": "Введите ваш пароль для отключения одноразовых паролей", - "login.totp.disable.help": "Теперь при входе в систему будет запрашиваться второй фактор, например, код для входа, отправленный по Email. Вы всегда можете повторно настроить одноразовые коды позже.", - "login.totp.disable.admin": "

Вы отключаете одноразовые коды для{user}.

Теперь при входе в систему будет запрашиваться другой второй фактор, например код для входа, отправленный по Email. {user} может повторно настроить одноразовые коды после следующего входа в систему.

", - "login.totp.disable.success": "Одноразовые коды выключены", - - "logout": "Выйти", - - "merge": "Объединить", - "menu": "Меню", - "meridiem": "До полудня / После полудня", - "mime": "Тип медиа", - "minutes": "Минуты", - - "month": "Месяц", - "months.april": "\u0410\u043f\u0440\u0435\u043b\u044c", - "months.august": "\u0410\u0432\u0433\u0443\u0441\u0442", - "months.december": "\u0414\u0435\u043a\u0430\u0431\u0440\u044c", - "months.february": "Февраль", - "months.january": "\u042f\u043d\u0432\u0430\u0440\u044c", - "months.july": "\u0418\u044e\u043b\u044c", - "months.june": "\u0418\u044e\u043d\u044c", - "months.march": "\u041c\u0430\u0440\u0442", - "months.may": "\u041c\u0430\u0439", - "months.november": "\u041d\u043e\u044f\u0431\u0440\u044c", - "months.october": "\u041e\u043a\u0442\u044f\u0431\u0440\u044c", - "months.september": "\u0421\u0435\u043d\u0442\u044f\u0431\u0440\u044c", - - "more": "Еще", - "move": "Переместить", - "name": "Название", - "next": "Дальше", - "night": "Ночь", - "no": "нет", - "off": "выключено", - "on": "включено", - "open": "Открыть", - "open.newWindow": "Открывать в новом окне", - "option": "Опция", - "options": "Параметры", - "options.none": "Параметров нет", - "options.all": "Показать все параметры ({count})", - - "orientation": "Ориентация", - "orientation.landscape": "Горизонтальная", - "orientation.portrait": "Портретная", - "orientation.square": "Квадрат", - - "page": "Страница", - "page.blueprint": "У страницы пока нет разметки. Вы можете определить новые секции и поля разметки в /site/blueprints/pages/{blueprint}.yml", - "page.changeSlug": "Изменить ссылку", - "page.changeSlug.fromTitle": "Создать из названия", - "page.changeStatus": "Изменить статус", - "page.changeStatus.position": "Пожалуйста, выберите позицию", - "page.changeStatus.select": "Выбрать новый статус", - "page.changeTemplate": "Изменить шаблон", - "page.changeTemplate.notice": "Изменение шаблона страницы приведет к удалению содержимого полей, которые не совпадут по типу. Используйте с осторожностью.", - "page.create": "Создать как {status}", - "page.delete.confirm": "Вы точно хотите удалить страницу {title}?", - "page.delete.confirm.subpages": "У этой страницы есть внутренние страницы.
Все внутренние страницы так же будут удалены.", - "page.delete.confirm.title": "Напишите название страницы, чтобы подтвердить", - "page.duplicate.appendix": "(копия)", - "page.duplicate.files": "Копировать файлы", - "page.duplicate.pages": "Копировать страницы", - "page.move": "Переместить", - "page.sort": "Изменить позицию", - "page.status": "Статус", - "page.status.draft": "Черновик", - "page.status.draft.description": "Страница находится в черновом режиме и видна только зарегистрированным пользователям или по секретной ссылке", - "page.status.listed": "Опубликована", - "page.status.listed.description": "Страница доступна для всех посетителей", - "page.status.unlisted": "Скрыта", - "page.status.unlisted.description": "Страница доступна только по URL", - - "pages": "Страницы", - "pages.empty": "Страниц нет", - "pages.status.draft": "Черновики", - "pages.status.listed": "Опубликовано", - "pages.status.unlisted": "Скрытая", - - "pagination.page": "Страница", - - "password": "\u041f\u0430\u0440\u043e\u043b\u044c", - "paste": "Вставить", - "paste.after": "Вставить после", - "paste.success": "{count} вставлено", - "pixel": "Пиксель", - "plugin": "Расширение", - "plugins": "Плагины", - "prev": "Предыдущий", - "preview": "Предпросмотр", - "remove": "Удалить", - "rename": "Переименовать", - "renew": "Обновить", - "replace": "\u0417\u0430\u043c\u0435\u043d\u0438\u0442\u044c", - "replace.with": "Заменить на", - "retry": "\u041f\u043e\u0432\u0442\u043e\u0440\u0438\u0442\u044c", - "revert": "\u0421\u0431\u0440\u043e\u0441", - "revert.confirm": "Вы действительно хотите удалить все несохраненные изменения?", - - "role": "\u0420\u043e\u043b\u044c", - "role.admin.description": "Администратор имеет все права", - "role.admin.title": "Администратор", - "role.all": "Все", - "role.empty": "Пользователей с такой ролью нет", - "role.description.placeholder": "Без описания", - "role.nobody.description": "Эта роль применяется если у пользователя нет никаких прав", - "role.nobody.title": "Никто", - - "save": "\u0421\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c", - "search": "Поиск", - "search.min": "Введите хотя бы {min} символов для поиска", - "search.all": "Показать все результаты ({count})", - "search.results.none": "Нет результатов", - - "section.invalid": "Неверная секция", - "section.required": "Секция обязательна", - - "security": "Безопасность", - "select": "Выбрать", - "server": "Сервер", - "settings": "Настройка", - "show": "Показать", - "site.blueprint": "У сайта пока нет разметки. Вы можете определить новые секции и поля разметки в /site/blueprints/site.yml", - "size": "Размер", - "slug": "URL", - "sort": "Сортировать", - "sort.drag": "Потяните для сортировки…", - "split": "Разделить", - - "stats.empty": "Статистики нет", - "status": "Статус", - - "system.info.copy": "Copy info", - "system.info.copied": "System info copied", - "system.issues.content": "Похоже, к папке content есть несанкционированный доступ", - "system.issues.eol.kirby": "Срок службы установленной вами версии Kirby истек, и она больше не будет получать обновления для системы безопасности", - "system.issues.eol.plugin": "Срок службы установленной вами версии плагина { plugin } истек, и он не будет получать дальнейших обновлений для системы безопасности", - "system.issues.eol.php": "Ваша версия PHP { release } устарела и не будет получать дальнейших обновлений для системы безопасности", - "system.issues.debug": "Включен режим отладки (debugging). Используйте его только при разработке.", - "system.issues.git": "Похоже, к папке .git есть несанкционированный доступ", - "system.issues.https": "Рекомендуется использовать HTTPS на всех сайтах", - "system.issues.kirby": "Похоже, к папке kirby есть несанкционированный доступ", - "system.issues.site": "Похоже, к папке site есть несанкционированный доступ", - "system.issues.vulnerability.kirby": "Обнаружена уязвимость уровня \"{ severity }\": { description }", - "system.issues.vulnerability.plugin": "В плагине { plugin } обнаружена уязвимость уровня \"{ severity }\": { description }", - "system.updateStatus": "Обновить статус", - "system.updateStatus.error": "Не удалось проверить обновления", - "system.updateStatus.not-vulnerable": "Известных уязвимостей не выявлено", - "system.updateStatus.security-update": "Доступно бесплатное обновление для системы безопасности { version }", - "system.updateStatus.security-upgrade": "Доступно обновление { version } с испарвлениями безопасности", - "system.updateStatus.unreleased": "Неизданная версия", - "system.updateStatus.up-to-date": "Последняя версия", - "system.updateStatus.update": "Доступно бесплатное обновление { version }", - "system.updateStatus.upgrade": "Доступно обновление { version }", - - "tel": "Телефон", - "tel.placeholder": "+79123456789", - "template": "\u0428\u0430\u0431\u043b\u043e\u043d", - "title": "Название", - "today": "Сегодня", - - "toolbar.button.clear": "Очистить форматирование", - "toolbar.button.code": "Код", - "toolbar.button.bold": "\u0416\u0438\u0440\u043d\u044b\u0439 \u0448\u0440\u0438\u0444\u0442", - "toolbar.button.email": "Email", - "toolbar.button.headings": "Заголовки", - "toolbar.button.heading.1": "Заголовок 1", - "toolbar.button.heading.2": "Заголовок 2", - "toolbar.button.heading.3": "Заголовок 3", - "toolbar.button.heading.4": "Заголовок 4", - "toolbar.button.heading.5": "Заголовок 5", - "toolbar.button.heading.6": "Заголовок 6", - "toolbar.button.italic": "Курсив", - "toolbar.button.file": "Файл", - "toolbar.button.file.select": "Выбрать файл", - "toolbar.button.file.upload": "Загрузить файл", - "toolbar.button.link": "\u0421\u0441\u044b\u043b\u043a\u0430", - "toolbar.button.paragraph": "Параграф", - "toolbar.button.strike": "Зачёркнутый", - "toolbar.button.sub": "Нижний индекс", - "toolbar.button.sup": "Верхний индекс", - "toolbar.button.ol": "Нумерованный список", - "toolbar.button.underline": "Подчёркнутый", - "toolbar.button.ul": "Маркированный список", - - "translation.author": "Команда Kirby", - "translation.direction": "ltr", - "translation.name": "Русский (Russian)", - "translation.locale": "ru_RU", - - "type": "Введите", - - "upload": "Загрузить", - "upload.error.cantMove": "Не удалось переместить загруженный файл", - "upload.error.cantWrite": "Не получилось записать файл на диск", - "upload.error.default": "Не удалось загрузить файл", - "upload.error.extension": "Загрузка файла остановлена из-за расширения", - "upload.error.formSize": "Загружаемый файл больше указанного в параметре MAX_FILE_SIZE в форме", - "upload.error.iniPostSize": "Загружаемый файл больше указанного в параметре \"post_max_size\" в php.ini", - "upload.error.iniSize": "Загружаемый файл больше указанного в параметре \"upload_max_filesize\" в php.ini", - "upload.error.noFile": "Файл не был загружен", - "upload.error.noFiles": "Файлы не были загружены", - "upload.error.partial": "Файл загружен только частично", - "upload.error.tmpDir": "Не хватает временной папки", - "upload.errors": "Ошибка", - "upload.progress": "Загрузка...", - - "url": "URL", - "url.placeholder": "https://example.com", - - "user": "Пользователь", - "user.blueprint": "Вы можете определить новые секции и поля разметки для пользователя в /site/blueprints/users/{blueprint}.yml", - "user.changeEmail": "Изменить Email", - "user.changeLanguage": "Изменить язык", - "user.changeName": "Переименовать пользователя", - "user.changePassword": "Изменить пароль", - "user.changePassword.new": "Новый пароль", - "user.changePassword.new.confirm": "Подтвердить новый пароль…", - "user.changeRole": "Изменить роль", - "user.changeRole.select": "Выбрать новую роль", - "user.create": "Добавить нового пользователя", - "user.delete": "Удалить этого пользователя", - "user.delete.confirm": "Вы действительно хотите аккаунт
{email}?", - - "users": "Пользователи", - - "version": "Версия", - "version.current": "Текущая версия", - "version.latest": "Последняя версия", - "versionInformation": "Информация о версии", - - "view.account": "Ваш аккаунт", - "view.installation": "\u0423\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430", - "view.languages": "Языки", - "view.resetPassword": "Сбросить пароль", - "view.site": "Сайт", - "view.system": "Система", - "view.users": "\u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0438", - - "welcome": "Добро пожаловать", - "year": "Год", - "yes": "да" + "account.changeName": "Изменить имя", + "account.delete": "Удалить аккаунт", + "account.delete.confirm": "Вы действительно хотите удалить свой аккаунт? Вы сразу покинете панель управления, а аккаунт нельзя будет восстановить.", + + "add": "\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c", + "author": "Автор", + "avatar": "\u0410\u0432\u0430\u0442\u0430\u0440 (\u0444\u043e\u0442\u043e)", + "back": "Назад", + "cancel": "\u041e\u0442\u043c\u0435\u043d\u0438\u0442\u044c", + "change": "\u0418\u0437\u043c\u0435\u043d\u0438\u0442\u044c", + "close": "\u0417\u0430\u043a\u0440\u044b\u0442\u044c", + "confirm": "Ок", + "collapse": "Свернуть", + "collapse.all": "Свернуть все", + "copy": "Скопировать", + "copy.all": "Копировать все", + "create": "Создать", + + "date": "Дата", + "date.select": "Выберите дату", + + "day": "День", + "days.fri": "\u041f\u0442", + "days.mon": "\u041f\u043d", + "days.sat": "\u0421\u0431", + "days.sun": "\u0412\u0441", + "days.thu": "\u0427\u0442", + "days.tue": "\u0412\u0442", + "days.wed": "\u0421\u0440", + + "debugging": "Отладка", + + "delete": "\u0423\u0434\u0430\u043b\u0438\u0442\u044c", + "delete.all": "Удалить все", + + "dialog.files.empty": "Нет файлов для выбора", + "dialog.pages.empty": "Нет страниц для выбора", + "dialog.users.empty": "Нет пользователей для выбора", + + "dimensions": "Размеры", + "disabled": "Отключено", + "discard": "\u0421\u0431\u0440\u043e\u0441", + "download": "Скачать", + "duplicate": "Дублировать", + + "edit": "\u041d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c", + + "email": "Email", + "email.placeholder": "mail@example.com", + + "entries": "Записи", + "entry": "Запись", + + "environment": "Среда", + + "error.access.code": "Неверный код", + "error.access.login": "Неправильный логин", + "error.access.panel": "У вас нет права доступа к панели", + "error.access.view": "У вас нет прав доступа к этой части панели", + + "error.avatar.create.fail": "Не удалось загрузить фотографию профиля", + "error.avatar.delete.fail": "\u0410\u0432\u0430\u0442\u0430\u0440 (\u0444\u043e\u0442\u043e) \u043a \u0430\u043a\u043a\u0430\u0443\u043d\u0442\u0443 \u043d\u0435 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0443\u0434\u0430\u043b\u0435\u043d", + "error.avatar.dimensions.invalid": "Пожалуйста, сделайте чтобы ширина или высота фотографии была меньше 3000 пикселей", + "error.avatar.mime.forbidden": "Фотография профиля должна быть JPEG или PNG", + + "error.blueprint.notFound": "Не удалось загрузить разметку \"{name}\"", + + "error.blocks.max.plural": "Вы не можете добавить больше {max} блоков", + "error.blocks.max.singular": "Вы не можете добавить больше одного блока", + "error.blocks.min.plural": "Вы должны добавить хотя бы {min} блоков", + "error.blocks.min.singular": "Вы должны добавить хотя бы один блок", + "error.blocks.validation": "Обнаружена ошибка в блоке {index}", + + "error.email.preset.notFound": "Шаблон эл. почты \"{name}\" не найден", + + "error.field.converter.invalid": "Неверный конвертер \"{converter}\"", + + "error.file.changeName.empty": "Название не может быть пустым", + "error.file.changeName.permission": "У вас нет права изменить название \"{filename}\"", + "error.file.duplicate": "Файл с названием \"{filename}\" уже есть", + "error.file.extension.forbidden": "Расширение файла \"{extension}\" неразрешено", + "error.file.extension.invalid": "Неверное разрешение: {extension}", + "error.file.extension.missing": "Файлу \"{filename}\" не хватает расширения", + "error.file.maxheight": "Высота изображения не должна превышать {height} px", + "error.file.maxsize": "Файл слишком большой", + "error.file.maxwidth": "Ширина изображения не должна превышать {width} px", + "error.file.mime.differs": "Загружаемый файл должен иметь такое же расширение (тип): \"{mime}\"", + "error.file.mime.forbidden": "Расширение (тип) \"{mime}\" не допускается", + "error.file.mime.invalid": "Неверное расширение (тип): {mime}", + "error.file.mime.missing": "Не удалось определить тип медиа для файла \"{filename}\"", + "error.file.minheight": "Высота файла должна быть хотя бы {height} px", + "error.file.minsize": "Файл слишком маленький", + "error.file.minwidth": "Ширина файла должна быть хотя бы {width} px", + "error.file.name.missing": "Название файла не может быть пустым", + "error.file.notFound": "\u0424\u0430\u0439\u043b \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d", + "error.file.orientation": "Ориентация изображения должна быть \"{orientation}\"", + "error.file.type.forbidden": "У вас нет права загружать файлы {type}", + "error.file.type.invalid": "Неверный тип файла: {type}", + "error.file.undefined": "\u0424\u0430\u0439\u043b \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d", + + "error.form.incomplete": "Пожалуйста, исправьте все ошибки в форме", + "error.form.notSaved": "Форма не может быть сохранена", + + "error.language.code": "Пожалуйста, впишите правильный код языка", + "error.language.duplicate": "Язык уже есть", + "error.language.name": "Пожалуйста, впишите правильное название языка", + "error.language.notFound": "Не получилось найти этот язык", + + "error.layout.validation.block": "Ошибка в блоке {blockIndex} в макете {layoutIndex}", + "error.layout.validation.settings": "Ошибка в настройках макета {index}", + + "error.license.format": "Пожалуйста, введите правильный лицензионный код", + "error.license.email": "Пожалуйста, введите правильный Email", + "error.license.verification": "Лицензия не подтверждена", + + "error.offline": "Панель управления не в сети", + + "error.page.changeSlug.permission": "\u0412\u044b \u043d\u0435 \u043c\u043e\u0436\u0435\u0442\u0435 \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c URL \u044d\u0442\u043e\u0439 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b", + "error.page.changeStatus.incomplete": "На странице есть ошибки и поэтому ее нельзя опубликовать", + "error.page.changeStatus.permission": "Невозможно изменить статус для этой страницы", + "error.page.changeStatus.toDraft.invalid": "Невозможно конвертировать в черновик страницу \"{slug}\"", + "error.page.changeTemplate.invalid": "Невозможно изменить шаблон страницы \"{slug}\"", + "error.page.changeTemplate.permission": "У вас нет права изменять шаблон для \"{slug}\"", + "error.page.changeTitle.empty": "Название не может быть пустым", + "error.page.changeTitle.permission": "у вас нет права изменять название \"{slug}\"", + "error.page.create.permission": "У вас нет права создать \"{slug}\"", + "error.page.delete": "Невозможно удалить страницу \"{slug}\"", + "error.page.delete.confirm": "Впишите название страницы чтобы подтвердить", + "error.page.delete.hasChildren": "У страницы есть внутренние страницы, поэтому ее невозможно удалить", + "error.page.delete.permission": "У вас нет права удалить \"{slug}\"", + "error.page.draft.duplicate": "Черновик страницы с аппендиксом URL \"{slug}\" уже есть", + "error.page.duplicate": "Страница с аппендиксом URL \"{slug}\" уже есть", + "error.page.duplicate.permission": "У вас нет права дублировать \"{slug}\"", + "error.page.notFound": "\u0421\u0442\u0440\u0430\u043d\u0438\u0446\u0430 \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d\u0430", + "error.page.num.invalid": "Пожалуйста, впишите правильное число сортировки. Число не может быть отрицательным.", + "error.page.slug.invalid": "Пожалуйста, введите правильный URL", + "error.page.slug.maxlength": "Длина ссылки должна быть короче \"{length}\" символов", + "error.page.sort.permission": "Невозможно сортировать страницу \"{slug}\"", + "error.page.status.invalid": "Пожалуйста, установите верный статус страницы", + "error.page.undefined": "\u0421\u0442\u0440\u0430\u043d\u0438\u0446\u0430 \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d\u0430", + "error.page.update.permission": "У вас нет права обновить \"{slug}\"", + + "error.section.files.max.plural": "Нельзя добавить больше чем {max} файлов в секции \"{section}\"", + "error.section.files.max.singular": "Можно добавить не больше 1 файла в секции \"{section}\"", + "error.section.files.min.plural": "Секция \"{section}\" требует хотя бы {min} файлов", + "error.section.files.min.singular": "Секция \"{section}\" требует хотя бы 1 файл", + + "error.section.pages.max.plural": "Можно добавить не больше {max} страниц в секции \"{section}\"", + "error.section.pages.max.singular": "Нельзя добавить больше чем 1 страницу в секции \"{section}\"", + "error.section.pages.min.plural": "Секция \"{section}\" требует хотя бы {min} страниц", + "error.section.pages.min.singular": "Секция \"{section}\" требует хотя бы одну страницу", + + "error.section.notLoaded": "Секция \"{name}\" не может быть загружена", + "error.section.type.invalid": "Тип секции {type} неверный", + + "error.site.changeTitle.empty": "Название не может быть пустым", + "error.site.changeTitle.permission": "У вас нет права изменять название сайта", + "error.site.update.permission": "У вас нет права обновить сайт", + + "error.template.default.notFound": "Нет шаблона по умолчанию", + + "error.unexpected": "Произошла непредвиденная ошибка! Включите режим отладки для получения дополнительной информации: https://getkirby.com/docs/reference/system/options/debug", + + "error.user.changeEmail.permission": "У вас нет права изменять Email пользователя \"{name}\"", + "error.user.changeLanguage.permission": "У вас нет права изменять язык для пользователя \"{name}\"", + "error.user.changeName.permission": "У вас нет права изменять имя пользователя \"{name}\"", + "error.user.changePassword.permission": "У вас нет права изменять пароль для пользователя \"{name}\"", + "error.user.changeRole.lastAdmin": "Роль единственного администратора нельзя изменить", + "error.user.changeRole.permission": "У вас нет права изменять роль пользователя \"{name}\"", + "error.user.changeRole.toAdmin": "У вас нет прав предоставить роль администратора", + "error.user.create.permission": "У вас нет права создать этого пользователя", + "error.user.delete": "\u0410\u043a\u043a\u0430\u0443\u043d\u0442 \u043d\u0435 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0443\u0434\u0430\u043b\u0435\u043d", + "error.user.delete.lastAdmin": "\u0412\u044b \u043d\u0435 \u043c\u043e\u0436\u0435\u0442\u0435 \u0443\u0434\u0430\u043b\u0438\u0442\u044c \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0433\u043e \u0430\u0434\u043c\u0438\u043d\u0438\u0441\u0442\u0440\u0430\u0442\u043e\u0440\u0430", + "error.user.delete.lastUser": "Нельзя удалить единственного пользователя", + "error.user.delete.permission": "У вас нет права удалить пользователя \"{name}\"", + "error.user.duplicate": "Пользователь с Email \"{email}\" уже есть", + "error.user.email.invalid": "Пожалуйста, введите правильный адрес эл. почты", + "error.user.language.invalid": "Введите правильный язык", + "error.user.notFound": "Пользователь \"{name}\" не найден", + "error.user.password.excessive": "Please enter a valid password. Passwords must not be longer than 1000 characters.", + "error.user.password.invalid": "Пожалуйста, введите правильный пароль. Он должен состоять минимум из 8 символов.", + "error.user.password.notSame": "\u041f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430, \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0434\u0438\u0442\u0435 \u043f\u0430\u0440\u043e\u043b\u044c", + "error.user.password.undefined": "У пользователя нет пароля", + "error.user.password.wrong": "Неверный пароль", + "error.user.role.invalid": "Введите правильную роль", + "error.user.undefined": "Аккаунт не найден", + "error.user.update.permission": "У вас нет права обновить пользователя \"{name}\"", + + "error.validation.accepted": "Пожалуйста, подтвердите", + "error.validation.alpha": "Пожалуйста, введите только буквы a-z", + "error.validation.alphanum": "Пожалуйста, введите только буквы a-z или числа 0-9", + "error.validation.between": "Пожалуйста, введите значение от \"{min}\" до \"{max}\"", + "error.validation.boolean": "Пожалуйста, подтвердите или отмените", + "error.validation.contains": "Пожалуйста, впишите значение, которое содержит \"{needle}\"", + "error.validation.date": "Пожалуйста, укажите правильную дату", + "error.validation.date.after": "Пожалуйста, укажите дату после {date}", + "error.validation.date.before": "Пожалуйста, укажите дату до {date}", + "error.validation.date.between": "Пожалуйста, укажите дату между {min} и {max}", + "error.validation.denied": "Пожалуйста отмените", + "error.validation.different": "Значение не может быть \"{other}\"", + "error.validation.email": "Пожалуйста, введите правильный Email", + "error.validation.endswith": "Значение должно заканчиваться с \"{end}\"", + "error.validation.filename": "Пожалуйста, введите правильное название файла", + "error.validation.in": "Пожалуйста, введите одно из следующих: ({in})", + "error.validation.integer": "Пожалуйста, введите правильное целое число", + "error.validation.ip": "Пожалуйста, введите правильный IP адрес", + "error.validation.less": "Пожалуйста, введите значение меньше чем {max}", + "error.validation.match": "Значение не соответствует ожидаемому шаблону", + "error.validation.max": "Пожалуйста, введите значение равное или больше чем {max}", + "error.validation.maxlength": "Пожалуйста, введите значение короче (макс. {max} символов)", + "error.validation.maxwords": "Пожалуйста, введите не более {max} слов ", + "error.validation.min": "Пожалуйста, введите значение равное или больше чем {min}", + "error.validation.minlength": "Пожалуйста, введите значение длиннее (мин. {min} символов)", + "error.validation.minwords": "Пожалуйста, введите хотя бы {min} слов", + "error.validation.more": "Пожалуйста, введите значение больше, чем {min}", + "error.validation.notcontains": "Пожалуйста, введите значение, которое не содержит \"{needle}\"", + "error.validation.notin": "Пожалуйста, не вписывайте одно из: ({notIn})", + "error.validation.option": "Пожалуйста, выберите правильную опцию ", + "error.validation.num": "Пожалуйста, введите правильный номер", + "error.validation.required": "Пожалуйста, введите что-нибудь", + "error.validation.same": "Пожалуйста, введите \"{other}\"", + "error.validation.size": "Значение размера должно быть \"{size}\"", + "error.validation.startswith": "Значение должно начинаться с \"{start}\"", + "error.validation.time": "Пожалуйста, введите правильную дату", + "error.validation.time.after": "Пожалуйста, укажите время после {time}", + "error.validation.time.before": "Пожалуйста, укажите время до {time}", + "error.validation.time.between": "Пожалуйста, укажите время между {min} и {max}", + "error.validation.url": "Пожалуйста, введите правильный URL", + + "expand": "Развернуть", + "expand.all": "Развернуть все", + + "field.required": "Поле обязательно", + "field.blocks.changeType": "Изменить тип", + "field.blocks.code.name": "Код", + "field.blocks.code.language": "Язык", + "field.blocks.code.placeholder": "Ваш код …", + "field.blocks.delete.confirm": "Вы действительно хотите удалить этот блок?", + "field.blocks.delete.confirm.all": "Вы действительно хотите удалить все блоки?", + "field.blocks.delete.confirm.selected": "Вы действительно хотите удалить эти блоки?", + "field.blocks.empty": "Блоков нет", + "field.blocks.fieldsets.label": "Пожалуйста, выберите тип блока…", + "field.blocks.fieldsets.paste": "Нажмите {{ shortcut }} чтобы вставить/импортировать блоки из буфера памяти", + "field.blocks.gallery.name": "Галерея", + "field.blocks.gallery.images.empty": "Изображений нет", + "field.blocks.gallery.images.label": "Изображения", + "field.blocks.heading.level": "Уровень", + "field.blocks.heading.name": "Заголовок", + "field.blocks.heading.text": "Текст", + "field.blocks.heading.placeholder": "Заголовок …", + "field.blocks.image.alt": "Альтернативный текст", + "field.blocks.image.caption": "Подпись", + "field.blocks.image.crop": "Обрезать", + "field.blocks.image.link": "Ссылка", + "field.blocks.image.location": "Расположение", + "field.blocks.image.name": "Картинка", + "field.blocks.image.placeholder": "Выберите изображение", + "field.blocks.image.ratio": "Соотношение", + "field.blocks.image.url": "URL изображения", + "field.blocks.line.name": "Линия", + "field.blocks.list.name": "Список", + "field.blocks.markdown.name": "Markdown", + "field.blocks.markdown.label": "Текст", + "field.blocks.markdown.placeholder": "Markdown …", + "field.blocks.quote.name": "Цитата", + "field.blocks.quote.text.label": "Текст", + "field.blocks.quote.text.placeholder": "Цитата …", + "field.blocks.quote.citation.label": "Цитирование", + "field.blocks.quote.citation.placeholder": "Автор …", + "field.blocks.text.name": "Текст", + "field.blocks.text.placeholder": "Текст …", + "field.blocks.video.caption": "Подпись", + "field.blocks.video.name": "Видео", + "field.blocks.video.placeholder": "Введите ссылку на видео", + "field.blocks.video.url.label": "Ссылка на видео", + "field.blocks.video.url.placeholder": "https://youtube.com/?v=", + + "field.files.empty": "Файлы не выбраны", + + "field.layout.delete": "Удалить разметку", + "field.layout.delete.confirm": "Вы действительно хотите удалить эту разметку?", + "field.layout.empty": "Строк нет", + "field.layout.select": "Выберите разметку", + + "field.pages.empty": "Страницы не выбраны", + "field.structure.delete.confirm": "Вы точно хотите удалить эту запись?", + "field.structure.empty": "Записей нет", + "field.users.empty": "Пользователей нет", + + "file.blueprint": "У файла пока нет разметки. Вы можете определить новые секции и поля разметки в /site/blueprints/files/{blueprint}.yml", + "file.delete.confirm": "Вы точно хотите удалить файл
{filename}?", + "file.sort": "Изменить позицию", + + "files": "Файлы", + "files.empty": "Еще нет файлов", + + "hide": "Скрыть", + "hour": "Час", + "import": "Импортировать", + "info": "Информация", + "insert": "\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044c", + "insert.after": "Вставить ниже", + "insert.before": "Вставить выше", + "install": "Установить", + + "installation": "Установка", + "installation.completed": "Панель установлена", + "installation.disabled": "Установка панели по умолчанию отключена на общедоступных серверах. Пожалуйста запустите установку на локальном сервере или включите такую возможность с помощью опции panel.install", + "installation.issues.accounts": "Каталог /site/accounts не существует или не имеет прав записи", + "installation.issues.content": "Каталог /content не существует или не имеет прав записи", + "installation.issues.curl": "Расширение CURL необходимо", + "installation.issues.headline": "Не удалось установить панель", + "installation.issues.mbstring": "Расширение MB String необходимо", + "installation.issues.media": "Каталог /media не существует или нет прав записи", + "installation.issues.php": "Убедитесь, что используется PHP 7+", + "installation.issues.server": "Kirby требует Apache, Nginx или Caddy ", + "installation.issues.sessions": "Каталог /site/sessions не существует или нет прав записи", + + "language": "\u042f\u0437\u044b\u043a", + "language.code": "Код", + "language.convert": "Установить по умолчанию", + "language.convert.confirm": "

Вы точно хотите конвертировать {name} в главный язык? Это нельзя будет отменить.

Если {name} имеет непереведенный контент, то больше не будет верного каскада и части вашего сайта могут быть пустыми.

", + "language.create": "Добавить новый язык", + "language.delete.confirm": "Вы точно хотите удалить {name} язык, включая все переводы? Это нельзя будет вернуть.", + "language.deleted": "Язык удален", + "language.direction": "Направление чтения", + "language.direction.ltr": "Слева направо", + "language.direction.rtl": "Справа налево", + "language.locale": "PHP locale string", + "language.locale.warning": "Вы используете кастомную локаль. Пожалуйста измените ее в файле языка в /site/languages", + "language.name": "Название", + "language.updated": "Язык обновлен", + + "languages": "Языки", + "languages.default": "Главный язык", + "languages.empty": "Языков нет", + "languages.secondary": "Дополнительные языки", + "languages.secondary.empty": "Дополнительных языков нет", + + "license": "Лицензия", + "license.buy": "Купить лицензию", + "license.register": "Зарегистрировать", + "license.manage": "Управление лицензиями", + "license.register.help": "После покупки вы получили по эл. почте код лицензии. Пожалуйста скопируйте и вставьте сюда чтобы зарегистрировать.", + "license.register.label": "Пожалуйста вставьте код лицензии", + "license.register.success": "Спасибо за поддержку Kirby", + "license.unregistered": "Это незарегистрированная версия Kirby", + "license.unregistered.label": "Не зарегистрировано", + + "link": "\u0421\u0441\u044b\u043b\u043a\u0430", + "link.text": "\u0422\u0435\u043a\u0441\u0442 \u0441\u0441\u044b\u043b\u043a\u0438", + + "loading": "Загрузка", + + "lock.unsaved": "Несохраненные изменения", + "lock.unsaved.empty": "Несохраненных изменений больше нет", + "lock.isLocked": "Несохраненные изменения пользователя {email}", + "lock.file.isLocked": "В данный момент этот файл редактирует {email}, поэтому его нельзя изменить.", + "lock.page.isLocked": "В данный момент эту страницу редактирует {email}, поэтому его нельзя изменить.", + "lock.unlock": "Разблокировать", + "lock.isUnlocked": "Ваши несохраненные изменения были перезаписаны другим пользователем. Вы можете загрузить ваши изменения и объединить их вручную.", + + "login": "Войти", + "login.code.label.login": "Код для входа", + "login.code.label.password-reset": "Код для сброса пароля", + "login.code.placeholder.email": "000 000", + "login.code.text.email": "Если ваш Email уже зарегистрирован, запрашиваемый код был отправлен на него.", + "login.email.login.body": "Привет, {user.nameOrEmail}!\n\nНедавно вы запросили код для входа на «{site}».\nСледующий код входа будет действителен в течение {timeout} минут:\n\n{code}\n\nЕсли вы не запрашивали код для входа, проигнорируйте это письмо или обратитесь к администратору, если у вас есть вопросы.\nВ целях безопасности НЕ ПЕРЕСЫЛАЙТЕ это письмо.", + "login.email.login.subject": "Ваш код для входа", + "login.email.password-reset.body": "Привет, {user.nameOrEmail}!\n\nНедавно вы запросили сброс пароля для входа на «{site}».\nСледующий код входа будет действителен в течение {timeout} минут:\n\n{code}\n\nЕсли вы не запрашивали сброс пароля, проигнорируйте это письмо или обратитесь к администратору, если у вас есть вопросы.\nВ целях безопасности НЕ ПЕРЕСЫЛАЙТЕ это письмо.", + "login.email.password-reset.subject": "Ваш код для сброса пароля", + "login.remember": "Сохранять вход активным", + "login.reset": "Сбросить пароль", + "login.toggleText.code.email": "Вход с помощью Email", + "login.toggleText.code.email-password": "Вход с паролем", + "login.toggleText.password-reset.email": "Забыли ваш пароль?", + "login.toggleText.password-reset.email-password": "← Вернуться к форме входа", + + "logout": "Выйти", + + "menu": "Меню", + "meridiem": "До полудня / После полудня", + "mime": "Тип медиа", + "minutes": "Минуты", + + "month": "Месяц", + "months.april": "\u0410\u043f\u0440\u0435\u043b\u044c", + "months.august": "\u0410\u0432\u0433\u0443\u0441\u0442", + "months.december": "\u0414\u0435\u043a\u0430\u0431\u0440\u044c", + "months.february": "Февраль", + "months.january": "\u042f\u043d\u0432\u0430\u0440\u044c", + "months.july": "\u0418\u044e\u043b\u044c", + "months.june": "\u0418\u044e\u043d\u044c", + "months.march": "\u041c\u0430\u0440\u0442", + "months.may": "\u041c\u0430\u0439", + "months.november": "\u041d\u043e\u044f\u0431\u0440\u044c", + "months.october": "\u041e\u043a\u0442\u044f\u0431\u0440\u044c", + "months.september": "\u0421\u0435\u043d\u0442\u044f\u0431\u0440\u044c", + + "more": "Подробнее", + "name": "Название", + "next": "Дальше", + "no": "нет", + "off": "выключено", + "on": "включено", + "open": "Открыть", + "open.newWindow": "Открывать в новом окне", + "options": "Опции", + "options.none": "Параметров нет", + + "orientation": "Ориентация", + "orientation.landscape": "Горизонтальная", + "orientation.portrait": "Портретная", + "orientation.square": "Квадрат", + + "page.blueprint": "У страницы пока нет разметки. Вы можете определить новые секции и поля разметки в /site/blueprints/pages/{blueprint}.yml", + "page.changeSlug": "Изменить ссылку", + "page.changeSlug.fromTitle": "Создать из названия", + "page.changeStatus": "Изменить статус", + "page.changeStatus.position": "Пожалуйста, выберите позицию", + "page.changeStatus.select": "Выбрать новый статус", + "page.changeTemplate": "Изменить шаблон", + "page.delete.confirm": "Вы точно хотите удалить страницу {title}?", + "page.delete.confirm.subpages": "У этой страницы есть внутренние страницы.
Все внутренние страницы так же будут удалены.", + "page.delete.confirm.title": "Напишите название страницы, чтобы подтвердить", + "page.draft.create": "Создать черновик", + "page.duplicate.appendix": "(копия)", + "page.duplicate.files": "Копировать файлы", + "page.duplicate.pages": "Копировать страницы", + "page.sort": "Изменить позицию", + "page.status": "Статус", + "page.status.draft": "Черновик", + "page.status.draft.description": "Страница находится в черновом режиме и видна только зарегистрированным пользователям или по секретной ссылке", + "page.status.listed": "Опубликована", + "page.status.listed.description": "Страница доступна для всех посетителей", + "page.status.unlisted": "Скрыта", + "page.status.unlisted.description": "Страница доступна только по URL", + + "pages": "Страницы", + "pages.empty": "Страниц нет", + "pages.status.draft": "Черновики", + "pages.status.listed": "Опубликовано", + "pages.status.unlisted": "Скрытая", + + "pagination.page": "Страница", + + "password": "\u041f\u0430\u0440\u043e\u043b\u044c", + "paste": "Вставить", + "paste.after": "Вставить после", + "pixel": "Пиксель", + "plugins": "Плагины", + "prev": "Предыдущий", + "preview": "Предпросмотр", + "remove": "Удалить", + "rename": "Переназвать", + "replace": "\u0417\u0430\u043c\u0435\u043d\u0438\u0442\u044c", + "retry": "\u041f\u043e\u0432\u0442\u043e\u0440\u0438\u0442\u044c", + "revert": "\u0421\u0431\u0440\u043e\u0441", + "revert.confirm": "Вы действительно хотите удалить все несохраненные изменения?", + + "role": "\u0420\u043e\u043b\u044c", + "role.admin.description": "Администратор имеет все права", + "role.admin.title": "Администратор", + "role.all": "Все", + "role.empty": "Пользователей с такой ролью нет", + "role.description.placeholder": "Без описания", + "role.nobody.description": "Эта роль применяется если у пользователя нет никаких прав", + "role.nobody.title": "Никто", + + "save": "\u0421\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c", + "search": "Поиск", + "search.min": "Введите хотя бы {min} символов для поиска", + "search.all": "Показать все", + "search.results.none": "Нет результатов", + + "section.required": "Секция обязательна", + + "security": "Безопасность", + "select": "Выбрать", + "server": "Сервер", + "settings": "Настройка", + "show": "Показать", + "site.blueprint": "У сайта пока нет разметки. Вы можете определить новые секции и поля разметки в /site/blueprints/site.yml", + "size": "Размер", + "slug": "Понятная ссылка", + "sort": "Сортировать", + + "stats.empty": "Статистики нет", + "system.issues.content": "Похоже, к папке content есть несанкционированный доступ", + "system.issues.debug": "Включен режим отладки (debugging). Используйте его только при разработке.", + "system.issues.git": "Похоже, к папке .git есть несанкционированный доступ", + "system.issues.https": "Рекомендуется использовать HTTPS на всех сайтах", + "system.issues.kirby": "Похоже, к папке kirby есть несанкционированный доступ", + "system.issues.site": "Похоже, к папке site есть несанкционированный доступ", + + "title": "Название", + "template": "\u0428\u0430\u0431\u043b\u043e\u043d", + "today": "Сегодня", + + "toolbar.button.code": "Код", + "toolbar.button.bold": "\u0416\u0438\u0440\u043d\u044b\u0439 \u0448\u0440\u0438\u0444\u0442", + "toolbar.button.email": "Email", + "toolbar.button.headings": "Заголовки", + "toolbar.button.heading.1": "Заголовок 1", + "toolbar.button.heading.2": "Заголовок 2", + "toolbar.button.heading.3": "Заголовок 3", + "toolbar.button.heading.4": "Заголовок 4", + "toolbar.button.heading.5": "Заголовок 5", + "toolbar.button.heading.6": "Заголовок 6", + "toolbar.button.italic": "Курсив", + "toolbar.button.file": "Файл", + "toolbar.button.file.select": "Выбрать файл", + "toolbar.button.file.upload": "Закачать файл", + "toolbar.button.link": "\u0421\u0441\u044b\u043b\u043a\u0430", + "toolbar.button.paragraph": "Параграф", + "toolbar.button.strike": "Зачёркнутый", + "toolbar.button.ol": "Нумерованный список", + "toolbar.button.underline": "Подчёркнутый", + "toolbar.button.ul": "Маркированный список", + + "translation.author": "Команда Kirby", + "translation.direction": "ltr", + "translation.name": "Русский (Russian)", + "translation.locale": "ru_RU", + + "upload": "Закачать", + "upload.error.cantMove": "Не удается переместить загруженный файл", + "upload.error.cantWrite": "Не получилось записать файл на диск", + "upload.error.default": "Не удалось загрузить файл", + "upload.error.extension": "Загрузка файла не удалась из за расширения", + "upload.error.formSize": "Загруженный файл больше чем MAX_FILE_SIZE настройка в форме", + "upload.error.iniPostSize": "Загружаемый файл больше чем post_max_size настройка в php.ini", + "upload.error.iniSize": "Загруженный файл больше чем настройка upload_max_filesize в php.ini", + "upload.error.noFile": "Файл не был загружен", + "upload.error.noFiles": "Файлы не были загружены", + "upload.error.partial": "Файл загружен только частично", + "upload.error.tmpDir": "Не хватает временной папки", + "upload.errors": "Ошибка", + "upload.progress": "Закачивается...", + + "url": "URL", + "url.placeholder": "https://example.com", + + "user": "Пользователь", + "user.blueprint": "Вы можете определить новые секции и поля разметки для пользователя в /site/blueprints/users/{blueprint}.yml", + "user.changeEmail": "Изменить Email", + "user.changeLanguage": "Изменить язык", + "user.changeName": "Переназвать этого пользователя", + "user.changePassword": "Изменить пароль", + "user.changePassword.new": "Новый пароль", + "user.changePassword.new.confirm": "Подтвердить новый пароль…", + "user.changeRole": "Изменить роль", + "user.changeRole.select": "Выбрать новую роль", + "user.create": "Добавить нового пользователя", + "user.delete": "Удалить этого пользователя", + "user.delete.confirm": "Вы действительно хотите аккаунт
{email}?", + + "users": "Пользователи", + + "version": "Версия", + + "view.account": "\u0412\u0430\u0448 \u0430\u043a\u043a\u0430\u0443\u043d\u0442", + "view.installation": "\u0423\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430", + "view.languages": "Языки", + "view.resetPassword": "Сбросить пароль", + "view.site": "Сайт", + "view.system": "Система", + "view.users": "\u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0438", + + "welcome": "Добро пожаловать", + "year": "Год", + "yes": "да" } diff --git a/kirby/i18n/translations/sk.json b/kirby/i18n/translations/sk.json index f893850..11ca7c1 100644 --- a/kirby/i18n/translations/sk.json +++ b/kirby/i18n/translations/sk.json @@ -1,730 +1,574 @@ { - "account.changeName": "Zmeniť vaše meno", - "account.delete": "Zmazať váš účet", - "account.delete.confirm": "Do you really want to delete your account? You will be logged out immediately. Your account cannot be recovered.", - - "activate": "Activate", - "add": "Pridať", - "alpha": "Alpha", - "author": "Autor", - "avatar": "Profilový obrázok", - "back": "Späť", - "cancel": "Zrušiť", - "change": "Zmeniť", - "close": "Zavrieť", - "changes": "Zmeny", - "confirm": "Ok", - "collapse": "Zabaliť", - "collapse.all": "Zabaliť všetky", - "color": "Farba", - "coordinates": "Koordináty", - "copy": "Kopírovať", - "copy.all": "Copy all", - "copy.success": "{count} copied!", - "create": "Vytvoriť", - "custom": "Custom", - - "date": "Dátum", - "date.select": "Zvoliť dátum", - - "day": "Deň", - "days.fri": "Pia", - "days.mon": "Pon", - "days.sat": "Sob", - "days.sun": "Ned", - "days.thu": "Štv", - "days.tue": "Uto", - "days.wed": "Str", - - "debugging": "Debugging", - - "delete": "Zmazať", - "delete.all": "Zmazať všetky", - - "dialog.fields.empty": "This dialog has no fields", - "dialog.files.empty": "No files to select", - "dialog.pages.empty": "No pages to select", - "dialog.text.empty": "This dialog does not define any text", - "dialog.users.empty": "Zvolení neboli žiadni uživátelia", - - "dimensions": "Rozmery", - "disable": "Disable", - "disabled": "Disabled", - "discard": "Zahodiť", - - "drawer.fields.empty": "This drawer has no fields", - - "domain": "Domain", - "download": "Stiahnuť", - "duplicate": "Duplikovať", - - "edit": "Upraviť", - - "email": "E-mail", - "email.placeholder": "mail@example.com", - - "enter": "Enter", - "entries": "Entries", - "entry": "Entry", - - "environment": "Environment", - - "error": "Chyba", - "error.access.code": "Neplatný kód", - "error.access.login": "Neplatné prihlásenie", - "error.access.panel": "Nemáte povolenie na prístup do Panel-u", - "error.access.view": "You are not allowed to access this part of the panel", - - "error.avatar.create.fail": "Profilový obrázok sa nepodarilo nahrať", - "error.avatar.delete.fail": "Profilový obrázok sa nepodarilo zmazať", - "error.avatar.dimensions.invalid": "Prosím, dodržte, aby šírka a výška profilového obrázka bola menšia ako 3000 pixelov", - "error.avatar.mime.forbidden": "Profilový obrázok musí byť súbor JPEG alebo PNG.", - - "error.blueprint.notFound": "Blueprint \"{name}\" sa nepodarilo načítať", - - "error.blocks.max.plural": "You must not add more than {max} blocks", - "error.blocks.max.singular": "You must not add more than one block", - "error.blocks.min.plural": "You must add at least {min} blocks", - "error.blocks.min.singular": "You must add at least one block", - "error.blocks.validation": "There's an error on the \"{field}\" field in block {index} using the \"{fieldset}\" block type", - - "error.cache.type.invalid": "Invalid cache type \"{type}\"", - - "error.email.preset.notFound": "E-mailovú predvoľbu \"{name}\" nie je možné nájsť", - - "error.field.converter.invalid": "Neplatný converter \"{converter}\"", - "error.field.type.missing": "Field \"{ name }\": The field type \"{ type }\" does not exist", - - "error.file.changeName.empty": "Meno nesmie byť prázdne", - "error.file.changeName.permission": "Nemáte povolenie na zmenu názvu pre \"{filename}\"", - "error.file.changeTemplate.invalid": "The template for the file \"{id}\" cannot be changed to \"{template}\" (valid: \"{blueprints}\")", - "error.file.changeTemplate.permission": "You are not allowed to change the template for the file \"{id}\"", - - "error.file.duplicate": "Súbor s názvom \"{filename}\" už existuje", - "error.file.extension.forbidden": "Prípona \"{extension}\" nie je povolená", - "error.file.extension.invalid": "Neplatná prípona: \"{extension}\"", - "error.file.extension.missing": "Prípona pre \"{filename}\" chýba", - "error.file.maxheight": "Výška obrázku nesmie prekročiť \"{height}\" pixelov", - "error.file.maxsize": "Súbor je príliš velký", - "error.file.maxwidth": "Šírka obrázku nesmie prekročiť \"{width}\" pixelov", - "error.file.mime.differs": "Mime typ nahratého súboru msa musí zhodovať s \"{mime}\"", - "error.file.mime.forbidden": "Typ média \"{mime}\" nie je povolený", - "error.file.mime.invalid": "Neplatný mime typ: \"{mime}\"", - "error.file.mime.missing": "Typ média pre \"{filename}\" sa nepodarilo zistiť", - "error.file.minheight": "Výška obrázku musí byť aspoň \"{height}\" pixelov", - "error.file.minsize": "Súbor je príliš malý", - "error.file.minwidth": "Šírka obrázku musí byť aspoň \"{width}\" pixelov", - "error.file.name.unique": "The filename must be unique", - "error.file.name.missing": "Názov súboru nemôže byť prázdny", - "error.file.notFound": "Súbor \"{filename}\" sa nepodarilo nájsť", - "error.file.orientation": "The orientation of the image must be \"{orientation}\"", - "error.file.type.forbidden": "Nemáte povolenie na nahrávanie súborov s typom {type}", - "error.file.type.invalid": "Neplatný typ súboru: \"{type}\"", - "error.file.undefined": "Súbor nie je možné nájsť", - - "error.form.incomplete": "Prosím, opravte všetky chyby v rámci formuláru...", - "error.form.notSaved": "Formulár sa nepodarilo uložiť", - - "error.language.code": "Please enter a valid code for the language", - "error.language.duplicate": "The language already exists", - "error.language.name": "Please enter a valid name for the language", - "error.language.notFound": "The language could not be found", - - "error.layout.validation.block": "There's an error on the \"{field}\" field in block {blockIndex} using the \"{fieldset}\" block type in layout {layoutIndex}", - "error.layout.validation.settings": "There's an error in layout {index} settings", - - "error.license.domain": "The domain for the license is missing", - "error.license.email": "Prosím, zadajte platnú e-mailovú adresu", - "error.license.format": "Please enter a valid license code", - "error.license.verification": "The license could not be verified", - - "error.login.totp.confirm.invalid": "Neplatný kód", - "error.login.totp.confirm.missing": "Please enter the current code", - - "error.object.validation": "There’s an error in the \"{label}\" field:\n{message}", - - "error.offline": "The Panel is currently offline", - - "error.page.changeSlug.permission": "Nemáte povolenie na zmenu URL príponu pre \"{slug}\"", - "error.page.changeSlug.reserved": "The path of top-level pages must not start with \"{path}\"", - "error.page.changeStatus.incomplete": "Stránka obsahuje chyby a nemôže byť zverejnená", - "error.page.changeStatus.permission": "Status tejto stránky nemôže byť zmenený", - "error.page.changeStatus.toDraft.invalid": "Stránka \"{slug}\" nemôže byť zmenená na koncept.", - "error.page.changeTemplate.invalid": "Šablónu pre stránku \"{slug}\" nie je možné zmeniť", - "error.page.changeTemplate.permission": "Nemáte povolenie na zmenu šablóny pre \"{slug}\"", - "error.page.changeTitle.empty": "Titulok nemôže byť prázdny", - "error.page.changeTitle.permission": "Nemáte povolenie na zmenu titulku pre \"{slug}\"", - "error.page.create.permission": "Nemáte povolenie na vytvorenie \"{slug}\"", - "error.page.delete": "Stránku \"{slug}\" nie je možné vymazať", - "error.page.delete.confirm": "Prosím, zadajte titulok stránky pre potvrdenie", - "error.page.delete.hasChildren": "Táto stránka obsahuje podstránky a nemôže byť zmazaná", - "error.page.delete.permission": "Nemáte povolenie na zmazanie stránky \"{slug}\"", - "error.page.draft.duplicate": "Koncept stránky s URL appendix-om \"{slug}\" už existuje", - "error.page.duplicate": "Stránka s URL appendix-om \"{slug}\" už existuje", - "error.page.duplicate.permission": "You are not allowed to duplicate \"{slug}\"", - "error.page.move.ancestor": "The page cannot be moved into itself", - "error.page.move.directory": "The page directory cannot be moved", - "error.page.move.duplicate": "A sub page with the URL appendix \"{slug}\" already exists", - "error.page.move.notFound": "The moved page could not be found", - "error.page.move.permission": "You are not allowed to move \"{slug}\"", - "error.page.move.template": "The \"{template}\" template is not accepted as a subpage of \"{parent}\"", - "error.page.notFound": "Stránku \"{slug}\" nie je možné nájsť", - "error.page.num.invalid": "Prosím, zadajte platné číslo pre radenie. Čísla nemôžu byť záporné.", - "error.page.slug.invalid": "Please enter a valid URL appendix", - "error.page.slug.maxlength": "Slug length must be less than \"{length}\" characters", - "error.page.sort.permission": "Stránku \"{slug}\" nie je možné preradiť.", - "error.page.status.invalid": "Prosím, nastavte platnú status pre stránku", - "error.page.undefined": "Stránku nie je možné nájsť", - "error.page.update.permission": "Nemáte povolenie na aktualizáciu \"{slug}\"", - - "error.section.files.max.plural": "Nemôžete pridať viac ako {max} súbory/ov do sekcie \"{section}\"", - "error.section.files.max.singular": "Nemôžete pridať viac ako 1 súbor do sekcie \"{section}\"", - "error.section.files.min.plural": "The \"{section}\" section requires at least {min} files", - "error.section.files.min.singular": "The \"{section}\" section requires at least one file", - - "error.section.pages.max.plural": "Nemôžete pridať viac ako {max} stránky/ok do sekcie \"{section}\"", - "error.section.pages.max.singular": "Nemôžete pridať viac ako 1 stránku do sekcie \"{section}\"", - "error.section.pages.min.plural": "The \"{section}\" section requires at least {min} pages", - "error.section.pages.min.singular": "The \"{section}\" section requires at least one page", - - "error.section.notLoaded": "Sekciu \"{name}\" sa nepodarilo nahrať", - "error.section.type.invalid": "Typ sekcie \"{type}\" nie je platný", - - "error.site.changeTitle.empty": "Titulok nemôže byť prázdny", - "error.site.changeTitle.permission": "Nemáte povolenie na zmenu titulku pre portál", - "error.site.update.permission": "Nemáte povolenie na aktualizovanie portálu", - - "error.structure.validation": "There's an error on the \"{field}\" field in row {index}", - - "error.template.default.notFound": "Predvolená šablóna neexistuje", - - "error.unexpected": "An unexpected error occurred! Enable debug mode for more info: https://getkirby.com/docs/reference/system/options/debug", - - "error.user.changeEmail.permission": "Nemáte povolenie na zmenu e-mailu pre užívateľa \"{name}\"", - "error.user.changeLanguage.permission": "Nemáte povolenie na zmenu jazyka pre užívateľa \"{name}\"", - "error.user.changeName.permission": "Nemáte povolenie na zmenu mena pre užívateľa \"{name}\"", - "error.user.changePassword.permission": "Nemáte povolenie na zmenu hesla pre užívateľa \"{name}\"", - "error.user.changeRole.lastAdmin": "Rolu pre posledného administrátora nie je možné zmeniť", - "error.user.changeRole.permission": "Nemáte povolenie na zmenu role pre užívateľa \"{name}\"", - "error.user.changeRole.toAdmin": "You are not allowed to promote someone to the admin role", - "error.user.create.permission": "Nemáte povolenie na vytvorenie tohto užívateľa", - "error.user.delete": "Užívateľa \"{name}\" nie je možné zmazať", - "error.user.delete.lastAdmin": "Posledného administrátora nie je možné zmazať", - "error.user.delete.lastUser": "Posledného užívateľa nie je možné zmazať", - "error.user.delete.permission": "Nemáte povolenie na zmazanie užívateľa \"{name}\"", - "error.user.duplicate": "Užívateľ s e-mailovou adresou \"{email}\" už existuje", - "error.user.email.invalid": "Prosím, zadajte platnú e-mailovú adresu", - "error.user.language.invalid": "Prosím, zadajte platný jazyk", - "error.user.notFound": "Užívateľa \"{name}\" nie je možné nájsť", - "error.user.password.excessive": "Please enter a valid password. Passwords must not be longer than 1000 characters.", - "error.user.password.invalid": "Prosím, zadajte platné heslo. Dĺžka hesla musí byť aspoň 8 znakov.", - "error.user.password.notSame": "Heslá nie sú rovnaké", - "error.user.password.undefined": "Užívateľ nemá heslo", - "error.user.password.wrong": "Wrong password", - "error.user.role.invalid": "Prosím, zadajte platnú rolu", - "error.user.undefined": "Užívateľa sa nepodarilo nájsť", - "error.user.update.permission": "Nemáte povolenie na aktualizáciu užívateľa \"{name}\"", - - "error.validation.accepted": "Prosím, potvrďte", - "error.validation.alpha": "Prosím, zadajte len znaky z hlások a-z", - "error.validation.alphanum": "Prosím, zadajte len znaky z hlások a-z a čísloviek 0-9", - "error.validation.anchor": "Please enter a correct link anchor", - "error.validation.between": "Prosím, zadajte hodnotu od \"{min}\" do \"{max}\"", - "error.validation.boolean": "Prosím, potvrďte alebo odmietnite", - "error.validation.color": "Please enter a valid color in the {format} format", - "error.validation.contains": "Prosím, zadajte hodnotu, ktorá obsahuje \"{needle}\"", - "error.validation.date": "Prosím, zadajte platný dátum", - "error.validation.date.after": "Please enter a date after {date}", - "error.validation.date.before": "Please enter a date before {date}", - "error.validation.date.between": "Please enter a date between {min} and {max}", - "error.validation.denied": "Prosím, odmietnite", - "error.validation.different": "Hodnota nemôže byť \"{other}\"", - "error.validation.email": "Prosím, zadajte platnú e-mailovú adresu", - "error.validation.endswith": "Hodnota musí končiť na \"{end}\"", - "error.validation.filename": "Prosím, zadajte platný názov súboru", - "error.validation.in": "Prosím, zadajte jedno z nasledujúcich: ({in})", - "error.validation.integer": "Prosím, zadajte platné celé číslo", - "error.validation.ip": "Prosím, zadajte platnú e-mailovú adresu", - "error.validation.less": "Prosím, zadajte hodnotu menšiu ako {max}", - "error.validation.linkType": "The link type is not allowed", - "error.validation.match": "Hodnota nezodpovedá očakávanému vzoru", - "error.validation.max": "Prosím, zadajte hodnotu rovnú alebo menšiu ako {max}", - "error.validation.maxlength": "Prosím, zadajte kratšiu hodnotu. (max. {max} charaktery/ov)", - "error.validation.maxwords": "Prosím, nezadávajte viac ako {max} slovo/á/ov", - "error.validation.min": "Prosím, zadajte hodnotu rovnú alebo väčšiu ako {min}", - "error.validation.minlength": "Prosím, zadajte dlhšiu hodnotu. (min. {min} charaktery/ov)", - "error.validation.minwords": "Prosím, zadajte aspoň {min} slovo/á/ov", - "error.validation.more": "Prosím zadajte hodnotu väčšiu ako {min}", - "error.validation.notcontains": "Prosím, zadajte hodnotu, ktorá neobsahuje \"{needle}\"", - "error.validation.notin": "Prosím, nezadávajte ani jedno z nasledujúcich: ({notIn})", - "error.validation.option": "Prosím, zadajte platnú voľbu", - "error.validation.num": "Prosím, zadajte platné číslo", - "error.validation.required": "Prosím, zadajte niečo", - "error.validation.same": "Prosím, zadajte \"{other}\"", - "error.validation.size": "Veľkosť hodnoty musí byť \"{size}\"", - "error.validation.startswith": "Hodnota musí začínať s \"{start}\"", - "error.validation.tel": "Please enter an unformatted phone number", - "error.validation.time": "Prosím, zadajte platný čas", - "error.validation.time.after": "Please enter a time after {time}", - "error.validation.time.before": "Please enter a time before {time}", - "error.validation.time.between": "Please enter a time between {min} and {max}", - "error.validation.uuid": "Please enter a valid UUID", - "error.validation.url": "Prosím, zadajte platnú URL", - - "expand": "Rozbaliť", - "expand.all": "Rozbaliť všetky", - - "field.invalid": "The field is invalid", - "field.required": "The field is required", - "field.blocks.changeType": "Change type", - "field.blocks.code.name": "Kód", - "field.blocks.code.language": "Jazyk", - "field.blocks.code.placeholder": "Váš kód ...", - "field.blocks.delete.confirm": "Naozaj chcete zmazať tento blok?", - "field.blocks.delete.confirm.all": "Naozaj chcete zmazať všetky bloky?", - "field.blocks.delete.confirm.selected": "Naozaj chcete zmazať vybrané bloky?", - "field.blocks.empty": "No blocks yet", - "field.blocks.fieldsets.empty": "No fieldsets yet", - "field.blocks.fieldsets.label": "Please select a block type …", - "field.blocks.fieldsets.paste": "Press {{ shortcut }} to import layouts/blocks from your clipboard Only those allowed in the current field will get inserted.", - "field.blocks.gallery.name": "Galéria", - "field.blocks.gallery.images.empty": "No images yet", - "field.blocks.gallery.images.label": "Obrázky", - "field.blocks.heading.level": "Level", - "field.blocks.heading.name": "Nadpis", - "field.blocks.heading.text": "Text", - "field.blocks.heading.placeholder": "Nadpis ...", - "field.blocks.image.alt": "Alternative text", - "field.blocks.image.caption": "Popis", - "field.blocks.image.crop": "Orezanie", - "field.blocks.image.link": "Odkaz", - "field.blocks.image.location": "Poloha", - "field.blocks.image.location.internal": "This website", - "field.blocks.image.location.external": "External source", - "field.blocks.image.name": "Obrázok", - "field.blocks.image.placeholder": "Select an image", - "field.blocks.image.ratio": "Ratio", - "field.blocks.image.url": "Image URL", - "field.blocks.line.name": "Line", - "field.blocks.list.name": "List", - "field.blocks.markdown.name": "Markdown", - "field.blocks.markdown.label": "Text", - "field.blocks.markdown.placeholder": "Markdown …", - "field.blocks.quote.name": "Quote", - "field.blocks.quote.text.label": "Text", - "field.blocks.quote.text.placeholder": "Quote …", - "field.blocks.quote.citation.label": "Citation", - "field.blocks.quote.citation.placeholder": "by …", - "field.blocks.text.name": "Text", - "field.blocks.text.placeholder": "Text …", - "field.blocks.video.autoplay": "Autoplay", - "field.blocks.video.caption": "Popis", - "field.blocks.video.controls": "Controls", - "field.blocks.video.location": "Poloha", - "field.blocks.video.loop": "Loop", - "field.blocks.video.muted": "Muted", - "field.blocks.video.name": "Video", - "field.blocks.video.placeholder": "Enter a video URL", - "field.blocks.video.poster": "Poster", - "field.blocks.video.preload": "Preload", - "field.blocks.video.url.label": "Video-URL", - "field.blocks.video.url.placeholder": "https://youtube.com/?v=", - - "field.files.empty": "Žiadne súbory zatiaľ neboli zvolené", - - "field.layout.change": "Change layout", - "field.layout.delete": "Delete layout", - "field.layout.delete.confirm": "Do you really want to delete this layout?", - "field.layout.delete.confirm.all": "Do you really want to delete all layouts?", - "field.layout.empty": "No rows yet", - "field.layout.select": "Select a layout", - - "field.object.empty": "No information yet", - - "field.pages.empty": "Žiadne stránky zatiaľ neboli zvolené", - - "field.structure.delete.confirm": "Ste si istý, že chcete zmazať tento riadok?", - "field.structure.delete.confirm.all": "Do you really want to delete all entries?", - "field.structure.empty": "Zatiaľ žiadne údaje", - - "field.users.empty": "Žiadni užívatelia zatiaľ neboli zvolení", - - "fields.empty": "No fields yet", - - "file": "Súbor", - "file.blueprint": "This file has no blueprint yet. You can define the setup in /site/blueprints/files/{blueprint}.yml", - "file.changeTemplate": "Zmeniť šablónu", - "file.changeTemplate.notice": "Changing the file's template will remove content for fields that don't match in type. If the new template defines certain rules, e.g. image dimensions, those will also be applied irreversibly. Use with caution.", - "file.delete.confirm": "Ste si istý, že chcete zmazať
{filename}?", - "file.focus.placeholder": "Set focal point", - "file.focus.reset": "Remove focal point", - "file.focus.title": "Focus", - "file.sort": "Change position", - - "files": "Súbory", - "files.empty": "Zatiaľ žiadne súbory", - - "filter": "Filter", - - "hide": "Hide", - "hour": "Hodina", - "hue": "Hue", - "import": "Import", - "info": "Info", - "insert": "Vložiť", - "insert.after": "Insert after", - "insert.before": "Insert before", - "install": "Inštalovať", - - "installation": "Inštalácia", - "installation.completed": "Panel bol nainštalovaný", - "installation.disabled": "Inštalácia Panelu na verejných serveroch je štandardne zablokovaná. Prosím, spustite inštaláciu na lokálnom serveri alebo aktivujte voľbu panel.install.", - "installation.issues.accounts": "Priečinok /site/accounts neexistuje alebo nie je nastavený ako zapisovateľný", - "installation.issues.content": "Priečinok /content neexistuje alebo nie je nastavený ako zapisovateľný", - "installation.issues.curl": "CURL rozšírenie je povinné", - "installation.issues.headline": "Panel nie je možné naištalovať", - "installation.issues.mbstring": "MB String rozšírenie je povinné", - "installation.issues.media": "Priečinok /media neexistuje alebo nie je nastavený ako zapisovateľný", - "installation.issues.php": "Uistite sa, že používate PHP 8+", - "installation.issues.sessions": "Priečinok /site/sessions neexistuje alebo nie je nastavený ako zapisovateľný", - - "language": "Jazyk", - "language.code": "Kód", - "language.convert": "Nastaviť ako predvolené", - "language.convert.confirm": "

Ste si istý, že chcete nastaviť {name} ako predvolený jazyk? Túto akciu nie je možné zvrátiť.

Ak {name} obsahuje nepreložený obsah, tak pre tento obsah nebude fungovať platné volanie a niektoré časti vašich stránok zostanú prázdne.

", - "language.create": "Pridať nový jazyk", - "language.default": "Predvolený jazyk", - "language.delete.confirm": "Ste si istý, že chcete zmazať jazyk {name} vrátane všetkých prekladov? Túto akciu nie je možné zvrátiť.", - "language.deleted": "Jazyk bol zmazaný", - "language.direction": "Smer čítania", - "language.direction.ltr": "Zľava doprava", - "language.direction.rtl": "Zprava doľava", - "language.locale": "PHP locale string", - "language.locale.warning": "You are using a custom locale set up. Please modify it in the language file in /site/languages", - "language.name": "Názov", - "language.secondary": "Secondary language", - "language.settings": "Language settings", - "language.updated": "Jazyk bol aktualizovaný", - "language.variables": "Language variables", - "language.variables.empty": "No translations yet", - - "language.variable.delete.confirm": "Do you really want to delete the variable for {key}?", - "language.variable.key": "Key", - "language.variable.notFound": "The variable could not be found", - "language.variable.value": "Value", - - "languages": "Jazyky", - "languages.default": "Predvolený jazyk", - "languages.empty": "Zatiaľ žiadne jazyky", - "languages.secondary": "Sekundárne jazyky", - "languages.secondary.empty": "Zatiaľ žiadne sekundárne jazyky", - - "license": "Licencia", - "license.activate": "Activate it now", - "license.activate.label": "Please activate your license", - "license.activate.domain": "Your license will be activated for {host}.", - "license.activate.local": "You are about to activate your Kirby license for your local domain {host}. If this site will be deployed to a public domain, please activate it there instead. If {host} is the domain you want to use your license for, please continue.", - "license.activated": "Activated", - "license.buy": "Zakúpiť licenciu", - "license.code": "Kód", - "license.code.help": "You received your license code after the purchase via email. Please copy and paste it here.", - "license.code.label": "Prosím, zadajte váš licenčný kód", - "license.status.active.info": "Includes new major versions until {date}", - "license.status.active.label": "Valid license", - "license.status.demo.info": "This is a demo installation", - "license.status.demo.label": "Demo", - "license.status.inactive.info": "Renew license to update to new major versions", - "license.status.inactive.label": "No new major versions", - "license.status.legacy.bubble": "Ready to renew your license?", - "license.status.legacy.info": "Your license does not cover this version", - "license.status.legacy.label": "Please renew your license", - "license.status.missing.bubble": "Ready to launch your site?", - "license.status.missing.info": "No valid license", - "license.status.missing.label": "Please activate your license", - "license.manage": "Manage your licenses", - "license.purchased": "Purchased", - "license.success": "Ďakujeme za vašu podporu Kirby", - "license.unregistered.label": "Unregistered", - - "link": "Odkaz", - "link.text": "Text odkazu", - - "loading": "Načítavanie", - - "lock.unsaved": "Unsaved changes", - "lock.unsaved.empty": "There are no more unsaved changes", - "lock.isLocked": "Unsaved changes by {email}", - "lock.unlock": "Unlock", - "lock.unlock.submit": "Unlock and overwrite unsaved changes by {email}", - "lock.isUnlocked": "Was unlocked by another user", - - "login": "Prihlásenie", - "login.code.label.login": "Login code", - "login.code.label.password-reset": "Password reset code", - "login.code.placeholder.email": "000 000", - "login.code.placeholder.totp": "000000", - "login.code.text.email": "If your email address is registered, the requested code was sent via email.", - "login.code.text.totp": "Please enter the one‑time code from your authenticator app.", - "login.email.login.body": "Hi {user.nameOrEmail},\n\nYou recently requested a login code for the Panel of {site}.\nThe following login code will be valid for {timeout} minutes:\n\n{code}\n\nIf you did not request a login code, please ignore this email or contact your administrator if you have questions.\nFor security, please DO NOT forward this email.", - "login.email.login.subject": "Your login code", - "login.email.password-reset.body": "Hi {user.nameOrEmail},\n\nYou recently requested a password reset code for the Panel of {site}.\nThe following password reset code will be valid for {timeout} minutes:\n\n{code}\n\nIf you did not request a password reset code, please ignore this email or contact your administrator if you have questions.\nFor security, please DO NOT forward this email.", - "login.email.password-reset.subject": "Your password reset code", - "login.remember": "Ponechať ma prihláseného", - "login.reset": "Reset password", - "login.toggleText.code.email": "Login via email", - "login.toggleText.code.email-password": "Login with password", - "login.toggleText.password-reset.email": "Forgot your password?", - "login.toggleText.password-reset.email-password": "← Back to login", - "login.totp.enable.option": "Set up one‑time codes", - "login.totp.enable.intro": "Authenticator apps can generate one‑time codes that are used as a second factor when signing into your account.", - "login.totp.enable.qr.label": "1. Scan this QR code", - "login.totp.enable.qr.help": "Unable to scan? Add the setup key {secret} manually to your authenticator app.", - "login.totp.enable.confirm.headline": "2. Confirm with generated code", - "login.totp.enable.confirm.text": "Your app generates a new one‑time code every 30 seconds. Enter the current code to complete the setup:", - "login.totp.enable.confirm.label": "Current code", - "login.totp.enable.confirm.help": "After this setup, we will ask you for a one‑time code every time you log in.", - "login.totp.enable.success": "One‑time codes enabled", - "login.totp.disable.option": "Disable one‑time codes", - "login.totp.disable.label": "Enter your password to disable one‑time codes", - "login.totp.disable.help": "In the future, a different second factor like a login code sent via email will be requested when you log in. You can always set up one‑time codes again later.", - "login.totp.disable.admin": "

This will disable one‑time codes for {user}.

In the future, a different second factor like a login code sent via email will be requested when they log in. {user} can set up one‑time codes again after their next login.

", - "login.totp.disable.success": "One‑time codes disabled", - - "logout": "Odhlásenie", - - "merge": "Merge", - "menu": "Menu", - "meridiem": "AM/PM", - "mime": "Typ média", - "minutes": "Minúty", - - "month": "Mesiac", - "months.april": "Apríl", - "months.august": "August", - "months.december": "December", - "months.february": "Február", - "months.january": "Január", - "months.july": "Júl", - "months.june": "Jún", - "months.march": "Marec", - "months.may": "Máj", - "months.november": "November", - "months.october": "Október", - "months.september": "September", - - "more": "Viac", - "move": "Move", - "name": "Meno", - "next": "Ďalej", - "night": "Night", - "no": "no", - "off": "off", - "on": "on", - "open": "Otvoriť", - "open.newWindow": "Open in new window", - "option": "Option", - "options": "Nastavenia", - "options.none": "No options", - "options.all": "Show all {count} options", - - "orientation": "Orientácia", - "orientation.landscape": "Širokouhlá", - "orientation.portrait": "Portrét", - "orientation.square": "Štvorec", - - "page": "Stránka", - "page.blueprint": "This page has no blueprint yet. You can define the setup in /site/blueprints/pages/{blueprint}.yml", - "page.changeSlug": "Zmeniť URL", - "page.changeSlug.fromTitle": "Vytvoriť z titulku", - "page.changeStatus": "Zmeniť status", - "page.changeStatus.position": "Prosím, zmeňte pozíciu", - "page.changeStatus.select": "Zvoľte nový status", - "page.changeTemplate": "Zmeniť šablónu", - "page.changeTemplate.notice": "Changing the page's template will remove content for fields that don't match in type. Use with caution.", - "page.create": "Create as {status}", - "page.delete.confirm": "Ste si istý, že chcete zmazať {title}?", - "page.delete.confirm.subpages": "Táto stránka obsahuje podstránky.
Všetky podstránky budú taktiež zmazané.", - "page.delete.confirm.title": "Pre potvrdenie zadajte titulok stránky", - "page.duplicate.appendix": "Kopírovať", - "page.duplicate.files": "Copy files", - "page.duplicate.pages": "Copy pages", - "page.move": "Move page", - "page.sort": "Change position", - "page.status": "Status", - "page.status.draft": "Koncept", - "page.status.draft.description": "The page is in draft mode and only visible for logged in editors or via secret link", - "page.status.listed": "Verejné", - "page.status.listed.description": "Stránka je prístupná pre všetkých", - "page.status.unlisted": "Skryté", - "page.status.unlisted.description": "Stránka je prístupná len prostredníctvom priamej URL", - - "pages": "Stránky", - "pages.empty": "Zatiaľ žiadne stránky", - "pages.status.draft": "Koncepty", - "pages.status.listed": "Zverejnené", - "pages.status.unlisted": "Skryté", - - "pagination.page": "Stránka", - - "password": "Heslo", - "paste": "Paste", - "paste.after": "Paste after", - "paste.success": "{count} pasted!", - "pixel": "Pixel", - "plugin": "Plugin", - "plugins": "Plugins", - "prev": "Predchádzajúci", - "preview": "Preview", - "remove": "Odstrániť", - "rename": "Premenovať", - "renew": "Renew", - "replace": "Nahradiť", - "replace.with": "Replace with", - "retry": "Skúsiť ešte raz", - "revert": "Vrátiť späť", - "revert.confirm": "Do you really want to delete all unsaved changes?", - - "role": "Rola", - "role.admin.description": "The admin has all rights", - "role.admin.title": "Admin", - "role.all": "Všetko", - "role.empty": "S touto rolou neexistujú žiadni užívatelia", - "role.description.placeholder": "Žiadny popis", - "role.nobody.description": "This is a fallback role without any permissions", - "role.nobody.title": "Nobody", - - "save": "Uložiť", - "search": "Hľadať", - "search.min": "Enter {min} characters to search", - "search.all": "Show all {count} results", - "search.results.none": "No results", - - "section.invalid": "The section is invalid", - "section.required": "The section is required", - - "security": "Security", - "select": "Zvoliť", - "server": "Server", - "settings": "Nastavenia", - "show": "Show", - "site.blueprint": "The site has no blueprint yet. You can define the setup in /site/blueprints/site.yml", - "size": "Veľkosť", - "slug": "URL appendix", - "sort": "Zoradiť", - "sort.drag": "Drag to sort …", - "split": "Split", - - "stats.empty": "No reports", - "status": "Status", - - "system.info.copy": "Copy info", - "system.info.copied": "System info copied", - "system.issues.content": "The content folder seems to be exposed", - "system.issues.eol.kirby": "Your installed Kirby version has reached end-of-life and will not receive further security updates", - "system.issues.eol.plugin": "Your installed version of the { plugin } plugin is has reached end-of-life and will not receive further security updates", - "system.issues.eol.php": "Your installed PHP release { release } has reached end-of-life and will not receive further security updates", - "system.issues.debug": "Debugging must be turned off in production", - "system.issues.git": "The .git folder seems to be exposed", - "system.issues.https": "We recommend HTTPS for all your sites", - "system.issues.kirby": "The kirby folder seems to be exposed", - "system.issues.site": "The site folder seems to be exposed", - "system.issues.vulnerability.kirby": "Your installation might be affected by the following vulnerability ({ severity } severity): { description }", - "system.issues.vulnerability.plugin": "Your installation might be affected by the following vulnerability in the { plugin } plugin ({ severity } severity): { description }", - "system.updateStatus": "Update status", - "system.updateStatus.error": "Could not check for updates", - "system.updateStatus.not-vulnerable": "No known vulnerabilities", - "system.updateStatus.security-update": "Free security update { version } available", - "system.updateStatus.security-upgrade": "Upgrade { version } with security fixes available", - "system.updateStatus.unreleased": "Unreleased version", - "system.updateStatus.up-to-date": "Up to date", - "system.updateStatus.update": "Free update { version } available", - "system.updateStatus.upgrade": "Upgrade { version } available", - - "tel": "Phone", - "tel.placeholder": "+49123456789", - "template": "Šablóna", - "title": "Titulok", - "today": "Dnes", - - "toolbar.button.clear": "Clear formatting", - "toolbar.button.code": "Kód", - "toolbar.button.bold": "Tučný", - "toolbar.button.email": "E-mail", - "toolbar.button.headings": "Nadpisy", - "toolbar.button.heading.1": "Nadpis 1", - "toolbar.button.heading.2": "Nadpis 2", - "toolbar.button.heading.3": "Nadpis 3", - "toolbar.button.heading.4": "Heading 4", - "toolbar.button.heading.5": "Heading 5", - "toolbar.button.heading.6": "Heading 6", - "toolbar.button.italic": "Kurzíva", - "toolbar.button.file": "Súbor", - "toolbar.button.file.select": "Select a file", - "toolbar.button.file.upload": "Upload a file", - "toolbar.button.link": "Odkaz", - "toolbar.button.paragraph": "Paragraph", - "toolbar.button.strike": "Strike-through", - "toolbar.button.sub": "Subscript", - "toolbar.button.sup": "Superscript", - "toolbar.button.ol": "Číslovaný zoznam", - "toolbar.button.underline": "Underline", - "toolbar.button.ul": "Odrážkový zoznam", - - "translation.author": "Tím Kirby", - "translation.direction": "ltr", - "translation.name": "Slovensky", - "translation.locale": "sk_SK", - - "type": "Type", - - "upload": "Nahrať", - "upload.error.cantMove": "The uploaded file could not be moved", - "upload.error.cantWrite": "Failed to write file to disk", - "upload.error.default": "The file could not be uploaded", - "upload.error.extension": "File upload stopped by extension", - "upload.error.formSize": "The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the form", - "upload.error.iniPostSize": "The uploaded file exceeds the post_max_size directive in php.ini", - "upload.error.iniSize": "The uploaded file exceeds the upload_max_filesize directive in php.ini", - "upload.error.noFile": "No file was uploaded", - "upload.error.noFiles": "No files were uploaded", - "upload.error.partial": "The uploaded file was only partially uploaded", - "upload.error.tmpDir": "Missing a temporary folder", - "upload.errors": "Chyba", - "upload.progress": "Nahrávanie...", - - "url": "URL", - "url.placeholder": "https://example.com", - - "user": "Užívateľ", - "user.blueprint": "You can define additional sections and form fields for this user role in /site/blueprints/users/{blueprint}.yml", - "user.changeEmail": "Zmeniť e-mail", - "user.changeLanguage": "Zmeniť jazyk", - "user.changeName": "Premenovať tohto užívateľa", - "user.changePassword": "Zmeniť heslo", - "user.changePassword.new": "Nové heslo", - "user.changePassword.new.confirm": "Potvrdiť nové heslo...", - "user.changeRole": "Zmeniť rolu", - "user.changeRole.select": "Zvoliť novú rolu", - "user.create": "Pridať nového užívateľa", - "user.delete": "Zmazať tohto užívateľa", - "user.delete.confirm": "Ste si istý, že chcete zmazať
{email}?", - - "users": "Užívatelia", - - "version": "Verzia", - "version.current": "Current version", - "version.latest": "Latest version", - "versionInformation": "Version information", - - "view.account": "Váš účet", - "view.installation": "Inštalácia", - "view.languages": "Jazyky", - "view.resetPassword": "Reset password", - "view.site": "Portál", - "view.system": "System", - "view.users": "Užívatelia", - - "welcome": "Vitajte", - "year": "Rok", - "yes": "yes" + "account.changeName": "Change your name", + "account.delete": "Delete your account", + "account.delete.confirm": "Do you really want to delete your account? You will be logged out immediately. Your account cannot be recovered.", + + "add": "Pridať", + "author": "Author", + "avatar": "Profilový obrázok", + "back": "Späť", + "cancel": "Zrušiť", + "change": "Zmeniť", + "close": "Zavrieť", + "confirm": "Ok", + "collapse": "Zabaliť", + "collapse.all": "Zabaliť všetky", + "copy": "Kopírovať", + "copy.all": "Copy all", + "create": "Vytvoriť", + + "date": "Dátum", + "date.select": "Zvoliť dátum", + + "day": "Deň", + "days.fri": "Pia", + "days.mon": "Pon", + "days.sat": "Sob", + "days.sun": "Ned", + "days.thu": "Štv", + "days.tue": "Uto", + "days.wed": "Str", + + "debugging": "Debugging", + + "delete": "Zmazať", + "delete.all": "Zmazať všetky", + + "dialog.files.empty": "No files to select", + "dialog.pages.empty": "No pages to select", + "dialog.users.empty": "No users to select", + + "dimensions": "Rozmery", + "disabled": "Disabled", + "discard": "Zahodiť", + "download": "Stiahnuť", + "duplicate": "Duplikovať", + + "edit": "Upraviť", + + "email": "E-mail", + "email.placeholder": "mail@example.com", + + "entries": "Entries", + "entry": "Entry", + + "environment": "Environment", + + "error.access.code": "Neplatný kód", + "error.access.login": "Neplatné prihlásenie", + "error.access.panel": "Nemáte povolenie na prístup do Panel-u", + "error.access.view": "You are not allowed to access this part of the panel", + + "error.avatar.create.fail": "Profilový obrázok sa nepodarilo nahrať", + "error.avatar.delete.fail": "Profilový obrázok sa nepodarilo zmazať", + "error.avatar.dimensions.invalid": "Prosím, dodržte, aby šírka a výška profilového obrázka bola menšia ako 3000 pixelov.", + "error.avatar.mime.forbidden": "Profilový obrázok musí byť súbor JPEG alebo PNG.", + + "error.blueprint.notFound": "Blueprint \"{name}\" sa nepodarilo načítať", + + "error.blocks.max.plural": "You must not add more than {max} blocks", + "error.blocks.max.singular": "You must not add more than one block", + "error.blocks.min.plural": "You must add at least {min} blocks", + "error.blocks.min.singular": "You must add at least one block", + "error.blocks.validation": "There's an error in block {index}", + + "error.email.preset.notFound": "E-mailovú predvoľbu \"{name}\" nie je možné nájsť", + + "error.field.converter.invalid": "Neplatný converter \"{converter}\"", + + "error.file.changeName.empty": "Meno nesmie byť prázdne", + "error.file.changeName.permission": "Nemáte povolenie na zmenu názvu pre \"{filename}\"", + "error.file.duplicate": "Súbor s názvom \"{filename}\" už existuje", + "error.file.extension.forbidden": "Prípona \"{extension}\" nie je povolená", + "error.file.extension.invalid": "Neplatná prípona: \"{extension}\"", + "error.file.extension.missing": "Prípona pre \"{filename}\" chýba", + "error.file.maxheight": "Výška obrázku nesmie prekročiť \"{height}\" pixelov", + "error.file.maxsize": "Súbor je príliš velký", + "error.file.maxwidth": "Šírka obrázku nesmie prekročiť \"{width}\" pixelov", + "error.file.mime.differs": "Mime typ nahratého súboru msa musí zhodovať s \"{mime}\"", + "error.file.mime.forbidden": "Typ média \"{mime}\" nie je povolený", + "error.file.mime.invalid": "Neplatný mime typ: \"{mime}\"", + "error.file.mime.missing": "Typ média pre \"{filename}\" sa nepodarilo zistiť", + "error.file.minheight": "Výška obrázku musí byť aspoň \"{height}\" pixelov", + "error.file.minsize": "Súbor je príliš malý", + "error.file.minwidth": "Šírka obrázku musí byť aspoň \"{width}\" pixelov", + "error.file.name.missing": "Názov súboru nemôže byť prázdny", + "error.file.notFound": "Súbor \"{filename}\" sa nepodarilo nájsť", + "error.file.orientation": "The orientation of the image must be \"{orientation}\"", + "error.file.type.forbidden": "Nemáte povolenie na nahrávanie súborov s typom {type}", + "error.file.type.invalid": "Neplatný typ súboru: \"{type}\"", + "error.file.undefined": "Súbor nie je možné nájsť", + + "error.form.incomplete": "Prosím, opravte všetky chyby v rámci formuláru...", + "error.form.notSaved": "Formulár sa nepodarilo uložiť", + + "error.language.code": "Please enter a valid code for the language", + "error.language.duplicate": "The language already exists", + "error.language.name": "Please enter a valid name for the language", + "error.language.notFound": "The language could not be found", + + "error.layout.validation.block": "There's an error in block {blockIndex} in layout {layoutIndex}", + "error.layout.validation.settings": "There's an error in layout {index} settings", + + "error.license.format": "Please enter a valid license key", + "error.license.email": "Prosím, zadajte platnú e-mailovú adresu", + "error.license.verification": "The license could not be verified", + + "error.offline": "The Panel is currently offline", + + "error.page.changeSlug.permission": "Nemáte povolenie na zmenu URL príponu pre \"{slug}\"", + "error.page.changeStatus.incomplete": "Stránka obsahuje chyby a nemôže byť zverejnená", + "error.page.changeStatus.permission": "Status tejto stránky nemôže byť zmenený", + "error.page.changeStatus.toDraft.invalid": "Stránka \"{slug}\" nemôže byť zmenená na koncept.", + "error.page.changeTemplate.invalid": "Šablónu pre stránku \"{slug}\" nie je možné zmeniť", + "error.page.changeTemplate.permission": "Nemáte povolenie na zmenu šablóny pre \"{slug}\"", + "error.page.changeTitle.empty": "Titulok nemôže byť prázdny", + "error.page.changeTitle.permission": "Nemáte povolenie na zmenu titulku pre \"{slug}\"", + "error.page.create.permission": "Nemáte povolenie na vytvorenie \"{slug}\"", + "error.page.delete": "Stránku \"{slug}\" nie je možné vymazať", + "error.page.delete.confirm": "Prosím, zadajte titulok stránky pre potvrdenie", + "error.page.delete.hasChildren": "Táto stránka obsahuje podstránky a nemôže byť zmazaná", + "error.page.delete.permission": "Nemáte povolenie na zmazanie stránky \"{slug}\"", + "error.page.draft.duplicate": "Koncept stránky s URL appendix-om \"{slug}\" už existuje", + "error.page.duplicate": "Stránka s URL appendix-om \"{slug}\" už existuje", + "error.page.duplicate.permission": "You are not allowed to duplicate \"{slug}\"", + "error.page.notFound": "Stránku \"{slug}\" nie je možné nájsť", + "error.page.num.invalid": "Prosím, zadajte platné číslo pre radenie. Čísla nemôžu byť záporné.", + "error.page.slug.invalid": "Please enter a valid URL appendix", + "error.page.slug.maxlength": "Slug length must be less than \"{length}\" characters", + "error.page.sort.permission": "Stránku \"{slug}\" nie je možné preradiť.", + "error.page.status.invalid": "Prosím, nastavte platnú status pre stránku", + "error.page.undefined": "Stránku nie je možné nájsť", + "error.page.update.permission": "Nemáte povolenie na aktualizáciu \"{slug}\"", + + "error.section.files.max.plural": "Nemôžete pridať viac ako {max} súbory/ov do sekcie \"{section}\"", + "error.section.files.max.singular": "Nemôžete pridať viac ako 1 súbor do sekcie \"{section}\"", + "error.section.files.min.plural": "The \"{section}\" section requires at least {min} files", + "error.section.files.min.singular": "The \"{section}\" section requires at least one file", + + "error.section.pages.max.plural": "Nemôžete pridať viac ako {max} stránky/ok do sekcie \"{section}\"", + "error.section.pages.max.singular": "Nemôžete pridať viac ako 1 stránku do sekcie \"{section}\"", + "error.section.pages.min.plural": "The \"{section}\" section requires at least {min} pages", + "error.section.pages.min.singular": "The \"{section}\" section requires at least one page", + + "error.section.notLoaded": "Sekciu \"{name}\" sa nepodarilo nahrať", + "error.section.type.invalid": "Typ sekcie \"{type}\" nie je platný", + + "error.site.changeTitle.empty": "Titulok nemôže byť prázdny", + "error.site.changeTitle.permission": "Nemáte povolenie na zmenu titulku pre portál", + "error.site.update.permission": "Nemáte povolenie na aktualizovanie portálu", + + "error.template.default.notFound": "Predvolená šablóna neexistuje", + + "error.unexpected": "An unexpected error occurred! Enable debug mode for more info: https://getkirby.com/docs/reference/system/options/debug", + + "error.user.changeEmail.permission": "Nemáte povolenie na zmenu e-mailu pre užívateľa \"{name}\"", + "error.user.changeLanguage.permission": "Nemáte povolenie na zmenu jazyka pre užívateľa \"{name}\"", + "error.user.changeName.permission": "Nemáte povolenie na zmenu mena pre užívateľa \"{name}\"", + "error.user.changePassword.permission": "Nemáte povolenie na zmenu hesla pre užívateľa \"{name}\"", + "error.user.changeRole.lastAdmin": "Rolu pre posledného administrátora nie je možné zmeniť", + "error.user.changeRole.permission": "Nemáte povolenie na zmenu role pre užívateľa \"{name}\"", + "error.user.changeRole.toAdmin": "You are not allowed to promote someone to the admin role", + "error.user.create.permission": "Nemáte povolenie na vytvorenie tohto užívateľa", + "error.user.delete": "Užívateľa \"{name}\" nie je možné zmazať", + "error.user.delete.lastAdmin": "Posledného administrátora nie je možné zmazať", + "error.user.delete.lastUser": "Posledného užívateľa nie je možné zmazať", + "error.user.delete.permission": "Nemáte povolenie na zmazanie užívateľa \"{name}\"", + "error.user.duplicate": "Užívateľ s e-mailovou adresou \"{email}\" už existuje", + "error.user.email.invalid": "Prosím, zadajte platnú e-mailovú adresu", + "error.user.language.invalid": "Prosím, zadajte platný jazyk", + "error.user.notFound": "Užívateľa \"{name}\" nie je možné nájsť", + "error.user.password.excessive": "Please enter a valid password. Passwords must not be longer than 1000 characters.", + "error.user.password.invalid": "Prosím, zadajte platné heslo. Dĺžka hesla musí byť aspoň 8 znakov.", + "error.user.password.notSame": "Heslá nie sú rovnaké", + "error.user.password.undefined": "Užívateľ nemá heslo", + "error.user.password.wrong": "Wrong password", + "error.user.role.invalid": "Prosím, zadajte platnú rolu", + "error.user.undefined": "Užívateľa sa nepodarilo nájsť", + "error.user.update.permission": "Nemáte povolenie na aktualizáciu užívateľa \"{name}\"", + + "error.validation.accepted": "Prosím, potvrďte", + "error.validation.alpha": "Prosím, zadajte len znaky z hlások a-z", + "error.validation.alphanum": "Prosím, zadajte len znaky z hlások a-z a čísloviek 0-9", + "error.validation.between": "Prosím, zadajte hodnotu od \"{min}\" do \"{max}\"", + "error.validation.boolean": "Prosím, potvrďte alebo odmietnite", + "error.validation.contains": "Prosím, zadajte hodnotu, ktorá obsahuje \"{needle}\"", + "error.validation.date": "Prosím, zadajte platný dátum", + "error.validation.date.after": "Please enter a date after {date}", + "error.validation.date.before": "Please enter a date before {date}", + "error.validation.date.between": "Please enter a date between {min} and {max}", + "error.validation.denied": "Prosím, odmietnite", + "error.validation.different": "Hodnota nemôže byť \"{other}\"", + "error.validation.email": "Prosím, zadajte platnú e-mailovú adresu", + "error.validation.endswith": "Hodnota musí končiť na \"{end}\"", + "error.validation.filename": "Prosím, zadajte platný názov súboru", + "error.validation.in": "Prosím, zadajte jedno z nasledujúcich: ({in})", + "error.validation.integer": "Prosím, zadajte platné celé číslo", + "error.validation.ip": "Prosím, zadajte platnú e-mailovú adresu", + "error.validation.less": "Prosím, zadajte hodnotu menšiu ako {max}", + "error.validation.match": "Hodnota nezodpovedá očakávanému vzoru", + "error.validation.max": "Prosím, zadajte hodnotu rovnú alebo menšiu ako {max}", + "error.validation.maxlength": "Prosím, zadajte kratšiu hodnotu. (max. {max} charaktery/ov)", + "error.validation.maxwords": "Prosím, nezadávajte viac ako {max} slovo/á/ov", + "error.validation.min": "Prosím, zadajte hodnotu rovnú alebo väčšiu ako {min}", + "error.validation.minlength": "Prosím, zadajte dlhšiu hodnotu. (min. {min} charaktery/ov)", + "error.validation.minwords": "Prosím, zadajte aspoň {min} slovo/á/ov", + "error.validation.more": "Prosím zadajte hodnotu väčšiu ako {min}", + "error.validation.notcontains": "Prosím, zadajte hodnotu, ktorá neobsahuje \"{needle}\"", + "error.validation.notin": "Prosím, nezadávajte ani jedno z nasledujúcich: ({notIn})", + "error.validation.option": "Prosím, zadajte platnú voľbu", + "error.validation.num": "Prosím, zadajte platné číslo", + "error.validation.required": "Prosím, zadajte niečo", + "error.validation.same": "Prosím, zadajte \"{other}\"", + "error.validation.size": "Veľkosť hodnoty musí byť \"{size}\"", + "error.validation.startswith": "Hodnota musí začínať s \"{start}\"", + "error.validation.time": "Prosím, zadajte platný čas", + "error.validation.time.after": "Please enter a time after {time}", + "error.validation.time.before": "Please enter a time before {time}", + "error.validation.time.between": "Please enter a time between {min} and {max}", + "error.validation.url": "Prosím, zadajte platnú URL", + + "expand": "Rozbaliť", + "expand.all": "Rozbaliť všetky", + + "field.required": "The field is required", + "field.blocks.changeType": "Change type", + "field.blocks.code.name": "Kód", + "field.blocks.code.language": "Jazyk", + "field.blocks.code.placeholder": "Váš kód ...", + "field.blocks.delete.confirm": "Naozaj chcete zmazať tento blok?", + "field.blocks.delete.confirm.all": "Naozaj chcete zmazať všetky bloky?", + "field.blocks.delete.confirm.selected": "Naozaj chcete zmazať vybrané bloky?", + "field.blocks.empty": "No blocks yet", + "field.blocks.fieldsets.label": "Please select a block type …", + "field.blocks.fieldsets.paste": "Press {{ shortcut }} to paste/import blocks from your clipboard", + "field.blocks.gallery.name": "Galéria", + "field.blocks.gallery.images.empty": "No images yet", + "field.blocks.gallery.images.label": "Obrázky", + "field.blocks.heading.level": "Level", + "field.blocks.heading.name": "Nadpis", + "field.blocks.heading.text": "Text", + "field.blocks.heading.placeholder": "Nadpis ...", + "field.blocks.image.alt": "Alternative text", + "field.blocks.image.caption": "Popis", + "field.blocks.image.crop": "Orezanie", + "field.blocks.image.link": "Odkaz", + "field.blocks.image.location": "Poloha", + "field.blocks.image.name": "Obrázok", + "field.blocks.image.placeholder": "Select an image", + "field.blocks.image.ratio": "Ratio", + "field.blocks.image.url": "Image URL", + "field.blocks.line.name": "Line", + "field.blocks.list.name": "List", + "field.blocks.markdown.name": "Markdown", + "field.blocks.markdown.label": "Text", + "field.blocks.markdown.placeholder": "Markdown …", + "field.blocks.quote.name": "Quote", + "field.blocks.quote.text.label": "Text", + "field.blocks.quote.text.placeholder": "Quote …", + "field.blocks.quote.citation.label": "Citation", + "field.blocks.quote.citation.placeholder": "by …", + "field.blocks.text.name": "Text", + "field.blocks.text.placeholder": "Text …", + "field.blocks.video.caption": "Popis", + "field.blocks.video.name": "Video", + "field.blocks.video.placeholder": "Enter a video URL", + "field.blocks.video.url.label": "Video-URL", + "field.blocks.video.url.placeholder": "https://youtube.com/?v=", + + "field.files.empty": "Žiadne súbory zatiaľ neboli zvolené", + + "field.layout.delete": "Delete layout", + "field.layout.delete.confirm": "Do you really want to delete this layout?", + "field.layout.empty": "No rows yet", + "field.layout.select": "Select a layout", + + "field.pages.empty": "Žiadne stránky zatiaľ neboli zvolené", + "field.structure.delete.confirm": "Ste si istý, že chcete zmazať tento riadok?", + "field.structure.empty": "Zatiaľ žiadne údaje", + "field.users.empty": "Žiadni užívatelia zatiaľ neboli zvolení", + + "file.blueprint": "This file has no blueprint yet. You can define the setup in /site/blueprints/files/{blueprint}.yml", + "file.delete.confirm": "Ste si istý, že chcete zmazať
{filename}?", + "file.sort": "Change position", + + "files": "Súbory", + "files.empty": "Zatiaľ žiadne súbory", + + "hide": "Hide", + "hour": "Hodina", + "import": "Import", + "info": "Info", + "insert": "Vložiť", + "insert.after": "Insert after", + "insert.before": "Insert before", + "install": "Inštalovať", + + "installation": "Inštalácia", + "installation.completed": "Panel bol nainštalovaný", + "installation.disabled": "Inštalácia Panelu na verejných serveroch je štandardne zablokovaná. Prosím, spustite inštaláciu na lokálnom serveri alebo aktivujte voľbu panel.install.", + "installation.issues.accounts": "Priečinok /site/accounts neexistuje alebo nie je nastavený ako zapisovateľný", + "installation.issues.content": "Priečinok /content neexistuje alebo nie je nastavený ako zapisovateľný", + "installation.issues.curl": "CURL rozšírenie je povinné", + "installation.issues.headline": "Panel nie je možné naištalovať", + "installation.issues.mbstring": "MB String rozšírenie je povinné", + "installation.issues.media": "Priečinok /media neexistuje alebo nie je nastavený ako zapisovateľný", + "installation.issues.php": "Uistite sa, že používate PHP 7+", + "installation.issues.server": "Kirby vyžaduje Apache, Nginx alebo Caddy", + "installation.issues.sessions": "Priečinok /site/sessions neexistuje alebo nie je nastavený ako zapisovateľný", + + "language": "Jazyk", + "language.code": "Kód", + "language.convert": "Nastaviť ako predvolené", + "language.convert.confirm": "

Ste si istý, že chcete nastaviť {name} ako predvolený jazyk? Túto akciu nie je možné zvrátiť.

Ak {name} obsahuje nepreložený obsah, tak pre tento obsah nebude fungovať platné volanie a niektoré časti vašich stránok zostanú prázdne.

", + "language.create": "Pridať nový jazyk", + "language.delete.confirm": "Ste si istý, že chcete zmazať jazyk {name} vrátane všetkých prekladov? Túto akciu nie je možné zvrátiť.", + "language.deleted": "Jazyk bol zmazaný", + "language.direction": "Smer čítania", + "language.direction.ltr": "Zľava doprava", + "language.direction.rtl": "Zprava doľava", + "language.locale": "PHP locale string", + "language.locale.warning": "You are using a custom locale set up. Please modify it in the language file in /site/languages", + "language.name": "Názov", + "language.updated": "Jazyk bol aktualizovaný", + + "languages": "Jazyky", + "languages.default": "Predvolený jazyk", + "languages.empty": "Zatiaľ žiadne jazyky", + "languages.secondary": "Sekundárne jazyky", + "languages.secondary.empty": "Zatiaľ žiadne sekundárne jazyky", + + "license": "Licencia", + "license.buy": "Zakúpiť licenciu", + "license.register": "Registrovať", + "license.manage": "Manage your licenses", + "license.register.help": "Licenčný kód vám bol doručený e-mailom po úspešnom nákupe. Prosím, skopírujte a prilepte ho na uskutočnenie registrácie.", + "license.register.label": "Prosím, zadajte váš licenčný kód", + "license.register.success": "Ďakujeme za vašu podporu Kirby", + "license.unregistered": "Toto je neregistrované demo Kirby", + "license.unregistered.label": "Unregistered", + + "link": "Odkaz", + "link.text": "Text odkazu", + + "loading": "Načítavanie", + + "lock.unsaved": "Unsaved changes", + "lock.unsaved.empty": "There are no more unsaved changes", + "lock.isLocked": "Unsaved changes by {email}", + "lock.file.isLocked": "The file is currently being edited by {email} and cannot be changed.", + "lock.page.isLocked": "The page is currently being edited by {email} and cannot be changed.", + "lock.unlock": "Unlock", + "lock.isUnlocked": "Your unsaved changes have been overwritten by another user. You can download your changes to merge them manually.", + + "login": "Prihlásenie", + "login.code.label.login": "Login code", + "login.code.label.password-reset": "Password reset code", + "login.code.placeholder.email": "000 000", + "login.code.text.email": "If your email address is registered, the requested code was sent via email.", + "login.email.login.body": "Hi {user.nameOrEmail},\n\nYou recently requested a login code for the Panel of {site}.\nThe following login code will be valid for {timeout} minutes:\n\n{code}\n\nIf you did not request a login code, please ignore this email or contact your administrator if you have questions.\nFor security, please DO NOT forward this email.", + "login.email.login.subject": "Your login code", + "login.email.password-reset.body": "Hi {user.nameOrEmail},\n\nYou recently requested a password reset code for the Panel of {site}.\nThe following password reset code will be valid for {timeout} minutes:\n\n{code}\n\nIf you did not request a password reset code, please ignore this email or contact your administrator if you have questions.\nFor security, please DO NOT forward this email.", + "login.email.password-reset.subject": "Your password reset code", + "login.remember": "Ponechať ma prihláseného", + "login.reset": "Reset password", + "login.toggleText.code.email": "Login via email", + "login.toggleText.code.email-password": "Login with password", + "login.toggleText.password-reset.email": "Forgot your password?", + "login.toggleText.password-reset.email-password": "← Back to login", + + "logout": "Odhlásenie", + + "menu": "Menu", + "meridiem": "AM/PM", + "mime": "Typ média", + "minutes": "Minúty", + + "month": "Mesiac", + "months.april": "Apríl", + "months.august": "August", + "months.december": "December", + "months.february": "Február", + "months.january": "Január", + "months.july": "Júl", + "months.june": "Jún", + "months.march": "Marec", + "months.may": "Máj", + "months.november": "November", + "months.october": "Október", + "months.september": "September", + + "more": "Viac", + "name": "Meno", + "next": "Ďalej", + "no": "no", + "off": "off", + "on": "on", + "open": "Otvoriť", + "open.newWindow": "Open in new window", + "options": "Nastavenia", + "options.none": "No options", + + "orientation": "Orientácia", + "orientation.landscape": "Širokouhlá", + "orientation.portrait": "Portrét", + "orientation.square": "Štvorec", + + "page.blueprint": "This page has no blueprint yet. You can define the setup in /site/blueprints/pages/{blueprint}.yml", + "page.changeSlug": "Zmeniť URL", + "page.changeSlug.fromTitle": "Vytvoriť z titulku", + "page.changeStatus": "Zmeniť status", + "page.changeStatus.position": "Prosím, zmeňte pozíciu", + "page.changeStatus.select": "Zvoľte nový status", + "page.changeTemplate": "Zmeniť šablónu", + "page.delete.confirm": "Ste si istý, že chcete zmazať {title}?", + "page.delete.confirm.subpages": "Táto stránka obsahuje podstránky.
Všetky podstránky budú taktiež zmazané.", + "page.delete.confirm.title": "Pre potvrdenie zadajte titulok stránky", + "page.draft.create": "Vytvoriť koncept", + "page.duplicate.appendix": "Kopírovať", + "page.duplicate.files": "Copy files", + "page.duplicate.pages": "Copy pages", + "page.sort": "Change position", + "page.status": "Status", + "page.status.draft": "Koncept", + "page.status.draft.description": "The page is in draft mode and only visible for logged in editors or via secret link", + "page.status.listed": "Verejné", + "page.status.listed.description": "Stránka je prístupná pre všetkých", + "page.status.unlisted": "Skryté", + "page.status.unlisted.description": "Stránka je prístupná len prostredníctvom priamej URL", + + "pages": "Stránky", + "pages.empty": "Zatiaľ žiadne stránky", + "pages.status.draft": "Koncepty", + "pages.status.listed": "Zverejnené", + "pages.status.unlisted": "Skryté", + + "pagination.page": "Stránka", + + "password": "Heslo", + "paste": "Paste", + "paste.after": "Paste after", + "pixel": "Pixel", + "plugins": "Plugins", + "prev": "Predchádzajúci", + "preview": "Preview", + "remove": "Odstrániť", + "rename": "Premenovať", + "replace": "Nahradiť", + "retry": "Skúsiť ešte raz", + "revert": "Vrátiť späť", + "revert.confirm": "Do you really want to delete all unsaved changes?", + + "role": "Rola", + "role.admin.description": "The admin has all rights", + "role.admin.title": "Admin", + "role.all": "Všetko", + "role.empty": "S touto rolou neexistujú žiadni užívatelia", + "role.description.placeholder": "Žiadny popis", + "role.nobody.description": "This is a fallback role without any permissions", + "role.nobody.title": "Nobody", + + "save": "Uložiť", + "search": "Hľadať", + "search.min": "Enter {min} characters to search", + "search.all": "Show all", + "search.results.none": "No results", + + "section.required": "The section is required", + + "security": "Security", + "select": "Zvoliť", + "server": "Server", + "settings": "Nastavenia", + "show": "Show", + "site.blueprint": "The site has no blueprint yet. You can define the setup in /site/blueprints/site.yml", + "size": "Veľkosť", + "slug": "URL appendix", + "sort": "Zoradiť", + + "stats.empty": "No reports", + "system.issues.content": "The content folder seems to be exposed", + "system.issues.debug": "Debugging must be turned off in production", + "system.issues.git": "The .git folder seems to be exposed", + "system.issues.https": "We recommend HTTPS for all your sites", + "system.issues.kirby": "The kirby folder seems to be exposed", + "system.issues.site": "The site folder seems to be exposed", + + "title": "Titulok", + "template": "Šablóna", + "today": "Dnes", + + "toolbar.button.code": "Kód", + "toolbar.button.bold": "Tučný", + "toolbar.button.email": "E-mail", + "toolbar.button.headings": "Nadpisy", + "toolbar.button.heading.1": "Nadpis 1", + "toolbar.button.heading.2": "Nadpis 2", + "toolbar.button.heading.3": "Nadpis 3", + "toolbar.button.heading.4": "Heading 4", + "toolbar.button.heading.5": "Heading 5", + "toolbar.button.heading.6": "Heading 6", + "toolbar.button.italic": "Kurzíva", + "toolbar.button.file": "Súbor", + "toolbar.button.file.select": "Select a file", + "toolbar.button.file.upload": "Upload a file", + "toolbar.button.link": "Odkaz", + "toolbar.button.paragraph": "Paragraph", + "toolbar.button.strike": "Strike-through", + "toolbar.button.ol": "Číslovaný zoznam", + "toolbar.button.underline": "Underline", + "toolbar.button.ul": "Odrážkový zoznam", + + "translation.author": "Tím Kirby", + "translation.direction": "ltr", + "translation.name": "Slovensky", + "translation.locale": "sk_SK", + + "upload": "Nahrať", + "upload.error.cantMove": "The uploaded file could not be moved", + "upload.error.cantWrite": "Failed to write file to disk", + "upload.error.default": "The file could not be uploaded", + "upload.error.extension": "File upload stopped by extension", + "upload.error.formSize": "The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the form", + "upload.error.iniPostSize": "The uploaded file exceeds the post_max_size directive in php.ini", + "upload.error.iniSize": "The uploaded file exceeds the upload_max_filesize directive in php.ini", + "upload.error.noFile": "No file was uploaded", + "upload.error.noFiles": "No files were uploaded", + "upload.error.partial": "The uploaded file was only partially uploaded", + "upload.error.tmpDir": "Missing a temporary folder", + "upload.errors": "Chyba", + "upload.progress": "Nahrávanie...", + + "url": "URL", + "url.placeholder": "https://example.com", + + "user": "Užívateľ", + "user.blueprint": "You can define additional sections and form fields for this user role in /site/blueprints/users/{blueprint}.yml", + "user.changeEmail": "Zmeniť e-mail", + "user.changeLanguage": "Zmeniť jazyk", + "user.changeName": "Premenovať tohto užívateľa", + "user.changePassword": "Zmeniť heslo", + "user.changePassword.new": "Nové heslo", + "user.changePassword.new.confirm": "Potvrdiť nové heslo...", + "user.changeRole": "Zmeniť rolu", + "user.changeRole.select": "Zvoliť novú rolu", + "user.create": "Pridať nového užívateľa", + "user.delete": "Zmazať tohto užívateľa", + "user.delete.confirm": "Ste si istý, že chcete zmazať
{email}?", + + "users": "Užívatelia", + + "version": "Verzia", + + "view.account": "Váš účet", + "view.installation": "Inštalácia", + "view.languages": "Jazyky", + "view.resetPassword": "Reset password", + "view.site": "Portál", + "view.system": "System", + "view.users": "Užívatelia", + + "welcome": "Vitajte", + "year": "Rok", + "yes": "yes" } diff --git a/kirby/i18n/translations/sv_SE.json b/kirby/i18n/translations/sv_SE.json index b390a61..ddb564e 100644 --- a/kirby/i18n/translations/sv_SE.json +++ b/kirby/i18n/translations/sv_SE.json @@ -1,730 +1,574 @@ { - "account.changeName": "Ändra ditt namn", - "account.delete": "Radera ditt konto", - "account.delete.confirm": "Vill du verkligen radera ditt konto? Du kommer att loggas ut omedelbart. Ditt konto kan inte återställas.", - - "activate": "Aktivera", - "add": "L\u00e4gg till", - "alpha": "Alpha", - "author": "Författare", - "avatar": "Profilbild", - "back": "Tillbaka", - "cancel": "Avbryt", - "change": "\u00c4ndra", - "close": "St\u00e4ng", - "changes": "Ändringar", - "confirm": "Spara", - "collapse": "Kollapsa", - "collapse.all": "Kollapsa alla", - "color": "Färg", - "coordinates": "Koordinater", - "copy": "Kopiera", - "copy.all": "Kopiera alla", - "copy.success": "{count} kopierad!", - "create": "Skapa", - "custom": "Anpassad", - - "date": "Datum", - "date.select": "Välj ett datum", - - "day": "Dag", - "days.fri": "Fre", - "days.mon": "M\u00e5n", - "days.sat": "L\u00f6r", - "days.sun": "S\u00f6n", - "days.thu": "Tor", - "days.tue": "Tis", - "days.wed": "Ons", - - "debugging": "Felsökning", - - "delete": "Radera", - "delete.all": "Radera allt", - - "dialog.fields.empty": "Den här dialogrutan har inga fält", - "dialog.files.empty": "Inga filer att välja", - "dialog.pages.empty": "Inga sidor att välja", - "dialog.text.empty": "Den här dialogrutan definierar ingen text", - "dialog.users.empty": "Inga användare att välja", - - "dimensions": "Dimensioner", - "disable": "Inaktivera", - "disabled": "Inaktiverad", - "discard": "Kassera", - - "drawer.fields.empty": "Denna vy har inga fält", - - "domain": "Domän", - "download": "Ladda ner", - "duplicate": "Duplicera", - - "edit": "Redigera", - - "email": "E-postadress", - "email.placeholder": "namn@exempel.se", - - "enter": "Enter", - "entries": "Poster", - "entry": "Post", - - "environment": "Miljö", - - "error": "Fel", - "error.access.code": "Ogiltig kod", - "error.access.login": "Ogiltig inloggning", - "error.access.panel": "Du saknar behörighet att nå panelen", - "error.access.view": "Du saknar behörighet att nå denna del av panelen", - - "error.avatar.create.fail": "Profilbilden kunde inte laddas upp", - "error.avatar.delete.fail": "Profilbilden kunde inte raderas", - "error.avatar.dimensions.invalid": "Se till att profilbildens bredd och höjd är mindre än 3000 pixlar", - "error.avatar.mime.forbidden": "Profilbilden måste vara i formatet JPEG eller PNG", - - "error.blueprint.notFound": "Blueprint \"{name}\" kunde inte laddas", - - "error.blocks.max.plural": "Du får inte lägga till mer än {max} block", - "error.blocks.max.singular": "Du får inte lägga till mer än ett block", - "error.blocks.min.plural": "Du måste lägga till minst {min} block", - "error.blocks.min.singular": "Du måste lägga till minst ett block", - "error.blocks.validation": "Det finns ett fel i fältet \"{field}\" i block {index} med blocktypen \"{fieldset}\"", - - "error.cache.type.invalid": "Ogiltig cachetyp \"{type}\"", - - "error.email.preset.notFound": "E-postförinställningen \"{name}\" kan inte hittas", - - "error.field.converter.invalid": "Ogiltig omvandlare \"{converter}\"", - "error.field.type.missing": "Fältet \"{ name }\": Fälttypen \"{ type }\" finns inte", - - "error.file.changeName.empty": "Namnet får inte vara tomt", - "error.file.changeName.permission": "Du har inte behörighet att ändra namnet på \"{filename}\"", - "error.file.changeTemplate.invalid": "Mallen för filen \"{id}\" kan inte ändras till \"{template}\" (giltiga mallar: \"{blueprints}\")", - "error.file.changeTemplate.permission": "Du saknar behörighet för att ändra mallen för filen \"{id}\"", - - "error.file.duplicate": "En fil med namnet \"{filename}\" existerar redan", - "error.file.extension.forbidden": "Filändelsen \"{extension}\" är inte tillåten", - "error.file.extension.invalid": "Ogiltig filändelse: {extension}", - "error.file.extension.missing": "Filen \"{filename}\" saknar filändelse", - "error.file.maxheight": "Bildens höjd får inte överstiga {height} pixlar", - "error.file.maxsize": "Filen är för stor", - "error.file.maxwidth": "Bildens bredd får inte överstiga {width} pixlar", - "error.file.mime.differs": "Den uppladdade filen måste vara av samma mime-typ \"{mime}\"", - "error.file.mime.forbidden": "Mediatypen \"{mime}\" är inte tillåten", - "error.file.mime.invalid": "Ogiltig mime-typ: {mime}", - "error.file.mime.missing": "Mediatypen för \"{filename}\" kan inte detekteras", - "error.file.minheight": "Bildens höjd måste vara minst {height} pixlar", - "error.file.minsize": "Filen är för liten", - "error.file.minwidth": "Bildens bredd måste vara minst {width} pixlar", - "error.file.name.unique": "Filnamnet måste vara unikt", - "error.file.name.missing": "Filnamnet får inte vara tomt", - "error.file.notFound": "Filen \"{filename}\" kan ej hittas", - "error.file.orientation": "Bildens orientering måste vara \"{orientation}\"", - "error.file.type.forbidden": "Du har inte behörighet att ladda upp filer av typen {type}", - "error.file.type.invalid": "Ogiltig filtyp: {type}", - "error.file.undefined": "Filen kan inte hittas", - - "error.form.incomplete": "Vänligen åtgärda alla formulärfel...", - "error.form.notSaved": "Formuläret kunde inte sparas", - - "error.language.code": "Ange en giltig kod för språket", - "error.language.duplicate": "Språket finns redan", - "error.language.name": "Ange ett giltigt namn för språket", - "error.language.notFound": "Språket hittades inte", - - "error.layout.validation.block": "Det finns ett fel i fältet \"{field}\" i blocket {blockIndex} med blocktypen \"{fieldset}\" i layouten {layoutIndex}", - "error.layout.validation.settings": "Det finns ett fel i inställningarna för layout {index}", - - "error.license.domain": "Domänen för licensen saknas", - "error.license.email": "Ange en giltig e-postadress", - "error.license.format": "Ange en giltig licenskod", - "error.license.verification": "Licensen kunde inte verifieras", - - "error.login.totp.confirm.invalid": "Ogiltig kod", - "error.login.totp.confirm.missing": "Vänligen ange den aktuella koden", - - "error.object.validation": "Det finns ett fel i fältet \"{label}\":\n{message}", - - "error.offline": "Panelen är för närvarande offline", - - "error.page.changeSlug.permission": "Du har inte behörighet att ändra URL-appendixen för \"{slug}\"", - "error.page.changeSlug.reserved": "Sökvägen till sidor på toppnivå får inte börja med \"{path}\"", - "error.page.changeStatus.incomplete": "Sidan innehåller fel och kan inte publiceras", - "error.page.changeStatus.permission": "Statusen för denna sida kan inte ändras", - "error.page.changeStatus.toDraft.invalid": "Statusen för sidan \"{slug}\" kan inte ändras till utkast", - "error.page.changeTemplate.invalid": "Mallen för sidan \"{slug}\" kan inte ändras", - "error.page.changeTemplate.permission": "Du har inte behörighet att ändra mallen för \"{slug}\"", - "error.page.changeTitle.empty": "Titeln får inte vara tom", - "error.page.changeTitle.permission": "Du har inte behörighet att ändra titeln för \"{slug}\"", - "error.page.create.permission": "Du har inte behörighet att skapa \"{slug}\"", - "error.page.delete": "Sidan \"{slug}\" kan inte raderas", - "error.page.delete.confirm": "Fyll i sidans titel för att bekräfta", - "error.page.delete.hasChildren": "Sidan har undersidor och kan inte raderas", - "error.page.delete.permission": "Du har inte behörighet att radera \"{slug}\"", - "error.page.draft.duplicate": "Ett utkast med URL-appendixen \"{slug}\" existerar redan", - "error.page.duplicate": "En sida med URL-appendixen \"{slug}\" existerar redan", - "error.page.duplicate.permission": "Du har inte behörighet att duplicera \"{slug}\"", - "error.page.move.ancestor": "Sidan kan inte flyttas in i sig själv", - "error.page.move.directory": "Sidans mapp kan inte flyttas", - "error.page.move.duplicate": "En undersida med URL-appendixen \"{slug}\" existerar redan", - "error.page.move.notFound": "Den flyttade sidan kunde inte hittas", - "error.page.move.permission": "Du saknar behörighet för att flytta \"{slug}\"", - "error.page.move.template": "Mallen \"{template}\" accepteras inte som en undersida till \"{parent}\"", - "error.page.notFound": "Sidan \"{slug}\" kan inte hittas", - "error.page.num.invalid": "Ange ett giltigt nummer för sortering. Numret får inte vara negativt.", - "error.page.slug.invalid": "Ange en giltig URL-appendix", - "error.page.slug.maxlength": "Permalänkens längd måste vara kortare än \"{length}\" tecken", - "error.page.sort.permission": "Sidan \"{slug}\" kan inte sorteras", - "error.page.status.invalid": "Sätt en giltig status för sidan", - "error.page.undefined": "Sidan kan inte hittas", - "error.page.update.permission": "Du har inte behörighet att uppdatera \"{slug}\"", - - "error.section.files.max.plural": "Du får inte lägga till mer än {max} filer till sektionen \"{section}\"", - "error.section.files.max.singular": "Du får inte lägga till mer än en fil i sektionen \"{section}\"", - "error.section.files.min.plural": "Sektionen \"{section}\" kräver minst {min} filer", - "error.section.files.min.singular": "Sektionen \"{section}\" kräver minst en fil", - - "error.section.pages.max.plural": "Du får inte lägga till mer än {max} sidor till sektionen \"{section}\"", - "error.section.pages.max.singular": "Du får inte lägga till mer än en sida i sektionen \"{section}\"", - "error.section.pages.min.plural": "Sektionen \"{section}\" kräver minst {min} sidor", - "error.section.pages.min.singular": "Sektionen \"{section}\" kräver minst en sida", - - "error.section.notLoaded": "Sektionen \"{name}\" kunde inte laddas", - "error.section.type.invalid": "Sektionstypen \"{type}\" är inte giltig", - - "error.site.changeTitle.empty": "Titeln får inte vara tom", - "error.site.changeTitle.permission": "Du har inte behörighet att ändra titeln på webbplatsen", - "error.site.update.permission": "Du har inte behörighet att uppdatera webbplatsen", - - "error.structure.validation": "Det finns ett fel i fältet \"{field}\" i rad {index}", - - "error.template.default.notFound": "Standardmallen finns inte", - - "error.unexpected": "Ett oväntat fel uppstod! Aktivera felsökningsläge för mer information: https://getkirby.com/docs/reference/system/options/debug", - - "error.user.changeEmail.permission": "Du har inte behörighet att ändra e-postadressen för användaren \"{name}\"", - "error.user.changeLanguage.permission": "Du har inte behörighet att ändra språket för användaren \"{name}\"", - "error.user.changeName.permission": "Du har inte behörighet att ändra namnet för användaren \"{name}\"", - "error.user.changePassword.permission": "Du har inte behörighet att ändra lösenordet för användaren \"{name}\"", - "error.user.changeRole.lastAdmin": "Rollen för den återstående adminanvändaren kan inte ändras", - "error.user.changeRole.permission": "Du har inte behörighet att ändra rollen för användaren \"{name}\"", - "error.user.changeRole.toAdmin": "Du har inte behörighet att ge någon en administratörsroll", - "error.user.create.permission": "Du har inte behörighet att skapa denna användare", - "error.user.delete": "Användaren kan inte raderas", - "error.user.delete.lastAdmin": "Den återstående administratören kan inte raderas", - "error.user.delete.lastUser": "Den återstående användaren kan inte raderas", - "error.user.delete.permission": "Du har inte behörighet att radera användaren \"{name}\"", - "error.user.duplicate": "En användare med e-postadressen \"{email}\" finns redan", - "error.user.email.invalid": "Ange en giltig e-postadress", - "error.user.language.invalid": "Ange ett giltigt språk", - "error.user.notFound": "Användaren \"{name}\" kan ej hittas", - "error.user.password.excessive": "Var vänlig skriv in ett giltigt lösenord. Lösenord får inte vara längre än 1000 tecken.", - "error.user.password.invalid": "Ange ett giltigt lösenord. Lösenordet måste vara minst 8 tecken långt.", - "error.user.password.notSame": "Lösenorden matchar inte", - "error.user.password.undefined": "Användaren har inget lösenord", - "error.user.password.wrong": "Fel lösenord", - "error.user.role.invalid": "Ange en giltig roll", - "error.user.undefined": "Användaren kan inte hittas", - "error.user.update.permission": "Du har inte behörighet att uppdatera användaren \"{name}\"", - - "error.validation.accepted": "Vänligen bekräfta", - "error.validation.alpha": "Ange endast tecken mellan a-z", - "error.validation.alphanum": "Ange endast tecken mellan a-z eller siffror 0-9", - "error.validation.anchor": "Vänligen ange en korrekt länk", - "error.validation.between": "Ange ett värde mellan \"{min}\" och \"{max}\"", - "error.validation.boolean": "Bekräfta eller neka", - "error.validation.color": "Ange en giltig färg i formatet {format}", - "error.validation.contains": "Ange ett värde som innehåller \"{needle}\"", - "error.validation.date": "Ange ett giltigt datum", - "error.validation.date.after": "Ange ett datum efter {date}", - "error.validation.date.before": "Ange ett datum före {date}", - "error.validation.date.between": "Ange ett datum mellan {min} och {max}", - "error.validation.denied": "Vänligen neka", - "error.validation.different": "Värdet får inte vara \"{other}\"", - "error.validation.email": "Ange en giltig e-postadress", - "error.validation.endswith": "Värdet måste sluta med \"{end}\"", - "error.validation.filename": "Ange ett giltigt filnamn", - "error.validation.in": "Ange ett av följande: ({in})", - "error.validation.integer": "Ange en giltig heltalssiffra", - "error.validation.ip": "Ange en giltig IP-adress", - "error.validation.less": "Ange ett värde lägre än {max}", - "error.validation.linkType": "Länktypen är inte tillåten", - "error.validation.match": "Värdet matchar inte det förväntade mönstret", - "error.validation.max": "Ange ett värde som är lika med eller lägre än {max}", - "error.validation.maxlength": "Ange ett kortare värde. (max {max} tecken)", - "error.validation.maxwords": "Ange inte mer än {max} ord", - "error.validation.min": "Ange ett värde som är lika med eller större än {min}", - "error.validation.minlength": "Ange ett längre värde. (minst {min} tecken)", - "error.validation.minwords": "Ange minst {min} ord", - "error.validation.more": "Ange ett större värde än {min}", - "error.validation.notcontains": "Ange ett värde som inte innehåller \"{needle}\"", - "error.validation.notin": "Ange inte något av följande: ({notIn})", - "error.validation.option": "Välj ett giltigt alternativ", - "error.validation.num": "Ange ett giltigt nummer", - "error.validation.required": "Ange någonting", - "error.validation.same": "Ange \"{other}\"", - "error.validation.size": "Storleken av värdet måste vara \"{size}\"", - "error.validation.startswith": "Värdet måste börja med \"{start}\"", - "error.validation.tel": "Ange ett oformaterat telefonnummer", - "error.validation.time": "Ange en giltig tid", - "error.validation.time.after": "Ange en tid efter {time}", - "error.validation.time.before": "Ange en tid före {time}", - "error.validation.time.between": "Ange en tid mellan {min} och {max}", - "error.validation.uuid": "Ange ett giltigt UUID", - "error.validation.url": "Ange en giltig URL", - - "expand": "Expandera", - "expand.all": "Expandera alla", - - "field.invalid": "Fältet är ogiltigt", - "field.required": "Fältet krävs", - "field.blocks.changeType": "Ändra typ", - "field.blocks.code.name": "Kod", - "field.blocks.code.language": "Språk", - "field.blocks.code.placeholder": "Din kod …", - "field.blocks.delete.confirm": "Vill du verkligen radera detta block?", - "field.blocks.delete.confirm.all": "Vill du verkligen radera alla block?", - "field.blocks.delete.confirm.selected": "Vill du verkligen radera de valda blocken?", - "field.blocks.empty": "Inga block än", - "field.blocks.fieldsets.empty": "Inga fältuppsättningar ännu", - "field.blocks.fieldsets.label": "Välj en typ av block …", - "field.blocks.fieldsets.paste": "Tryck på {{ shortcut }} för att importera layouter/block från urklipp Endast de som är tillåtna i det aktuella fältet kommer att infogas.", - "field.blocks.gallery.name": "Galleri", - "field.blocks.gallery.images.empty": "Inga bilder än", - "field.blocks.gallery.images.label": "Bilder", - "field.blocks.heading.level": "Nivå", - "field.blocks.heading.name": "Rubrik", - "field.blocks.heading.text": "Text", - "field.blocks.heading.placeholder": "Rubrik …", - "field.blocks.image.alt": "Alternativ text", - "field.blocks.image.caption": "Rubrik", - "field.blocks.image.crop": "Beskär", - "field.blocks.image.link": "Länk", - "field.blocks.image.location": "Plats", - "field.blocks.image.location.internal": "Denna webbplats", - "field.blocks.image.location.external": "Extern källa", - "field.blocks.image.name": "Bild", - "field.blocks.image.placeholder": "Välj en bild", - "field.blocks.image.ratio": "Bildförhållande", - "field.blocks.image.url": "Bild-URL", - "field.blocks.line.name": "Linje", - "field.blocks.list.name": "Punktlista", - "field.blocks.markdown.name": "Markdown", - "field.blocks.markdown.label": "Text", - "field.blocks.markdown.placeholder": "Markdown …", - "field.blocks.quote.name": "Citat", - "field.blocks.quote.text.label": "Text", - "field.blocks.quote.text.placeholder": "Citat …", - "field.blocks.quote.citation.label": "Citat", - "field.blocks.quote.citation.placeholder": "av …", - "field.blocks.text.name": "Text", - "field.blocks.text.placeholder": "Text …", - "field.blocks.video.autoplay": "Autospela", - "field.blocks.video.caption": "Rubrik", - "field.blocks.video.controls": "Kontroller", - "field.blocks.video.location": "Plats", - "field.blocks.video.loop": "Loopa", - "field.blocks.video.muted": "Ljud av", - "field.blocks.video.name": "Video", - "field.blocks.video.placeholder": "Ange en URL till en video", - "field.blocks.video.poster": "Stillbild", - "field.blocks.video.preload": "Förladda", - "field.blocks.video.url.label": "Video-URL", - "field.blocks.video.url.placeholder": "https://youtube.com/?v=", - - "field.files.empty": "Inga filer valda än", - - "field.layout.change": "Ändra layout", - "field.layout.delete": "Radera layout", - "field.layout.delete.confirm": "Vill du verkligen radera denna layout?", - "field.layout.delete.confirm.all": "Vill du verkligen ta bort alla layouter?", - "field.layout.empty": "Inga rader än", - "field.layout.select": "Välj en layout", - - "field.object.empty": "Ingen information ännu", - - "field.pages.empty": "Inga sidor valda än", - - "field.structure.delete.confirm": "Vill du verkligen radera denna rad?", - "field.structure.delete.confirm.all": "Vill du verkligen radera alla poster?", - "field.structure.empty": "Inga poster än", - - "field.users.empty": "Inga användare valda än", - - "fields.empty": "Inga fält ännu", - - "file": "Fil", - "file.blueprint": "Denna fil har ingen blueprint än. Du kan skapa en i /site/blueprints/files/{blueprint}.yml", - "file.changeTemplate": "Ändra mall", - "file.changeTemplate.notice": "Att ändra filens mall kommer att ta bort innehåll för fält som inte matchar fältets typ. Om den nya mallen definierar vissa regler, t.ex. bilddimensioner, kommer de också att tillämpas oåterkalleligt. Använd med försiktighet.", - "file.delete.confirm": "Vill du verkligen radera
{filename}?", - "file.focus.placeholder": "Ange fokuspunkt", - "file.focus.reset": "Ta bort fokuspunkt", - "file.focus.title": "Fokus", - "file.sort": "Ändra position", - - "files": "Filer", - "files.empty": "Inga filer än", - - "filter": "Filter", - - "hide": "Göm", - "hour": "Timme", - "hue": "Nyans", - "import": "Importera", - "info": "Info", - "insert": "Infoga", - "insert.after": "Infoga efter", - "insert.before": "Infoga före", - "install": "Installera", - - "installation": "Installation", - "installation.completed": "Panelen har installerats", - "installation.disabled": "Installeraren för panelen är som standard inaktiverad på offentliga servrar. Kör installeraren på en lokal maskin eller aktivera den med alternativet panel.install.", - "installation.issues.accounts": "Mappen /site/accounts finns inte eller är inte skrivbar", - "installation.issues.content": "Mappen /content finns inte eller är inte skrivbar", - "installation.issues.curl": "Tillägget CURL krävs", - "installation.issues.headline": "Panelen kan inte installeras", - "installation.issues.mbstring": "Tillägget MB String krävs", - "installation.issues.media": "Mappen /media finns inte eller är inte skrivbar", - "installation.issues.php": "Se till att du använder PHP 8+", - "installation.issues.sessions": "Mappen /site/sessions finns inte eller är inte skrivbar", - - "language": "Spr\u00e5k", - "language.code": "Kod", - "language.convert": "Ange som standard", - "language.convert.confirm": "

Vill du verkligen göra {name} till standardspråket? Detta kan inte ångras.

Om {name} har oöversatt innehåll, kommer det inte längre finnas en alternativ översättning och delar av sajten kommer kanske att vara tom.

", - "language.create": "Lägg till ett nytt språk", - "language.default": "Standardspråk", - "language.delete.confirm": "Vill du verkligen radera språket {name} inklusive alla översättningar? Detta kan inte ångras!", - "language.deleted": "Språket har raderats", - "language.direction": "Läsriktning", - "language.direction.ltr": "Vänster till höger", - "language.direction.rtl": "Höger till vänster", - "language.locale": "PHP locale string", - "language.locale.warning": "Du använder en anpassad språkinställning. Ändra den i språkfilen i mappen /site/languages", - "language.name": "Namn", - "language.secondary": "Sekundärt språk", - "language.settings": "Språkinställningar", - "language.updated": "Språket har uppdaterats", - "language.variables": "Språkvariabler", - "language.variables.empty": "Inga översättningar ännu", - - "language.variable.delete.confirm": "Vill du verkligen ta bort variabeln för {key}?", - "language.variable.key": "Nyckel", - "language.variable.notFound": "Variabeln kunde inte hittas", - "language.variable.value": "Värde", - - "languages": "Språk", - "languages.default": "Standardspråk", - "languages.empty": "Det finns inga språk ännu", - "languages.secondary": "Sekundära språk", - "languages.secondary.empty": "Det finns inga sekundära språk ännu", - - "license": "Licens", - "license.activate": "Aktivera nu", - "license.activate.label": "Vänligen aktivera din licens", - "license.activate.domain": "Din licens kommer att vara aktiverad för {host}.", - "license.activate.local": "Du är på väg att aktivera din Kirby-licens för din lokala domän {host}. Om den här webbplatsen kommer att publiceras på en offentlig domän, aktivera den där istället. Om {host} är domänen du vill använda din licens för, fortsätt.", - "license.activated": "Aktiverad", - "license.buy": "Köp en licens", - "license.code": "Kod", - "license.code.help": "Du fick din licenskod efter köpet via e-post. Kopiera och klistra in det här.", - "license.code.label": "Ange din licenskod", - "license.status.active.info": "Inkluderar nya större versioner fram till {date}", - "license.status.active.label": "Giltig licens", - "license.status.demo.info": "Detta är en demoinstallation", - "license.status.demo.label": "Demo", - "license.status.inactive.info": "Förnya licensen för att uppdatera till nyare större versioner", - "license.status.inactive.label": "Inga nya större versioner", - "license.status.legacy.bubble": "Är du redo att förnya din licens?", - "license.status.legacy.info": "Din licens täcker inte denna version", - "license.status.legacy.label": "Vänligen förnya din licens", - "license.status.missing.bubble": "Är du redo att lansera din webbplats?", - "license.status.missing.info": "Ingen giltig licens", - "license.status.missing.label": "Vänligen aktivera din licens", - "license.manage": "Hantera dina licenser", - "license.purchased": "Köpt", - "license.success": "Tack för att du stödjer Kirby", - "license.unregistered.label": "Oregistrerad", - - "link": "L\u00e4nk", - "link.text": "L\u00e4nktext", - - "loading": "Laddar", - - "lock.unsaved": "Osparade ändringar", - "lock.unsaved.empty": "Det finns inga fler osparade ändringar", - "lock.isLocked": "Osparade ändringar av {email}", - "lock.unlock": "Lås upp", - "lock.unlock.submit": "Lås upp och skriv över osparade ändringar av {email}", - "lock.isUnlocked": "Låstes upp av en annan användare", - - "login": "Logga in", - "login.code.label.login": "Inloggningskod", - "login.code.label.password-reset": "Kod för återställning av lösenord", - "login.code.placeholder.email": "000 000", - "login.code.placeholder.totp": "000000", - "login.code.text.email": "Om din e-postadress är registrerad skickades den begärda koden via e-post.", - "login.code.text.totp": "Ange engångskoden från din autentiseringsapp.", - "login.email.login.body": "Hej {user.nameOrEmail}.\n\nDu begärde nyligen en inloggningskod till panelen för {site}.\nFöljande kod är giltig i {timeout} minuter:\n\n{code}\n\nOm du inte har begärt någon inloggningskod, ignorera detta e-postmeddelande eller kontakta din administratör om du har frågor.\nAv säkerhetsskäl, vidarebefordra INTE detta e-postmeddelande.", - "login.email.login.subject": "Din inloggningskod", - "login.email.password-reset.body": "Hej {user.nameOrEmail}.\n\nDu begärde nyligen en kod för återställning av ditt lösenord till panelen för {site}.\nFöljande kod är giltig i {timeout} minuter:\n\n{code}\n\nOm du inte har begärt en återställning av ditt lösenord, ignorera detta e-postmeddelande eller kontakta din administratör om du har frågor.\nAv säkerhetsskäl, vidarebefordra INTE detta e-postmeddelande.", - "login.email.password-reset.subject": "Din kod för återställning av lösenord", - "login.remember": "Håll mig inloggad", - "login.reset": "Återställ lösenord", - "login.toggleText.code.email": "Logga in via e-post", - "login.toggleText.code.email-password": "Logga in med lösenord", - "login.toggleText.password-reset.email": "Glömt ditt lösenord?", - "login.toggleText.password-reset.email-password": "← Tillbaka till inloggning", - "login.totp.enable.option": "Ställ in engångskoder", - "login.totp.enable.intro": "Autentiseringsappar kan generera engångskoder som används som en andra faktor när du loggar in på ditt konto.", - "login.totp.enable.qr.label": "1. Skanna den här QR-koden", - "login.totp.enable.qr.help": "Kan du inte skanna? Lägg till inställningsnyckeln {secret} manuellt i din autentiseringsapp.", - "login.totp.enable.confirm.headline": "2. Bekräfta med genererad kod", - "login.totp.enable.confirm.text": "Din app genererar en ny engångskod var 30:e sekund. Ange den aktuella koden för att slutföra installationen:", - "login.totp.enable.confirm.label": "Nuvarande kod", - "login.totp.enable.confirm.help": "Efter denna installation kommer vi att be dig om en engångskod varje gång du loggar in.", - "login.totp.enable.success": "Engångskoder aktiverade", - "login.totp.disable.option": "Inaktivera engångskoder", - "login.totp.disable.label": "Ange ditt lösenord för att inaktivera engångskoder", - "login.totp.disable.help": "I fortsättningen kommer en annan andra faktor som en inloggningskod som skickas via e-post att begäras när du loggar in. Du kan alltid ställa in engångskoder igen senare.", - "login.totp.disable.admin": "

Detta kommer att inaktivera engångskoder för {user}.

I fortsättningen kommer en annan andra faktor som en inloggningskod som skickas via e-post att begäras när de loggar in. {user} kan ställa in engångskoder igen efter nästa inloggning.

", - "login.totp.disable.success": "Engångskoder inaktiverade", - - "logout": "Logga ut", - - "merge": "Slå ihop", - "menu": "Meny", - "meridiem": "a.m./p.m.", - "mime": "Mediatyp", - "minutes": "Minuter", - - "month": "Månad", - "months.april": "April", - "months.august": "Augusti", - "months.december": "December", - "months.february": "Februari", - "months.january": "Januari", - "months.july": "Juli", - "months.june": "Juni", - "months.march": "Mars", - "months.may": "Maj", - "months.november": "November", - "months.october": "Oktober", - "months.september": "September", - - "more": "Mer", - "move": "Flytta", - "name": "Namn", - "next": "Nästa", - "night": "Natt", - "no": "nej", - "off": "av", - "on": "på", - "open": "Öppna", - "open.newWindow": "Öppna i nytt fönster", - "option": "Alternativ", - "options": "Alternativ", - "options.none": "Inga alternativ", - "options.all": "Visa alla {count} alternativ", - - "orientation": "Orientering", - "orientation.landscape": "Liggande", - "orientation.portrait": "Stående", - "orientation.square": "Kvadrat", - - "page": "Sida", - "page.blueprint": "Denna sida har ingen blueprint än. Du kan skapa en i /site/blueprints/pages/{blueprint}.yml", - "page.changeSlug": "Ändra URL", - "page.changeSlug.fromTitle": "Skapa utifr\u00e5n titel", - "page.changeStatus": "Ändra status", - "page.changeStatus.position": "Välj en ny position", - "page.changeStatus.select": "Välj en ny status", - "page.changeTemplate": "Ändra mall", - "page.changeTemplate.notice": "Att ändra filens mall kommer att ta bort innehåll för fält som inte matchar fältets typ. Använd med försiktighet.", - "page.create": "Skapa som {status}", - "page.delete.confirm": "Vill du verkligen radera {title}?", - "page.delete.confirm.subpages": "Denna sida har undersidor.
Alla undersidor kommer också att raderas.", - "page.delete.confirm.title": "Fyll i sidans titel för att bekräfta", - "page.duplicate.appendix": "Kopiera", - "page.duplicate.files": "Kopiera filer", - "page.duplicate.pages": "Kopiera sidor", - "page.move": "Flytta sidan", - "page.sort": "Ändra position", - "page.status": "Status", - "page.status.draft": "Utkast", - "page.status.draft.description": "Sidan är ett utkast och endast synlig för inloggade redaktörer eller via en hemlig länk", - "page.status.listed": "Publik", - "page.status.listed.description": "Sidan är publik för vem som helst", - "page.status.unlisted": "Olistad", - "page.status.unlisted.description": "Sidan är endast åtkomlig via URL", - - "pages": "Sidor", - "pages.empty": "Inga sidor än", - "pages.status.draft": "Utkast", - "pages.status.listed": "Publicerade", - "pages.status.unlisted": "Olistade", - - "pagination.page": "Sida", - - "password": "L\u00f6senord", - "paste": "Klistra in", - "paste.after": "Klistra in efter", - "paste.success": "{count} har klistrats in!", - "pixel": "Pixel", - "plugin": "Tillägg", - "plugins": "Tillägg", - "prev": "Föregående", - "preview": "Förhandsgranska", - "remove": "Ta bort", - "rename": "Byt namn", - "renew": "Förnya", - "replace": "Ersätt", - "replace.with": "Ersätt med", - "retry": "F\u00f6rs\u00f6k igen", - "revert": "Återgå", - "revert.confirm": "Vill du verkligen radera alla osparade ändringar?", - - "role": "Roll", - "role.admin.description": "Administratören har alla behörigheter", - "role.admin.title": "Administratör", - "role.all": "Alla", - "role.empty": "Det finns inga användare med denna roll", - "role.description.placeholder": "Ingen beskrivning", - "role.nobody.description": "Detta är en roll utan några behörigheter", - "role.nobody.title": "Ingen", - - "save": "Spara", - "search": "Sök", - "search.min": "Ange {min} tecken för att söka", - "search.all": "Visa alla {count} resultat", - "search.results.none": "Inga träffar", - - "section.invalid": "Sektionen är ogiltig", - "section.required": "Sektionen krävs", - - "security": "Säkerhet", - "select": "Välj", - "server": "Server", - "settings": "Inställningar", - "show": "Visa", - "site.blueprint": "Webbplatsen har ingen blueprint än. Du kan skapa en i /site/blueprints/site.yml", - "size": "Storlek", - "slug": "URL-appendix", - "sort": "Sortera", - "sort.drag": "Dra för att sortera …", - "split": "Dela", - - "stats.empty": "Inga rapporter", - "status": "Status", - - "system.info.copy": "Copy info", - "system.info.copied": "System info copied", - "system.issues.content": "Mappen content verkar vara exponerad", - "system.issues.eol.kirby": "Din installerade Kirby-version har nått slutet av sin livscykel och kommer inte att få fler säkerhetsuppdateringar", - "system.issues.eol.plugin": "Den installerade versionen av tillägget { plugin } har nått slutet på sin livscykel och kommer inte att få fler säkerhetsuppdateringar.", - "system.issues.eol.php": "Din installerade PHP-version { release } har nått slutet av sin livslängd och kommer inte att få fler säkerhetsuppdateringar", - "system.issues.debug": "Felsökningsläget måste vara avstängt i produktion", - "system.issues.git": "Mappen .git verkar vara exponerad", - "system.issues.https": "Vi rekommenderar HTTPS för alla dina webbplatser", - "system.issues.kirby": "Mappen kirby verkar vara exponerad", - "system.issues.site": "Mappen site verkar vara exponerad", - "system.issues.vulnerability.kirby": "Din installation kan vara påverkad av följande sårbarhet ({ severity } allvarlighetsgrad): { description }", - "system.issues.vulnerability.plugin": "Din installation kan vara påverkad av följande sårbarhet i tillägget { plugin } ({ severity } allvarlighetsgrad): { description }", - "system.updateStatus": "Uppdateringsstatus", - "system.updateStatus.error": "Det gick inte att söka efter uppdateringar", - "system.updateStatus.not-vulnerable": "Inga kända sårbarheter", - "system.updateStatus.security-update": "Gratis säkerhetsuppdatering { version } tillgänglig", - "system.updateStatus.security-upgrade": "Uppgradering { version } med säkerhetskorrigeringar är tillgänglig", - "system.updateStatus.unreleased": "Osläppt version", - "system.updateStatus.up-to-date": "Uppdaterad", - "system.updateStatus.update": "Gratis uppdatering { version } tillgänglig", - "system.updateStatus.upgrade": "Uppgradering { version } tillgänglig", - - "tel": "Telefon", - "tel.placeholder": "+46701234567", - "template": "Mall", - "title": "Titel", - "today": "Idag", - - "toolbar.button.clear": "Rensa formatering", - "toolbar.button.code": "Kod", - "toolbar.button.bold": "Fet", - "toolbar.button.email": "E-post", - "toolbar.button.headings": "Rubriker", - "toolbar.button.heading.1": "Rubrik 1", - "toolbar.button.heading.2": "Rubrik 2", - "toolbar.button.heading.3": "Rubrik 3", - "toolbar.button.heading.4": "Rubrik 4", - "toolbar.button.heading.5": "Rubrik 5", - "toolbar.button.heading.6": "Rubrik 6", - "toolbar.button.italic": "Kursiv", - "toolbar.button.file": "Fil", - "toolbar.button.file.select": "Välj en fil", - "toolbar.button.file.upload": "Ladda upp en fil", - "toolbar.button.link": "L\u00e4nk", - "toolbar.button.paragraph": "Stycke", - "toolbar.button.strike": "Genomstruken", - "toolbar.button.sub": "Nedsänkt", - "toolbar.button.sup": "Upphöjd", - "toolbar.button.ol": "Sorterad lista", - "toolbar.button.underline": "Understruken", - "toolbar.button.ul": "Punktlista", - - "translation.author": "Kirby-teamet, Ola Christensson", - "translation.direction": "ltr", - "translation.name": "Svenska", - "translation.locale": "sv_SE", - - "type": "Typ", - - "upload": "Ladda upp", - "upload.error.cantMove": "Den överförda filen kunde inte flyttas", - "upload.error.cantWrite": "Det gick inte att skriva filen till hårddisken", - "upload.error.default": "Filen kunde inte laddas upp", - "upload.error.extension": "Filuppladdningen förhindrades på grund av filändelsen", - "upload.error.formSize": "Den överförda filen överskrider den maximala filstorlek som anges i formuläret (MAX_FILE_SIZE)", - "upload.error.iniPostSize": "Den överförda filen överskrider post_max_size-direktivet i php.ini", - "upload.error.iniSize": "Den överförda filen överskrider direktivet upload_max_filesize i php.ini", - "upload.error.noFile": "Ingen fil laddades upp", - "upload.error.noFiles": "Inga filer laddades upp", - "upload.error.partial": "Den överförda filen laddades bara delvis upp", - "upload.error.tmpDir": "Saknar en temporär mapp", - "upload.errors": "Fel", - "upload.progress": "Laddar upp...", - - "url": "URL", - "url.placeholder": "https://exempel.se", - - "user": "Användare", - "user.blueprint": "Du kan skapa ytterligare sektioner och fält för den här användarrollen i /site/blueprints/users/{blueprint}.yml", - "user.changeEmail": "Ändra e-postadress", - "user.changeLanguage": "Ändra språk", - "user.changeName": "Byt namn på denna användare", - "user.changePassword": "Ändra lösenord", - "user.changePassword.new": "Nytt lösenord", - "user.changePassword.new.confirm": "Bekräfta det nya lösenordet...", - "user.changeRole": "Ändra roll", - "user.changeRole.select": "Välj en ny roll", - "user.create": "Lägg till en ny användare", - "user.delete": "Radera denna användare", - "user.delete.confirm": "Vill du verkligen radera
{email}?", - - "users": "Användare", - - "version": "Version", - "version.current": "Aktuell version", - "version.latest": "Senaste version", - "versionInformation": "Versionsinformation", - - "view.account": "Ditt konto", - "view.installation": "Installation", - "view.languages": "Språk", - "view.resetPassword": "Återställ lösenord", - "view.site": "Webbplats", - "view.system": "System", - "view.users": "Anv\u00e4ndare", - - "welcome": "Välkommen", - "year": "År", - "yes": "ja" + "account.changeName": "Ändra ditt namn", + "account.delete": "Radera ditt konto", + "account.delete.confirm": "Vill du verkligen radera ditt konto? Du kommer att loggas ut omedelbart. Ditt konto kan inte återställas.", + + "add": "L\u00e4gg till", + "author": "Författare", + "avatar": "Profilbild", + "back": "Tillbaka", + "cancel": "Avbryt", + "change": "\u00c4ndra", + "close": "St\u00e4ng", + "confirm": "Spara", + "collapse": "Kollapsa", + "collapse.all": "Kollapsa alla", + "copy": "Kopiera", + "copy.all": "Kopiera alla", + "create": "Skapa", + + "date": "Datum", + "date.select": "Välj ett datum", + + "day": "Dag", + "days.fri": "Fre", + "days.mon": "M\u00e5n", + "days.sat": "L\u00f6r", + "days.sun": "S\u00f6n", + "days.thu": "Tor", + "days.tue": "Tis", + "days.wed": "Ons", + + "debugging": "Felsökning", + + "delete": "Radera", + "delete.all": "Radera allt", + + "dialog.files.empty": "Inga filer att välja", + "dialog.pages.empty": "Inga sidor att välja", + "dialog.users.empty": "Inga användare att välja", + + "dimensions": "Dimensioner", + "disabled": "Inaktiverad", + "discard": "Kassera", + "download": "Ladda ner", + "duplicate": "Duplicera", + + "edit": "Redigera", + + "email": "E-postadress", + "email.placeholder": "namn@exempel.se", + + "entries": "Poster", + "entry": "Post", + + "environment": "Miljö", + + "error.access.code": "Ogiltig kod", + "error.access.login": "Ogiltig inloggning", + "error.access.panel": "Du saknar behörighet att nå panelen", + "error.access.view": "Du saknar behörighet att nå denna del av panelen", + + "error.avatar.create.fail": "Profilbilden kunde inte laddas upp", + "error.avatar.delete.fail": "Profilbilden kunde inte raderas", + "error.avatar.dimensions.invalid": "Se till att profilbildens bredd och höjd är mindre än 3000 pixlar", + "error.avatar.mime.forbidden": "Profilbilden måste vara i formatet JPEG eller PNG", + + "error.blueprint.notFound": "Blueprint \"{name}\" kunde inte laddas", + + "error.blocks.max.plural": "Du får inte lägga till mer än {max} block", + "error.blocks.max.singular": "Du får inte lägga till mer än ett block", + "error.blocks.min.plural": "Du måste lägga till minst {min} block", + "error.blocks.min.singular": "Du måste lägga till minst ett block", + "error.blocks.validation": "Det finns ett fel i block {index}", + + "error.email.preset.notFound": "E-postförinställningen \"{name}\" kan inte hittas", + + "error.field.converter.invalid": "Ogiltig omvandlare \"{converter}\"", + + "error.file.changeName.empty": "Namnet får inte vara tomt", + "error.file.changeName.permission": "Du har inte behörighet att ändra namnet på \"{filename}\"", + "error.file.duplicate": "En fil med namnet \"{filename}\" existerar redan", + "error.file.extension.forbidden": "Filändelsen \"{extension}\" är inte tillåten", + "error.file.extension.invalid": "Ogiltig filändelse: {extension}", + "error.file.extension.missing": "Filen \"{filename}\" saknar filändelse", + "error.file.maxheight": "Bildens höjd får inte överstiga {height} pixlar", + "error.file.maxsize": "Filen är för stor", + "error.file.maxwidth": "Bildens bredd får inte överstiga {width} pixlar", + "error.file.mime.differs": "Den uppladdade filen måste vara av samma mime-typ \"{mime}\"", + "error.file.mime.forbidden": "Mediatypen \"{mime}\" är inte tillåten", + "error.file.mime.invalid": "Ogiltig mime-typ: {mime}", + "error.file.mime.missing": "Mediatypen för \"{filename}\" kan inte detekteras", + "error.file.minheight": "Bildens höjd måste vara minst {height} pixlar", + "error.file.minsize": "Filen är för liten", + "error.file.minwidth": "Bildens bredd måste vara minst {width} pixlar", + "error.file.name.missing": "Filnamnet får inte vara tomt", + "error.file.notFound": "Filen \"{filename}\" kan ej hittas", + "error.file.orientation": "Bildens orientering måste vara \"{orientation}\"", + "error.file.type.forbidden": "Du har inte behörighet att ladda upp filer av typen {type}", + "error.file.type.invalid": "Ogiltig filtyp: {type}", + "error.file.undefined": "Filen kan inte hittas", + + "error.form.incomplete": "Vänligen åtgärda alla formulärfel...", + "error.form.notSaved": "Formuläret kunde inte sparas", + + "error.language.code": "Ange en giltig kod för språket", + "error.language.duplicate": "Språket finns redan", + "error.language.name": "Ange ett giltigt namn för språket", + "error.language.notFound": "Språket hittades inte", + + "error.layout.validation.block": "Det finns ett fel i block {blockIndex} i layout {layoutIndex}", + "error.layout.validation.settings": "Det finns ett fel i inställningarna för layout {index}", + + "error.license.format": "Ange en giltig licensnyckel", + "error.license.email": "Ange en giltig e-postadress", + "error.license.verification": "Licensen kunde inte verifieras", + + "error.offline": "Panelen är för närvarande offline", + + "error.page.changeSlug.permission": "Du har inte behörighet att ändra URL-appendixen för \"{slug}\"", + "error.page.changeStatus.incomplete": "Sidan innehåller fel och kan inte publiceras", + "error.page.changeStatus.permission": "Statusen för denna sida kan inte ändras", + "error.page.changeStatus.toDraft.invalid": "Statusen för sidan \"{slug}\" kan inte ändras till utkast", + "error.page.changeTemplate.invalid": "Mallen för sidan \"{slug}\" kan inte ändras", + "error.page.changeTemplate.permission": "Du har inte behörighet att ändra mallen för \"{slug}\"", + "error.page.changeTitle.empty": "Titeln får inte vara tom", + "error.page.changeTitle.permission": "Du har inte behörighet att ändra titeln för \"{slug}\"", + "error.page.create.permission": "Du har inte behörighet att skapa \"{slug}\"", + "error.page.delete": "Sidan \"{slug}\" kan inte raderas", + "error.page.delete.confirm": "Fyll i sidans titel för att bekräfta", + "error.page.delete.hasChildren": "Sidan har undersidor och kan inte raderas", + "error.page.delete.permission": "Du har inte behörighet att radera \"{slug}\"", + "error.page.draft.duplicate": "Ett utkast med URL-appendixen \"{slug}\" existerar redan", + "error.page.duplicate": "En sida med URL-appendixen \"{slug}\" existerar redan", + "error.page.duplicate.permission": "Du har inte behörighet att duplicera \"{slug}\"", + "error.page.notFound": "Sidan \"{slug}\" kan inte hittas", + "error.page.num.invalid": "Ange ett giltigt nummer för sortering. Numret får inte vara negativt.", + "error.page.slug.invalid": "Ange en giltig URL-appendix", + "error.page.slug.maxlength": "Permalänkens längd måste vara kortare än \"{length}\" tecken", + "error.page.sort.permission": "Sidan \"{slug}\" kan inte sorteras", + "error.page.status.invalid": "Sätt en giltig status för sidan", + "error.page.undefined": "Sidan kan inte hittas", + "error.page.update.permission": "Du har inte behörighet att uppdatera \"{slug}\"", + + "error.section.files.max.plural": "Du får inte lägga till mer än {max} filer till sektionen \"{section}\"", + "error.section.files.max.singular": "Du får inte lägga till mer än en fil i sektionen \"{section}\"", + "error.section.files.min.plural": "Sektionen \"{section}\" kräver minst {min} filer", + "error.section.files.min.singular": "Sektionen \"{section}\" kräver minst en fil", + + "error.section.pages.max.plural": "Du får inte lägga till mer än {max} sidor till sektionen \"{section}\"", + "error.section.pages.max.singular": "Du får inte lägga till mer än en sida i sektionen \"{section}\"", + "error.section.pages.min.plural": "Sektionen \"{section}\" kräver minst {min} sidor", + "error.section.pages.min.singular": "Sektionen \"{section}\" kräver minst en sida", + + "error.section.notLoaded": "Sektionen \"{name}\" kunde inte laddas", + "error.section.type.invalid": "Sektionstypen \"{type}\" är inte giltig", + + "error.site.changeTitle.empty": "Titeln får inte vara tom", + "error.site.changeTitle.permission": "Du har inte behörighet att ändra titeln på webbplatsen", + "error.site.update.permission": "Du har inte behörighet att uppdatera webbplatsen", + + "error.template.default.notFound": "Standardmallen existerar inte", + + "error.unexpected": "Ett oväntat fel uppstod! Aktivera felsökningsläge för mer information: https://getkirby.com/docs/reference/system/options/debug", + + "error.user.changeEmail.permission": "Du har inte behörighet att ändra e-postadressen för användaren \"{name}\"", + "error.user.changeLanguage.permission": "Du har inte behörighet att ändra språket för användaren \"{name}\"", + "error.user.changeName.permission": "Du har inte behörighet att ändra namnet för användaren \"{name}\"", + "error.user.changePassword.permission": "Du har inte behörighet att ändra lösenordet för användaren \"{name}\"", + "error.user.changeRole.lastAdmin": "Rollen för den återstående adminanvändaren kan inte ändras", + "error.user.changeRole.permission": "Du har inte behörighet att ändra rollen för användaren \"{name}\"", + "error.user.changeRole.toAdmin": "Du har inte behörighet att ge någon en administratörsroll", + "error.user.create.permission": "Du har inte behörighet att skapa denna användare", + "error.user.delete": "Användaren kan inte raderas", + "error.user.delete.lastAdmin": "Den återstående administratören kan inte raderas", + "error.user.delete.lastUser": "Den återstående användaren kan inte raderas", + "error.user.delete.permission": "Du har inte behörighet att radera användaren \"{name}\"", + "error.user.duplicate": "En användare med e-postadressen \"{email}\" finns redan", + "error.user.email.invalid": "Ange en giltig e-postadress", + "error.user.language.invalid": "Ange ett giltigt språk", + "error.user.notFound": "Användaren \"{name}\" kan ej hittas", + "error.user.password.excessive": "Please enter a valid password. Passwords must not be longer than 1000 characters.", + "error.user.password.invalid": "Ange ett giltigt lösenord. Lösenordet måste vara minst 8 tecken långt.", + "error.user.password.notSame": "Lösenorden matchar inte", + "error.user.password.undefined": "Användaren har inget lösenord", + "error.user.password.wrong": "Fel lösenord", + "error.user.role.invalid": "Ange en giltig roll", + "error.user.undefined": "Användaren kan inte hittas", + "error.user.update.permission": "Du har inte behörighet att uppdatera användaren \"{name}\"", + + "error.validation.accepted": "Vänligen bekräfta", + "error.validation.alpha": "Ange endast tecken mellan a-z", + "error.validation.alphanum": "Ange endast tecken mellan a-z eller siffror 0-9", + "error.validation.between": "Ange ett värde mellan \"{min}\" och \"{max}\"", + "error.validation.boolean": "Bekräfta eller neka", + "error.validation.contains": "Ange ett värde som innehåller \"{needle}\"", + "error.validation.date": "Ange ett giltigt datum", + "error.validation.date.after": "Ange ett datum efter {date}", + "error.validation.date.before": "Ange ett datum före {date}", + "error.validation.date.between": "Ange ett datum mellan {min} och {max}", + "error.validation.denied": "Vänligen neka", + "error.validation.different": "Värdet får inte vara \"{other}\"", + "error.validation.email": "Ange en giltig e-postadress", + "error.validation.endswith": "Värdet måste sluta med \"{end}\"", + "error.validation.filename": "Ange ett giltigt filnamn", + "error.validation.in": "Ange ett av följande: ({in})", + "error.validation.integer": "Ange en giltig heltalssiffra", + "error.validation.ip": "Ange en giltig IP-adress", + "error.validation.less": "Ange ett värde lägre än {max}", + "error.validation.match": "Värdet matchar inte det förväntade mönstret", + "error.validation.max": "Ange ett värde som är lika med eller lägre än {max}", + "error.validation.maxlength": "Ange ett kortare värde. (max {max} tecken)", + "error.validation.maxwords": "Ange inte mer än {max} ord", + "error.validation.min": "Ange ett värde som är lika med eller större än {min}", + "error.validation.minlength": "Ange ett längre värde. (minst {min} tecken)", + "error.validation.minwords": "Ange minst {min} ord", + "error.validation.more": "Ange ett större värde än {min}", + "error.validation.notcontains": "Ange ett värde som inte innehåller \"{needle}\"", + "error.validation.notin": "Ange inte något av följande: ({notIn})", + "error.validation.option": "Välj ett giltigt alternativ", + "error.validation.num": "Ange ett giltigt nummer", + "error.validation.required": "Ange någonting", + "error.validation.same": "Ange \"{other}\"", + "error.validation.size": "Storleken av värdet måste vara \"{size}\"", + "error.validation.startswith": "Värdet måste börja med \"{start}\"", + "error.validation.time": "Ange en giltig tid", + "error.validation.time.after": "Ange en tid efter {time}", + "error.validation.time.before": "Ange en tid före {time}", + "error.validation.time.between": "Ange en tid mellan {min} och {max}", + "error.validation.url": "Ange en giltig URL", + + "expand": "Expandera", + "expand.all": "Expandera alla", + + "field.required": "Fältet krävs", + "field.blocks.changeType": "Ändra typ", + "field.blocks.code.name": "Kod", + "field.blocks.code.language": "Språk", + "field.blocks.code.placeholder": "Din kod …", + "field.blocks.delete.confirm": "Vill du verkligen radera detta block?", + "field.blocks.delete.confirm.all": "Vill du verkligen radera alla block?", + "field.blocks.delete.confirm.selected": "Vill du verkligen radera de valda blocken?", + "field.blocks.empty": "Inga block än", + "field.blocks.fieldsets.label": "Välj en typ av block …", + "field.blocks.fieldsets.paste": "Tryck på {{ shortcut }} för att klistra in/importera block från ditt urklipp", + "field.blocks.gallery.name": "Galleri", + "field.blocks.gallery.images.empty": "Inga bilder än", + "field.blocks.gallery.images.label": "Bilder", + "field.blocks.heading.level": "Nivå", + "field.blocks.heading.name": "Rubrik", + "field.blocks.heading.text": "Text", + "field.blocks.heading.placeholder": "Rubrik …", + "field.blocks.image.alt": "Alternativ text", + "field.blocks.image.caption": "Rubrik", + "field.blocks.image.crop": "Beskär", + "field.blocks.image.link": "Länk", + "field.blocks.image.location": "Plats", + "field.blocks.image.name": "Bild", + "field.blocks.image.placeholder": "Välj en bild", + "field.blocks.image.ratio": "Bildförhållande", + "field.blocks.image.url": "Bild-URL", + "field.blocks.line.name": "Linje", + "field.blocks.list.name": "Punktlista", + "field.blocks.markdown.name": "Markdown", + "field.blocks.markdown.label": "Text", + "field.blocks.markdown.placeholder": "Markdown …", + "field.blocks.quote.name": "Citat", + "field.blocks.quote.text.label": "Text", + "field.blocks.quote.text.placeholder": "Citat …", + "field.blocks.quote.citation.label": "Citat", + "field.blocks.quote.citation.placeholder": "av …", + "field.blocks.text.name": "Text", + "field.blocks.text.placeholder": "Text …", + "field.blocks.video.caption": "Rubrik", + "field.blocks.video.name": "Video", + "field.blocks.video.placeholder": "Ange en URL till en video", + "field.blocks.video.url.label": "Video-URL", + "field.blocks.video.url.placeholder": "https://youtube.com/?v=", + + "field.files.empty": "Inga filer valda än", + + "field.layout.delete": "Radera layout", + "field.layout.delete.confirm": "Vill du verkligen radera denna layout?", + "field.layout.empty": "Inga rader än", + "field.layout.select": "Välj en layout", + + "field.pages.empty": "Inga sidor valda än", + "field.structure.delete.confirm": "Vill du verkligen radera denna rad?", + "field.structure.empty": "Inga poster än", + "field.users.empty": "Inga användare valda än", + + "file.blueprint": "Denna fil har ingen blueprint än. Du kan skapa en i /site/blueprints/files/{blueprint}.yml", + "file.delete.confirm": "Vill du verkligen radera
{filename}?", + "file.sort": "Ändra position", + + "files": "Filer", + "files.empty": "Inga filer än", + + "hide": "Göm", + "hour": "Timme", + "import": "Importera", + "info": "Info", + "insert": "Infoga", + "insert.after": "Infoga efter", + "insert.before": "Infoga före", + "install": "Installera", + + "installation": "Installation", + "installation.completed": "Panelen har installerats", + "installation.disabled": "Installeraren för panelen är som standard inaktiverad på offentliga servrar. Kör installeraren på en lokal maskin eller aktivera den med alternativet panel.install.", + "installation.issues.accounts": "Mappen /site/accounts finns inte eller är inte skrivbar", + "installation.issues.content": "Mappen /content finns inte eller är inte skrivbar", + "installation.issues.curl": "Tillägget CURL krävs", + "installation.issues.headline": "Panelen kan inte installeras", + "installation.issues.mbstring": "Tillägget MB String krävs", + "installation.issues.media": "Mappen /media finns inte eller är inte skrivbar", + "installation.issues.php": "Se till att du använder PHP 7+", + "installation.issues.server": "Kirby kräver Apache, Nginx eller Caddy", + "installation.issues.sessions": "Mappen /site/sessions finns inte eller är inte skrivbar", + + "language": "Spr\u00e5k", + "language.code": "Kod", + "language.convert": "Ange som standard", + "language.convert.confirm": "

Vill du verkligen göra {name} till standardspråket? Detta kan inte ångras.

Om {name} har oöversatt innehåll, kommer det inte längre finnas en alternativ översättning och delar av sajten kommer kanske att vara tom.

", + "language.create": "Lägg till ett nytt språk", + "language.delete.confirm": "Vill du verkligen radera språket {name} inklusive alla översättningar? Detta kan inte ångras!", + "language.deleted": "Språket har raderats", + "language.direction": "Läsriktning", + "language.direction.ltr": "Vänster till höger", + "language.direction.rtl": "Höger till vänster", + "language.locale": "PHP locale string", + "language.locale.warning": "Du använder en anpassad språkinställning. Ändra den i språkfilen i mappen /site/languages", + "language.name": "Namn", + "language.updated": "Språket har uppdaterats", + + "languages": "Språk", + "languages.default": "Standardspråk", + "languages.empty": "Det finns inga språk ännu", + "languages.secondary": "Sekundära språk", + "languages.secondary.empty": "Det finns inga sekundära språk ännu", + + "license": "Licens", + "license.buy": "Köp en licens", + "license.register": "Registrera", + "license.manage": "Hantera dina licenser", + "license.register.help": "Du fick din licenskod via e-post efter inköpet. Kopiera och klistra in den för att registrera licensen.", + "license.register.label": "Ange din licenskod", + "license.register.success": "Tack för att du stödjer Kirby", + "license.unregistered": "Detta är en oregistrerad demo av Kirby", + "license.unregistered.label": "Oregistrerad", + + "link": "L\u00e4nk", + "link.text": "L\u00e4nktext", + + "loading": "Laddar", + + "lock.unsaved": "Osparade ändringar", + "lock.unsaved.empty": "Det finns inga fler osparade ändringar", + "lock.isLocked": "Osparade ändringar av {email}", + "lock.file.isLocked": "Filen redigeras just nu av {email} och kan inte redigeras.", + "lock.page.isLocked": "Sidan redigeras just nu av {email} och kan inte redigeras.", + "lock.unlock": "Lås upp", + "lock.isUnlocked": "Dina osparade ändringar har skrivits över av en annan användare. Du kan ladda ner dina ändringar för att slå ihop dem manuellt.", + + "login": "Logga in", + "login.code.label.login": "Inloggningskod", + "login.code.label.password-reset": "Kod för återställning av lösenord", + "login.code.placeholder.email": "000 000", + "login.code.text.email": "Om din e-postadress är registrerad skickades den begärda koden via e-post.", + "login.email.login.body": "Hej {user.nameOrEmail}.\n\nDu begärde nyligen en inloggningskod till panelen för {site}.\nFöljande kod är giltig i {timeout} minuter:\n\n{code}\n\nOm du inte har begärt någon inloggningskod, ignorera detta e-postmeddelande eller kontakta din administratör om du har frågor.\nAv säkerhetsskäl, vidarebefordra INTE detta e-postmeddelande.", + "login.email.login.subject": "Din inloggningskod", + "login.email.password-reset.body": "Hej {user.nameOrEmail}.\n\nDu begärde nyligen en kod för återställning av ditt lösenord till panelen för {site}.\nFöljande kod är giltig i {timeout} minuter:\n\n{code}\n\nOm du inte har begärt en återställning av ditt lösenord, ignorera detta e-postmeddelande eller kontakta din administratör om du har frågor.\nAv säkerhetsskäl, vidarebefordra INTE detta e-postmeddelande.", + "login.email.password-reset.subject": "Din kod för återställning av lösenord", + "login.remember": "Håll mig inloggad", + "login.reset": "Återställ lösenord", + "login.toggleText.code.email": "Logga in via e-post", + "login.toggleText.code.email-password": "Logga in med lösenord", + "login.toggleText.password-reset.email": "Glömt ditt lösenord?", + "login.toggleText.password-reset.email-password": "← Tillbaka till inloggning", + + "logout": "Logga ut", + + "menu": "Meny", + "meridiem": "a.m./p.m.", + "mime": "Mediatyp", + "minutes": "Minuter", + + "month": "Månad", + "months.april": "April", + "months.august": "Augusti", + "months.december": "December", + "months.february": "Februari", + "months.january": "Januari", + "months.july": "Juli", + "months.june": "Juni", + "months.march": "Mars", + "months.may": "Maj", + "months.november": "November", + "months.october": "Oktober", + "months.september": "September", + + "more": "Mer", + "name": "Namn", + "next": "Nästa", + "no": "nej", + "off": "av", + "on": "på", + "open": "Öppna", + "open.newWindow": "Öppna i nytt fönster", + "options": "Alternativ", + "options.none": "Inga alternativ", + + "orientation": "Orientering", + "orientation.landscape": "Liggande", + "orientation.portrait": "Stående", + "orientation.square": "Kvadrat", + + "page.blueprint": "Denna sida har ingen blueprint än. Du kan skapa en i /site/blueprints/pages/{blueprint}.yml", + "page.changeSlug": "Ändra URL", + "page.changeSlug.fromTitle": "Skapa utifr\u00e5n titel", + "page.changeStatus": "Ändra status", + "page.changeStatus.position": "Välj en ny position", + "page.changeStatus.select": "Välj en ny status", + "page.changeTemplate": "Ändra mall", + "page.delete.confirm": "Vill du verkligen radera {title}?", + "page.delete.confirm.subpages": "Denna sida har undersidor.
Alla undersidor kommer också att raderas.", + "page.delete.confirm.title": "Fyll i sidans titel för att bekräfta", + "page.draft.create": "Skapa utkast", + "page.duplicate.appendix": "Kopiera", + "page.duplicate.files": "Kopiera filer", + "page.duplicate.pages": "Kopiera sidor", + "page.sort": "Ändra position", + "page.status": "Status", + "page.status.draft": "Utkast", + "page.status.draft.description": "Sidan är ett utkast och endast synlig för inloggade redaktörer eller via en hemlig länk", + "page.status.listed": "Publik", + "page.status.listed.description": "Sidan är publik för vem som helst", + "page.status.unlisted": "Olistad", + "page.status.unlisted.description": "Sidan är endast åtkomlig via URL", + + "pages": "Sidor", + "pages.empty": "Inga sidor än", + "pages.status.draft": "Utkast", + "pages.status.listed": "Publicerade", + "pages.status.unlisted": "Olistade", + + "pagination.page": "Sida", + + "password": "L\u00f6senord", + "paste": "Klistra in", + "paste.after": "Klistra in efter", + "pixel": "Pixel", + "plugins": "Tillägg", + "prev": "Föregående", + "preview": "Förhandsgranska", + "remove": "Ta bort", + "rename": "Byt namn", + "replace": "Ersätt", + "retry": "F\u00f6rs\u00f6k igen", + "revert": "Återgå", + "revert.confirm": "Vill du verkligen radera alla osparade ändringar?", + + "role": "Roll", + "role.admin.description": "Administratören har alla behörigheter", + "role.admin.title": "Administratör", + "role.all": "Alla", + "role.empty": "Det finns inga användare med denna roll", + "role.description.placeholder": "Ingen beskrivning", + "role.nobody.description": "Detta är en roll utan några behörigheter", + "role.nobody.title": "Ingen", + + "save": "Spara", + "search": "Sök", + "search.min": "Ange {min} tecken för att söka", + "search.all": "Visa alla", + "search.results.none": "Inga träffar", + + "section.required": "Sektionen krävs", + + "security": "Säkerhet", + "select": "Välj", + "server": "Server", + "settings": "Inställningar", + "show": "Visa", + "site.blueprint": "Webbplatsen har ingen blueprint än. Du kan skapa en i /site/blueprints/site.yml", + "size": "Storlek", + "slug": "URL-appendix", + "sort": "Sortera", + + "stats.empty": "Inga rapporter", + "system.issues.content": "Mappen content verkar vara exponerad", + "system.issues.debug": "Felsökningsläget måste vara avstängt i produktion", + "system.issues.git": "Mappen .git verkar vara exponerad", + "system.issues.https": "Vi rekommenderar HTTPS för alla dina webbplatser", + "system.issues.kirby": "Mappen kirby verkar vara exponerad", + "system.issues.site": "Mappen site verkar vara exponerad", + + "title": "Titel", + "template": "Mall", + "today": "Idag", + + "toolbar.button.code": "Kod", + "toolbar.button.bold": "Fet", + "toolbar.button.email": "E-post", + "toolbar.button.headings": "Rubriker", + "toolbar.button.heading.1": "Rubrik 1", + "toolbar.button.heading.2": "Rubrik 2", + "toolbar.button.heading.3": "Rubrik 3", + "toolbar.button.heading.4": "Rubrik 4", + "toolbar.button.heading.5": "Rubrik 5", + "toolbar.button.heading.6": "Rubrik 6", + "toolbar.button.italic": "Kursiv", + "toolbar.button.file": "Fil", + "toolbar.button.file.select": "Välj en fil", + "toolbar.button.file.upload": "Ladda upp en fil", + "toolbar.button.link": "L\u00e4nk", + "toolbar.button.paragraph": "Stycke", + "toolbar.button.strike": "Genomstruken", + "toolbar.button.ol": "Sorterad lista", + "toolbar.button.underline": "Understruken", + "toolbar.button.ul": "Punktlista", + + "translation.author": "Kirby-teamet, Ola Christensson", + "translation.direction": "ltr", + "translation.name": "Svenska", + "translation.locale": "sv_SE", + + "upload": "Ladda upp", + "upload.error.cantMove": "Den överförda filen kunde inte flyttas", + "upload.error.cantWrite": "Det gick inte att skriva filen till hårddisken", + "upload.error.default": "Filen kunde inte laddas upp", + "upload.error.extension": "Filuppladdningen förhindrades på grund av filändelsen", + "upload.error.formSize": "Den överförda filen överskrider den maximala filstorlek som anges i formuläret (MAX_FILE_SIZE)", + "upload.error.iniPostSize": "Den överförda filen överskrider post_max_size-direktivet i php.ini", + "upload.error.iniSize": "Den överförda filen överskrider direktivet upload_max_filesize i php.ini", + "upload.error.noFile": "Ingen fil laddades upp", + "upload.error.noFiles": "Inga filer laddades upp", + "upload.error.partial": "Den överförda filen laddades bara delvis upp", + "upload.error.tmpDir": "Saknar en temporär mapp", + "upload.errors": "Fel", + "upload.progress": "Laddar upp...", + + "url": "URL", + "url.placeholder": "https://exempel.se", + + "user": "Användare", + "user.blueprint": "Du kan skapa ytterligare sektioner och fält för den här användarrollen i /site/blueprints/users/{blueprint}.yml", + "user.changeEmail": "Ändra e-postadress", + "user.changeLanguage": "Ändra språk", + "user.changeName": "Byt namn på denna användare", + "user.changePassword": "Ändra lösenord", + "user.changePassword.new": "Nytt lösenord", + "user.changePassword.new.confirm": "Bekräfta det nya lösenordet...", + "user.changeRole": "Ändra roll", + "user.changeRole.select": "Välj en ny roll", + "user.create": "Lägg till en ny användare", + "user.delete": "Radera denna användare", + "user.delete.confirm": "Vill du verkligen radera
{email}?", + + "users": "Användare", + + "version": "Version", + + "view.account": "Ditt konto", + "view.installation": "Installation", + "view.languages": "Språk", + "view.resetPassword": "Återställ lösenord", + "view.site": "Webbplats", + "view.system": "System", + "view.users": "Anv\u00e4ndare", + + "welcome": "Välkommen", + "year": "År", + "yes": "ja" } diff --git a/kirby/i18n/translations/tr.json b/kirby/i18n/translations/tr.json index 16de5e3..970ab5d 100644 --- a/kirby/i18n/translations/tr.json +++ b/kirby/i18n/translations/tr.json @@ -1,730 +1,574 @@ { - "account.changeName": "İsminizi değiştirin", - "account.delete": "Hesabınızı silin", - "account.delete.confirm": "Hesabınızı gerçekten silmek istiyor musunuz? Oturumunuz hemen sonlandırılacaktır. Hesabınız daha sonra geri alınamaz.", - - "activate": "Etkinleştir", - "add": "Ekle", - "alpha": "Alfa", - "author": "Yazar", - "avatar": "Profil resmi", - "back": "Geri", - "cancel": "\u0130ptal", - "change": "De\u011fi\u015ftir", - "close": "Kapat", - "changes": "Değişiklikler", - "confirm": "Tamam", - "collapse": "Daralt", - "collapse.all": "Tümünü daralt", - "color": "Renk", - "coordinates": "Koordinatlar", - "copy": "Kopyala", - "copy.all": "Tümünü kopyala", - "copy.success": "{count} kopyalandı!", - "create": "Oluştur", - "custom": "Özel", - - "date": "Tarih", - "date.select": "Bir tarih seçiniz", - - "day": "Gün", - "days.fri": "Cum", - "days.mon": "Pzt", - "days.sat": "Cmt", - "days.sun": "Paz", - "days.thu": "Per", - "days.tue": "Sal", - "days.wed": "\u00c7ar", - - "debugging": "Hata ayıklama", - - "delete": "Sil", - "delete.all": "Tümünü sil", - - "dialog.fields.empty": "Bu iletişim kutusunda alan yok", - "dialog.files.empty": "Seçilecek dosya yok", - "dialog.pages.empty": "Seçilecek sayfa yok", - "dialog.text.empty": "Bu iletişim kutusu herhangi bir metin tanımlamaz", - "dialog.users.empty": "Seçilecek kullanıcı yok", - - "dimensions": "Boyutlar", - "disable": "Devre dışı bırak", - "disabled": "Devredışı", - "discard": "Vazge\u00e7", - - "drawer.fields.empty": "Bu çekmecede alan yok", - - "domain": "Alan adı", - "download": "İndir", - "duplicate": "Kopyala", - - "edit": "D\u00fczenle", - - "email": "E-Posta", - "email.placeholder": "eposta@ornek.com", - - "enter": "Giriş", - "entries": "Girdiler", - "entry": "Girdi", - - "environment": "Ortam", - - "error": "Hata", - "error.access.code": "Geçersiz kod", - "error.access.login": "Geçersiz giriş", - "error.access.panel": "Panel'e erişim izniniz yok", - "error.access.view": "Panel'in bu bölümüne erişim izniniz yok", - - "error.avatar.create.fail": "Profil resmi yüklenemedi", - "error.avatar.delete.fail": "Profil resmi silinemedi", - "error.avatar.dimensions.invalid": "Lütfen profil resminin genişliğini ve yüksekliğini 3000 pikselin altında tutun", - "error.avatar.mime.forbidden": "Profil resmi JPEG veya PNG dosyaları olmalıdır", - - "error.blueprint.notFound": "\"{name}\" adlı plan yüklenemedi", - - "error.blocks.max.plural": "{max} bloktan fazlasını eklememelisiniz", - "error.blocks.max.singular": "Birden fazla blok eklememelisiniz", - "error.blocks.min.plural": "En az {min} blok eklemelisiniz", - "error.blocks.min.singular": "En az bir blok eklemelisiniz", - "error.blocks.validation": "\"{fieldset}\" blok türünü kullanan {index}. bloktaki \"{field}\" alanında bir hata var", - - "error.cache.type.invalid": "Geçersiz önbellek türü \"{type}\"", - - "error.email.preset.notFound": "\"{name}\" e-posta adresi bulunamadı", - - "error.field.converter.invalid": "Geçersiz dönüştürücü \"{converter}\"", - "error.field.type.missing": "\"{ name }\" alanı: \"{ type }\" alan türü mevcut değil", - - "error.file.changeName.empty": "İsim boş olmamalıdır", - "error.file.changeName.permission": "\"{filename}\" adını değiştiremezsiniz", - "error.file.changeTemplate.invalid": "\"{id}\" dosyası için şablon \"{template}\" olarak değiştirilemez (geçerli: \"{blueprints}\")", - "error.file.changeTemplate.permission": "\"{id}\" dosyası için şablonu değiştirmenize izin verilmiyor", - - "error.file.duplicate": "\"{filename}\" isimli bir dosya zaten var", - "error.file.extension.forbidden": "\"{extension}\" dosya uzantısına izin verilmiyor", - "error.file.extension.invalid": "Geçersiz uzantı: {extension}", - "error.file.extension.missing": "\"{filename}\" dosyasının uzantısı yok", - "error.file.maxheight": "Resmin yüksekliği {height} pikselden büyük olmamalıdır", - "error.file.maxsize": "Dosya çok büyük", - "error.file.maxwidth": "Resmin genişliği {width} pikselden büyük olmamalıdır", - "error.file.mime.differs": "Yüklenen dosya aynı dosya türü \"{mime}\" olmalıdır", - "error.file.mime.forbidden": "\"{mime}\" medya türüne izin verilmiyor", - "error.file.mime.invalid": "Geçersiz medya türü: {mime}", - "error.file.mime.missing": "\"{filename}\" için medya türü tespit edilemiyor", - "error.file.minheight": "Resmin yüksekliği en az {height} piksel olmalıdır", - "error.file.minsize": "Dosya çok küçük", - "error.file.minwidth": "Resmin genişliği en az {width} piksel olmalıdır", - "error.file.name.unique": "Dosya adı benzersiz olmalıdır", - "error.file.name.missing": "Dosya adı boş bırakılamaz", - "error.file.notFound": "\"{filename}\" dosyası bulunamadı", - "error.file.orientation": "Resmin oryantasyonu \"{orientation}\" olmalıdır", - "error.file.type.forbidden": "{type} dosya yükleme izni yok", - "error.file.type.invalid": "Geçersiz dosya türü: {type}", - "error.file.undefined": "Dosya bulunamad\u0131", - - "error.form.incomplete": "Lütfen tüm form hatalarını düzeltin...", - "error.form.notSaved": "Form kaydedilemedi", - - "error.language.code": "Lütfen dil için geçerli bir kod girin", - "error.language.duplicate": "Bu dil zaten var", - "error.language.name": "Lütfen dil için geçerli bir isim girin", - "error.language.notFound": "Dil bulunamadı", - - "error.layout.validation.block": "{layoutIndex}. sıradaki düzende \"{fieldset}\" blok türünü kullanan {blockIndex}. bloktaki \"{field}\" alanında bir hata var", - "error.layout.validation.settings": "{index}. düzen ayarlarında bir hata var", - - "error.license.domain": "Lisans için alan adı eksik", - "error.license.email": "Lütfen geçerli bir e-posta adresi girin", - "error.license.format": "Lütfen geçerli bir lisans anahtarı girin", - "error.license.verification": "Lisans doğrulanamadı", - - "error.login.totp.confirm.invalid": "Geçersiz kod", - "error.login.totp.confirm.missing": "Lütfen geçerli kodu girin", - - "error.object.validation": "\"{label}\" alanında bir hata var:\n{message}", - - "error.offline": "Panel şu anda çevrimdışı", - - "error.page.changeSlug.permission": "\"{slug}\" uzantısına sahip bu sayfanın adresini değiştirilemez", - "error.page.changeSlug.reserved": "Üst düzey sayfaların yolu \"{path}\" ile başlamamalıdır", - "error.page.changeStatus.incomplete": "Sayfada hatalar var ve yayınlanamadı", - "error.page.changeStatus.permission": "Bu sayfanın durumu değiştirilemez", - "error.page.changeStatus.toDraft.invalid": "\"{slug}\" sayfası bir taslak haline dönüştürülemiyor", - "error.page.changeTemplate.invalid": "\"{slug}\" sayfası için şablon değiştirilemiyor", - "error.page.changeTemplate.permission": "\"{slug}\" için şablonu değiştiremezsiniz", - "error.page.changeTitle.empty": "Başlık boş bırakılamaz", - "error.page.changeTitle.permission": "\"{slug}\" için başlığı değiştiremezsiniz", - "error.page.create.permission": "\"{slug}\" oluşturmanıza izin verilmiyor", - "error.page.delete": "\"{slug}\" sayfası silinemedi", - "error.page.delete.confirm": "Onaylamak için sayfa başlığını girin", - "error.page.delete.hasChildren": "Sayfada alt sayfalar var ve silinemiyor", - "error.page.delete.permission": "\"{slug}\" öğesini silmenize izin verilmiyor", - "error.page.draft.duplicate": "\"{slug}\" adres eki olan bir sayfa taslağı zaten mevcut", - "error.page.duplicate": "\"{slug}\" adres eki içeren bir sayfa zaten mevcut", - "error.page.duplicate.permission": "\"{slug}\" öğesini çoğaltmanıza izin verilmiyor", - "error.page.move.ancestor": "Sayfa kendi içine taşınamaz", - "error.page.move.directory": "Sayfa dizini taşınamaz", - "error.page.move.duplicate": "\"{slug}\" URL ekine sahip bir alt sayfa zaten mevcut", - "error.page.move.notFound": "Taşınan sayfa bulunamadı", - "error.page.move.permission": "\"{slug}\" öğesini taşımanıza izin verilmiyor", - "error.page.move.template": "\"{template}\" şablonu \"{parent}\" alt sayfası olarak kabul edilmiyor", - "error.page.notFound": "\"{slug}\" uzantısındaki sayfa bulunamadı", - "error.page.num.invalid": "Lütfen geçerli bir sıralama numarası girin. Sayılar negatif olmamalıdır.", - "error.page.slug.invalid": "Lütfen geçerli bir URL eki girin", - "error.page.slug.maxlength": "Adres uzantısı \"{length}\" karakterden az olmalıdır", - "error.page.sort.permission": "\"{slug}\" sayfası sıralanamıyor", - "error.page.status.invalid": "Lütfen geçerli bir sayfa durumu ayarlayın", - "error.page.undefined": "Sayfa bulunamad\u0131", - "error.page.update.permission": "\"{slug}\" güncellemesine izin verilmiyor", - - "error.section.files.max.plural": "\"{section}\" bölümüne {max} dosyadan daha fazlasını eklememelisiniz", - "error.section.files.max.singular": "\"{section}\" bölümüne birden fazla dosya eklememelisiniz", - "error.section.files.min.plural": "\"{section}\" bölümü en az {min} dosya gerektiriyor", - "error.section.files.min.singular": "\"{section}\" bölümü en az bir dosya gerektiriyor", - - "error.section.pages.max.plural": "\"{section}\" bölümüne maksimum {max} sayfadan fazla ekleyemezsiniz", - "error.section.pages.max.singular": "\"{section}\" bölümüne birden fazla sayfa ekleyemezsiniz", - "error.section.pages.min.plural": "\"{section}\" bölümü en az {min} sayfa gerektiriyor", - "error.section.pages.min.singular": "\"{section}\" bölümü en az bir sayfa gerektiriyor", - - "error.section.notLoaded": "\"{name}\" bölümü yüklenemedi", - "error.section.type.invalid": "\"{type}\" tipi geçerli değil", - - "error.site.changeTitle.empty": "Başlık boş bırakılamaz", - "error.site.changeTitle.permission": "Sitenin başlığını değiştiremezsin", - "error.site.update.permission": "Siteyi güncellemenize izin verilmiyor", - - "error.structure.validation": "{index} satırındaki \"{field}\" alanında bir hata var", - - "error.template.default.notFound": "Varsayılan şablon yok", - - "error.unexpected": "Beklenmeyen bir hata oluştu! Daha fazla bilgi için hata ayıklama modunu etkinleştirin: https://getkirby.com/docs/reference/system/options/debug", - - "error.user.changeEmail.permission": "\"{name}\" kullanıcısı için e-postayı değiştiremezsiniz", - "error.user.changeLanguage.permission": "\"{name}\" kullanıcısının dilini değiştiremezsin", - "error.user.changeName.permission": "\"{name}\" kullanıcısının adını değiştiremezsiniz", - "error.user.changePassword.permission": "\"{name}\" kullanıcısının şifresini değiştiremezsiniz", - "error.user.changeRole.lastAdmin": "Son yöneticinin rolü değiştirilemez", - "error.user.changeRole.permission": "\"{name}\" kullanıcısının rolünü değiştiremezsin", - "error.user.changeRole.toAdmin": "Birini yönetici rolüne tanıtmanıza izin verilmiyor", - "error.user.create.permission": "Bu kullanıcıyı oluşturmanıza izin verilmiyor", - "error.user.delete": "\"{name}\" kullanıcısı silinemedi", - "error.user.delete.lastAdmin": "Son y\u00f6netici kullan\u0131c\u0131y\u0131 silemezsiniz", - "error.user.delete.lastUser": "Son kullanıcı silinemez", - "error.user.delete.permission": "\"{name}\" kullanıcısını silme yetkiniz yok", - "error.user.duplicate": "\"{email}\" e-posta adresine sahip bir kullanıcı zaten var", - "error.user.email.invalid": "Lütfen geçerli bir e-posta adresi girin", - "error.user.language.invalid": "Lütfen geçerli bir dil girin", - "error.user.notFound": "\"{name}\" kullanıcısı bulunamadı", - "error.user.password.excessive": "Lütfen geçerli bir şifre girin. Şifreler 1000 karakterden uzun olmamalıdır.", - "error.user.password.invalid": "Lütfen geçerli bir şifre giriniz. Şifreler en az 8 karakter uzunluğunda olmalıdır.", - "error.user.password.notSame": "L\u00fctfen \u015fifreyi do\u011frulay\u0131n", - "error.user.password.undefined": "Bu kullanıcının şifresi yok", - "error.user.password.wrong": "Yanlış şifre", - "error.user.role.invalid": "Lütfen geçerli bir rol girin", - "error.user.undefined": "Kullanıcı bulunamadı", - "error.user.update.permission": "\"{name}\" kullanıcısını güncellemenize izin verilmiyor", - - "error.validation.accepted": "Lütfen onaylayın", - "error.validation.alpha": "Lütfen sadece a-z arasındaki karakterleri girin", - "error.validation.alphanum": "Lütfen sadece a-z veya 0-9 arasındaki rakamları girin", - "error.validation.anchor": "Lütfen doğru bir bağlantı çapası girin", - "error.validation.between": "Lütfen \"{min}\" ile \"{max}\" arasında bir değer girin", - "error.validation.boolean": "Lütfen onaylayın veya reddedin", - "error.validation.color": "Lütfen {format} biçiminde geçerli bir renk girin", - "error.validation.contains": "Lütfen \"{needle}\" içeren bir değer girin", - "error.validation.date": "Lütfen geçerli bir tarih girin", - "error.validation.date.after": "Lütfen {date} tarihinden sonra bir tarih girin", - "error.validation.date.before": "Lütfen {date} tarihinden önce bir tarih girin", - "error.validation.date.between": "Lütfen {min} ve {max} arasında bir tarih girin", - "error.validation.denied": "Lütfen reddedin", - "error.validation.different": "Değer \"{other}\" olmamalıdır", - "error.validation.email": "Lütfen geçerli bir e-posta adresi girin", - "error.validation.endswith": "Değer \"{end}\" ile bitmelidir", - "error.validation.filename": "Lütfen geçerli bir dosya adı girin", - "error.validation.in": "Lütfen bunlardan birini girin: ({in})", - "error.validation.integer": "Lütfen geçerli bir tamsayı girin", - "error.validation.ip": "Lütfen geçerli bir ip adresi girin", - "error.validation.less": "Lütfen {max} 'dan daha düşük bir değer girin", - "error.validation.linkType": "Bağlantı türüne izin verilmiyor", - "error.validation.match": "Değer beklenen modelle eşleşmiyor", - "error.validation.max": "Lütfen {max} 'a eşit veya daha küçük bir değer girin", - "error.validation.maxlength": "Lütfen daha kısa bir değer girin. (maks. {max} karakter)", - "error.validation.maxwords": "Lütfen en fazla {max} kelime(ler) girin", - "error.validation.min": "Lütfen {min} ile eşit veya daha büyük bir değer girin", - "error.validation.minlength": "Lütfen daha uzun bir değer girin. (min. {min} karakter)", - "error.validation.minwords": "Lütfen en az {min} kelime(ler) girin", - "error.validation.more": "Lütfen {min} değerinden daha büyük bir değer girin", - "error.validation.notcontains": "Lütfen \"{needle}\" içermeyen bir değer girin", - "error.validation.notin": "Lütfen bunlardan herhangi birini girmeyin: ({notIn})", - "error.validation.option": "Lütfen geçerli bir seçenek girin", - "error.validation.num": "Lütfen geçerli bir sayı girin", - "error.validation.required": "Lütfen birşeyler girin", - "error.validation.same": "Lütfen \"{other}\" yazınız", - "error.validation.size": "Değerin boyutu \"{size}\" olmalıdır", - "error.validation.startswith": "Değer \"{start}\" ile başlamalıdır", - "error.validation.tel": "Lütfen biçimlendirilmemiş bir telefon numarası girin", - "error.validation.time": "Lütfen geçerli bir zaman girin", - "error.validation.time.after": "Lütfen {time} sonrası bir tarih girin", - "error.validation.time.before": "Lütfen {time} öncesi bir tarih girin", - "error.validation.time.between": "Lütfen {min} ile {max} arasında bir tarih girin", - "error.validation.uuid": "Lütfen geçerli bir UUID girin", - "error.validation.url": "Lütfen geçerli bir adres girin", - - "expand": "Genişlet", - "expand.all": "Tümünü genişlet", - - "field.invalid": "Bu alan geçersizdir", - "field.required": "Alan gereklidir", - "field.blocks.changeType": "Türü değiştir", - "field.blocks.code.name": "Kod", - "field.blocks.code.language": "Dil", - "field.blocks.code.placeholder": "Kodunuz …", - "field.blocks.delete.confirm": "Bu bloğu gerçekten silmek istiyor musunuz?", - "field.blocks.delete.confirm.all": "Tüm blokları gerçekten silmek istiyor musunuz?", - "field.blocks.delete.confirm.selected": "Seçilen blokları gerçekten silmek istiyor musunuz?", - "field.blocks.empty": "Henüz blok yok", - "field.blocks.fieldsets.empty": "Henüz alan kümesi yok", - "field.blocks.fieldsets.label": "Lütfen bir blok türü seçiniz …", - "field.blocks.fieldsets.paste": "Panonuzdan düzenleri/blokları içe aktarmak için {{ shortcut }} tuşuna basın Yalnızca geçerli alanda izin verilenler eklenecektir.", - "field.blocks.gallery.name": "Galeri", - "field.blocks.gallery.images.empty": "Henüz görsel yok", - "field.blocks.gallery.images.label": "Görseller", - "field.blocks.heading.level": "Seviye", - "field.blocks.heading.name": "Başlık", - "field.blocks.heading.text": "Metin", - "field.blocks.heading.placeholder": "Başlık …", - "field.blocks.image.alt": "Alternatif metin", - "field.blocks.image.caption": "Altyazı", - "field.blocks.image.crop": "Kırp", - "field.blocks.image.link": "Bağlantı", - "field.blocks.image.location": "Lokasyon", - "field.blocks.image.location.internal": "Bu website", - "field.blocks.image.location.external": "Dış kaynak", - "field.blocks.image.name": "Görsel", - "field.blocks.image.placeholder": "Bir görsel seçin", - "field.blocks.image.ratio": "Oran", - "field.blocks.image.url": "Görsel URL", - "field.blocks.line.name": "Çizgi", - "field.blocks.list.name": "Liste", - "field.blocks.markdown.name": "Markdown", - "field.blocks.markdown.label": "Metin", - "field.blocks.markdown.placeholder": "Markdown …", - "field.blocks.quote.name": "Alıntı", - "field.blocks.quote.text.label": "Metin", - "field.blocks.quote.text.placeholder": "Alıntı …", - "field.blocks.quote.citation.label": "Alıntı", - "field.blocks.quote.citation.placeholder": "yazar …", - "field.blocks.text.name": "Metin", - "field.blocks.text.placeholder": "Metin …", - "field.blocks.video.autoplay": "Otomatik oynatma", - "field.blocks.video.caption": "Altyazı", - "field.blocks.video.controls": "Kontroller", - "field.blocks.video.location": "Lokasyon", - "field.blocks.video.loop": "Döngü", - "field.blocks.video.muted": "Sessiz", - "field.blocks.video.name": "Video", - "field.blocks.video.placeholder": "Bir video URL'si girin", - "field.blocks.video.poster": "Kapak", - "field.blocks.video.preload": "Önyükleme", - "field.blocks.video.url.label": "Video-URL", - "field.blocks.video.url.placeholder": "https://youtube.com/?v=", - - "field.files.empty": "Henüz dosya seçilmedi", - - "field.layout.change": "Düzeni değiştir", - "field.layout.delete": "Düzeni sil", - "field.layout.delete.confirm": "Bu düzeni gerçekten silmek istiyor musunuz?", - "field.layout.delete.confirm.all": "Gerçekten tüm düzenleri silmek istiyor musunuz?", - "field.layout.empty": "Henüz satır yok", - "field.layout.select": "Bir düzen seçin", - - "field.object.empty": "Henüz bilgi yok", - - "field.pages.empty": "Henüz sayfa seçilmedi", - - "field.structure.delete.confirm": "Bu girdiyi silmek istedi\u011finizden emin misiniz?", - "field.structure.delete.confirm.all": "Tüm girdileri gerçekten silmek istiyor musunuz?", - "field.structure.empty": "Hen\u00fcz bir girdi yok", - - "field.users.empty": "Henüz kullanıcı seçilmedi", - - "fields.empty": "Henüz alan yok", - - "file": "Dosya", - "file.blueprint": "Bu dosyanın henüz bir planı yok. Kurulumu /site/blueprints/files/{blueprint}.yml dosyasında tanımlayabilirsiniz.", - "file.changeTemplate": "Şablonu değiştir", - "file.changeTemplate.notice": "Dosyanın şablonunun değiştirilmesi, tür olarak eşleşmeyen alanların içeriğini kaldıracaktır. Yeni şablon, görüntü boyutları gibi belirli kuralları tanımlıyorsa, bunlar da geri döndürülemez şekilde uygulanacaktır. Dikkatli kullanın.", - "file.delete.confirm": "{filename} dosyasını silmek istediğinizden emin misiniz?", - "file.focus.placeholder": "Odak noktasını belirleyin", - "file.focus.reset": "Odak noktasını kaldırın", - "file.focus.title": "Odak", - "file.sort": "Pozisyon değiştir", - - "files": "Dosyalar", - "files.empty": "Henüz dosya yok", - - "filter": "Filtre", - - "hide": "Gizle", - "hour": "Saat", - "hue": "Renk tonu", - "import": "İçe aktar", - "info": "Bilgi", - "insert": "Ekle", - "insert.after": "Sonrasına ekle", - "insert.before": "Öncesine ekle", - "install": "Kurulum", - - "installation": "Kurulum", - "installation.completed": "Panel kuruldu", - "installation.disabled": "Panel yükleyici, herkese açık sunucularda varsayılan olarak devre dışıdır. Lütfen yükleyiciyi yerel bir makinede çalıştırın veya panel.install seçeneğiyle etkinleştirin.", - "installation.issues.accounts": "/site/accounts klasörü yok yada yazılabilir değil", - "installation.issues.content": "/content klasörü yok yada yazılabilir değil", - "installation.issues.curl": "CURL eklentisi gerekli", - "installation.issues.headline": "Panel kurulamadı", - "installation.issues.mbstring": "MB String eklentisi gerekli", - "installation.issues.media": "/media klasörü yok yada yazılamaz", - "installation.issues.php": "PHP 8+ kullandığınızdan emin olun. ", - "installation.issues.sessions": "/site/sessions klasörü mevcut değil veya yazılabilir değil", - - "language": "Dil", - "language.code": "Kod", - "language.convert": "Varsayılan yap", - "language.convert.confirm": "

{name}'i varsayılan dile dönüştürmek istiyor musunuz? Bu geri alınamaz.

{name} çevrilmemiş içeriğe sahipse, artık geçerli bir geri dönüş olmaz ve sitenizin bazı bölümleri boş olabilir.

", - "language.create": "Yeni bir dil ekle", - "language.default": "Varsayılan dil", - "language.delete.confirm": "Tüm çevirileri içeren {name} dilini gerçekten silmek istiyor musunuz? Bu geri alınamaz!", - "language.deleted": "Dil silindi", - "language.direction": "Okuma yönü", - "language.direction.ltr": "Soldan sağa", - "language.direction.rtl": "Sağdan sola", - "language.locale": "PHP yerel dizesi", - "language.locale.warning": "Özel bir yerel ayar kullanıyorsunuz. Lütfen /site/languages konumundaki dil dosyasından değiştirin.", - "language.name": "İsim", - "language.secondary": "İkincil dil", - "language.settings": "Dil ayarları", - "language.updated": "Dil güncellendi", - "language.variables": "Dil değişkenleri", - "language.variables.empty": "Henüz çeviri yok", - - "language.variable.delete.confirm": "Gerçekten {key} değişkenini silmek istiyor musunuz?", - "language.variable.key": "Anahtar", - "language.variable.notFound": "Değişken bulunamadı", - "language.variable.value": "Değer", - - "languages": "Diller", - "languages.default": "Varsayılan dil", - "languages.empty": "Henüz hiç dil yok", - "languages.secondary": "İkincil diller", - "languages.secondary.empty": "Henüz ikincil bir dil yok", - - "license": "Lisans", - "license.activate": "Şimdi etkinleştirin", - "license.activate.label": "Lütfen lisansınızı etkinleştirin", - "license.activate.domain": "Lisansınız {host} için etkinleştirilecektir.", - "license.activate.local": "Yerel etki alanınız {host} için Kirby lisansınızı etkinleştirmek üzeresiniz. Bu site genel bir etki alanına kurulacaksa, lütfen bunun yerine orada etkinleştirin. Eğer lisansınızı kullanmak istediğiniz alan adı {host} ise lütfen devam edin.", - "license.activated": "Etkinleştirildi", - "license.buy": "Bir lisans satın al", - "license.code": "Kod", - "license.code.help": "Lisans kodunuzu satın alma işleminden sonra e-posta yoluyla aldınız. Lütfen kopyalayıp buraya yapıştırın.", - "license.code.label": "Lütfen lisans kodunu giriniz", - "license.status.active.info": "{date} tarihine kadar yeni ana sürümleri içerir", - "license.status.active.label": "Geçerli lisans", - "license.status.demo.info": "Bu bir demo kurulumudur", - "license.status.demo.label": "Demo", - "license.status.inactive.info": "Yeni ana sürümlere güncellemek için lisansı yenileyin", - "license.status.inactive.label": "Yeni ana sürüm yok", - "license.status.legacy.bubble": "Lisansınızı yenilemeye hazır mısınız?", - "license.status.legacy.info": "Lisansınız bu sürümü kapsamıyor", - "license.status.legacy.label": "Lütfen lisansınızı yenileyin", - "license.status.missing.bubble": "Sitenizi yayına almaya hazır mısınız?", - "license.status.missing.info": "Geçerli lisans yok", - "license.status.missing.label": "Lütfen lisansınızı etkinleştirin", - "license.manage": "Lisanslarınızı yönetin", - "license.purchased": "Satın alındı", - "license.success": "Kirby'yi desteklediğiniz için teşekkürler", - "license.unregistered.label": "Kayıtsız", - - "link": "Ba\u011flant\u0131", - "link.text": "Ba\u011flant\u0131 yaz\u0131s\u0131", - - "loading": "Yükleniyor", - - "lock.unsaved": "Kaydedilmemiş değişiklikler", - "lock.unsaved.empty": "Daha fazla kaydedilmemiş değişiklik yok", - "lock.isLocked": "{email} tarafından yapılan kaydedilmemiş değişiklikler", - "lock.unlock": "Kilidi Aç", - "lock.unlock.submit": "Kaydedilmemiş değişikliklerin kilidini {email} ile açın ve üzerine yazın", - "lock.isUnlocked": "Başka bir kullanıcı tarafından kilidi açıldı", - - "login": "Giriş", - "login.code.label.login": "Giriş kodu", - "login.code.label.password-reset": "Şifre sıfırlama kodu", - "login.code.placeholder.email": "000 000", - "login.code.placeholder.totp": "000000", - "login.code.text.email": "E-posta adresiniz kayıtlıysa, istenen kod e-posta yoluyla gönderilmiştir.", - "login.code.text.totp": "Lütfen kimlik doğrulayıcı uygulamanızdaki tek seferlik kodu girin.", - "login.email.login.body": "Merhaba {user.nameOrEmail},\n\nKısa süre önce {site} Panel'i için bir giriş kodu istediniz.\nAşağıdaki giriş kodu {timeout} dakika boyunca geçerli olacaktır:\n\n{code}\n\nBir giriş kodu istemediyseniz, lütfen bu e-postayı dikkate almayın veya sorularınız varsa yöneticinize başvurun.\nGüvenliğiniz için lütfen bu e-postayı İLETMEYİN.", - "login.email.login.subject": "Giriş kodunuz", - "login.email.password-reset.body": "Merhaba {user.nameOrEmail},\n\nKısa süre önce {site} Panel'i için bir şifre sıfırlama kodu istediniz.\nAşağıdaki şifre sıfırlama kodu {timeout} dakika boyunca geçerli olacaktır:\n\n{code}\n\nŞifre sıfırlama kodu istemediyseniz, lütfen bu e-postayı dikkate almayın veya sorularınız varsa yöneticinizle iletişime geçin.\nGüvenliğiniz için lütfen bu e-postayı İLETMEYİN.", - "login.email.password-reset.subject": "Şifre sıfırlama kodunuz", - "login.remember": "Oturumumu açık tut", - "login.reset": "Şifreyi sıfırla", - "login.toggleText.code.email": "E-posta ile giriş yapın", - "login.toggleText.code.email-password": "Şifre ile giriş yapın", - "login.toggleText.password-reset.email": "Şifrenizi mi unuttunuz?", - "login.toggleText.password-reset.email-password": "← Girişe geri dön", - "login.totp.enable.option": "Tek seferlik kodlar ayarlama", - "login.totp.enable.intro": "Kimlik doğrulayıcı uygulamalar, hesabınızda oturum açarken ikinci bir faktör olarak kullanılan tek seferlik kodlar oluşturabilir.", - "login.totp.enable.qr.label": "1. Bu QR kodunu tarayın", - "login.totp.enable.qr.help": "Tarama yapılamıyor mu? Kurulum anahtarını {secret} kimlik doğrulayıcı uygulamanıza elle ekleyin.", - "login.totp.enable.confirm.headline": "2. Oluşturulan kod ile onaylayın", - "login.totp.enable.confirm.text": "Uygulamanız her 30 saniyede bir yeni bir kerelik kod oluşturur. Kurulumu tamamlamak için geçerli kodu girin:", - "login.totp.enable.confirm.label": "Geçerli kod", - "login.totp.enable.confirm.help": "Bu kurulumdan sonra, her oturum açtığınızda sizden tek seferlik bir kod isteyeceğiz.", - "login.totp.enable.success": "Tek seferlik kodlar etkinleştirildi", - "login.totp.disable.option": "Tek seferlik kodları devre dışı bırakma", - "login.totp.disable.label": "Tek seferlik kodları devre dışı bırakmak için şifrenizi girin", - "login.totp.disable.help": "Gelecekte, oturum açtığınızda e-posta yoluyla gönderilen bir oturum açma kodu gibi farklı bir ikinci faktör istenecektir. Tek seferlik kodları daha sonra her zaman yeniden ayarlayabilirsiniz.", - "login.totp.disable.admin": "

Bu {user} için tek seferlik kodları devre dışı bırakacaktır.

Gelecekte, oturum açtıklarında e-posta yoluyla gönderilen bir oturum açma kodu gibi farklı bir ikinci faktör istenecektir. {user} bir sonraki girişinden sonra tek seferlik kodları tekrar ayarlayabilir.

", - "login.totp.disable.success": "Tek seferlik kodlar devre dışı", - - "logout": "Oturumu kapat", - - "merge": "Birleştir", - "menu": "Menü", - "meridiem": "AM/PM", - "mime": "Medya Türü", - "minutes": "Dakika", - - "month": "Ay", - "months.april": "Nisan", - "months.august": "A\u011fustos", - "months.december": "Aral\u0131k", - "months.february": "Şubat", - "months.january": "Ocak", - "months.july": "Temmuz", - "months.june": "Haziran", - "months.march": "Mart", - "months.may": "May\u0131s", - "months.november": "Kas\u0131m", - "months.october": "Ekim", - "months.september": "Eyl\u00fcl", - - "more": "Daha Fazla", - "move": "Taşı", - "name": "İsim", - "next": "Sonraki", - "night": "Gece", - "no": "hayır", - "off": "kapalı", - "on": "açık", - "open": "Önizleme", - "open.newWindow": "Yeni pencerede aç", - "option": "Seçenek", - "options": "Seçenekler", - "options.none": "Seçenek yok", - "options.all": "Tüm {count} seçeneklerini göster", - - "orientation": "Oryantasyon", - "orientation.landscape": "Yatay", - "orientation.portrait": "Dikey", - "orientation.square": "Kare", - - "page": "Sayfa", - "page.blueprint": "Bu dosyanın henüz bir planı yok. Kurulumu /site/blueprints/pages/{blueprint}.yml dosyasında tanımlayabilirsiniz.", - "page.changeSlug": "Web Adresini Değiştir", - "page.changeSlug.fromTitle": "Ba\u015fl\u0131ktan olu\u015ftur", - "page.changeStatus": "Durumu değiştir", - "page.changeStatus.position": "Lütfen bir pozisyon seçin", - "page.changeStatus.select": "Yeni bir durum seçin", - "page.changeTemplate": "Şablonu değiştir", - "page.changeTemplate.notice": "Sayfanın şablonunu değiştirmek, tür olarak eşleşmeyen alanların içeriğini kaldıracaktır. Dikkatli kullanın.", - "page.create": "{status} olarak oluştur", - "page.delete.confirm": "{title} sayfasını silmek istediğinizden emin misiniz?", - "page.delete.confirm.subpages": "Bu sayfada alt sayfalar var.
Tüm alt sayfalar da silinecek.", - "page.delete.confirm.title": "Onaylamak için sayfa başlığını girin", - "page.duplicate.appendix": "Kopya", - "page.duplicate.files": "Dosyaları kopyala", - "page.duplicate.pages": "Sayfaları kopyala", - "page.move": "Sayfayı taşı", - "page.sort": "Pozisyon değiştir", - "page.status": "Durum", - "page.status.draft": "Taslak", - "page.status.draft.description": "Sayfa taslak halinde ve yalnızca oturum açmış editörler için veya gizli bağlantı üzerinden görülebilir", - "page.status.listed": "Herkese Açık", - "page.status.listed.description": "Bu sayfa herkese açık", - "page.status.unlisted": "Liste Dışı", - "page.status.unlisted.description": "Bu sayfa sadece bağlantı adresi ile erişilebilir", - - "pages": "Sayfalar", - "pages.empty": "Henüz sayfa yok", - "pages.status.draft": "Taslaklar", - "pages.status.listed": "Yayınlandı", - "pages.status.unlisted": "Liste Dışı", - - "pagination.page": "Sayfa", - - "password": "\u015eifre", - "paste": "Yapıştır", - "paste.after": "Sonrasına yapıştır", - "paste.success": "{count} yapıştırıldı!", - "pixel": "Piksel", - "plugin": "Eklenti", - "plugins": "Eklentiler", - "prev": "Önceki", - "preview": "Önizle", - "remove": "Kaldır", - "rename": "Yeniden Adlandır", - "renew": "Yenileme", - "replace": "De\u011fi\u015ftir", - "replace.with": "Değiştir", - "retry": "Tekrar Dene", - "revert": "Vazge\u00e7", - "revert.confirm": "Gerçekten kaydedilmemiş tüm değişiklikleri silmek istiyor musunuz?", - - "role": "Rol", - "role.admin.description": "Yönetici tüm haklara sahiptir", - "role.admin.title": "Yönetici", - "role.all": "Tümü", - "role.empty": "Bu role ait kullanıcı bulunamadı", - "role.description.placeholder": "Açıklama yok", - "role.nobody.description": "Bu hiçbir izni olmayan bir geri dönüş rolüdür.", - "role.nobody.title": "Hiçkimse", - - "save": "Kaydet", - "search": "Arama", - "search.min": "Aramak için {min} karakter girin", - "search.all": "Tüm {count} sonuçlarını göster", - "search.results.none": "Sonuç yok", - - "section.invalid": "Bu bölüm geçersizdir", - "section.required": "Bölüm gereklidir", - - "security": "Güvenlik", - "select": "Seç", - "server": "Sunucu", - "settings": "Ayarlar", - "show": "Göster", - "site.blueprint": "Sitenin henüz bir planı yok. Kurulumu /site/blueprints/site.yml'de tanımlayabilirsiniz.", - "size": "Boyut", - "slug": "Web Adres Uzantısı", - "sort": "Sırala", - "sort.drag": "Sıralamak için sürükleyin …", - "split": "Ayır", - - "stats.empty": "Rapor yok", - "status": "Durum", - - "system.info.copy": "Copy info", - "system.info.copied": "System info copied", - "system.issues.content": "İçerik klasörü açığa çıkmış görünüyor", - "system.issues.eol.kirby": "Yüklü Kirby sürümünüz kullanım ömrünün sonuna ulaştı ve daha fazla güvenlik güncellemesi almayacak", - "system.issues.eol.plugin": "{ plugin } eklentisinin yüklü sürümü kullanım ömrünün sonuna ulaştı ve daha fazla güvenlik güncellemesi almayacak", - "system.issues.eol.php": "Yüklü PHP sürümünüz { release } kullanım ömrünün sonuna ulaşmıştır ve başka güvenlik güncellemeleri almayacaktır", - "system.issues.debug": "Canlı modda hata ayıklama kapatılmalıdır", - "system.issues.git": ".git klasörü açığa çıkmış görünüyor", - "system.issues.https": "Tüm siteleriniz için HTTPS'yi öneriyoruz", - "system.issues.kirby": "Kirby klasörü açığa çıkmış görünüyor", - "system.issues.site": "Site klasörü açığa çıkmış görünüyor", - "system.issues.vulnerability.kirby": "Kurulumunuz aşağıdaki güvenlik açığından ({ severity } önem derecesi) etkilenebilir: { description }", - "system.issues.vulnerability.plugin": "Kurulumunuz, { plugin } eklentisindeki ({ severity } önem derecesi) aşağıdaki güvenlik açığından etkilenebilir: { description }", - "system.updateStatus": "Güncelleme durumu", - "system.updateStatus.error": "Güncellemeler kontrol edilemedi", - "system.updateStatus.not-vulnerable": "Bilinen güvenlik açığı yok", - "system.updateStatus.security-update": "Ücretsiz güvenlik güncellemesi { version } mevcut", - "system.updateStatus.security-upgrade": "Mevcut güvenlik düzeltmeleriyle { version } sürümüne yükseltin", - "system.updateStatus.unreleased": "Yayınlanmamış sürüm", - "system.updateStatus.up-to-date": "Güncel", - "system.updateStatus.update": "Ücretsiz güncelleme { version } mevcut", - "system.updateStatus.upgrade": "{ version } yükseltme mevcut", - - "tel": "Telefon", - "tel.placeholder": "+49123456789", - "template": "\u015eablon", - "title": "Başlık", - "today": "Bugün", - - "toolbar.button.clear": "Biçimlendirmeyi temizle", - "toolbar.button.code": "Kod", - "toolbar.button.bold": "Kalın Yazı", - "toolbar.button.email": "E-Posta", - "toolbar.button.headings": "Başlıklar", - "toolbar.button.heading.1": "Başlık 1", - "toolbar.button.heading.2": "Başlık 2", - "toolbar.button.heading.3": "Başlık 3", - "toolbar.button.heading.4": "Başlık 4", - "toolbar.button.heading.5": "Başlık 5", - "toolbar.button.heading.6": "Başlık 6", - "toolbar.button.italic": "Eğik Yazı", - "toolbar.button.file": "Dosya", - "toolbar.button.file.select": "Bir dosya seçin", - "toolbar.button.file.upload": "Bir dosya yükleyin", - "toolbar.button.link": "Ba\u011flant\u0131", - "toolbar.button.paragraph": "Paragraf", - "toolbar.button.strike": "Üstü çizili", - "toolbar.button.sub": "Alt simge", - "toolbar.button.sup": "Üst simge", - "toolbar.button.ol": "Sıralı liste", - "toolbar.button.underline": "Altı çizili", - "toolbar.button.ul": "Madde listesi", - - "translation.author": "Kirby Takımı", - "translation.direction": "ltr", - "translation.name": "T\u00fcrk\u00e7e", - "translation.locale": "tr_TR", - - "type": "Tür", - - "upload": "Yükle", - "upload.error.cantMove": "Yüklenen dosya taşınamadı", - "upload.error.cantWrite": "Dosya diske yazılamadı", - "upload.error.default": "Dosya yüklenemedi", - "upload.error.extension": "Dosya yükleme uzantısı tarafından durduruldu", - "upload.error.formSize": "Yüklenen dosya, formda belirtilen MAX_FILE_SIZE yönergesini aşıyor", - "upload.error.iniPostSize": "Yüklenen dosya php.ini içindeki post_max_size yönergesini aşıyor", - "upload.error.iniSize": "Yüklenen dosya php.ini içindeki upload_max_filesize yönergesini aşıyor", - "upload.error.noFile": "Dosya yüklenmedi", - "upload.error.noFiles": "Dosyalar yüklenmedi", - "upload.error.partial": "Yüklenen dosya sadece kısmen yüklendi", - "upload.error.tmpDir": "Geçici klasör eksik", - "upload.errors": "Hata", - "upload.progress": "Yükleniyor...", - - "url": "Url", - "url.placeholder": "https://ornek.com", - - "user": "Kullanıcı", - "user.blueprint": "Bu kullanıcı rolü için /site/blueprints/users/{blueprint}.yml içinde ek bölümler ve form alanları tanımlayabilirsiniz", - "user.changeEmail": "E-postayı değiştir", - "user.changeLanguage": "Dili değiştir", - "user.changeName": "Kullanıcıyı yeniden adlandır", - "user.changePassword": "Şifre değiştir", - "user.changePassword.new": "Yeni Şifre", - "user.changePassword.new.confirm": "Şifreyi onaylayın...", - "user.changeRole": "Rolü değiştir", - "user.changeRole.select": "Yeni bir rol seçin", - "user.create": "Yeni bir kullanıcı ekle", - "user.delete": "Bu kullanıcıyı sil", - "user.delete.confirm": "{email} kullanıcısını silmek istediğinizden emin misiniz?", - - "users": "Kullanıcılar", - - "version": "Versiyon", - "version.current": "Mevcut sürüm", - "version.latest": "En son sürüm", - "versionInformation": "Sürüm bilgisi", - - "view.account": "Hesap Bilgilerin", - "view.installation": "Kurulum", - "view.languages": "Diller", - "view.resetPassword": "Şifreyi sıfırla", - "view.site": "Site", - "view.system": "Sistem", - "view.users": "Kullan\u0131c\u0131lar", - - "welcome": "Hoşgeldiniz", - "year": "Yıl", - "yes": "evet" + "account.changeName": "İsminizi değiştirin", + "account.delete": "Hesabınızı silin", + "account.delete.confirm": "Hesabınızı gerçekten silmek istiyor musunuz? Oturumunuz hemen sonlandırılacaktır. Hesabınız daha sonra geri alınamaz.", + + "add": "Ekle", + "author": "Yazar", + "avatar": "Profil resmi", + "back": "Geri", + "cancel": "\u0130ptal", + "change": "De\u011fi\u015ftir", + "close": "Kapat", + "confirm": "Tamam", + "collapse": "Daralt", + "collapse.all": "Tümünü daralt", + "copy": "Kopyala", + "copy.all": "Tümünü kopyala", + "create": "Oluştur", + + "date": "Tarih", + "date.select": "Bir tarih seçiniz", + + "day": "Gün", + "days.fri": "Cum", + "days.mon": "Pzt", + "days.sat": "Cmt", + "days.sun": "Paz", + "days.thu": "Per", + "days.tue": "Sal", + "days.wed": "\u00c7ar", + + "debugging": "Hata ayıklama", + + "delete": "Sil", + "delete.all": "Tümünü sil", + + "dialog.files.empty": "Seçilecek dosya yok", + "dialog.pages.empty": "Seçilecek sayfa yok", + "dialog.users.empty": "Seçilecek kullanıcı yok", + + "dimensions": "Boyutlar", + "disabled": "Devredışı", + "discard": "Vazge\u00e7", + "download": "İndir", + "duplicate": "Kopyala", + + "edit": "D\u00fczenle", + + "email": "E-Posta", + "email.placeholder": "eposta@ornek.com", + + "entries": "Girdiler", + "entry": "Girdi", + + "environment": "Ortam", + + "error.access.code": "Geçersiz kod", + "error.access.login": "Geçersiz giriş", + "error.access.panel": "Panel'e erişim izniniz yok", + "error.access.view": "Panel'in bu bölümüne erişim izniniz yok", + + "error.avatar.create.fail": "Profil resmi yüklenemedi", + "error.avatar.delete.fail": "Profil resmi silinemedi", + "error.avatar.dimensions.invalid": "Lütfen profil resminin genişliğini ve yüksekliğini 3000 pikselin altında tutun", + "error.avatar.mime.forbidden": "Profil resmi JPEG veya PNG dosyaları olmalıdır", + + "error.blueprint.notFound": "\"{name}\" adlı plan yüklenemedi", + + "error.blocks.max.plural": "{max} bloktan fazlasını eklememelisiniz", + "error.blocks.max.singular": "Birden fazla blok eklememelisiniz", + "error.blocks.min.plural": "En az {min} blok eklemelisiniz", + "error.blocks.min.singular": "En az bir blok eklemelisiniz", + "error.blocks.validation": "{index} bloğunda bir hata var", + + "error.email.preset.notFound": "\"{name}\" e-posta adresi bulunamadı", + + "error.field.converter.invalid": "Geçersiz dönüştürücü \"{converter}\"", + + "error.file.changeName.empty": "İsim boş olmamalıdır", + "error.file.changeName.permission": "\"{filename}\" adını değiştiremezsiniz", + "error.file.duplicate": "\"{filename}\" isimli bir dosya zaten var", + "error.file.extension.forbidden": "\"{extension}\" dosya uzantısına izin verilmiyor", + "error.file.extension.invalid": "Geçersiz uzantı: {extension}", + "error.file.extension.missing": "\"{filename}\" dosyasının uzantısı yok", + "error.file.maxheight": "Resmin yüksekliği {height} pikselden büyük olmamalıdır", + "error.file.maxsize": "Dosya çok büyük", + "error.file.maxwidth": "Resmin genişliği {width} pikselden büyük olmamalıdır", + "error.file.mime.differs": "Yüklenen dosya aynı dosya türü \"{mime}\" olmalıdır", + "error.file.mime.forbidden": "\"{mime}\" medya türüne izin verilmiyor", + "error.file.mime.invalid": "Geçersiz medya türü: {mime}", + "error.file.mime.missing": "\"{filename}\" için medya türü tespit edilemiyor", + "error.file.minheight": "Resmin yüksekliği en az {height} piksel olmalıdır", + "error.file.minsize": "Dosya çok küçük", + "error.file.minwidth": "Resmin genişliği en az {width} piksel olmalıdır", + "error.file.name.missing": "Dosya adı boş bırakılamaz", + "error.file.notFound": "\"{filename}\" dosyası bulunamadı", + "error.file.orientation": "Resmin oryantasyonu \"{orientation}\" olmalıdır", + "error.file.type.forbidden": "{type} dosya yükleme izni yok", + "error.file.type.invalid": "Geçersiz dosya türü: {type}", + "error.file.undefined": "Dosya bulunamad\u0131", + + "error.form.incomplete": "Lütfen tüm form hatalarını düzeltin...", + "error.form.notSaved": "Form kaydedilemedi", + + "error.language.code": "Lütfen dil için geçerli bir kod girin", + "error.language.duplicate": "Bu dil zaten var", + "error.language.name": "Lütfen dil için geçerli bir isim girin", + "error.language.notFound": "Dil bulunamadı", + + "error.layout.validation.block": "{layoutIndex}. düzenin {blockIndex}. bloğunda bir hata var", + "error.layout.validation.settings": "{index}. düzen ayarlarında bir hata var", + + "error.license.format": "Lütfen geçerli bir lisans anahtarı girin", + "error.license.email": "Lütfen geçerli bir e-posta adresi girin", + "error.license.verification": "Lisans doğrulanamadı", + + "error.offline": "Panel şu anda çevrimdışı", + + "error.page.changeSlug.permission": "\"{slug}\" uzantısına sahip bu sayfanın adresini değiştirilemez", + "error.page.changeStatus.incomplete": "Sayfada hatalar var ve yayınlanamadı", + "error.page.changeStatus.permission": "Bu sayfanın durumu değiştirilemez", + "error.page.changeStatus.toDraft.invalid": "\"{slug}\" sayfası bir taslak haline dönüştürülemiyor", + "error.page.changeTemplate.invalid": "\"{slug}\" sayfası için şablon değiştirilemiyor", + "error.page.changeTemplate.permission": "\"{slug}\" için şablonu değiştiremezsiniz", + "error.page.changeTitle.empty": "Başlık boş bırakılamaz", + "error.page.changeTitle.permission": "\"{slug}\" için başlığı değiştiremezsiniz", + "error.page.create.permission": "\"{slug}\" oluşturmanıza izin verilmiyor", + "error.page.delete": "\"{slug}\" sayfası silinemedi", + "error.page.delete.confirm": "Onaylamak için sayfa başlığını girin", + "error.page.delete.hasChildren": "Sayfada alt sayfalar var ve silinemiyor", + "error.page.delete.permission": "\"{slug}\" öğesini silmenize izin verilmiyor", + "error.page.draft.duplicate": "\"{slug}\" adres eki olan bir sayfa taslağı zaten mevcut", + "error.page.duplicate": "\"{slug}\" adres eki içeren bir sayfa zaten mevcut", + "error.page.duplicate.permission": "\"{slug}\" öğesini çoğaltmanıza izin verilmiyor", + "error.page.notFound": "\"{slug}\" uzantısındaki sayfa bulunamadı", + "error.page.num.invalid": "Lütfen geçerli bir sıralama numarası girin. Sayılar negatif olmamalıdır.", + "error.page.slug.invalid": "Lütfen geçerli bir URL eki girin", + "error.page.slug.maxlength": "Adres uzantısı \"{length}\" karakterden az olmalıdır", + "error.page.sort.permission": "\"{slug}\" sayfası sıralanamıyor", + "error.page.status.invalid": "Lütfen geçerli bir sayfa durumu ayarlayın", + "error.page.undefined": "Sayfa bulunamad\u0131", + "error.page.update.permission": "\"{slug}\" güncellemesine izin verilmiyor", + + "error.section.files.max.plural": "\"{section}\" bölümüne {max} dosyadan daha fazlasını eklememelisiniz", + "error.section.files.max.singular": "\"{section}\" bölümüne birden fazla dosya eklememelisiniz", + "error.section.files.min.plural": "\"{section}\" bölümü en az {min} dosya gerektiriyor", + "error.section.files.min.singular": "\"{section}\" bölümü en az bir dosya gerektiriyor", + + "error.section.pages.max.plural": "\"{section}\" bölümüne maksimum {max} sayfadan fazla ekleyemezsiniz", + "error.section.pages.max.singular": "\"{section}\" bölümüne birden fazla sayfa ekleyemezsiniz", + "error.section.pages.min.plural": "\"{section}\" bölümü en az {min} sayfa gerektiriyor", + "error.section.pages.min.singular": "\"{section}\" bölümü en az bir sayfa gerektiriyor", + + "error.section.notLoaded": "\"{name}\" bölümü yüklenemedi", + "error.section.type.invalid": "\"{type}\" tipi geçerli değil", + + "error.site.changeTitle.empty": "Başlık boş bırakılamaz", + "error.site.changeTitle.permission": "Sitenin başlığını değiştiremezsin", + "error.site.update.permission": "Siteyi güncellemenize izin verilmiyor", + + "error.template.default.notFound": "Varsayılan şablon yok", + + "error.unexpected": "Beklenmeyen bir hata oluştu! Daha fazla bilgi için hata ayıklama modunu etkinleştirin: https://getkirby.com/docs/reference/system/options/debug", + + "error.user.changeEmail.permission": "\"{name}\" kullanıcısı için e-postayı değiştiremezsiniz", + "error.user.changeLanguage.permission": "\"{name}\" kullanıcısının dilini değiştiremezsin", + "error.user.changeName.permission": "\"{name}\" kullanıcısının adını değiştiremezsiniz", + "error.user.changePassword.permission": "\"{name}\" kullanıcısının şifresini değiştiremezsiniz", + "error.user.changeRole.lastAdmin": "Son yöneticinin rolü değiştirilemez", + "error.user.changeRole.permission": "\"{name}\" kullanıcısının rolünü değiştiremezsin", + "error.user.changeRole.toAdmin": "Birini yönetici rolüne tanıtmanıza izin verilmiyor", + "error.user.create.permission": "Bu kullanıcıyı oluşturmanıza izin verilmiyor", + "error.user.delete": "\"{name}\" kullanıcısı silinemedi", + "error.user.delete.lastAdmin": "Son y\u00f6netici kullan\u0131c\u0131y\u0131 silemezsiniz", + "error.user.delete.lastUser": "Son kullanıcı silinemez", + "error.user.delete.permission": "\"{name}\" kullanıcısını silme yetkiniz yok", + "error.user.duplicate": "\"{email}\" e-posta adresine sahip bir kullanıcı zaten var", + "error.user.email.invalid": "Lütfen geçerli bir e-posta adresi girin", + "error.user.language.invalid": "Lütfen geçerli bir dil girin", + "error.user.notFound": "\"{name}\" kullanıcısı bulunamadı", + "error.user.password.excessive": "Please enter a valid password. Passwords must not be longer than 1000 characters.", + "error.user.password.invalid": "Lütfen geçerli bir şifre giriniz. Şifreler en az 8 karakter uzunluğunda olmalıdır.", + "error.user.password.notSame": "L\u00fctfen \u015fifreyi do\u011frulay\u0131n", + "error.user.password.undefined": "Bu kullanıcının şifresi yok", + "error.user.password.wrong": "Yanlış şifre", + "error.user.role.invalid": "Lütfen geçerli bir rol girin", + "error.user.undefined": "Kullanıcı bulunamadı", + "error.user.update.permission": "\"{name}\" kullanıcısını güncellemenize izin verilmiyor", + + "error.validation.accepted": "Lütfen onaylayın", + "error.validation.alpha": "Lütfen sadece a-z arasındaki karakterleri girin", + "error.validation.alphanum": "Lütfen sadece a-z veya 0-9 arasındaki rakamları girin", + "error.validation.between": "Lütfen \"{min}\" ile \"{max}\" arasında bir değer girin", + "error.validation.boolean": "Lütfen onaylayın veya reddedin", + "error.validation.contains": "Lütfen \"{needle}\" içeren bir değer girin", + "error.validation.date": "Lütfen geçerli bir tarih girin", + "error.validation.date.after": "Lütfen {date} tarihinden sonra bir tarih girin", + "error.validation.date.before": "Lütfen {date} tarihinden önce bir tarih girin", + "error.validation.date.between": "Lütfen {min} ve {max} arasında bir tarih girin", + "error.validation.denied": "Lütfen reddedin", + "error.validation.different": "Değer \"{other}\" olmamalıdır", + "error.validation.email": "Lütfen geçerli bir e-posta adresi girin", + "error.validation.endswith": "Değer \"{end}\" ile bitmelidir", + "error.validation.filename": "Lütfen geçerli bir dosya adı girin", + "error.validation.in": "Lütfen bunlardan birini girin: ({in})", + "error.validation.integer": "Lütfen geçerli bir tamsayı girin", + "error.validation.ip": "Lütfen geçerli bir ip adresi girin", + "error.validation.less": "Lütfen {max} 'dan daha düşük bir değer girin", + "error.validation.match": "Değer beklenen modelle eşleşmiyor", + "error.validation.max": "Lütfen {max} 'a eşit veya daha küçük bir değer girin", + "error.validation.maxlength": "Lütfen daha kısa bir değer girin. (maks. {max} karakter)", + "error.validation.maxwords": "Lütfen en fazla {max} kelime(ler) girin", + "error.validation.min": "Lütfen {min} ile eşit veya daha büyük bir değer girin", + "error.validation.minlength": "Lütfen daha uzun bir değer girin. (min. {min} karakter)", + "error.validation.minwords": "Lütfen en az {min} kelime(ler) girin", + "error.validation.more": "Lütfen {min} değerinden daha büyük bir değer girin", + "error.validation.notcontains": "Lütfen \"{needle}\" içermeyen bir değer girin", + "error.validation.notin": "Lütfen bunlardan herhangi birini girmeyin: ({notIn})", + "error.validation.option": "Lütfen geçerli bir seçenek girin", + "error.validation.num": "Lütfen geçerli bir sayı girin", + "error.validation.required": "Lütfen birşeyler girin", + "error.validation.same": "Lütfen \"{other}\" yazınız", + "error.validation.size": "Değerin boyutu \"{size}\" olmalıdır", + "error.validation.startswith": "Değer \"{start}\" ile başlamalıdır", + "error.validation.time": "Lütfen geçerli bir zaman girin", + "error.validation.time.after": "Lütfen {time} sonrası bir tarih girin", + "error.validation.time.before": "Lütfen {time} öncesi bir tarih girin", + "error.validation.time.between": "Lütfen {min} ile {max} arasında bir tarih girin", + "error.validation.url": "Lütfen geçerli bir adres girin", + + "expand": "Genişlet", + "expand.all": "Tümünü genişlet", + + "field.required": "Alan gereklidir", + "field.blocks.changeType": "Türü değiştir", + "field.blocks.code.name": "Kod", + "field.blocks.code.language": "Dil", + "field.blocks.code.placeholder": "Kodunuz …", + "field.blocks.delete.confirm": "Bu bloğu gerçekten silmek istiyor musunuz?", + "field.blocks.delete.confirm.all": "Tüm blokları gerçekten silmek istiyor musunuz?", + "field.blocks.delete.confirm.selected": "Seçilen blokları gerçekten silmek istiyor musunuz?", + "field.blocks.empty": "Henüz blok yok", + "field.blocks.fieldsets.label": "Lütfen bir blok türü seçiniz …", + "field.blocks.fieldsets.paste": "Panonuzdan blokları yapıştırmak veya içe aktarmak için {{ shortcut }}'e basın", + "field.blocks.gallery.name": "Galeri", + "field.blocks.gallery.images.empty": "Henüz görsel yok", + "field.blocks.gallery.images.label": "Görseller", + "field.blocks.heading.level": "Seviye", + "field.blocks.heading.name": "Başlık", + "field.blocks.heading.text": "Metin", + "field.blocks.heading.placeholder": "Başlık …", + "field.blocks.image.alt": "Alternatif metin", + "field.blocks.image.caption": "Altyazı", + "field.blocks.image.crop": "Kırp", + "field.blocks.image.link": "Bağlantı", + "field.blocks.image.location": "Lokasyon", + "field.blocks.image.name": "Görsel", + "field.blocks.image.placeholder": "Bir görsel seçin", + "field.blocks.image.ratio": "Oran", + "field.blocks.image.url": "Görsel URL", + "field.blocks.line.name": "Çizgi", + "field.blocks.list.name": "Liste", + "field.blocks.markdown.name": "Markdown", + "field.blocks.markdown.label": "Metin", + "field.blocks.markdown.placeholder": "Markdown …", + "field.blocks.quote.name": "Alıntı", + "field.blocks.quote.text.label": "Metin", + "field.blocks.quote.text.placeholder": "Alıntı …", + "field.blocks.quote.citation.label": "Alıntı", + "field.blocks.quote.citation.placeholder": "yazar …", + "field.blocks.text.name": "Metin", + "field.blocks.text.placeholder": "Metin …", + "field.blocks.video.caption": "Altyazı", + "field.blocks.video.name": "Video", + "field.blocks.video.placeholder": "Bir video URL'si girin", + "field.blocks.video.url.label": "Video-URL", + "field.blocks.video.url.placeholder": "https://youtube.com/?v=", + + "field.files.empty": "Henüz dosya seçilmedi", + + "field.layout.delete": "Düzeni sil", + "field.layout.delete.confirm": "Bu düzeni gerçekten silmek istiyor musunuz?", + "field.layout.empty": "Henüz satır yok", + "field.layout.select": "Bir düzen seçin", + + "field.pages.empty": "Henüz sayfa seçilmedi", + "field.structure.delete.confirm": "Bu girdiyi silmek istedi\u011finizden emin misiniz?", + "field.structure.empty": "Hen\u00fcz bir girdi yok", + "field.users.empty": "Henüz kullanıcı seçilmedi", + + "file.blueprint": "Bu dosyanın henüz bir planı yok. Kurulumu /site/blueprints/files/{blueprint}.yml dosyasında tanımlayabilirsiniz.", + "file.delete.confirm": "{filename} dosyasını silmek istediğinizden emin misiniz?", + "file.sort": "Pozisyon değiştir", + + "files": "Dosyalar", + "files.empty": "Henüz dosya yok", + + "hide": "Gizle", + "hour": "Saat", + "import": "İçe aktar", + "info": "Bilgi", + "insert": "Ekle", + "insert.after": "Sonrasına ekle", + "insert.before": "Öncesine ekle", + "install": "Kurulum", + + "installation": "Kurulum", + "installation.completed": "Panel kuruldu", + "installation.disabled": "Panel yükleyici, herkese açık sunucularda varsayılan olarak devre dışıdır. Lütfen yükleyiciyi yerel bir makinede çalıştırın veya panel.install seçeneğiyle etkinleştirin.", + "installation.issues.accounts": "/site/accounts klasörü yok yada yazılabilir değil", + "installation.issues.content": "/content klasörü yok yada yazılabilir değil", + "installation.issues.curl": "CURL eklentisi gerekli", + "installation.issues.headline": "Panel kurulamadı", + "installation.issues.mbstring": "MB String eklentisi gerekli", + "installation.issues.media": "/media klasörü yok yada yazılamaz", + "installation.issues.php": "PHP 7+ kullandığınızdan emin olun. ", + "installation.issues.server": "Kirby Apache, Nginx veya Caddy gerektirir", + "installation.issues.sessions": "/site/sessions klasörü mevcut değil veya yazılabilir değil", + + "language": "Dil", + "language.code": "Kod", + "language.convert": "Varsayılan yap", + "language.convert.confirm": "

{name}'i varsayılan dile dönüştürmek istiyor musunuz? Bu geri alınamaz.

{name} çevrilmemiş içeriğe sahipse, artık geçerli bir geri dönüş olmaz ve sitenizin bazı bölümleri boş olabilir.

", + "language.create": "Yeni bir dil ekle", + "language.delete.confirm": "Tüm çevirileri içeren {name} dilini gerçekten silmek istiyor musunuz? Bu geri alınamaz!", + "language.deleted": "Dil silindi", + "language.direction": "Okuma yönü", + "language.direction.ltr": "Soldan sağa", + "language.direction.rtl": "Sağdan sola", + "language.locale": "PHP yerel dizesi", + "language.locale.warning": "Özel bir yerel ayar kullanıyorsunuz. Lütfen /site/languages konumundaki dil dosyasından değiştirin.", + "language.name": "İsim", + "language.updated": "Dil güncellendi", + + "languages": "Diller", + "languages.default": "Varsayılan dil", + "languages.empty": "Henüz hiç dil yok", + "languages.secondary": "İkincil diller", + "languages.secondary.empty": "Henüz ikincil bir dil yok", + + "license": "Lisans", + "license.buy": "Bir lisans satın al", + "license.register": "Kayıt Ol", + "license.manage": "Lisanslarınızı yönetin", + "license.register.help": "Satın alma işleminden sonra e-posta yoluyla lisans kodunuzu aldınız. Lütfen kayıt olmak için kodu kopyalayıp yapıştırın.", + "license.register.label": "Lütfen lisans kodunu giriniz", + "license.register.success": "Kirby'yi desteklediğiniz için teşekkürler", + "license.unregistered": "Bu Kirby'nin kayıtsız bir demosu", + "license.unregistered.label": "Kayıtsız", + + "link": "Ba\u011flant\u0131", + "link.text": "Ba\u011flant\u0131 yaz\u0131s\u0131", + + "loading": "Yükleniyor", + + "lock.unsaved": "Kaydedilmemiş değişiklikler", + "lock.unsaved.empty": "Daha fazla kaydedilmemiş değişiklik yok", + "lock.isLocked": "{email} tarafından kaydedilmemiş değişiklikler", + "lock.file.isLocked": "Dosya şu anda {email} tarafından düzenlenmektedir ve değiştirilemez.", + "lock.page.isLocked": "Sayfa şu anda {email} tarafından düzenlenmektedir ve değiştirilemez.", + "lock.unlock": "Kilidi Aç", + "lock.isUnlocked": "Kaydedilmemiş değişikliklerin üzerine başka bir kullanıcı yazmış. Değişikliklerinizi el ile birleştirmek için değişikliklerinizi indirebilirsiniz.", + + "login": "Giriş", + "login.code.label.login": "Giriş kodu", + "login.code.label.password-reset": "Şifre sıfırlama kodu", + "login.code.placeholder.email": "000 000", + "login.code.text.email": "E-posta adresiniz kayıtlıysa, istenen kod e-posta yoluyla gönderilmiştir.", + "login.email.login.body": "Merhaba {user.nameOrEmail},\n\nKısa süre önce {site} Panel'i için bir giriş kodu istediniz.\nAşağıdaki giriş kodu {timeout} dakika boyunca geçerli olacaktır:\n\n{code}\n\nBir giriş kodu istemediyseniz, lütfen bu e-postayı dikkate almayın veya sorularınız varsa yöneticinize başvurun.\nGüvenliğiniz için lütfen bu e-postayı İLETMEYİN.", + "login.email.login.subject": "Giriş kodunuz", + "login.email.password-reset.body": "Merhaba {user.nameOrEmail},\n\nKısa süre önce {site} Panel'i için bir şifre sıfırlama kodu istediniz.\nAşağıdaki şifre sıfırlama kodu {timeout} dakika boyunca geçerli olacaktır:\n\n{code}\n\nŞifre sıfırlama kodu istemediyseniz, lütfen bu e-postayı dikkate almayın veya sorularınız varsa yöneticinizle iletişime geçin.\nGüvenliğiniz için lütfen bu e-postayı İLETMEYİN.", + "login.email.password-reset.subject": "Şifre sıfırlama kodunuz", + "login.remember": "Oturumumu açık tut", + "login.reset": "Şifreyi sıfırla", + "login.toggleText.code.email": "E-posta ile giriş yapın", + "login.toggleText.code.email-password": "Şifre ile giriş yapın", + "login.toggleText.password-reset.email": "Şifrenizi mi unuttunuz?", + "login.toggleText.password-reset.email-password": "← Girişe geri dön", + + "logout": "Güvenli Çıkış", + + "menu": "Menü", + "meridiem": "AM/PM", + "mime": "Medya Türü", + "minutes": "Dakika", + + "month": "Ay", + "months.april": "Nisan", + "months.august": "A\u011fustos", + "months.december": "Aral\u0131k", + "months.february": "Şubat", + "months.january": "Ocak", + "months.july": "Temmuz", + "months.june": "Haziran", + "months.march": "Mart", + "months.may": "May\u0131s", + "months.november": "Kas\u0131m", + "months.october": "Ekim", + "months.september": "Eyl\u00fcl", + + "more": "Daha Fazla", + "name": "İsim", + "next": "Sonraki", + "no": "hayır", + "off": "kapalı", + "on": "açık", + "open": "Önizleme", + "open.newWindow": "Yeni pencerede aç", + "options": "Seçenekler", + "options.none": "Seçenek yok", + + "orientation": "Oryantasyon", + "orientation.landscape": "Yatay", + "orientation.portrait": "Dikey", + "orientation.square": "Kare", + + "page.blueprint": "Bu dosyanın henüz bir planı yok. Kurulumu /site/blueprints/pages/{blueprint}.yml dosyasında tanımlayabilirsiniz.", + "page.changeSlug": "Web Adresini Değiştir", + "page.changeSlug.fromTitle": "Ba\u015fl\u0131ktan olu\u015ftur", + "page.changeStatus": "Durumu değiştir", + "page.changeStatus.position": "Lütfen bir pozisyon seçin", + "page.changeStatus.select": "Yeni bir durum seçin", + "page.changeTemplate": "Şablonu değiştir", + "page.delete.confirm": "{title} sayfasını silmek istediğinizden emin misiniz?", + "page.delete.confirm.subpages": "Bu sayfada alt sayfalar var.
Tüm alt sayfalar da silinecek.", + "page.delete.confirm.title": "Onaylamak için sayfa başlığını girin", + "page.draft.create": "Taslak oluştur", + "page.duplicate.appendix": "Kopya", + "page.duplicate.files": "Dosyaları kopyala", + "page.duplicate.pages": "Sayfaları kopyala", + "page.sort": "Pozisyon değiştir", + "page.status": "Durum", + "page.status.draft": "Taslak", + "page.status.draft.description": "Sayfa taslak halinde ve yalnızca oturum açmış editörler için veya gizli bağlantı üzerinden görülebilir", + "page.status.listed": "Herkese Açık", + "page.status.listed.description": "Bu sayfa herkese açık", + "page.status.unlisted": "Liste Dışı", + "page.status.unlisted.description": "Bu sayfa sadece bağlantı adresi ile erişilebilir", + + "pages": "Sayfalar", + "pages.empty": "Henüz sayfa yok", + "pages.status.draft": "Taslaklar", + "pages.status.listed": "Yayınlandı", + "pages.status.unlisted": "Liste Dışı", + + "pagination.page": "Sayfa", + + "password": "\u015eifre", + "paste": "Yapıştır", + "paste.after": "Sonrasına yapıştır", + "pixel": "Piksel", + "plugins": "Eklentiler", + "prev": "Önceki", + "preview": "Önizle", + "remove": "Kaldır", + "rename": "Yeniden Adlandır", + "replace": "De\u011fi\u015ftir", + "retry": "Tekrar Dene", + "revert": "Vazge\u00e7", + "revert.confirm": "Gerçekten kaydedilmemiş tüm değişiklikleri silmek istiyor musunuz?", + + "role": "Rol", + "role.admin.description": "Yönetici tüm haklara sahiptir", + "role.admin.title": "Yönetici", + "role.all": "Tümü", + "role.empty": "Bu role ait kullanıcı bulunamadı", + "role.description.placeholder": "Açıklama yok", + "role.nobody.description": "Bu hiçbir izni olmayan bir geri dönüş rolüdür.", + "role.nobody.title": "Hiçkimse", + + "save": "Kaydet", + "search": "Arama", + "search.min": "Aramak için {min} karakter girin", + "search.all": "Tümünü göster", + "search.results.none": "Sonuç yok", + + "section.required": "Bölüm gereklidir", + + "security": "Güvenlik", + "select": "Seç", + "server": "Sunucu", + "settings": "Ayarlar", + "show": "Göster", + "site.blueprint": "Sitenin henüz bir planı yok. Kurulumu /site/blueprints/site.yml'de tanımlayabilirsiniz.", + "size": "Boyut", + "slug": "Web Adres Uzantısı", + "sort": "Sırala", + + "stats.empty": "Rapor yok", + "system.issues.content": "İçerik klasörü açığa çıkmış görünüyor", + "system.issues.debug": "Canlı modda hata ayıklama kapatılmalıdır", + "system.issues.git": ".git klasörü açığa çıkmış görünüyor", + "system.issues.https": "Tüm siteleriniz için HTTPS'yi öneriyoruz", + "system.issues.kirby": "Kirby klasörü açığa çıkmış görünüyor", + "system.issues.site": "Site klasörü açığa çıkmış görünüyor", + + "title": "Başlık", + "template": "\u015eablon", + "today": "Bugün", + + "toolbar.button.code": "Kod", + "toolbar.button.bold": "Kalın Yazı", + "toolbar.button.email": "E-Posta", + "toolbar.button.headings": "Başlıklar", + "toolbar.button.heading.1": "Başlık 1", + "toolbar.button.heading.2": "Başlık 2", + "toolbar.button.heading.3": "Başlık 3", + "toolbar.button.heading.4": "Başlık 4", + "toolbar.button.heading.5": "Başlık 5", + "toolbar.button.heading.6": "Başlık 6", + "toolbar.button.italic": "Eğik Yazı", + "toolbar.button.file": "Dosya", + "toolbar.button.file.select": "Bir dosya seçin", + "toolbar.button.file.upload": "Bir dosya yükleyin", + "toolbar.button.link": "Ba\u011flant\u0131", + "toolbar.button.paragraph": "Paragraf", + "toolbar.button.strike": "Üstü çizili", + "toolbar.button.ol": "Sıralı liste", + "toolbar.button.underline": "Altı çizili", + "toolbar.button.ul": "Madde listesi", + + "translation.author": "Kirby Takımı", + "translation.direction": "ltr", + "translation.name": "T\u00fcrk\u00e7e", + "translation.locale": "tr_TR", + + "upload": "Yükle", + "upload.error.cantMove": "Yüklenen dosya taşınamadı", + "upload.error.cantWrite": "Dosya diske yazılamadı", + "upload.error.default": "Dosya yüklenemedi", + "upload.error.extension": "Dosya yükleme uzantısı tarafından durduruldu", + "upload.error.formSize": "Yüklenen dosya, formda belirtilen MAX_FILE_SIZE yönergesini aşıyor", + "upload.error.iniPostSize": "Yüklenen dosya php.ini içindeki post_max_size yönergesini aşıyor", + "upload.error.iniSize": "Yüklenen dosya php.ini içindeki upload_max_filesize yönergesini aşıyor", + "upload.error.noFile": "Dosya yüklenmedi", + "upload.error.noFiles": "Dosyalar yüklenmedi", + "upload.error.partial": "Yüklenen dosya sadece kısmen yüklendi", + "upload.error.tmpDir": "Geçici klasör eksik", + "upload.errors": "Hata", + "upload.progress": "Yükleniyor...", + + "url": "Url", + "url.placeholder": "https://ornek.com", + + "user": "Kullanıcı", + "user.blueprint": "Bu kullanıcı rolü için /site/blueprints/users/{blueprint}.yml içinde ek bölümler ve form alanları tanımlayabilirsiniz", + "user.changeEmail": "E-postayı değiştir", + "user.changeLanguage": "Dili değiştir", + "user.changeName": "Kullanıcıyı yeniden adlandır", + "user.changePassword": "Şifre değiştir", + "user.changePassword.new": "Yeni Şifre", + "user.changePassword.new.confirm": "Şifreyi onaylayın...", + "user.changeRole": "Rolü değiştir", + "user.changeRole.select": "Yeni bir rol seçin", + "user.create": "Yeni bir kullanıcı ekle", + "user.delete": "Bu kullanıcıyı sil", + "user.delete.confirm": "{email} kullanıcısını silmek istediğinizden emin misiniz?", + + "users": "Kullanıcılar", + + "version": "Versiyon", + + "view.account": "Hesap Bilgilerin", + "view.installation": "Kurulum", + "view.languages": "Diller", + "view.resetPassword": "Şifreyi sıfırla", + "view.site": "Site", + "view.system": "Sistem", + "view.users": "Kullan\u0131c\u0131lar", + + "welcome": "Hoşgeldiniz", + "year": "Yıl", + "yes": "evet" } diff --git a/kirby/package-lock.json b/kirby/package-lock.json deleted file mode 100644 index 7c78dd2..0000000 --- a/kirby/package-lock.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "name": "kirby", - "lockfileVersion": 3, - "requires": true, - "packages": {} -} diff --git a/kirby/panel/.prettierignore b/kirby/panel/.prettierignore deleted file mode 100644 index 511620b..0000000 --- a/kirby/panel/.prettierignore +++ /dev/null @@ -1,2 +0,0 @@ - -src/components/Text/Highlight.vue \ No newline at end of file diff --git a/kirby/panel/dist/apple-touch-icon-dark.png b/kirby/panel/dist/apple-touch-icon-dark.png deleted file mode 100644 index 321598b9dd0244c8d5488bc932ba41a61f248207..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1148 zcmV-?1cUpDP)+q+1c5@zrV1su#btZ*Om4U|?EWT1-q#J3BiuF)=78C>k0X!otGl z=H}AU(u0G8a&mG~Qc^1`E4R0|?Ck8hxw*8ow4R=xYinyzP*6fbLOwn|jEsybDk^bU zT}l7|17%4>K~#9!?AVD;;!qfd;qRkTp+IG;EP{%N;(`K#2;%PjU(+OH+MWy`Ft%`- z{LdA-3(DeR(ny!qn&Y)y764V@k}juaLL1|f*EM~g>oVV`bd|=? z!&${20SyBS7!7~yRL-z_&1*mCxsN6K&;Ey9H?dphQ_HI<-{S}OWx85VCU!?HIlNs_ zV%{FA-?uB17yqAUn^>ut^+(dn1iN5l)!DWAoXr~8HuYzhKCrfr(vkrcK6S@v)y&QI zp_aN2ZBPGIS-?`*P)b=OU;Ee&<0whjpojm^8_<e~(?m`*b2;P@+O^w?Kh#gn1 z!e0njj-FuOx~x-ratM|;Yua4|tlReHb~w?)4noiwh8Z2!953F47;PXVhD1xWL`$?p zOSDAqB-%2uHq+81I$q9WP5E+MmuNCwz#0l^Qln_HQpXDQ3aME%S)JeqlPalUG!rok zOIWc4^^7KyjT9D0HIk&Z(WEmn=7L5JsdY3tt=Ul6wJE86G&#(e{u}F%j6^h9%3~&9 zA|n$$+ihlhNu;95!GMfhG^us;*x}kv#+pR`Y3Gb_5QL&2Xw-;GLq$VkL@B9>iM98? zl2!yiDwtTjF*7Haj{m~$F3wdmPr0e`DDUY9`5f(Ck;gd#dhH42eWc4}{K6QsT^?ec zTRrKFSw$Iwv(O2da@*2;E)Twlx4GD9N6TgT`E3LHBN-O301E zZ4l`N@%M$&N-I5X)#zX51D{OW=)x?UTA)rnN){%0-)^+X3quMD1vskpe;FO z9}(L8Ogpxh%~XdtM8_7|W@h%rp$+|H3!!|qg;2)ZLV&JLF!w$BC6(kAw5mccsX#Yt zl69ai%R0h35OaqKx_AZM7K5(1G57MI%Y@JkND&bc5fKp)5fKrQPuu~GLsDh*#mvJ1 O0000nav{display:flex;direction:ltr}.k-calendar-input>nav .k-button{padding:.5rem}.k-calendar-selects{flex-grow:1;display:flex;align-items:center;justify-content:center}[dir=ltr] .k-calendar-selects{direction:ltr}[dir=rtl] .k-calendar-selects{direction:rtl}.k-calendar-selects .k-select-input{padding:0 .5rem;font-weight:var(--font-normal);font-size:var(--text-sm)}.k-calendar-selects .k-select-input:focus-within{color:var(--color-focus-light)!important}.k-calendar-input th{padding:.5rem 0;color:var(--color-gray-500);font-size:var(--text-xs);font-weight:400;text-align:center}.k-calendar-day .k-button{width:2rem;height:2rem;margin-left:auto;margin-right:auto;color:var(--color-white);line-height:1.75rem;display:flex;justify-content:center;border-radius:50%;border:2px solid transparent}.k-calendar-day .k-button .k-button-text{opacity:1}.k-calendar-table .k-button:hover{color:var(--color-white)}.k-calendar-day:hover .k-button:not([data-disabled=true]){border-color:#ffffff40}.k-calendar-day[aria-current=date] .k-button{text-decoration:underline}.k-calendar-day[aria-selected=date] .k-button{border-color:currentColor;font-weight:600;color:var(--color-focus-light)}.k-calendar-today{text-align:center;padding-top:.5rem}.k-calendar-today .k-button{font-size:var(--text-xs);padding:1rem;text-decoration:underline}.k-calendar-today .k-button-text{opacity:1;vertical-align:baseline}.k-counter{font-size:var(--text-xs);color:var(--color-gray-900);font-weight:var(--font-bold)}.k-counter[data-invalid=true]{box-shadow:none;border:0;color:var(--color-negative)}[dir=ltr] .k-counter-rules{padding-left:.5rem}[dir=rtl] .k-counter-rules{padding-right:.5rem}.k-counter-rules{color:var(--color-gray-600);font-weight:var(--font-normal)}.k-form-submitter{display:none}.k-form-buttons[data-theme]{background:var(--theme-light)}.k-form-buttons .k-view{display:flex;justify-content:space-between;align-items:center}.k-form-button.k-button{font-weight:500;white-space:nowrap;line-height:1;height:2.5rem;display:flex;padding:0 1rem;align-items:center}[dir=ltr] .k-form-button:first-child{margin-left:-1rem}[dir=rtl] .k-form-button:first-child{margin-right:-1rem}[dir=ltr] .k-form-button:last-child{margin-right:-1rem}[dir=rtl] .k-form-button:last-child{margin-left:-1rem}[dir=ltr] .k-form-lock-info{margin-right:3rem}[dir=rtl] .k-form-lock-info{margin-left:3rem}.k-form-lock-info{display:flex;font-size:var(--text-sm);align-items:center;line-height:1.5em;padding:.625rem 0}[dir=ltr] .k-form-lock-info>.k-icon{margin-right:.5rem}[dir=rtl] .k-form-lock-info>.k-icon{margin-left:.5rem}.k-form-lock-buttons{display:flex;flex-shrink:0}.k-form-lock-loader{animation:Spin 4s linear infinite}.k-form-lock-loader .k-icon-loader{display:flex}.k-form-indicator-toggle{color:var(--color-notice-light)}.k-form-indicator-info{font-size:var(--text-sm);font-weight:var(--font-bold);padding:.75rem 1rem .25rem;line-height:1.25em;width:15rem}.k-field-label{font-weight:var(--font-bold);display:block;padding:0 0 .75rem;flex-grow:1;line-height:1.25rem}[dir=ltr] .k-field-label abbr{padding-left:.25rem}[dir=rtl] .k-field-label abbr{padding-right:.25rem}.k-field-label abbr{text-decoration:none;color:var(--color-gray-500)}.k-field-header{position:relative;display:flex;align-items:baseline}[dir=ltr] .k-field-options{right:0}[dir=rtl] .k-field-options{left:0}.k-field-options{position:absolute;top:calc(-.5rem - 1px)}.k-field-options.k-button-group .k-dropdown{height:auto}.k-field-options.k-button-group .k-field-options-button.k-button{padding:.75rem;display:flex}.k-field[data-disabled=true]{cursor:not-allowed}.k-field[data-disabled=true] *{pointer-events:none}.k-field[data-disabled=true] .k-text[data-theme=help] *{pointer-events:initial}.k-field:focus-within>.k-field-header>.k-field-counter{display:block}.k-field-help{padding-top:.5rem}.k-fieldset{border:0}.k-fieldset .k-grid{grid-row-gap:2.25rem}@media screen and (min-width:30em){.k-fieldset .k-grid{grid-column-gap:1.5rem}}.k-sections>.k-column[data-width="1/3"] .k-fieldset .k-grid,.k-sections>.k-column[data-width="1/4"] .k-fieldset .k-grid{grid-template-columns:repeat(1,1fr)}.k-sections>.k-column[data-width="1/3"] .k-fieldset .k-grid .k-column,.k-sections>.k-column[data-width="1/4"] .k-fieldset .k-grid .k-column{grid-column-start:initial}.k-input{display:flex;align-items:center;line-height:1;border:0;outline:0;background:0 0}.k-input-element{flex-grow:1}.k-input-icon{display:flex;justify-content:center;align-items:center;line-height:0}.k-input[data-disabled=true]{pointer-events:none}[data-disabled=true] .k-input-icon{color:var(--color-gray-600)}.k-input[data-theme=field]{line-height:1;border:var(--field-input-border);background:var(--field-input-background);border-radius:var(--rounded)}.k-input[data-theme=field]:focus-within{border:var(--field-input-focus-border);box-shadow:var(--color-focus-outline) 0 0 0 2px}.k-input[data-theme=field][data-disabled=true]{background:var(--color-background)}.k-input[data-theme=field] .k-input-icon{width:var(--field-input-height);align-self:stretch;display:flex;align-items:center;flex-shrink:0}.k-input[data-theme=field] .k-input-after,.k-input[data-theme=field] .k-input-before{align-self:stretch;display:flex;align-items:center;flex-shrink:0;padding:0 var(--field-input-padding)}[dir=ltr] .k-input[data-theme=field] .k-input-before{padding-right:0}[dir=ltr] .k-input[data-theme=field] .k-input-after,[dir=rtl] .k-input[data-theme=field] .k-input-before{padding-left:0}.k-input[data-theme=field] .k-input-before{color:var(--field-input-color-before)}[dir=rtl] .k-input[data-theme=field] .k-input-after{padding-right:0}.k-input[data-theme=field] .k-input-after{color:var(--field-input-color-after)}.k-input[data-theme=field] .k-input-icon>.k-dropdown{width:100%;height:100%}.k-input[data-theme=field] .k-input-icon-button{width:100%;height:100%;display:flex;align-items:center;justify-content:center;flex-shrink:0}.k-input[data-theme=field] .k-number-input,.k-input[data-theme=field] .k-select-input,.k-input[data-theme=field] .k-text-input{padding:var(--field-input-padding);line-height:var(--field-input-line-height)}.k-input[data-theme=field] .k-date-input .k-select-input,.k-input[data-theme=field] .k-time-input .k-select-input{padding-left:0;padding-right:0}[dir=ltr] .k-input[data-theme=field] .k-date-input .k-select-input:first-child,[dir=ltr] .k-input[data-theme=field] .k-time-input .k-select-input:first-child{padding-left:var(--field-input-padding)}[dir=rtl] .k-input[data-theme=field] .k-date-input .k-select-input:first-child,[dir=rtl] .k-input[data-theme=field] .k-time-input .k-select-input:first-child{padding-right:var(--field-input-padding)}.k-input[data-theme=field] .k-date-input .k-select-input:focus-within,.k-input[data-theme=field] .k-time-input .k-select-input:focus-within{color:var(--color-focus);font-weight:var(--font-bold)}[dir=ltr] .k-input[data-theme=field].k-time-input .k-time-input-meridiem{padding-left:var(--field-input-padding)}[dir=rtl] .k-input[data-theme=field].k-time-input .k-time-input-meridiem{padding-right:var(--field-input-padding)}.k-input[data-theme=field][data-type=checkboxes] .k-checkboxes-input li,.k-input[data-theme=field][data-type=checkboxes] .k-radio-input li,.k-input[data-theme=field][data-type=radio] .k-checkboxes-input li,.k-input[data-theme=field][data-type=radio] .k-radio-input li{min-width:0;overflow-wrap:break-word}[dir=ltr] .k-input[data-theme=field][data-type=checkboxes] .k-input-before{border-right:1px solid var(--color-background)}[dir=ltr] .k-input[data-theme=field][data-type=checkboxes] .k-input-element+.k-input-after,[dir=ltr] .k-input[data-theme=field][data-type=checkboxes] .k-input-element+.k-input-icon,[dir=rtl] .k-input[data-theme=field][data-type=checkboxes] .k-input-before{border-left:1px solid var(--color-background)}[dir=ltr] .k-input[data-theme=field][data-type=checkboxes] .k-checkboxes-input li,[dir=rtl] .k-input[data-theme=field][data-type=checkboxes] .k-input-element+.k-input-after,[dir=rtl] .k-input[data-theme=field][data-type=checkboxes] .k-input-element+.k-input-icon{border-right:1px solid var(--color-background)}.k-input[data-theme=field][data-type=checkboxes] .k-input-element{overflow:hidden}[dir=ltr] .k-input[data-theme=field][data-type=checkboxes] .k-checkboxes-input{margin-right:-1px}[dir=rtl] .k-input[data-theme=field][data-type=checkboxes] .k-checkboxes-input{margin-left:-1px}.k-input[data-theme=field][data-type=checkboxes] .k-checkboxes-input{display:grid;grid-template-columns:1fr;margin-bottom:-1px}@media screen and (min-width:65em){.k-input[data-theme=field][data-type=checkboxes] .k-checkboxes-input{grid-template-columns:repeat(var(--columns),1fr)}}[dir=rtl] .k-input[data-theme=field][data-type=checkboxes] .k-checkboxes-input li{border-left:1px solid var(--color-background)}.k-input[data-theme=field][data-type=checkboxes] .k-checkboxes-input li,.k-input[data-theme=field][data-type=radio] .k-radio-input li{border-bottom:1px solid var(--color-background)}.k-input[data-theme=field][data-type=checkboxes] .k-checkboxes-input label{display:block;line-height:var(--field-input-line-height);padding:var(--field-input-padding) var(--field-input-padding)}[dir=ltr] .k-input[data-theme=field][data-type=checkboxes] .k-checkbox-input-icon,[dir=ltr] .k-input[data-theme=field][data-type=radio] .k-radio-input label:before{left:var(--field-input-padding)}[dir=rtl] .k-input[data-theme=field][data-type=checkboxes] .k-checkbox-input-icon,[dir=rtl] .k-input[data-theme=field][data-type=radio] .k-radio-input label:before{right:var(--field-input-padding)}.k-input[data-theme=field][data-type=checkboxes] .k-checkbox-input-icon{top:calc((var(--field-input-height) - var(--field-input-font-size))/2);margin-top:0}[dir=ltr] .k-input[data-theme=field][data-type=radio] .k-input-before{border-right:1px solid var(--color-background)}[dir=ltr] .k-input[data-theme=field][data-type=radio] .k-input-element+.k-input-after,[dir=ltr] .k-input[data-theme=field][data-type=radio] .k-input-element+.k-input-icon,[dir=rtl] .k-input[data-theme=field][data-type=radio] .k-input-before{border-left:1px solid var(--color-background)}[dir=ltr] .k-input[data-theme=field][data-type=radio] .k-radio-input li,[dir=rtl] .k-input[data-theme=field][data-type=radio] .k-input-element+.k-input-after,[dir=rtl] .k-input[data-theme=field][data-type=radio] .k-input-element+.k-input-icon{border-right:1px solid var(--color-background)}.k-input[data-theme=field][data-type=radio] .k-input-element{overflow:hidden}[dir=ltr] .k-input[data-theme=field][data-type=radio] .k-radio-input{margin-right:-1px}[dir=rtl] .k-input[data-theme=field][data-type=radio] .k-radio-input{margin-left:-1px}.k-input[data-theme=field][data-type=radio] .k-radio-input{display:grid;grid-template-columns:1fr;margin-bottom:-1px}@media screen and (min-width:65em){.k-input[data-theme=field][data-type=radio] .k-radio-input{grid-template-columns:repeat(var(--columns),1fr)}}[dir=rtl] .k-input[data-theme=field][data-type=radio] .k-radio-input li{border-left:1px solid var(--color-background)}.k-input[data-theme=field][data-type=radio] .k-radio-input label{display:block;flex-grow:1;min-height:var(--field-input-height);line-height:var(--field-input-line-height);padding:calc((var(--field-input-height) - var(--field-input-line-height))/2) var(--field-input-padding)}.k-input[data-theme=field][data-type=radio] .k-radio-input label:before{top:calc((var(--field-input-height) - 1rem)/2);margin-top:-1px}.k-input[data-theme=field][data-type=radio] .k-radio-input .k-radio-input-info{display:block;font-size:var(--text-sm);color:var(--color-gray-600);line-height:var(--field-input-line-height);padding-top:calc(var(--field-input-line-height)/10)}.k-input[data-theme=field][data-type=radio] .k-radio-input .k-icon{width:var(--field-input-height);height:var(--field-input-height);display:flex;align-items:center;justify-content:center}.k-input[data-theme=field][data-type=range] .k-range-input{padding:var(--field-input-padding)}.k-input[data-theme=field][data-type=multiselect],.k-input[data-theme=field][data-type=select]{position:relative}[dir=ltr] .k-input[data-theme=field][data-type=select] .k-input-icon{right:0}[dir=rtl] .k-input[data-theme=field][data-type=select] .k-input-icon{left:0}.k-input[data-theme=field][data-type=select] .k-input-icon{position:absolute;top:0;bottom:0}.k-input[data-theme=field][data-type=tags] .k-tags-input{padding:.25rem .25rem 0}[dir=ltr] .k-input[data-theme=field][data-type=tags] .k-tag{margin-right:.25rem}[dir=rtl] .k-input[data-theme=field][data-type=tags] .k-tag{margin-left:.25rem}.k-input[data-theme=field][data-type=tags] .k-tag{margin-bottom:.25rem;height:auto;min-height:1.75rem;font-size:var(--text-sm)}.k-input[data-theme=field][data-type=tags] .k-tags-input input{font-size:var(--text-sm);padding:0 .25rem;height:1.75rem;line-height:1;margin-bottom:.25rem}.k-input[data-theme=field][data-type=tags] .k-tags-input .k-dropdown-content{top:calc(100% + .5rem + 2px)}.k-input[data-theme=field][data-type=tags] .k-tags-input .k-dropdown-content[data-dropup]{top:calc(100% + .5rem + 2px);bottom:initial;margin-bottom:initial}.k-input[data-theme=field][data-type=multiselect] .k-multiselect-input{padding:.25rem 2rem 0 .25rem;min-height:2.25rem}[dir=ltr] .k-input[data-theme=field][data-type=multiselect] .k-tag{margin-right:.25rem}[dir=rtl] .k-input[data-theme=field][data-type=multiselect] .k-tag{margin-left:.25rem}.k-input[data-theme=field][data-type=multiselect] .k-tag{margin-bottom:.25rem;height:1.75rem;font-size:var(--text-sm)}[dir=ltr] .k-input[data-theme=field][data-type=multiselect] .k-input-icon{right:0}[dir=rtl] .k-input[data-theme=field][data-type=multiselect] .k-input-icon{left:0}.k-input[data-theme=field][data-type=multiselect] .k-input-icon{position:absolute;top:0;bottom:0;pointer-events:none}.k-input[data-theme=field][data-type=textarea] .k-textarea-input-native{padding:.25rem var(--field-input-padding);line-height:1.5rem}[dir=ltr] .k-input[data-theme=field][data-type=toggle] .k-input-before{padding-right:calc(var(--field-input-padding)/2)}[dir=rtl] .k-input[data-theme=field][data-type=toggle] .k-input-before{padding-left:calc(var(--field-input-padding)/2)}[dir=ltr] .k-input[data-theme=field][data-type=toggle] .k-toggle-input{padding-left:var(--field-input-padding)}[dir=rtl] .k-input[data-theme=field][data-type=toggle] .k-toggle-input{padding-right:var(--field-input-padding)}.k-input[data-theme=field][data-type=toggle] .k-toggle-input-label{padding:0 var(--field-input-padding)0 .75rem;line-height:var(--field-input-height)}.k-login-code-form .k-user-info{height:38px;margin-bottom:2.25rem;padding:.5rem;background:var(--color-white);border-radius:var(--rounded-xs);box-shadow:var(--shadow)}.k-times{padding:var(--spacing-4) var(--spacing-6);display:grid;line-height:1;grid-template-columns:1fr 1fr;grid-gap:var(--spacing-6)}.k-times .k-icon{width:1rem;margin-bottom:var(--spacing-2)}.k-times-slot .k-button{padding:var(--spacing-1) var(--spacing-3) var(--spacing-1)0;font-variant-numeric:tabular-nums;white-space:nowrap}.k-times .k-times-slot hr{position:relative;opacity:1;margin:var(--spacing-2)0;border:0;height:1px;top:1px;background:var(--color-dark)}[dir=ltr] .k-upload input{left:-3000px}[dir=rtl] .k-upload input{right:-3000px}.k-upload input{position:absolute;top:0}.k-upload-dialog .k-headline{margin-bottom:.75rem}.k-upload-error-list,.k-upload-list{line-height:1.5em;font-size:var(--text-sm)}.k-upload-list-filename{color:var(--color-gray-600)}.k-upload-error-list li{padding:.75rem;background:var(--color-white);border-radius:var(--rounded-xs)}.k-upload-error-list li:not(:last-child){margin-bottom:2px}.k-upload-error-filename{color:var(--color-negative);font-weight:var(--font-bold)}.k-upload-error-message{color:var(--color-gray-600)}.k-writer-toolbar{position:absolute;display:flex;background:var(--color-black);height:30px;transform:translate(-50%) translateY(-.75rem);z-index:calc(var(--z-dropdown) + 1);box-shadow:var(--shadow);color:var(--color-white);border-radius:var(--rounded)}.k-writer-toolbar-button.k-button{display:flex;align-items:center;justify-content:center;height:30px;width:30px;font-size:var(--text-sm)!important;color:currentColor;line-height:1}.k-writer-toolbar-button.k-button:hover{background:rgba(255,255,255,.15)}.k-writer-toolbar-button.k-writer-toolbar-button-active{color:var(--color-blue-300)}.k-writer-toolbar-button.k-writer-toolbar-nodes{width:auto;padding:0 .75rem}[dir=ltr] .k-writer-toolbar .k-dropdown+.k-writer-toolbar-button{border-left:1px solid var(--color-gray-700)}[dir=rtl] .k-writer-toolbar .k-dropdown+.k-writer-toolbar-button{border-right:1px solid var(--color-gray-700)}[dir=ltr] .k-writer-toolbar-button.k-writer-toolbar-nodes:after{margin-left:.5rem}[dir=rtl] .k-writer-toolbar-button.k-writer-toolbar-nodes:after{margin-right:.5rem}.k-writer-toolbar-button.k-writer-toolbar-nodes:after{content:"";border-top:4px solid var(--color-white);border-left:4px solid transparent;border-right:4px solid transparent}.k-writer-toolbar .k-dropdown-content{color:var(--color-black);background:var(--color-white);margin-top:.5rem}.k-writer-toolbar .k-dropdown-content .k-dropdown-item[aria-current]{color:var(--color-focus);font-weight:500}.k-writer{position:relative;width:100%;grid-template-areas:"content";display:grid}.k-writer .ProseMirror{overflow-wrap:break-word;word-wrap:break-word;word-break:break-word;white-space:pre-wrap;font-variant-ligatures:none;line-height:inherit;grid-area:content}.k-writer .ProseMirror:focus{outline:0}.k-writer .ProseMirror *{caret-color:currentColor}.k-writer .ProseMirror a{color:var(--color-focus);text-decoration:underline}.k-writer .ProseMirror>:last-child{margin-bottom:0}.k-writer .ProseMirror h1,.k-writer .ProseMirror h2,.k-writer .ProseMirror h3,.k-writer .ProseMirror ol,.k-writer .ProseMirror p,.k-writer .ProseMirror ul{margin-bottom:.75rem}.k-writer .ProseMirror h1{font-size:var(--text-3xl);line-height:1.25em}.k-writer .ProseMirror h2{font-size:var(--text-2xl);line-height:1.25em}.k-writer .ProseMirror h3{font-size:var(--text-xl);line-height:1.25em}.k-writer .ProseMirror h1 strong,.k-writer .ProseMirror h2 strong,.k-writer .ProseMirror h3 strong{font-weight:700}.k-writer .ProseMirror strong{font-weight:600}.k-writer .ProseMirror code{position:relative;font-size:.925em;display:inline-block;line-height:1.325;padding:.05em .325em;background:var(--color-gray-300);border-radius:var(--rounded)}[dir=ltr] .k-writer .ProseMirror ol,[dir=ltr] .k-writer .ProseMirror ul{padding-left:1.75rem}[dir=rtl] .k-writer .ProseMirror ol,[dir=rtl] .k-writer .ProseMirror ul{padding-right:1.75rem}.k-writer .ProseMirror ul>li{list-style:disc}.k-writer .ProseMirror ul ul>li{list-style:circle}.k-writer .ProseMirror ul ul ul>li{list-style:square}.k-writer .ProseMirror ol>li{list-style:decimal}.k-writer .ProseMirror li>ol,.k-writer .ProseMirror li>p,.k-writer .ProseMirror li>ul{margin:0}.k-writer-code pre{-moz-tab-size:2;-o-tab-size:2;tab-size:2;font-size:var(--text-sm);line-height:2em;overflow-x:auto;overflow-y:hidden;-webkit-overflow-scrolling:touch;white-space:pre}.k-writer .ProseMirror code,.k-writer-code code{font-family:var(--font-mono)}.k-writer[data-placeholder][data-empty=true]:before{grid-area:content;content:attr(data-placeholder);line-height:inherit;color:var(--color-gray-500);pointer-events:none;white-space:pre-wrap;word-wrap:break-word}.k-login-alert{padding:.5rem .75rem;display:flex;justify-content:space-between;align-items:center;min-height:38px;margin-bottom:2rem;background:var(--color-negative);color:var(--color-white);font-size:var(--text-sm);border-radius:var(--rounded-xs);box-shadow:var(--shadow-lg);cursor:pointer}.k-structure-backdrop{position:absolute;top:0;right:0;bottom:0;left:0;z-index:2;height:100vh}.k-structure-form section{position:relative;z-index:3;border-radius:var(--rounded-xs);margin-bottom:1px;box-shadow:#1111110d 0 0 0 3px;border:1px solid var(--color-border);background:var(--color-background)}.k-structure-form-fields{padding:1.5rem 1.5rem 2rem}.k-structure-form-buttons{border-top:1px solid var(--color-border);display:flex;justify-content:space-between}.k-structure-form-buttons .k-pagination{display:none}@media screen and (min-width:65em){.k-structure-form-buttons .k-pagination{display:flex}}.k-structure-form-buttons .k-pagination>.k-button,.k-structure-form-buttons .k-pagination>span{padding:.875rem 1rem!important}.k-structure-form-cancel-button,.k-structure-form-submit-button{padding:.875rem 1.5rem;line-height:1rem;display:flex}[dir=ltr] .k-toolbar,[dir=rtl] .k-toolbar{border-top-right-radius:var(--rounded);border-top-left-radius:var(--rounded)}.k-toolbar{background:var(--color-white);border-bottom:1px solid var(--color-background);height:38px}.k-toolbar-wrapper{position:absolute;top:0;left:0;right:0;max-width:100%}.k-toolbar-buttons{display:flex}.k-toolbar-divider{width:1px;background:var(--color-background)}.k-toolbar-button{width:36px;height:36px}.k-toolbar-button:hover{background:rgba(239,239,239,.5)}.k-checkbox-input{position:relative;cursor:pointer}[dir=ltr] .k-checkbox-input-label{padding-left:1.75rem}[dir=rtl] .k-checkbox-input-label{padding-right:1.75rem}.k-checkbox-input-label{display:block}[dir=ltr] .k-checkbox-input-icon{left:0}[dir=rtl] .k-checkbox-input-icon{right:0}.k-checkbox-input-icon{position:absolute;width:1rem;height:1rem;border-radius:var(--rounded);border:2px solid var(--color-gray-500)}.k-checkbox-input-icon svg{position:absolute;width:12px;height:12px;display:none}.k-checkbox-input-icon path{stroke:var(--color-white)}.k-checkbox-input-native:checked+.k-checkbox-input-icon{border-color:var(--color-gray-900);background:var(--color-gray-900)}[data-disabled=true] .k-checkbox-input-native:checked+.k-checkbox-input-icon{border-color:var(--color-gray-600);background:var(--color-gray-600)}.k-checkbox-input-native:checked+.k-checkbox-input-icon svg{display:block}.k-checkbox-input-native:focus+.k-checkbox-input-icon{border-color:var(--color-blue-600)}.k-checkbox-input-native:focus:checked+.k-checkbox-input-icon{background:var(--color-focus)}.k-text-input{width:100%;border:0;background:0 0;font:inherit;color:inherit;font-variant-numeric:tabular-nums}.k-text-input::-moz-placeholder{color:var(--color-gray-500)}.k-text-input::placeholder{color:var(--color-gray-500)}.k-text-input:focus{outline:0}.k-text-input:invalid{box-shadow:none;outline:0}.k-list-input .ProseMirror{line-height:1.5em}.k-list-input .ProseMirror ol>li::marker{font-size:var(--text-sm);color:var(--color-gray-500)}.k-multiselect-input{display:flex;flex-wrap:wrap;position:relative;font-size:var(--text-sm);min-height:2.25rem;line-height:1}.k-multiselect-input .k-sortable-ghost{background:var(--color-focus)}.k-multiselect-input .k-tag{border-radius:var(--rounded-sm)}.k-multiselect-input .k-dropdown-content,.k-multiselect-input[data-layout=list] .k-tag{width:100%}.k-multiselect-search{margin-top:0!important;color:var(--color-white);background:var(--color-gray-900);border-bottom:1px dashed rgba(255,255,255,.2)}.k-multiselect-search>.k-button-text{flex:1;opacity:1!important}.k-multiselect-search input{width:100%;color:var(--color-white);background:0 0;border:0;outline:0;padding:.25rem 0;font:inherit}.k-multiselect-options{position:relative;max-height:275px;padding:.5rem 0}.k-multiselect-option{position:relative}.k-multiselect-option.selected{color:var(--color-positive-light)}.k-multiselect-option.disabled:not(.selected) .k-icon{opacity:0}.k-multiselect-option b{color:var(--color-focus-light);font-weight:700}[dir=ltr] .k-multiselect-value{margin-left:.25rem}[dir=rtl] .k-multiselect-value{margin-right:.25rem}.k-multiselect-value{color:var(--color-gray-500)}.k-multiselect-value:before{content:" ("}.k-multiselect-value:after{content:")"}[dir=ltr] .k-multiselect-input[data-layout=list] .k-tag{margin-right:0!important}[dir=rtl] .k-multiselect-input[data-layout=list] .k-tag{margin-left:0!important}.k-multiselect-more{width:100%;padding:.75rem;color:#fffc;text-align:center;border-top:1px dashed rgba(255,255,255,.2)}.k-multiselect-more:hover{color:var(--color-white)}.k-number-input{width:100%;border:0;background:0 0;font:inherit;color:inherit}.k-number-input::-moz-placeholder{color:var(--color-gray-500)}.k-number-input::placeholder{color:var(--color-gray-500)}.k-number-input:focus{outline:0}.k-number-input:invalid{box-shadow:none;outline:0}[dir=ltr] .k-radio-input li{padding-left:1.75rem}[dir=rtl] .k-radio-input li{padding-right:1.75rem}.k-radio-input li{position:relative;line-height:1.5rem}.k-radio-input input{position:absolute;width:0;height:0;-webkit-appearance:none;-moz-appearance:none;appearance:none;opacity:0}.k-radio-input label{cursor:pointer;align-items:center}[dir=ltr] .k-radio-input label:before{left:0}[dir=rtl] .k-radio-input label:before{right:0}.k-radio-input label:before{position:absolute;top:.175em;content:"";width:1rem;height:1rem;border-radius:50%;border:2px solid var(--color-gray-500);box-shadow:var(--color-white) 0 0 0 2px inset}.k-radio-input input:checked+label:before{border-color:var(--color-gray-900);background:var(--color-gray-900)}[data-disabled=true] .k-radio-input input:checked+label:before{border-color:var(--color-gray-600);background:var(--color-gray-600)}.k-radio-input input:focus+label:before{border-color:var(--color-blue-600)}.k-radio-input input:focus:checked+label:before{background:var(--color-focus)}.k-radio-input-text{display:block}.k-range-input{--range-thumb-size:16px;--range-thumb-border:4px solid var(--color-gray-900);--range-thumb-border-disabled:4px solid var(--color-gray-600);--range-thumb-background:var(--color-background);--range-thumb-focus-border:4px solid var(--color-focus);--range-thumb-focus-background:var(--color-background);--range-track-height:4px;--range-track-background:var(--color-border);--range-track-color:var(--color-gray-900);--range-track-color-disabled:var(--color-gray-600);--range-track-focus-color:var(--color-focus);display:flex;align-items:center}.k-range-input-native{--min:0;--max:100;--value:0;--range:calc(var(--max) - var(--min));--ratio:calc((var(--value) - var(--min)) / var(--range));--position:calc( .5 * var(--range-thumb-size) + var(--ratio) * calc(100% - var(--range-thumb-size)) );-webkit-appearance:none;-moz-appearance:none;appearance:none;width:100%;height:var(--range-thumb-size);background:0 0;font-size:var(--text-sm);line-height:1}.k-range-input-native::-webkit-slider-thumb{-webkit-appearance:none;appearance:none}.k-range-input-native::-webkit-slider-runnable-track{border:0;border-radius:var(--range-track-height);width:100%;height:var(--range-track-height);background:var(--range-track-background)}.k-range-input-native::-moz-range-track{border:0;border-radius:var(--range-track-height);width:100%;height:var(--range-track-height);background:var(--range-track-background)}.k-range-input-native::-ms-track{border:0;border-radius:var(--range-track-height);width:100%;height:var(--range-track-height);background:var(--range-track-background)}.k-range-input-native::-webkit-slider-runnable-track{background:linear-gradient(var(--range-track-color),var(--range-track-color))0/var(--position) 100%no-repeat var(--range-track-background)}.k-range-input-native::-moz-range-progress{height:var(--range-track-height);background:var(--range-track-color)}.k-range-input-native::-ms-fill-lower{height:var(--range-track-height);background:var(--range-track-color)}.k-range-input-native::-webkit-slider-thumb{margin-top:calc(.5*(var(--range-track-height) - var(--range-thumb-size)));box-sizing:border-box;width:var(--range-thumb-size);height:var(--range-thumb-size);background:var(--range-thumb-background);border:var(--range-thumb-border);border-radius:50%;cursor:pointer}.k-range-input-native::-moz-range-thumb{box-sizing:border-box;width:var(--range-thumb-size);height:var(--range-thumb-size);background:var(--range-thumb-background);border:var(--range-thumb-border);border-radius:50%;cursor:pointer}.k-range-input-native::-ms-thumb{box-sizing:border-box;width:var(--range-thumb-size);height:var(--range-thumb-size);background:var(--range-thumb-background);border:var(--range-thumb-border);border-radius:50%;cursor:pointer;margin-top:0}.k-range-input-native::-ms-tooltip{display:none}.k-range-input-native:focus{outline:0}.k-range-input-native:focus::-webkit-slider-runnable-track{border:0;border-radius:var(--range-track-height);width:100%;height:var(--range-track-height);background:var(--range-track-background);background:linear-gradient(var(--range-track-focus-color),var(--range-track-focus-color))0/var(--position) 100%no-repeat var(--range-track-background)}.k-range-input-native:focus::-moz-range-progress{height:var(--range-track-height);background:var(--range-track-focus-color)}.k-range-input-native:focus::-ms-fill-lower{height:var(--range-track-height);background:var(--range-track-focus-color)}.k-range-input-native:focus::-webkit-slider-thumb{background:var(--range-thumb-focus-background);border:var(--range-thumb-focus-border)}.k-range-input-native:focus::-moz-range-thumb{background:var(--range-thumb-focus-background);border:var(--range-thumb-focus-border)}.k-range-input-native:focus::-ms-thumb{background:var(--range-thumb-focus-background);border:var(--range-thumb-focus-border)}[dir=ltr] .k-range-input-tooltip{margin-left:1rem}[dir=rtl] .k-range-input-tooltip{margin-right:1rem}.k-range-input-tooltip{position:relative;max-width:20%;display:flex;align-items:center;color:var(--color-white);font-size:var(--text-xs);line-height:1;text-align:center;border-radius:var(--rounded-xs);background:var(--color-gray-900);padding:0 .25rem;white-space:nowrap}[dir=ltr] .k-range-input-tooltip:after{left:-5px}[dir=rtl] .k-range-input-tooltip:after{right:-5px}[dir=ltr] .k-range-input-tooltip:after{border-right:5px solid var(--color-gray-900)}[dir=rtl] .k-range-input-tooltip:after{border-left:5px solid var(--color-gray-900)}.k-range-input-tooltip:after{position:absolute;top:50%;width:0;height:0;transform:translateY(-50%);border-top:5px solid transparent;border-bottom:5px solid transparent;content:""}.k-range-input-tooltip>*{padding:4px}[data-disabled=true] .k-range-input-native::-webkit-slider-runnable-track{background:linear-gradient(var(--range-track-color-disabled),var(--range-track-color-disabled))0/var(--position) 100%no-repeat var(--range-track-background)}[data-disabled=true] .k-range-input-native::-moz-range-progress{height:var(--range-track-height);background:var(--range-track-color-disabled)}[data-disabled=true] .k-range-input-native::-ms-fill-lower{height:var(--range-track-height);background:var(--range-track-color-disabled)}[data-disabled=true] .k-range-input-native::-webkit-slider-thumb{border:var(--range-thumb-border-disabled)}[data-disabled=true] .k-range-input-native::-moz-range-thumb{border:var(--range-thumb-border-disabled)}[data-disabled=true] .k-range-input-native::-ms-thumb{border:var(--range-thumb-border-disabled)}[data-disabled=true] .k-range-input-tooltip{background:var(--color-gray-600)}[dir=ltr] [data-disabled=true] .k-range-input-tooltip:after{border-right:5px solid var(--color-gray-600)}[dir=rtl] [data-disabled=true] .k-range-input-tooltip:after{border-left:5px solid var(--color-gray-600)}.k-select-input{position:relative;display:block;cursor:pointer;overflow:hidden}.k-select-input-native{position:absolute;top:0;right:0;bottom:0;left:0;opacity:0;width:100%;font:inherit;z-index:1;cursor:pointer;-webkit-appearance:none;-moz-appearance:none;appearance:none;font-weight:var(--font-normal)}.k-select-input-native[disabled]{cursor:default}.k-tags-input{display:flex;flex-wrap:wrap}.k-tags-input .k-tag{border-radius:var(--rounded-sm)}.k-tags-input .k-sortable-ghost{background:var(--color-focus)}.k-tags-input-element{flex-grow:1;flex-basis:0;min-width:0}.k-tags-input:focus-within .k-tags-input-element{flex-basis:4rem}.k-tags-input-element input{font:inherit;border:0;width:100%;background:0 0}.k-tags-input-element input:focus{outline:0}[dir=ltr] .k-tags-input[data-layout=list] .k-tag{margin-right:0!important}[dir=rtl] .k-tags-input[data-layout=list] .k-tag{margin-left:0!important}.k-tags-input[data-layout=list] .k-tag{width:100%}.k-textarea-input[data-size=small]{--size:7.5rem}.k-textarea-input[data-size=medium]{--size:15rem}.k-textarea-input[data-size=large]{--size:30rem}.k-textarea-input[data-size=huge]{--size:45rem}.k-textarea-input-wrapper{position:relative}.k-textarea-input-native{resize:none;border:0;width:100%;background:0 0;font:inherit;line-height:1.5em;color:inherit;min-height:var(--size)}.k-textarea-input-native::-moz-placeholder{color:var(--color-gray-500)}.k-textarea-input-native::placeholder{color:var(--color-gray-500)}.k-textarea-input-native:focus{outline:0}.k-textarea-input-native:invalid{box-shadow:none;outline:0}.k-textarea-input-native[data-font=monospace]{font-family:var(--font-mono)}.k-toolbar{margin-bottom:.25rem;color:#aaa}.k-textarea-input:focus-within .k-toolbar{position:sticky;top:0;left:0;right:0;z-index:1;box-shadow:#0000000d 0 2px 5px;border-bottom:1px solid rgba(0,0,0,.1);color:#000}.k-toggle-input{--toggle-background:var(--color-white);--toggle-color:var(--color-gray-500);--toggle-active-color:var(--color-gray-900);--toggle-focus-color:var(--color-focus);--toggle-height:16px;display:flex;align-items:center}.k-toggle-input-native{position:relative;height:var(--toggle-height);width:calc(var(--toggle-height)*2);border-radius:var(--toggle-height);border:2px solid var(--toggle-color);box-shadow:inset 0 0 0 2px var(--toggle-background),inset calc(var(--toggle-height)*-1) 0 0 2px var(--toggle-background);background-color:var(--toggle-color);outline:0;transition:all ease-in-out .1s;-webkit-appearance:none;-moz-appearance:none;appearance:none;cursor:pointer;flex-shrink:0}.k-toggle-input-native:checked{border-color:var(--toggle-active-color);box-shadow:inset 0 0 0 2px var(--toggle-background),inset var(--toggle-height) 0 0 2px var(--toggle-background);background-color:var(--toggle-active-color)}.k-toggle-input-native[disabled]{border-color:var(--color-border);box-shadow:inset 0 0 0 2px var(--color-background),inset calc(var(--toggle-height)*-1) 0 0 2px var(--color-background);background-color:var(--color-border)}.k-toggle-input-native[disabled]:checked{box-shadow:inset 0 0 0 2px var(--color-background),inset var(--toggle-height) 0 0 2px var(--color-background)}.k-toggle-input-native:focus:checked{border:2px solid var(--color-focus);background-color:var(--toggle-focus-color)}.k-toggle-input-native::-ms-check{opacity:0}.k-toggle-input-label{cursor:pointer;flex-grow:1}.k-input[data-type=toggles]{display:inline-flex}.k-input[data-type=toggles].grow{display:flex}.k-toggles-input{display:grid;grid-template-columns:repeat(var(--options),minmax(0,1fr));gap:1px;border-radius:var(--rounded);line-height:1;background:var(--color-border);overflow:hidden}.k-toggles-input li{height:var(--field-input-height);background:var(--color-white)}.k-toggles-input label{align-items:center;background:var(--color-white);cursor:pointer;display:flex;font-size:var(--text-sm);justify-content:center;line-height:1.25;padding:0 var(--spacing-3);height:100%}[dir=ltr] .k-toggles-input .k-icon+.k-toggles-text{margin-left:var(--spacing-2)}[dir=rtl] .k-toggles-input .k-icon+.k-toggles-text{margin-right:var(--spacing-2)}.k-toggles-input input:focus:not(:checked)+label{background:var(--color-gray-200)}.k-toggles-input input:checked+label{background:var(--color-black);color:var(--color-white)}.k-blocks-field{position:relative}.k-date-field-body{display:flex;flex-wrap:wrap;line-height:1;border:var(--field-input-border);background:var(--color-gray-300);gap:1px;border-radius:var(--rounded);--multiplier:calc(25rem - 100%)}.k-date-field-body:focus-within{border:var(--field-input-focus-border);box-shadow:var(--color-focus-outline) 0 0 0 2px}.k-date-field[data-disabled] .k-date-field-body{background:0 0}.k-date-field-body>.k-input[data-theme=field]{border:0;box-shadow:none;border-radius:var(--rounded)}.k-date-field-body>.k-input[data-invalid=true],.k-date-field-body>.k-input[data-invalid=true]:focus-within{border:0!important;box-shadow:none!important}.k-date-field-body>*{flex-grow:1;flex-basis:calc(var(--multiplier)*999);max-width:100%}.k-date-field-body .k-input[data-type=date]{min-width:60%}.k-date-field-body .k-input[data-type=time]{min-width:30%}.k-files-field[data-disabled=true] *{pointer-events:all!important}body{counter-reset:headline-counter}.k-headline-field{position:relative;padding-top:1.5rem}.k-fieldset>.k-grid .k-column:first-child .k-headline-field{padding-top:0}[dir=ltr] .k-headline-field .k-headline[data-numbered]:before{padding-right:.25rem}[dir=rtl] .k-headline-field .k-headline[data-numbered]:before{padding-left:.25rem}.k-headline-field .k-headline[data-numbered]:before{counter-increment:headline-counter;content:counter(headline-counter,decimal-leading-zero);color:var(--color-focus);font-weight:400}.k-info-field .k-headline{padding-bottom:.75rem;line-height:1.25rem}.k-layout-column{position:relative;height:100%;display:flex;flex-direction:column;background:var(--color-white);min-height:6rem}.k-layout-column:focus{outline:0}.k-layout-column .k-blocks{background:0 0;box-shadow:none;padding:0;height:100%;background:var(--color-white);min-height:4rem}.k-layout-column .k-blocks[data-empty=true]{min-height:6rem}.k-layout-column .k-blocks-list{display:flex;flex-direction:column;height:100%}.k-layout-column .k-blocks .k-block-container:last-of-type{flex-grow:1}.k-layout-column .k-blocks-empty{position:absolute;top:0;right:0;bottom:0;left:0;justify-content:center;opacity:0;transition:opacity .3s;border:0}.k-layout-column .k-blocks-empty:hover{opacity:1}[dir=ltr] .k-layout-column .k-blocks-empty.k-empty .k-icon{border-right:0}[dir=rtl] .k-layout-column .k-blocks-empty.k-empty .k-icon{border-left:0}.k-layout-column .k-blocks-empty.k-empty .k-icon{width:1rem}[dir=ltr] .k-layout{padding-right:var(--layout-toolbar-width)}[dir=rtl] .k-layout{padding-left:var(--layout-toolbar-width)}.k-layout{--layout-border-color:var(--color-gray-300);--layout-toolbar-width:2rem;position:relative;background:#fff;box-shadow:var(--shadow)}[dir=ltr] [data-disabled=true] .k-layout{padding-right:0}[dir=rtl] [data-disabled=true] .k-layout{padding-left:0}.k-layout:not(:last-of-type){margin-bottom:1px}.k-layout:focus{outline:0}[dir=ltr] .k-layout-toolbar{right:0}[dir=rtl] .k-layout-toolbar{left:0}[dir=ltr] .k-layout-toolbar{border-left:1px solid var(--color-light)}[dir=rtl] .k-layout-toolbar{border-right:1px solid var(--color-light)}.k-layout-toolbar{position:absolute;top:0;bottom:0;width:var(--layout-toolbar-width);display:flex;flex-direction:column;font-size:var(--text-sm);background:var(--color-gray-100);color:var(--color-gray-500)}.k-layout-toolbar:hover{color:var(--color-black)}.k-layout-toolbar-button{width:var(--layout-toolbar-width);height:var(--layout-toolbar-width)}.k-layout-toolbar .k-sort-handle{margin-top:auto;color:currentColor}.k-layout-columns.k-grid{grid-gap:1px;background:var(--layout-border-color);background:var(--color-gray-300)}.k-layout:not(:first-child) .k-layout-columns.k-grid{border-top:0}.k-layouts .k-sortable-ghost{position:relative;box-shadow:#11111140 0 5px 10px;outline:2px solid var(--color-focus);cursor:grabbing;cursor:-webkit-grabbing;z-index:1}.k-layout-selector.k-dialog{background:#313740;color:var(--color-white)}.k-layout-selector .k-headline{line-height:1;margin-top:-.25rem;margin-bottom:1.5rem}.k-layout-selector ul{display:grid;grid-template-columns:repeat(3,1fr);grid-gap:1.5rem}.k-layout-selector-option .k-grid{height:5rem;grid-gap:2px;box-shadow:var(--shadow);cursor:pointer}.k-layout-selector-option:hover{outline:2px solid var(--color-green-300);outline-offset:2px}.k-layout-selector-option:last-child{margin-bottom:0}.k-layout-selector-option .k-column{display:flex;background:rgba(255,255,255,.2);justify-content:center;font-size:var(--text-xs);align-items:center}.k-layout-add-button{display:flex;align-items:center;width:100%;color:var(--color-gray-500);justify-content:center;padding:.75rem 0}.k-layout-add-button:hover{color:var(--color-black)}.k-line-field{position:relative;border:0;height:3rem;width:auto}.k-line-field:after{position:absolute;content:"";top:50%;margin-top:-1px;left:0;right:0;height:1px;background:var(--color-border)}.k-list-field .k-list-input{padding:.375rem .5rem .375rem .75rem}.k-pages-field[data-disabled=true] *{pointer-events:all!important}.k-structure-field:not([data-disabled=true]) td.k-table-column{cursor:pointer}.k-field-counter{display:none}.k-text-field:focus-within .k-field-counter{display:block}.k-users-field[data-disabled=true] *{pointer-events:all!important}.k-writer-field-input{line-height:1.5em;padding:.375rem .5rem}.k-aspect-ratio{position:relative;display:block;overflow:hidden;padding-bottom:100%}.k-aspect-ratio>*{position:absolute!important;top:0;right:0;bottom:0;left:0;height:100%;width:100%;-o-object-fit:contain;object-fit:contain}.k-aspect-ratio[data-cover=true]>*{-o-object-fit:cover;object-fit:cover}.k-bar{display:flex;align-items:center;justify-content:space-between;line-height:1}.k-bar-slot{flex-grow:1}.k-bar-slot[data-position=center]{text-align:center}[dir=ltr] .k-bar-slot[data-position=right]{text-align:right}[dir=rtl] .k-bar-slot[data-position=right]{text-align:left}.k-box{word-wrap:break-word;font-size:var(--text-sm)}.k-box:not([data-theme=none]){background:var(--color-white);border-radius:var(--rounded);line-height:1.25rem;padding:.5rem .75rem}.k-box[data-theme=code]{background:var(--color-gray-900);border:1px solid var(--color-black);color:var(--color-light);font-family:Input,Menlo,monospace;font-size:var(--text-sm);line-height:1.5}.k-box[data-theme=button]{padding:0}[dir=ltr] .k-box[data-theme=button] .k-button{text-align:left}[dir=rtl] .k-box[data-theme=button] .k-button{text-align:right}.k-box[data-theme=button] .k-button{padding:0 .75rem;height:2.25rem;width:100%;display:flex;align-items:center;line-height:2rem}[dir=ltr] .k-box[data-theme=info],[dir=ltr] .k-box[data-theme=negative],[dir=ltr] .k-box[data-theme=notice],[dir=ltr] .k-box[data-theme=positive]{border-left-color:var(--theme-light)}[dir=rtl] .k-box[data-theme=info],[dir=rtl] .k-box[data-theme=negative],[dir=rtl] .k-box[data-theme=notice],[dir=rtl] .k-box[data-theme=positive]{border-right-color:var(--theme-light)}.k-box[data-theme=info],.k-box[data-theme=negative],.k-box[data-theme=notice],.k-box[data-theme=positive]{border:0;background:var(--theme-bg)}[dir=ltr] .k-box[data-theme=empty]{border-left:0}[dir=rtl] .k-box[data-theme=empty]{border-right:0}.k-box[data-theme=empty]{text-align:center;padding:3rem 1.5rem;display:flex;justify-content:center;align-items:center;flex-direction:column;background:var(--color-background);border:1px dashed var(--color-border)}.k-box[data-theme=empty] .k-icon{margin-bottom:.5rem;color:var(--color-gray-500)}.k-box[data-theme=empty],.k-box[data-theme=empty] p{color:var(--color-gray-600)}.k-bubble{display:flex;padding:0 .5rem;white-space:nowrap;align-items:center;line-height:1.5;font-size:var(--text-xs);height:1.525rem;background:var(--color-light);color:var(--color-black);border-radius:var(--rounded);overflow:hidden}[dir=ltr] .k-bubble .k-item-figure{margin-left:-.5rem}[dir=rtl] .k-bubble .k-item-figure{margin-right:-.5rem}[dir=ltr] .k-bubble .k-item-figure{margin-right:var(--spacing-2)}[dir=rtl] .k-bubble .k-item-figure{margin-left:var(--spacing-2)}.k-bubble .k-item-figure{width:1.525rem;height:1.525rem}.k-bubbles{display:flex;gap:.25rem}.k-collection-help{padding:.5rem .75rem}.k-collection-footer{display:flex;justify-content:space-between;margin-left:-.75rem;margin-right:-.75rem}.k-collection-pagination{line-height:1.25rem;flex-shrink:0;min-height:2.75rem}.k-collection-pagination .k-pagination .k-button{padding:.5rem .75rem;line-height:1.125rem}.k-column{min-width:0;grid-column-start:span 12}.k-column[data-sticky=true]>div{position:sticky;top:4vh;z-index:2}@media screen and (min-width:65em){.k-column[data-width="1/1"],.k-column[data-width="12/12"],.k-column[data-width="2/2"],.k-column[data-width="3/3"],.k-column[data-width="4/4"],.k-column[data-width="6/6"]{grid-column-start:span 12}.k-column[data-width="11/12"]{grid-column-start:span 11}.k-column[data-width="10/12"],.k-column[data-width="5/6"]{grid-column-start:span 10}.k-column[data-width="3/4"],.k-column[data-width="9/12"]{grid-column-start:span 9}.k-column[data-width="2/3"],.k-column[data-width="4/6"],.k-column[data-width="8/12"]{grid-column-start:span 8}.k-column[data-width="7/12"]{grid-column-start:span 7}.k-column[data-width="1/2"],.k-column[data-width="2/4"],.k-column[data-width="3/6"],.k-column[data-width="6/12"]{grid-column-start:span 6}.k-column[data-width="5/12"]{grid-column-start:span 5}.k-column[data-width="1/3"],.k-column[data-width="2/6"],.k-column[data-width="4/12"]{grid-column-start:span 4}.k-column[data-width="1/4"],.k-column[data-width="3/12"]{grid-column-start:span 3}.k-column[data-width="1/6"],.k-column[data-width="2/12"]{grid-column-start:span 2}.k-column[data-width="1/12"]{grid-column-start:span 1}}.k-column[data-disabled=true]{cursor:not-allowed;opacity:.4}.k-column[data-disabled=true] *{pointer-events:none}.k-column[data-disabled=true] .k-text[data-theme=help] *{pointer-events:initial}.k-dropzone{position:relative}.k-dropzone:after{content:"";position:absolute;top:0;right:0;bottom:0;left:0;display:none;pointer-events:none;z-index:1}.k-dropzone[data-over=true]:after{display:block;outline:1px solid var(--color-focus);box-shadow:var(--color-focus-outline) 0 0 0 3px}.k-empty{display:flex;align-items:stretch;border-radius:var(--rounded);color:var(--color-gray-600);border:1px dashed var(--color-border)}button.k-empty{width:100%}button.k-empty:focus{outline:0}.k-empty p{font-size:var(--text-sm);color:var(--color-gray-600)}.k-empty>.k-icon{color:var(--color-gray-500)}.k-empty[data-layout=cardlets],.k-empty[data-layout=cards]{text-align:center;padding:1.5rem;justify-content:center;flex-direction:column}.k-empty[data-layout=cardlets] .k-icon,.k-empty[data-layout=cards] .k-icon{margin-bottom:1rem}.k-empty[data-layout=cardlets] .k-icon svg,.k-empty[data-layout=cards] .k-icon svg{width:2rem;height:2rem}.k-empty[data-layout=list],.k-empty[data-layout=table]{min-height:38px}[dir=ltr] .k-empty[data-layout=list]>.k-icon,[dir=ltr] .k-empty[data-layout=table]>.k-icon{border-right:1px solid rgba(0,0,0,.05)}[dir=rtl] .k-empty[data-layout=list]>.k-icon,[dir=rtl] .k-empty[data-layout=table]>.k-icon{border-left:1px solid rgba(0,0,0,.05)}.k-empty[data-layout=list]>.k-icon,.k-empty[data-layout=table]>.k-icon{width:36px;min-height:36px}.k-empty[data-layout=list]>p,.k-empty[data-layout=table]>p{line-height:1.25rem;padding:.5rem .75rem}.k-file-preview{background:var(--color-gray-800)}.k-file-preview-layout{display:grid;grid-template-columns:50%auto}.k-file-preview-layout>*{min-width:0}.k-file-preview-image{position:relative;display:flex;align-items:center;justify-content:center;background:var(--bg-pattern)}.k-file-preview-image-link{display:block;width:100%;padding:min(4vw,3rem);outline:0}.k-file-preview-image-link[data-tabbed=true]{box-shadow:none;outline:2px solid var(--color-focus);outline-offset:-2px}.k-file-preview-details{padding:1.5rem;flex-grow:1}.k-file-preview-details ul{line-height:1.5em;max-width:50rem;display:grid;grid-gap:1.5rem 3rem;grid-template-columns:repeat(auto-fill,minmax(100px,1fr))}.k-file-preview-details h3{font-size:var(--text-sm);font-weight:500;color:var(--color-gray-500)}.k-file-preview-details a,.k-file-preview-details p{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;color:#ffffffbf;font-size:var(--text-sm)}@media screen and (min-width:30em){.k-file-preview-details ul{grid-template-columns:repeat(auto-fill,minmax(200px,1fr))}}@media screen and (max-width:65em){.k-file-preview-layout{padding:0!important}}@media screen and (min-width:65em){.k-file-preview-layout{grid-template-columns:33.333%auto;align-items:center}.k-file-preview-details{padding:3rem}}@media screen and (min-width:90em){.k-file-preview-layout{grid-template-columns:25%auto}}.k-grid{--columns:12;display:grid;grid-column-gap:0;grid-row-gap:0;grid-template-columns:1fr}@media screen and (min-width:30em){.k-grid[data-gutter=small]{grid-column-gap:1rem;grid-row-gap:1rem}.k-grid[data-gutter=huge],.k-grid[data-gutter=large],.k-grid[data-gutter=medium]{grid-column-gap:1.5rem;grid-row-gap:1.5rem}}@media screen and (min-width:65em){.k-grid{grid-template-columns:repeat(var(--columns),1fr)}.k-grid[data-gutter=large]{grid-column-gap:3rem}.k-grid[data-gutter=huge]{grid-column-gap:4.5rem}}@media screen and (min-width:90em){.k-grid[data-gutter=large]{grid-column-gap:4.5rem}.k-grid[data-gutter=huge]{grid-column-gap:6rem}}@media screen and (min-width:120em){.k-grid[data-gutter=large]{grid-column-gap:6rem}.k-grid[data-gutter=huge]{grid-column-gap:7.5rem}}.k-header{padding-top:4vh;margin-bottom:2rem;border-bottom:1px solid var(--color-border)}.k-header[data-tabs=true]{border-bottom:0}.k-header .k-headline{min-height:1.25em;margin-bottom:.5rem;word-wrap:break-word}.k-header .k-header-buttons{margin-top:-.5rem;height:3.25rem}.k-header .k-headline-editable{cursor:pointer}[dir=ltr] .k-header .k-headline-editable .k-icon{margin-left:.5rem}[dir=rtl] .k-header .k-headline-editable .k-icon{margin-right:.5rem}.k-header .k-headline-editable .k-icon{color:var(--color-gray-500);opacity:0;transition:opacity .3s;display:inline-block}.k-header .k-headline-editable:hover .k-icon{opacity:1}.k-panel-inside{position:absolute;top:0;right:0;bottom:0;left:0;display:flex;flex-direction:column}.k-panel-inside:focus{outline:0}.k-panel-header{z-index:var(--z-navigation);flex-shrink:0}.k-panel-view{flex-grow:1;padding-bottom:6rem}.k-item{position:relative;background:var(--color-white);border-radius:var(--rounded);box-shadow:var(--shadow);display:grid;grid-template-columns:auto;line-height:1}.k-item a:focus,.k-item:focus{outline:0}.k-item:focus-within{box-shadow:var(--shadow-outline)}.k-item-sort-handle.k-sort-handle{position:absolute;opacity:0;width:1.25rem;height:1.5rem;z-index:2;border-radius:1px}.k-item:hover .k-item-sort-handle{opacity:1}.k-item-figure{grid-area:figure}.k-item-content{grid-area:content;overflow:hidden}.k-item-info,.k-item-title{font-size:var(--text-sm);font-weight:400;text-overflow:ellipsis;white-space:nowrap;line-height:1.125rem;overflow:hidden}.k-item-info{grid-area:info;color:var(--color-gray-500)}.k-item-title-link.k-link[data-=true]{box-shadow:none}.k-item-title-link:after{position:absolute;content:"";top:0;right:0;bottom:0;left:0;z-index:1}.k-item-footer{grid-area:footer;display:flex;justify-content:space-between;align-items:center;min-width:0}[dir=ltr] .k-item-label{margin-right:.5rem}[dir=rtl] .k-item-label{margin-left:.5rem}.k-item-buttons{position:relative;display:flex;justify-content:flex-end;flex-shrink:0;flex-grow:1}.k-item-buttons>.k-button,.k-item-buttons>.k-dropdown{position:relative;width:38px;height:38px;display:flex!important;align-items:center;justify-content:center;line-height:1}.k-item-buttons>.k-button{z-index:1}.k-item-buttons>.k-options-dropdown>.k-options-dropdown-toggle{z-index:var(--z-toolbar)}.k-list-item{display:flex;align-items:center;height:38px}[dir=ltr] .k-list-item .k-item-sort-handle{left:-1.5rem}[dir=rtl] .k-list-item .k-item-sort-handle{right:-1.5rem}.k-list-item .k-item-sort-handle{width:1.5rem}[dir=ltr] .k-list-item .k-item-figure{border-top-left-radius:var(--rounded)}[dir=rtl] .k-list-item .k-item-figure{border-top-right-radius:var(--rounded)}[dir=ltr] .k-list-item .k-item-figure{border-bottom-left-radius:var(--rounded)}[dir=rtl] .k-list-item .k-item-figure{border-bottom-right-radius:var(--rounded)}.k-list-item .k-item-figure{width:38px}[dir=ltr] .k-list-item .k-item-content{margin-left:.75rem}[dir=rtl] .k-list-item .k-item-content{margin-right:.75rem}.k-list-item .k-item-content{display:flex;flex-grow:1;flex-shrink:2;justify-content:space-between;align-items:center}.k-list-item .k-item-info,.k-list-item .k-item-title{flex-grow:1;line-height:1.5rem}[dir=ltr] .k-list-item .k-item-title{margin-right:.5rem}[dir=rtl] .k-list-item .k-item-title{margin-left:.5rem}.k-list-item .k-item-title{flex-shrink:1}[dir=ltr] .k-list-item .k-item-info{text-align:right}[dir=rtl] .k-list-item .k-item-info{text-align:left}[dir=ltr] .k-list-item .k-item-info{margin-right:.5rem}[dir=rtl] .k-list-item .k-item-info{margin-left:.5rem}.k-list-item .k-item-info{flex-shrink:2;justify-self:end}.k-list-item .k-item-buttons,.k-list-item .k-item-footer{flex-shrink:0}.k-item:not(.k-list-item) .k-item-sort-handle{margin:var(--spacing-2);background:var(--color-background);box-shadow:var(--shadow-lg);border-radius:var(--rounded-sm)}[dir=ltr] .k-item:not(.k-list-item) .k-item-label{margin-left:-2px}[dir=rtl] .k-item:not(.k-list-item) .k-item-label{margin-right:-2px}.k-item:not(.k-list-item) .k-item-content{padding:.625rem .75rem}.k-cardlets-item{height:6rem;grid-template-rows:auto 38px;grid-template-areas:"content""footer"}.k-cardlets-item[data-has-figure=true]{grid-template-columns:6rem auto;grid-template-areas:"figure content""figure footer"}[dir=ltr] .k-cardlets-item .k-item-figure{border-top-left-radius:var(--rounded)}[dir=rtl] .k-cardlets-item .k-item-figure{border-top-right-radius:var(--rounded)}[dir=ltr] .k-cardlets-item .k-item-figure{border-bottom-left-radius:var(--rounded)}[dir=rtl] .k-cardlets-item .k-item-figure{border-bottom-right-radius:var(--rounded)}.k-cardlets-item .k-item-footer{padding-top:.5rem;padding-bottom:.5rem}.k-cards-item{grid-template-columns:auto;grid-template-rows:auto 1fr;grid-template-areas:"figure""content";--item-content-wrapper:0}[dir=ltr] .k-cards-item .k-item-figure,[dir=rtl] .k-cards-item .k-item-figure{border-top-right-radius:var(--rounded);border-top-left-radius:var(--rounded)}.k-cards-item .k-item-content{padding:.5rem .75rem!important;overflow:hidden}.k-cards-item .k-item-info,.k-cards-item .k-item-title{line-height:1.375rem;white-space:normal}.k-cards-item .k-item-info:after,.k-cards-item .k-item-title:after{display:inline-block;content:"\a0";width:var(--item-content-wrapper)}.k-cards-item[data-has-flag=true],.k-cards-item[data-has-options=true]{--item-content-wrapper:38px}.k-cards-item[data-has-flag=true][data-has-options=true]{--item-content-wrapper:76px}.k-cards-item[data-has-info=true] .k-item-title:after{display:none}[dir=ltr] .k-cards-item .k-item-footer{right:0}[dir=rtl] .k-cards-item .k-item-footer{left:0}.k-cards-item .k-item-footer{position:absolute;bottom:0;width:auto}.k-item-figure{overflow:hidden;flex-shrink:0}.k-cards-items{--min:13rem;--max:1fr;--gap:1.5rem;--column-gap:var(--gap);--row-gap:var(--gap);display:grid;grid-column-gap:var(--column-gap);grid-row-gap:var(--row-gap);grid-template-columns:repeat(auto-fill,minmax(var(--min),var(--max)))}@media screen and (min-width:30em){.k-cards-items[data-size=tiny]{--min:10rem}.k-cards-items[data-size=small]{--min:16rem}.k-cards-items[data-size=medium]{--min:24rem}.k-cards-items[data-size=huge],.k-cards-items[data-size=large],.k-column[data-width="1/4"] .k-cards-items,.k-column[data-width="1/5"] .k-cards-items,.k-column[data-width="1/6"] .k-cards-items{--min:1fr}}@media screen and (min-width:65em){.k-cards-items[data-size=large]{--min:32rem}}.k-cardlets-items{display:grid;grid-template-columns:repeat(auto-fill,minmax(16rem,1fr));grid-gap:.5rem}.k-list-items .k-list-item:not(:last-child){margin-bottom:2px}.k-overlay{position:fixed;top:0;right:0;bottom:0;left:0;width:100%;height:100%;z-index:var(--z-dialog);transform:translateZ(0)}.k-overlay[data-centered=true]{display:flex;align-items:center;justify-content:center}.k-overlay[data-dimmed=true]{background:var(--color-backdrop)}.k-overlay-loader{color:var(--color-white)}.k-panel[data-loading=true]{animation:LoadingCursor .5s}.k-panel[data-dragging=true],.k-panel[data-loading=true]:after{-webkit-user-select:none;-moz-user-select:none;user-select:none}.k-stats{display:grid;grid-template-columns:repeat(auto-fit,minmax(14rem,1fr));grid-gap:var(--spacing-2px)}.k-stat{display:flex;flex-direction:column;background:var(--color-white);box-shadow:var(--shadow);padding:var(--spacing-3) var(--spacing-6);line-height:var(--leading-normal);border-radius:var(--rounded)}.k-stat.k-link:hover,.k-stat[data-click=true]:hover{cursor:pointer;background:var(--color-gray-100)}.k-stat dd,.k-stat dt{display:block}.k-stat-value{font-size:var(--value);margin-bottom:var(--spacing-1);order:1}.k-stat-info,.k-stat-label{font-size:var(--text-xs)}.k-stat-label{order:2}.k-stat-info{order:3;color:var(--theme, var(--color-gray-500))}.k-stats[data-size=small]{--value:var(--text-base)}.k-stats[data-size=medium]{--value:var(--text-xl)}.k-stats[data-size=large]{--value:var(--text-2xl)}.k-stats[data-size=huge]{--value:var(--text-3xl)}.k-table{--table-row-height:38px;position:relative;table-layout:fixed;background:var(--color-white);font-size:var(--text-sm);border-spacing:0;box-shadow:var(--shadow);border-radius:var(--rounded);font-variant-numeric:tabular-nums}.k-table td,.k-table th{height:var(--table-row-height);overflow:hidden;text-overflow:ellipsis;line-height:1.25em}.k-table,.k-table td{width:100%}[dir=ltr] .k-table th:first-child{border-top-left-radius:var(--rounded)}[dir=rtl] .k-table th:first-child{border-top-right-radius:var(--rounded)}[dir=ltr] .k-table th:last-child{border-top-right-radius:var(--rounded)}[dir=rtl] .k-table th:last-child{border-top-left-radius:var(--rounded)}[dir=ltr] .k-table td:last-child,[dir=ltr] .k-table th:last-child{border-right:0}[dir=rtl] .k-table td:last-child,[dir=rtl] .k-table th:last-child{border-left:0}.k-table td:last-child,.k-table th:last-child{height:var(--table-row-height)}.k-table th,.k-table tr:not(:last-child) td{border-bottom:1px solid var(--color-background)}.k-table td:last-child{overflow:visible}[dir=ltr] .k-table td,[dir=ltr] .k-table th{border-right:1px solid var(--color-background)}[dir=rtl] .k-table td,[dir=rtl] .k-table th{border-left:1px solid var(--color-background)}.k-table tbody tr:hover td{background:rgba(239,239,239,.25)}.k-table-column[data-align]{text-align:var(--align)}.k-table-column[data-align=right]>.k-input{flex-direction:column;align-items:flex-end}.k-table th{position:sticky;top:0;left:0;right:0;width:100%;padding:0 .75rem;z-index:1;font-family:var(--font-mono);font-size:var(--text-xs);font-weight:400;color:var(--color-gray-600);background:var(--color-gray-100)}[dir=ltr] .k-table th{text-align:left}[dir=rtl] .k-table th{text-align:right}.k-table th:after{content:"";position:absolute;top:100%;left:0;right:0;height:.5rem;background:linear-gradient(to bottom,rgba(#000,.05),rgba(#000,0));z-index:2}.k-table .k-sort-handle,.k-table-index{display:grid;place-items:center;width:100%;height:var(--table-row-height)}.k-table .k-sort-handle,.k-table tr:hover .k-table-index-column[data-sortable=true] .k-table-index{display:none}.k-table tr:hover .k-sort-handle{display:grid!important}.k-table-row-ghost{background:var(--color-white);box-shadow:#11111140 0 5px 10px;outline:2px solid var(--color-focus);margin-bottom:2px;cursor:grabbing;cursor:-webkit-grabbing}.k-table-row-fallback{opacity:0!important}td.k-table-index-column,td.k-table-options-column,th.k-table-index-column,th.k-table-options-column{width:var(--table-row-height);text-align:center!important}.k-table-index{font-size:var(--text-xs);color:var(--color-gray-500);line-height:1.1em}.k-table-empty{color:var(--color-gray-600);font-size:var(--text-sm)}[data-disabled=true] .k-table{background:var(--color-background)}[dir=ltr] [data-disabled=true] .k-table td,[dir=ltr] [data-disabled=true] .k-table th{border-right:1px solid var(--color-border)}[dir=rtl] [data-disabled=true] .k-table td,[dir=rtl] [data-disabled=true] .k-table th{border-left:1px solid var(--color-border)}[data-disabled=true] .k-table td,[data-disabled=true] .k-table th{background:var(--color-background);border-bottom:1px solid var(--color-border)}[data-disabled=true] .k-table td:last-child{overflow:hidden;text-overflow:ellipsis}@media screen and (max-width:65em){.k-table td:not([data-mobile]),.k-table th:not([data-mobile]){display:none}}.k-tabs{position:relative;background:#e9e9e9;border:1px solid var(--color-border);border-radius:var(--rounded)}.k-tabs nav{display:flex;justify-content:center;margin-left:-1px;margin-right:-1px}[dir=ltr] .k-tab-button.k-button{border-left:1px solid transparent}[dir=rtl] .k-tab-button.k-button{border-right:1px solid transparent}[dir=ltr] .k-tab-button.k-button{border-right:1px solid var(--color-border)}[dir=rtl] .k-tab-button.k-button{border-left:1px solid var(--color-border)}.k-tab-button.k-button{position:relative;z-index:1;display:inline-flex;justify-content:center;align-items:center;padding:.625rem .75rem;font-size:var(--text-xs);text-transform:uppercase;text-align:center;font-weight:500;flex-grow:1;flex-shrink:1;flex-direction:column;max-width:15rem}@media screen and (min-width:30em){.k-tab-button.k-button{flex-direction:row}[dir=ltr] .k-tab-button.k-button .k-icon{margin-right:.5rem}[dir=rtl] .k-tab-button.k-button .k-icon{margin-left:.5rem}}[dir=ltr] .k-tab-button.k-button>.k-button-text{padding-left:0}[dir=rtl] .k-tab-button.k-button>.k-button-text{padding-right:0}.k-tab-button.k-button>.k-button-text{padding-top:.375rem;font-size:10px;overflow:hidden;max-width:10rem;text-overflow:ellipsis;opacity:1}@media screen and (min-width:30em){.k-tab-button.k-button>.k-button-text{font-size:var(--text-xs);padding-top:0}}[dir=ltr] .k-tab-button:last-child{border-right:1px solid transparent}[dir=rtl] .k-tab-button:last-child{border-left:1px solid transparent}[dir=ltr] .k-tab-button[aria-current]{border-right:1px solid var(--color-border)}[dir=rtl] .k-tab-button[aria-current]{border-left:1px solid var(--color-border)}.k-tab-button[aria-current]{position:relative;background:var(--color-background);pointer-events:none}[dir=ltr] .k-tab-button[aria-current]:first-child{border-left:1px solid var(--color-border)}[dir=rtl] .k-tab-button[aria-current]:first-child{border-right:1px solid var(--color-border)}.k-tab-button[aria-current]:after,.k-tab-button[aria-current]:before{position:absolute;content:""}.k-tab-button[aria-current]:before{left:-1px;right:-1px;top:-1px;height:2px;background:var(--color-black)}.k-tab-button[aria-current]:after{left:0;right:0;bottom:-1px;height:1px;background:var(--color-background)}[dir=ltr] .k-tabs-dropdown{right:0}[dir=rtl] .k-tabs-dropdown{left:0}.k-tabs-dropdown{top:100%}[dir=ltr] .k-tabs-badge{right:2px}[dir=rtl] .k-tabs-badge{left:2px}.k-tabs-badge{position:absolute;top:3px;font-variant-numeric:tabular-nums;line-height:1.5;padding:0 .25rem;border-radius:2px;font-size:10px;box-shadow:var(--shadow-md)}.k-tabs[data-theme=notice] .k-tabs-badge{background:var(--theme-light);color:var(--color-black)}.k-view{padding-left:1.5rem;padding-right:1.5rem;margin:0 auto;max-width:100rem}@media screen and (min-width:30em){.k-view{padding-left:3rem;padding-right:3rem}}@media screen and (min-width:90em){.k-view{padding-left:6rem;padding-right:6rem}}.k-view[data-align=center]{height:100vh;display:flex;align-items:center;justify-content:center;padding:0 3rem;overflow:auto}.k-view[data-align=center]>*{flex-basis:22.5rem}.k-fatal{position:fixed;top:0;right:0;bottom:0;left:0;background:var(--color-backdrop);display:flex;z-index:var(--z-fatal);align-items:center;justify-content:center;padding:1.5rem}.k-fatal-box{width:100%;height:100%;display:flex;flex-direction:column;color:var(--color-black);background:var(--color-red-400);box-shadow:var(--shadow-xl);border-radius:var(--rounded)}.k-fatal-box .k-headline{line-height:1;font-size:var(--text-sm);padding:.75rem}.k-fatal-box .k-button{padding:.75rem}.k-fatal-iframe{border:0;width:100%;flex-grow:1;background:var(--color-white)}.k-headline{--size:var(--text-base);font-size:var(--size);font-weight:var(--font-bold);line-height:1.5em}.k-headline[data-size=small]{--size:var(--text-sm)}.k-headline[data-size=large]{--size:var(--text-xl);font-weight:var(--font-normal)}@media screen and (min-width:65em){.k-headline[data-size=large]{--size:var(--text-2xl)}}.k-headline[data-size=huge]{--size:var(--text-2xl);line-height:1.15em}@media screen and (min-width:65em){.k-headline[data-size=huge]{--size:var(--text-3xl)}}.k-headline[data-theme]{color:var(--theme)}[dir=ltr] .k-headline abbr{padding-left:.25rem}[dir=rtl] .k-headline abbr{padding-right:.25rem}.k-headline abbr{color:var(--color-gray-500);text-decoration:none}.k-icon{--size:1rem;position:relative;line-height:0;display:flex;align-items:center;justify-content:center;flex-shrink:0;font-size:var(--size)}.k-icon[data-size=medium]{--size:2rem}.k-icon[data-size=large]{--size:3rem}.k-icon svg{width:var(--size);height:var(--size);-moz-transform:scale(1)}.k-icon svg *{fill:currentColor}.k-icon[data-back=black]{color:var(--color-white)}.k-icon[data-back=white]{color:var(--color-gray-900)}.k-icon[data-back=pattern]{color:var(--color-white)}[data-disabled=true] .k-icon[data-back=pattern] svg{opacity:1}.k-icon-emoji{display:block;line-height:1;font-style:normal;font-size:var(--size)}@media only screen and (-webkit-min-device-pixel-ratio:2),not all,only screen and (min-resolution:192dpi),only screen and (min-resolution:2dppx){.k-icon-emoji{font-size:1.25em}}.k-icons{position:absolute;width:0;height:0}.k-image span{position:relative;display:block;line-height:0;padding-bottom:100%}.k-image img{position:absolute;top:0;right:0;bottom:0;left:0;width:100%;height:100%;-o-object-fit:contain;object-fit:contain}[dir=ltr] .k-image-error{left:50%}[dir=rtl] .k-image-error{right:50%}.k-image-error{position:absolute;top:50%;transform:translate(-50%,-50%);color:var(--color-white);font-size:.9em}.k-image-error svg *{fill:#ffffff4d}.k-image[data-cover=true] img{-o-object-fit:cover;object-fit:cover}.k-image[data-back=black] span{background:var(--color-gray-900)}.k-image[data-back=white] span{background:var(--color-white);color:var(--color-gray-900)}.k-image[data-back=white] .k-image-error{background:var(--color-gray-900);color:var(--color-white)}.k-image[data-back=pattern] span{background:var(--color-gray-800) var(--bg-pattern)}.k-loader{z-index:1}.k-loader-icon{animation:Spin .9s linear infinite}.k-offline-warning{position:fixed;top:0;right:0;bottom:0;left:0;z-index:var(--z-offline);background:var(--color-backdrop);display:flex;align-items:center;justify-content:center;line-height:1}.k-offline-warning p{display:flex;align-items:center;gap:.5rem;background:var(--color-white);box-shadow:var(--shadow);padding:.75rem;border-radius:var(--rounded)}.k-offline-warning p .k-icon{color:var(--color-red-400)}.k-progress{-webkit-appearance:none;width:100%;height:.5rem;border-radius:5rem;background:var(--color-border);overflow:hidden;border:0}.k-progress::-webkit-progress-bar{border:0;background:var(--color-border);height:.5rem;border-radius:20px}.k-progress::-webkit-progress-value{border-radius:inherit;background:var(--color-focus);-webkit-transition:width .3s;transition:width .3s}.k-progress::-moz-progress-bar{border-radius:inherit;background:var(--color-focus);-moz-transition:width .3s;transition:width .3s}[dir=ltr] .k-registration,[dir=ltr] .k-registration p{margin-right:1rem}[dir=rtl] .k-registration,[dir=rtl] .k-registration p{margin-left:1rem}.k-registration{display:flex;align-items:center}.k-registration p{color:var(--color-negative-light);font-size:var(--text-sm);font-weight:600}@media screen and (max-width:90em){.k-registration p{display:none}}.k-registration .k-button{color:var(--color-white)}.k-sort-handle{cursor:move;cursor:grab;cursor:-webkit-grab;color:var(--color-gray-900);justify-content:center;align-items:center;line-height:0;width:2rem;height:2rem;display:flex;will-change:opacity,color;transition:opacity .3s;z-index:1}.k-sort-handle svg{width:1rem;height:1rem}.k-sort-handle:active{cursor:grabbing;cursor:-webkit-grabbing}.k-status-icon svg{width:14px;height:14px}.k-status-icon .k-icon{color:var(--theme-light)}.k-status-icon .k-button-text{color:var(--color-black)}.k-status-icon[data-disabled=true]{opacity:1!important}.k-status-icon[data-disabled=true] .k-icon{color:var(--color-gray-400);opacity:.5}.k-text{line-height:1.5em}[dir=ltr] .k-text ol,[dir=ltr] .k-text ul{margin-left:1rem}[dir=rtl] .k-text ol,[dir=rtl] .k-text ul{margin-right:1rem}.k-text li{list-style:inherit}.k-text p,.k-text>ol,.k-text>ul{margin-bottom:1.5em}.k-text a{text-decoration:underline}.k-text>:last-child{margin-bottom:0}.k-text[data-size=tiny]{font-size:var(--text-xs)}.k-text[data-size=small]{font-size:var(--text-sm)}.k-text[data-size=medium]{font-size:var(--text-base)}.k-text[data-size=large]{font-size:var(--text-xl)}.k-text[data-align]{text-align:var(--align)}.k-text[data-theme=help]{font-size:var(--text-sm);color:var(--color-gray-600);line-height:1.25rem}.k-dialog-body .k-text{word-wrap:break-word}.k-user-info{display:flex;align-items:center;line-height:1;font-size:var(--text-sm)}[dir=ltr] .k-user-info .k-image{margin-right:.75rem}[dir=rtl] .k-user-info .k-image{margin-left:.75rem}.k-user-info .k-image{width:1.5rem}[dir=ltr] .k-user-info .k-icon{margin-right:.75rem}[dir=rtl] .k-user-info .k-icon{margin-left:.75rem}.k-user-info .k-icon{width:1.5rem;height:1.5rem;background:var(--color-black);color:var(--color-white)}.k-breadcrumb{padding-left:.5rem;padding-right:.5rem}.k-breadcrumb-dropdown{height:2.5rem;width:2.5rem;display:flex;align-items:center;justify-content:center}.k-breadcrumb ol{display:none;align-items:center}@media screen and (min-width:30em){.k-breadcrumb ol{display:flex}.k-breadcrumb-dropdown{display:none}}.k-breadcrumb li,.k-breadcrumb-link{display:flex;align-items:center;min-width:0}.k-breadcrumb-link{font-size:var(--text-sm);align-self:stretch;padding-top:.625rem;padding-bottom:.625rem;line-height:1.25rem}.k-breadcrumb li{flex-shrink:3}.k-breadcrumb li:last-child{flex-shrink:1}.k-breadcrumb li:not(:last-child):after{content:"/";padding-left:.5rem;padding-right:.5rem;opacity:.5;flex-shrink:0}.k-breadcrumb li:not(:first-child):not(:last-child){max-width:15vw}[dir=ltr] .k-breadcrumb-icon{margin-right:.5rem}[dir=rtl] .k-breadcrumb-icon{margin-left:.5rem}.k-breadcrumb-icon.k-loader{opacity:.5}.k-breadcrumb-link-text{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}button{line-height:inherit;border:0;font-family:var(--font-sans);font-size:1rem;color:currentColor;background:0 0;cursor:pointer}button::-moz-focus-inner{padding:0;border:0}.k-button{display:inline-block;position:relative;font-size:var(--text-sm);transition:color .3s;outline:0}.k-button:focus,.k-button:hover{outline:0}.k-button *{vertical-align:middle}.k-button[data-responsive=true] .k-button-text{display:none}@media screen and (min-width:30em){.k-button[data-responsive=true] .k-button-text{display:inline}}.k-button[data-theme]{color:var(--theme)}.k-button-icon{display:inline-flex;align-items:center;line-height:0}[dir=ltr] .k-button-icon~.k-button-text{padding-left:.5rem}[dir=rtl] .k-button-icon~.k-button-text{padding-right:.5rem}.k-button-text{opacity:.75}.k-button:focus .k-button-text,.k-button:hover .k-button-text{opacity:1}.k-button-text b,.k-button-text span{vertical-align:baseline}.k-button[data-disabled=true]{opacity:.5;pointer-events:none;cursor:default}.k-card-options>.k-button[data-disabled=true]{display:inline-flex}.k-button-group{--padding-x:.75rem;--padding-y:1rem;--line-height:1rem;font-size:0;margin:0 calc(var(--padding-x)*-1)}.k-button-group>.k-dropdown{height:calc(var(--line-height) + (var(--padding-y)*2));display:inline-block}.k-button-group>.k-button,.k-button-group>.k-dropdown>.k-button{padding:var(--padding-y) var(--padding-x);line-height:var(--line-height)}.k-button-group .k-dropdown-content{top:calc(100% + 1px);margin:0 var(--padding-x)}.k-dropdown{position:relative}[dir=ltr] .k-dropdown-content{text-align:left}[dir=rtl] .k-dropdown-content{text-align:right}.k-dropdown-content{position:absolute;top:100%;background:var(--color-black);color:var(--color-white);z-index:var(--z-dropdown);box-shadow:var(--shadow-lg);border-radius:var(--rounded);margin-bottom:6rem}[dir=ltr] .k-dropdown-content[data-align=left]{left:0}[dir=ltr] .k-dropdown-content[data-align=right],[dir=rtl] .k-dropdown-content[data-align=left]{right:0}[dir=rtl] .k-dropdown-content[data-align=right]{left:0}.k-dropdown-content>.k-dropdown-item:first-child{margin-top:.5rem}.k-dropdown-content>.k-dropdown-item:last-child{margin-bottom:.5rem}.k-dropdown-content[data-dropup=true]{top:auto;bottom:100%;margin-bottom:.5rem}.k-dropdown-content hr{border-color:currentColor;opacity:.2;margin:.5rem 1rem}.k-dropdown-content[data-theme=light]{background:var(--color-white);color:var(--color-black)}.k-dropdown-item{white-space:nowrap;line-height:1;display:flex;width:100%;align-items:center;font-size:var(--text-sm);padding:6px 16px}.k-dropdown-item:focus{outline:0;box-shadow:var(--shadow-outline)}[dir=ltr] .k-dropdown-item .k-button-figure{padding-right:.5rem}[dir=rtl] .k-dropdown-item .k-button-figure{padding-left:.5rem}.k-dropdown-item .k-button-figure{text-align:center}.k-link{outline:0}.k-options-dropdown,.k-options-dropdown-toggle{display:flex;justify-content:center;align-items:center;height:38px}.k-options-dropdown-toggle{min-width:38px;padding:0 .75rem}.k-pagination{-webkit-user-select:none;-moz-user-select:none;user-select:none;direction:ltr}.k-pagination .k-button{padding:1rem}.k-pagination-details{white-space:nowrap}.k-pagination>span{font-size:var(--text-sm)}.k-pagination[data-align]{text-align:var(--align)}[dir=ltr] .k-dropdown-content.k-pagination-selector{left:50%}[dir=rtl] .k-dropdown-content.k-pagination-selector{right:50%}.k-dropdown-content.k-pagination-selector{position:absolute;top:100%;transform:translate(-50%);background:var(--color-black)}[dir=ltr] .k-dropdown-content.k-pagination-selector{direction:ltr}[dir=rtl] .k-dropdown-content.k-pagination-selector{direction:rtl}.k-pagination-settings{display:flex;align-items:center;justify-content:space-between}.k-pagination-settings .k-button{line-height:1}[dir=ltr] .k-pagination-settings label{border-right:1px solid rgba(255,255,255,.35)}[dir=rtl] .k-pagination-settings label{border-left:1px solid rgba(255,255,255,.35)}.k-pagination-settings label{display:flex;align-items:center;padding:.625rem 1rem;font-size:var(--text-xs)}[dir=ltr] .k-pagination-settings label span{margin-right:.5rem}[dir=rtl] .k-pagination-settings label span{margin-left:.5rem}.k-prev-next{direction:ltr}.k-search{max-width:30rem;margin:2.5rem auto;box-shadow:var(--shadow-lg);background:var(--color-light);border-radius:var(--rounded)}.k-search-input{display:flex}.k-search-types{flex-shrink:0;display:flex}[dir=ltr] .k-search-types>.k-button{padding-left:1rem}[dir=rtl] .k-search-types>.k-button{padding-right:1rem}.k-search-types>.k-button{font-size:var(--text-base);line-height:1;height:2.5rem}.k-search-types>.k-button .k-icon{height:2.5rem}.k-search-types>.k-button .k-button-text{opacity:1;font-weight:500}.k-search-input input{background:0 0;flex-grow:1;font:inherit;padding:.75rem;border:0;height:2.5rem}.k-search-close{width:3rem;line-height:1}.k-search-close .k-icon-loader{animation:Spin 2s linear infinite}.k-search input:focus{outline:0}.k-search-results{padding:.5rem 1rem 1rem}.k-search .k-item:not(:last-child){margin-bottom:.25rem}.k-search .k-item[data-selected=true]{outline:2px solid var(--color-focus)}.k-search .k-item-info,.k-search-empty{font-size:var(--text-xs)}.k-search-empty{text-align:center;color:var(--color-gray-600)}.k-tag{position:relative;font-size:var(--text-sm);line-height:1;cursor:pointer;background-color:var(--color-gray-900);color:var(--color-light);border-radius:var(--rounded);display:flex;align-items:center;justify-content:space-between;-webkit-user-select:none;-moz-user-select:none;user-select:none}.k-tag:focus{outline:0;background-color:var(--color-focus);color:#fff}.k-tag-text{padding:.3rem .75rem .375rem;line-height:var(--leading-tight)}[dir=ltr] .k-tag-toggle{padding-right:1px}[dir=rtl] .k-tag-toggle{padding-left:1px}[dir=ltr] .k-tag-toggle{border-left:1px solid rgba(255,255,255,.15)}[dir=rtl] .k-tag-toggle{border-right:1px solid rgba(255,255,255,.15)}.k-tag-toggle{color:#ffffffb3;width:1.75rem;height:100%}.k-tag-toggle:hover{background:rgba(255,255,255,.2);color:#fff}[data-disabled=true] .k-tag{background-color:var(--color-gray-600)}[data-disabled=true] .k-tag .k-tag-toggle{display:none}.k-topbar{--bg:var(--color-gray-900);position:relative;color:var(--color-white);flex-shrink:0;height:2.5rem;line-height:1;background:var(--bg)}.k-topbar-wrapper{position:relative;display:flex;align-items:center;margin-left:-.75rem;margin-right:-.75rem}[dir=ltr] .k-topbar-wrapper:after{left:100%}[dir=rtl] .k-topbar-wrapper:after{right:100%}.k-topbar-wrapper:after{position:absolute;content:"";height:2.5rem;background:var(--bg);width:3rem}.k-topbar-menu{flex-shrink:0}.k-topbar-menu ul{padding:.5rem 0}.k-topbar .k-button[data-theme]{color:var(--theme-light)}.k-topbar .k-button-text{opacity:1}.k-topbar-menu-button{display:flex;align-items:center}.k-topbar-menu .k-link[aria-current]{color:var(--color-focus);font-weight:500}.k-topbar-button{padding:.75rem;line-height:1;font-size:var(--text-sm)}.k-topbar-button .k-button-text{display:flex}[dir=ltr] .k-topbar-view-button{padding-right:0}[dir=rtl] .k-topbar-view-button{padding-left:0}.k-topbar-view-button{flex-shrink:0;display:flex;align-items:center}[dir=ltr] .k-topbar-view-button .k-icon{margin-right:.5rem}[dir=rtl] .k-topbar-view-button .k-icon{margin-left:.5rem}[dir=ltr] .k-topbar-signals{right:0}[dir=rtl] .k-topbar-signals{left:0}.k-topbar-signals{position:absolute;top:0;background:var(--bg);height:2.5rem;display:flex;align-items:center}.k-topbar-signals:before{position:absolute;content:"";top:-.5rem;bottom:0;width:.5rem;background:-webkit-linear-gradient(inline-start,rgba(17,17,17,0),#111)}.k-topbar-signals .k-button{line-height:1}.k-topbar-notification{font-weight:var(--font-bold);line-height:1;display:flex}@media screen and (max-width:30em){.k-topbar .k-button[data-theme=negative] .k-button-text{display:none}}.k-section,.k-sections{padding-bottom:3rem}.k-section-header{position:relative;display:flex;align-items:baseline;z-index:1}[dir=ltr] .k-section-header .k-headline{padding-right:var(--spacing-3)}[dir=rtl] .k-section-header .k-headline{padding-left:var(--spacing-3)}.k-section-header .k-headline{line-height:1.25rem;min-height:2rem;flex-grow:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}[dir=ltr] .k-section-header .k-button-group{right:0}[dir=rtl] .k-section-header .k-button-group{left:0}.k-section-header .k-button-group{position:absolute;top:calc(-.5rem - 1px)}.k-section-header .k-button-group>.k-button{padding:.75rem;display:inline-flex}.k-fields-issue-headline{margin-bottom:.5rem}.k-fields-section input[type=submit]{display:none}[data-locked=true] .k-fields-section{opacity:.2;pointer-events:none}.k-models-section[data-processing=true]{pointer-events:none}.k-models-section-search.k-input{margin-bottom:var(--spacing-3);background:var(--color-gray-300);padding:var(--spacing-2) var(--spacing-3);height:var(--field-input-height);border-radius:var(--rounded);font-size:var(--text-sm)}.k-info-section-headline{margin-bottom:.5rem}.k-user-profile{background:var(--color-white)}.k-user-profile>.k-view{padding-top:3rem;padding-bottom:3rem;display:flex;align-items:center;line-height:0}[dir=ltr] .k-user-profile .k-button-group{margin-left:.75rem}[dir=rtl] .k-user-profile .k-button-group{margin-right:.75rem}.k-user-profile .k-button-group{overflow:hidden}.k-user-profile .k-button-group .k-button{display:block;padding-top:.25rem;padding-bottom:.25rem;overflow:hidden;white-space:nowrap}.k-user-view-image .k-icon,.k-user-view-image .k-image{width:5rem;height:5rem;border-radius:var(--rounded);line-height:0;overflow:hidden}.k-user-view-image[data-disabled=true]{opacity:1}.k-user-view-image .k-image{display:block}.k-user-view-image .k-button-text{opacity:1}.k-user-name-placeholder{color:var(--color-gray-500);transition:color .3s}.k-header[data-editable=true] .k-user-name-placeholder:hover{color:var(--color-gray-900)}.k-error-view{position:absolute;top:0;right:0;bottom:0;left:0;display:flex;align-items:center;justify-content:center}.k-error-view-content{line-height:1.5em;max-width:25rem;text-align:center}.k-error-view-icon{color:var(--color-negative);display:inline-block}.k-error-view-content p:not(:last-child){margin-bottom:.75rem}.k-installation-view .k-button{display:block;margin-top:1.5rem}.k-installation-view .k-headline{margin-bottom:.75rem}.k-installation-issues{line-height:1.5em;font-size:var(--text-sm)}[dir=ltr] .k-installation-issues li{padding-left:3.5rem}[dir=rtl] .k-installation-issues li{padding-right:3.5rem}.k-installation-issues li{position:relative;padding:1.5rem;background:var(--color-white)}[dir=ltr] .k-installation-issues .k-icon{left:1.5rem}[dir=rtl] .k-installation-issues .k-icon{right:1.5rem}.k-installation-issues .k-icon{position:absolute;top:calc(1.5rem + 2px)}.k-installation-issues .k-icon svg *{fill:var(--color-negative)}.k-installation-issues li:not(:last-child){margin-bottom:2px}.k-installation-issues li code{font:inherit;color:var(--color-negative)}[dir=ltr] .k-installation-view .k-button[type=submit]{margin-left:-1rem}[dir=rtl] .k-installation-view .k-button[type=submit]{margin-right:-1rem}.k-installation-view .k-button[type=submit]{padding:1rem}.k-languages-view .k-header{margin-bottom:1.5rem}.k-languages-view-section-header{margin-bottom:.5rem}.k-languages-view-section{margin-bottom:3rem}.k-login-fields{position:relative}[dir=ltr] .k-login-toggler{right:0}[dir=rtl] .k-login-toggler{left:0}.k-login-toggler{position:absolute;top:0;z-index:1;text-decoration:underline;font-size:.875rem}.k-login-form label abbr{visibility:hidden}.k-login-buttons{display:flex;align-items:center;justify-content:flex-end;padding:1.5rem 0}[dir=ltr] .k-login-button{margin-right:-1rem}[dir=rtl] .k-login-button{margin-left:-1rem}.k-login-button{padding:.5rem 1rem;font-weight:500;transition:opacity .3s}.k-login-button span{opacity:1}.k-login-button[disabled]{opacity:.25}.k-login-back-button,.k-login-checkbox{display:flex;align-items:center;flex-grow:1}[dir=ltr] .k-login-back-button{margin-left:-1rem}[dir=rtl] .k-login-back-button{margin-right:-1rem}.k-login-checkbox{padding:.5rem 0;font-size:var(--text-sm);cursor:pointer}.k-login-checkbox .k-checkbox-text{opacity:.75;transition:opacity .3s}.k-login-checkbox:focus span,.k-login-checkbox:hover span{opacity:1}.k-password-reset-view .k-user-info{height:38px;margin-bottom:2.25rem;padding:.5rem;background:var(--color-white);border-radius:var(--rounded-xs);box-shadow:var(--shadow)}.k-system-view .k-header{margin-bottom:1.5rem}.k-system-view-section-header{margin-bottom:.5rem;display:flex;justify-content:space-between}.k-system-view-section{margin-bottom:3rem}.k-system-info [data-theme] .k-stat-value{color:var(--theme)}.k-block-type-code-editor{position:relative;font-size:var(--text-sm);line-height:1.5em;background:#000;border-radius:var(--rounded);padding:.5rem .75rem 3rem;color:#fff;font-family:var(--font-mono)}.k-block-type-code-editor .k-editor{white-space:pre-wrap;line-height:1.75em}[dir=ltr] .k-block-type-code-editor-language{right:0}[dir=ltr] .k-block-type-code-editor-language .k-icon,[dir=rtl] .k-block-type-code-editor-language{left:0}.k-block-type-code-editor-language{font-size:var(--text-sm);position:absolute;bottom:0}[dir=rtl] .k-block-type-code-editor-language .k-icon{right:0}.k-block-type-code-editor-language .k-icon{position:absolute;top:0;height:1.5rem;display:flex;width:2rem;z-index:0}.k-block-type-code-editor-language .k-select-input{position:relative;padding:.325rem .75rem .5rem 2rem;z-index:1;font-size:var(--text-xs)}.k-block-type-default .k-block-title{line-height:1.5em}.k-block-type-gallery ul{display:grid;grid-gap:.75rem;grid-template-columns:repeat(auto-fit,minmax(6rem,1fr));line-height:0;align-items:center;justify-content:center;cursor:pointer}.k-block-type-gallery li:empty{padding-bottom:100%;background:var(--color-background)}.k-block-type-gallery li{display:flex;position:relative;align-items:center;justify-content:center}.k-block-type-gallery li img{flex-grow:1;max-width:100%}.k-block-type-heading-input{line-height:1.25em;font-weight:var(--font-bold)}.k-block-type-heading-input[data-level=h1]{font-size:var(--text-3xl);line-height:1.125em}.k-block-type-heading-input[data-level=h2]{font-size:var(--text-2xl)}.k-block-type-heading-input[data-level=h3]{font-size:var(--text-xl)}.k-block-type-heading-input[data-level=h4]{font-size:var(--text-lg)}.k-block-type-heading-input[data-level=h5]{line-height:1.5em;font-size:var(--text-base)}.k-block-type-heading-input[data-level=h6]{line-height:1.5em;font-size:var(--text-sm)}.k-block-type-heading-input .ProseMirror strong{font-weight:700}.k-block-type-image .k-block-figure-container{display:block;text-align:center;line-height:0}.k-block-type-image-auto{max-width:100%;max-height:30rem}.k-block-type-line hr{margin-top:.75rem;margin-bottom:.75rem;border:0;border-top:2px solid var(--color-gray-400)}.k-block-type-markdown-input{position:relative;font-size:var(--text-sm);line-height:1.5em;background:var(--color-background);border-radius:var(--rounded);padding:.5rem .5rem 0;font-family:var(--font-mono)}[dir=ltr] .k-block-type-quote-editor{padding-left:1rem}[dir=rtl] .k-block-type-quote-editor{padding-right:1rem}[dir=ltr] .k-block-type-quote-editor{border-left:2px solid var(--color-black)}[dir=rtl] .k-block-type-quote-editor{border-right:2px solid var(--color-black)}.k-block-type-quote-text{font-size:var(--text-xl);margin-bottom:.25rem;line-height:1.25em}.k-block-type-quote-citation{font-style:italic;font-size:var(--text-sm);color:var(--color-gray-600)}.k-block-type-table-preview{cursor:pointer;border:1px solid var(--color-gray-300);border-spacing:0;border-radius:var(--rounded-sm);overflow:hidden}[dir=ltr] .k-block-type-table-preview td,[dir=ltr] .k-block-type-table-preview th{text-align:left}[dir=rtl] .k-block-type-table-preview td,[dir=rtl] .k-block-type-table-preview th{text-align:right}.k-block-type-table-preview td,.k-block-type-table-preview th{line-height:1.5em;font-size:var(--text-sm)}.k-block-type-table-preview th{padding:.5rem .75rem}.k-block-type-table-preview td:not(.k-table-index-column){padding:0 .75rem}.k-block-type-table-preview td [class$=-field-preview],.k-block-type-table-preview td>*{padding:0}.k-block-type-text-input{font-size:var(--text-base);line-height:1.5em;height:100%}.k-block-container-type-text,.k-block-type-text,.k-block-type-text .k-writer .ProseMirror{height:100%}.k-block-container{position:relative;padding:.75rem;background:var(--color-white);border-radius:var(--rounded)}.k-block-container:not(:last-of-type){border-bottom:1px dashed rgba(0,0,0,.1)}.k-block-container:focus{outline:0}.k-block-container[data-batched=true],.k-block-container[data-selected=true]{z-index:2;border-bottom-color:transparent}.k-block-container[data-batched=true]:after{position:absolute;top:0;right:0;bottom:0;left:0;content:"";background:rgba(238,242,246,.375);mix-blend-mode:multiply;border:1px solid var(--color-focus)}.k-block-container[data-selected=true]{box-shadow:var(--color-focus) 0 0 0 1px,var(--color-focus-outline) 0 0 0 3px}[dir=ltr] .k-block-container .k-block-options{right:.75rem}[dir=rtl] .k-block-container .k-block-options{left:.75rem}.k-block-container .k-block-options{display:none;position:absolute;top:0;margin-top:calc(-1.75rem + 2px)}.k-block-container[data-last-in-batch=true]>.k-block-options,.k-block-container[data-selected=true]>.k-block-options{display:flex}.k-block-container[data-hidden=true] .k-block{opacity:.25}.k-drawer-options .k-button[data-disabled=true]{vertical-align:middle;display:inline-grid}[data-disabled=true] .k-block-container{background:var(--color-background)}.k-block-importer.k-dialog{background:#313740;color:var(--color-white)}.k-block-importer .k-dialog-body{padding:0}.k-block-importer label{display:block;padding:var(--spacing-6) var(--spacing-6)0;color:var(--color-gray-400)}.k-block-importer label kbd{background:rgba(0,0,0,.5);font-family:var(--font-mono);letter-spacing:.1em;padding:.25rem;border-radius:var(--rounded);margin:0 .25rem}.k-block-importer textarea{width:100%;height:20rem;background:0 0;font:inherit;color:var(--color-white);border:0;padding:var(--spacing-6);resize:none}.k-block-importer textarea:focus{outline:0}.k-blocks{background:var(--color-white);box-shadow:var(--shadow);border-radius:var(--rounded)}[data-disabled=true] .k-blocks{background:var(--color-background)}.k-blocks[data-multi-select-key=true] .k-block-container>*{pointer-events:none}.k-blocks[data-empty=true]{padding:0;background:0 0;box-shadow:none}.k-blocks .k-sortable-ghost{outline:2px solid var(--color-focus);box-shadow:#11111140 0 5px 10px;cursor:grabbing;cursor:-webkit-grabbing}.k-blocks-list>.k-blocks-empty{display:flex;align-items:center}.k-blocks-list>.k-blocks-empty:not(:only-child){display:none}.k-block-figure{cursor:pointer}.k-block-figure iframe{border:0;pointer-events:none;background:var(--color-black)}.k-block-figure figcaption{padding-top:.5rem;color:var(--color-gray-600);font-size:var(--text-sm);text-align:center}.k-block-figure-empty.k-button{display:flex;width:100%;height:6rem;border-radius:var(--rounded-sm);align-items:center;justify-content:center;color:var(--color-gray-600);background:var(--color-background)}.k-block-options{display:flex;align-items:center;background:var(--color-white);z-index:var(--z-dropdown);box-shadow:#0000001a -2px 0 5px,var(--shadow),var(--shadow-xl);color:var(--color-black);border-radius:var(--rounded)}[dir=ltr] .k-block-options-button{border-right:1px solid var(--color-background)}[dir=rtl] .k-block-options-button{border-left:1px solid var(--color-background)}.k-block-options-button{--block-options-button-size:30px;width:var(--block-options-button-size);height:var(--block-options-button-size);line-height:1;display:inline-flex;align-items:center;justify-content:center}[dir=ltr] .k-block-options-button:first-child{border-top-left-radius:var(--rounded)}[dir=rtl] .k-block-options-button:first-child{border-top-right-radius:var(--rounded)}[dir=ltr] .k-block-options-button:first-child{border-bottom-left-radius:var(--rounded)}[dir=rtl] .k-block-options-button:first-child{border-bottom-right-radius:var(--rounded)}[dir=ltr] .k-block-options-button:last-child{border-top-right-radius:var(--rounded)}[dir=rtl] .k-block-options-button:last-child{border-top-left-radius:var(--rounded)}[dir=ltr] .k-block-options-button:last-child{border-bottom-right-radius:var(--rounded)}[dir=rtl] .k-block-options-button:last-child{border-bottom-left-radius:var(--rounded)}[dir=ltr] .k-block-options-button:last-of-type{border-right:0}[dir=rtl] .k-block-options-button:last-of-type{border-left:0}.k-block-options-button[aria-current]{color:var(--color-focus)}.k-block-options-button:hover{background:var(--color-gray-100)}.k-block-options .k-dropdown-content{margin-top:.5rem}.k-block-selector.k-dialog{background:var(--color-dark);color:var(--color-white)}.k-block-selector .k-headline{margin-bottom:1rem}.k-block-selector details:not(:last-of-type){margin-bottom:1.5rem}.k-block-selector summary{font-size:var(--text-xs);cursor:pointer;color:var(--color-gray-400)}.k-block-selector details:only-of-type summary{pointer-events:none}.k-block-selector summary:focus{outline:0}.k-block-selector summary:focus-visible{color:var(--color-green-400)}.k-block-types{display:grid;grid-gap:2px;margin-top:.75rem;grid-template-columns:repeat(1,1fr)}[dir=ltr] .k-block-types .k-button{text-align:left}[dir=rtl] .k-block-types .k-button{text-align:right}.k-block-types .k-button{display:flex;align-items:flex-start;border-radius:var(--rounded);background:rgba(0,0,0,.5);width:100%;padding:0 .75rem 0 0;line-height:1.5em}.k-block-types .k-button:focus{outline:2px solid var(--color-green-300)}.k-block-types .k-button .k-button-text{padding:.5rem 0 .5rem .5rem}.k-block-types .k-button .k-icon{width:38px;height:38px}.k-clipboard-hint{padding-top:1.5rem;font-size:var(--text-xs);color:var(--color-gray-400)}.k-clipboard-hint kbd{background:rgba(0,0,0,.5);font-family:var(--font-mono);letter-spacing:.1em;padding:.25rem;border-radius:var(--rounded);margin:0 .25rem}[dir=ltr] .k-block-title{padding-right:.75rem}[dir=rtl] .k-block-title{padding-left:.75rem}.k-block-title{display:flex;align-items:center;min-width:0;font-size:var(--text-sm);line-height:1}[dir=ltr] .k-block-icon{margin-right:.5rem}[dir=rtl] .k-block-icon{margin-left:.5rem}.k-block-icon{width:1rem;color:var(--color-gray-500)}[dir=ltr] .k-block-name{margin-right:.5rem}[dir=rtl] .k-block-name{margin-left:.5rem}.k-block-label{color:var(--color-gray-600);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.k-bubbles-field-preview{padding:.325rem .75rem}.k-text-field-preview{padding:.325rem .75rem;overflow-x:hidden;text-overflow:ellipsis;white-space:nowrap}.k-url-field-preview{padding:.325rem .75rem}.k-url-field-preview a{color:var(--color-focus);text-decoration:underline;transition:color .3s;white-space:nowrap;max-width:100%}.k-url-field-preview a:hover{color:var(--color-black)}.k-flag-field-preview{height:var(--table-row-height);width:var(--table-row-height);display:flex;justify-content:center;align-items:center}.k-html-field-preview{padding:.325rem .75rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;line-height:1.5em}.k-html-field-preview p:not(:last-child){margin-bottom:1.5em}[dir=ltr] .k-html-field-preview ol,[dir=ltr] .k-html-field-preview ul{margin-left:1rem}[dir=rtl] .k-html-field-preview ol,[dir=rtl] .k-html-field-preview ul{margin-right:1rem}.k-html-field-preview ul>li{list-style:disc}.k-html-field-preview ol ul>li,.k-html-field-preview ul ul>li{list-style:circle}.k-html-field-preview ol>li{list-style:decimal}.k-html-field-preview ol>li::marker{color:var(--color-gray-500);font-size:var(--text-xs)}.k-toggle-field-preview label{padding:0 .25rem 0 .75rem;display:flex;height:38px;cursor:pointer;overflow:hidden;white-space:nowrap}[dir=ltr] .k-toggle-field-preview .k-toggle-input-label{padding-left:.5rem}[dir=ltr] [data-align=right] .k-toggle-field-preview .k-toggle-input-label,[dir=rtl] .k-toggle-field-preview .k-toggle-input-label{padding-right:.5rem}[dir=rtl] [data-align=right] .k-toggle-field-preview .k-toggle-input-label{padding-left:.5rem}[dir=ltr] .k-toggle-field-preview .k-toggle-input{padding-left:.75rem;padding-right:.25rem}.k-toggle-field-preview .k-toggle-input{padding-top:0;padding-bottom:0}[dir=ltr] [data-align=right] .k-toggle-field-preview .k-toggle-input,[dir=rtl] .k-toggle-field-preview .k-toggle-input{padding-left:.25rem;padding-right:.75rem}[dir=rtl] [data-align=right] .k-toggle-field-preview .k-toggle-input{padding-right:.25rem;padding-left:.75rem}[data-align=right] .k-toggle-field-preview .k-toggle-input{flex-direction:row-reverse}[data-align=left]{--align:start}[data-align=center]{--align:center}[data-align=right]{--align:end}[data-invalid=true]{border:1px solid var(--color-negative-outline);box-shadow:var(--color-negative-outline) 0 0 3px 2px}[data-invalid=true]:focus-within{border:var(--field-input-invalid-focus-border)!important;box-shadow:var(--color-negative-outline) 0 0 0 2px!important}[data-tabbed=true]{box-shadow:var(--shadow-outline);border-radius:var(--rounded)}[data-theme=positive],[data-theme=success]{--theme:var(--color-positive);--theme-light:var(--color-positive-light);--theme-bg:var(--color-green-300)}[data-theme=error],[data-theme=negative]{--theme:var(--color-negative);--theme-light:var(--color-negative-light);--theme-bg:var(--color-red-300)}[data-theme=notice]{--theme:var(--color-notice);--theme-light:var(--color-notice-light);--theme-bg:var(--color-orange-300)}[data-theme=info]{--theme:var(--color-focus);--theme-light:var(--color-focus-light);--theme-bg:var(--color-blue-200)}.scroll-x,.scroll-x-auto,.scroll-y,.scroll-y-auto{-webkit-overflow-scrolling:touch;transform:translateZ(0)}.scroll-x,.scroll-x-auto{overflow-x:scroll;overflow-y:hidden}.scroll-x-auto{overflow-x:auto}.scroll-y,.scroll-y-auto{overflow-x:hidden;overflow-y:scroll}.scroll-y-auto{overflow-y:auto}.input-hidden{position:absolute;-webkit-appearance:none;-moz-appearance:none;appearance:none;width:0;height:0;opacity:0}.k-offscreen,.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0} diff --git a/kirby/panel/dist/css/style.min.css b/kirby/panel/dist/css/style.min.css deleted file mode 100644 index 98c734d..0000000 --- a/kirby/panel/dist/css/style.min.css +++ /dev/null @@ -1 +0,0 @@ -.k-items{position:relative;display:grid;container-type:inline-size}.k-items[data-layout=list]{gap:2px}.k-items[data-layout=cardlets]{--items-size: 1fr;display:grid;gap:.75rem;grid-template-columns:repeat(auto-fill,minmax(var(--items-size),1fr))}@container (min-width: 15rem){.k-items[data-layout=cardlets]{--items-size: 15rem}}.k-items[data-layout=cards]{display:grid;gap:1.5rem;grid-template-columns:1fr}@container (min-width: 6rem){.k-items[data-layout=cards][data-size=tiny]{grid-template-columns:repeat(auto-fill,minmax(6rem,1fr))}}@container (min-width: 9rem){.k-items[data-layout=cards][data-size=small]{grid-template-columns:repeat(auto-fill,minmax(9rem,1fr))}}@container (min-width: 12rem){.k-items[data-layout=cards][data-size=auto],.k-items[data-layout=cards][data-size=medium]{grid-template-columns:repeat(auto-fill,minmax(12rem,1fr))}}@container (min-width: 15rem){.k-items[data-layout=cards][data-size=large]{grid-template-columns:repeat(auto-fill,minmax(15rem,1fr))}}@container (min-width: 18rem){.k-items[data-layout=cards][data-size=huge]{grid-template-columns:repeat(auto-fill,minmax(18rem,1fr))}}.k-collection-footer{display:flex;justify-content:space-between;align-items:flex-start;flex-wrap:nowrap;gap:var(--spacing-12);margin-top:var(--spacing-2)}.k-empty{max-width:100%}:root{--item-button-height: var(--height-md);--item-button-width: var(--height-md);--item-height: auto;--item-height-cardlet: calc(var(--height-md) * 3)}.k-item{position:relative;background:var(--color-white);box-shadow:var(--shadow);border-radius:var(--rounded);height:var(--item-height);container-type:inline-size}.k-item:has(a:focus){outline:2px solid var(--color-focus)}@supports not selector(:has(*)){.k-item:focus-within{outline:2px solid var(--color-focus)}}.k-item .k-icon-frame{--back: var(--color-gray-300)}.k-item-content{line-height:1.25;overflow:hidden;padding:var(--spacing-2)}.k-item-content a:focus{outline:0}.k-item-content a:after{content:"";position:absolute;top:0;right:0;bottom:0;left:0}.k-item-info{color:var(--color-text-dimmed)}.k-item-options{transform:translate(0);z-index:1;display:flex;align-items:center;justify-content:space-between}.k-item-options[data-only-option=true]{justify-content:flex-end}.k-item-options .k-button{--button-height: var(--item-button-height);--button-width: var(--item-button-width)}.k-item .k-sort-button{position:absolute;z-index:2}.k-item:not(:hover):not(.k-sortable-fallback) .k-sort-button{opacity:0}.k-item[data-layout=list]{--item-height: var( --field-input-height );--item-button-height: var(--item-height);--item-button-width: auto;display:grid;height:var(--item-height);align-items:center;grid-template-columns:1fr auto}.k-item[data-layout=list][data-has-image=true]{grid-template-columns:var(--item-height) 1fr auto}.k-item[data-layout=list] .k-frame{--ratio: 1/1;border-start-start-radius:var(--rounded);border-end-start-radius:var(--rounded);height:var(--item-height)}.k-item[data-layout=list] .k-item-content{display:flex;min-width:0;white-space:nowrap;gap:var(--spacing-2);justify-content:space-between}.k-item[data-layout=list] .k-item-title,.k-item[data-layout=list] .k-item-info{overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.k-item[data-layout=list] .k-item-title{flex-shrink:1}.k-item[data-layout=list] .k-item-info{flex-shrink:2}@container (max-width: 30rem){.k-item[data-layout=list] .k-item-title{overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.k-item[data-layout=list] .k-item-info{display:none}}.k-item[data-layout=list] .k-sort-button{--button-width: calc(1.5rem + var(--spacing-1));--button-height: var(--item-height);left:calc(-1 * var(--button-width))}.k-item:is([data-layout=cardlets],[data-layout=cards]) .k-sort-button{top:var(--spacing-2);inset-inline-start:var(--spacing-2);background:#ffffff7f;-webkit-backdrop-filter:blur(5px);backdrop-filter:blur(5px);box-shadow:0 2px 5px #0003;--button-width: 1.5rem;--button-height: 1.5rem;--button-rounded: var(--rounded-sm);--button-padding: 0;--icon-size: 14px}.k-item:is([data-layout=cardlets],[data-layout=cards]) .k-sort-button:hover{background:#fffffff2}.k-item[data-layout=cardlets]{--item-height: var(--item-height-cardlet);display:grid;grid-template-areas:"content" "options";grid-template-columns:1fr;grid-template-rows:1fr var(--height-md)}.k-item[data-layout=cardlets][data-has-image=true]{grid-template-areas:"image content" "image options";grid-template-columns:minmax(0,var(--item-height)) 1fr}.k-item[data-layout=cardlets] .k-frame{grid-area:image;border-start-start-radius:var(--rounded);border-end-start-radius:var(--rounded);aspect-ratio:auto;height:var(--item-height)}.k-item[data-layout=cardlets] .k-item-content{grid-area:content}.k-item[data-layout=cardlets] .k-item-info{margin-top:.125em;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.k-item[data-layout=cardlets] .k-item-options{grid-area:options}.k-item[data-layout=cards]{display:flex;flex-direction:column}.k-item[data-layout=cards] .k-frame{border-start-start-radius:var(--rounded);border-start-end-radius:var(--rounded)}.k-item[data-layout=cards] .k-item-content{flex-grow:1;padding:var(--spacing-2)}.k-item[data-layout=cards] .k-item-info{margin-top:.125em}.k-item[data-theme=disabled]{background:transparent;box-shadow:none;outline:1px solid var(--color-border);outline-offset:-1px}.k-dialog-body{padding:var(--dialog-padding)}.k-dialog[data-has-footer=true] .k-dialog-body{padding-bottom:0}.k-button-group.k-dialog-buttons{display:grid;grid-template-columns:1fr 1fr;gap:var(--spacing-3);--button-height: var(--height-lg)}.k-dialog-fields{padding-bottom:.5rem;container-type:inline-size}.k-dialog-footer{padding:var(--dialog-padding);line-height:1;flex-shrink:0}.k-dialog .k-notification{padding-block:.325rem;border-start-start-radius:var(--dialog-rounded);border-start-end-radius:var(--dialog-rounded);margin-top:-1px}.k-dialog-search{margin-bottom:.75rem;--input-color-border: transparent;--input-color-back: var(--color-gray-300)}:root{--dialog-color-back: var(--color-light);--dialog-color-text: currentColor;--dialog-margin: var(--spacing-6);--dialog-padding: var(--spacing-6);--dialog-rounded: var(--rounded-xl);--dialog-shadow: var(--shadow-xl);--dialog-width: 22rem}.k-dialog-portal{padding:var(--dialog-margin)}.k-dialog{position:relative;background:var(--dialog-color-back);color:var(--dialog-color-text);width:clamp(10rem,100%,var(--dialog-width));box-shadow:var(--dialog-shadow);border-radius:var(--dialog-rounded);line-height:1;display:flex;flex-direction:column;overflow:clip;container-type:inline-size}@media screen and (min-width: 20rem){.k-dialog[data-size=small]{--dialog-width: 20rem}}@media screen and (min-width: 22rem){.k-dialog[data-size=default]{--dialog-width: 22rem}}@media screen and (min-width: 30rem){.k-dialog[data-size=medium]{--dialog-width: 30rem}}@media screen and (min-width: 40rem){.k-dialog[data-size=large]{--dialog-width: 40rem}}@media screen and (min-width: 60rem){.k-dialog[data-size=huge]{--dialog-width: 60rem}}.k-dialog .k-pagination{margin-bottom:-1.5rem;display:flex;justify-content:center;align-items:center}.k-changes-dialog .k-headline{margin-top:-.5rem;margin-bottom:var(--spacing-3)}.k-error-details{background:var(--color-white);display:block;overflow:auto;padding:1rem;font-size:var(--text-sm);line-height:1.25em;margin-top:.75rem}.k-error-details dt{color:var(--color-red-500);margin-bottom:.25rem}.k-error-details dd{overflow:hidden;overflow-wrap:break-word;text-overflow:ellipsis}.k-error-details dd:not(:last-of-type){margin-bottom:1.5em}.k-error-details li{white-space:pre-line}.k-error-details li:not(:last-child){border-bottom:1px solid var(--color-background);padding-bottom:.25rem;margin-bottom:.25rem}.k-models-dialog .k-list-item{cursor:pointer}.k-models-dialog .k-collection-footer .k-pagination{margin-bottom:0}.k-license-dialog-status{display:flex;align-items:center;gap:var(--spacing-2)}.k-license-dialog .k-icon{color:var(--theme-color-700)}.k-page-template-switch{margin-bottom:var(--spacing-6);padding-bottom:var(--spacing-6);border-bottom:1px dashed var(--color-gray-300)}.k-page-move-dialog .k-headline{margin-bottom:var(--spacing-2)}.k-page-move-parent{--tree-color-back: var(--color-white);--tree-color-hover-back: var(--color-light);padding:var(--spacing-3);background:var(--color-white);border-radius:var(--rounded);box-shadow:var(--shadow)}.k-pages-dialog-navbar{display:flex;align-items:center;justify-content:center;margin-bottom:.5rem;padding-inline-end:38px}.k-pages-dialog-navbar .k-button[aria-disabled]{opacity:0}.k-pages-dialog-navbar .k-headline{flex-grow:1;text-align:center}.k-pages-dialog-option[aria-disabled]{opacity:.25}.k-search-dialog{--dialog-padding: 0;--dialog-rounded: var(--rounded);overflow:visible}.k-overlay[open][data-type=dialog]>.k-portal>.k-search-dialog{margin-top:0}.k-search-dialog-input{--button-height: var(--input-height);display:flex;align-items:center}.k-search-dialog-types{flex-shrink:0}.k-search-dialog-input input{flex-grow:1;padding-inline:.75rem;height:var(--input-height);border-left:1px solid var(--color-border);line-height:var(--input-height);border-radius:var(--rounded);font-size:var(--input-font-size)}.k-search-dialog-input input:focus{outline:0}.k-search-dialog-input .k-search-dialog-close{flex-shrink:0}.k-search-dialog-results{border-top:1px solid var(--color-border);padding:1rem}.k-search-dialog-results .k-item[data-selected=true]{outline:var(--outline)}.k-search-dialog-footer{text-align:center}.k-search-dialog-footer p{color:var(--color-text-dimmed)}.k-search-dialog-footer .k-button{margin-top:var(--spacing-4)}.k-totp-dialog-headline{margin-bottom:var(--spacing-1)}.k-totp-dialog-intro{margin-bottom:var(--spacing-6)}.k-totp-dialog-grid{display:grid;gap:var(--spacing-6)}@media screen and (min-width: 40rem){.k-totp-dialog-grid{grid-template-columns:1fr 1fr;gap:var(--spacing-8)}}.k-totp-qrcode .k-box[data-theme]{padding:var(--box-padding-inline)}.k-totp-dialog-fields .k-field-name-confirm{--input-height: var(--height-xl);--input-rounded: var(--rounded);--input-font-size: var(--text-3xl)}.k-upload-dialog.k-dialog{--dialog-width: 40rem}.k-upload-replace-dialog .k-upload-items{display:flex;gap:var(--spacing-3);align-items:center}.k-upload-original{width:6rem;border-radius:var(--rounded);box-shadow:var(--shadow);overflow:hidden}.k-upload-replace-dialog .k-upload-item{flex-grow:1}.k-drawer-body{padding:var(--drawer-body-padding);flex-grow:1;background:var(--color-background)}.k-drawer-body .k-writer-input:focus-within .k-toolbar:not([data-inline=true]),.k-drawer-body .k-textarea-input-wrapper:focus-within .k-toolbar,.k-drawer-body .k-table th{top:-1.5rem}.k-drawer-header{--button-height: calc(var(--drawer-header-height) - var(--spacing-1));flex-shrink:0;height:var(--drawer-header-height);padding-inline-start:var(--drawer-header-padding);display:flex;align-items:center;line-height:1;justify-content:space-between;background:var(--color-white);font-size:var(--text-sm)}.k-drawer-breadcrumb{flex-grow:1}.k-drawer-options{display:flex;align-items:center;padding-inline-end:.75rem}.k-drawer-option{--button-width: var(--button-height)}.k-drawer-option[aria-disabled]{opacity:var(--opacity-disabled)}.k-notification.k-drawer-notification{padding:.625rem 1.5rem}.k-drawer-tabs{display:flex;align-items:center;line-height:1}.k-drawer-tab.k-button{--button-height: calc(var(--drawer-header-height) - var(--spacing-1));--button-padding: var(--spacing-3);display:flex;align-items:center;font-size:var(--text-xs);overflow-x:visible}.k-drawer-tab.k-button[aria-current]:after{position:absolute;bottom:-2px;inset-inline:var(--button-padding);content:"";background:var(--color-black);height:2px;z-index:1}:root{--drawer-body-padding: 1.5rem;--drawer-color-back: var(--color-light);--drawer-header-height: 2.5rem;--drawer-header-padding: 1rem;--drawer-shadow: var(--shadow-xl);--drawer-width: 50rem}.k-drawer-overlay+.k-drawer-overlay{--overlay-color-back: none}.k-drawer{--header-sticky-offset: calc(var(--drawer-body-padding) * -1);z-index:var(--z-toolbar);flex-basis:var(--drawer-width);position:relative;display:flex;flex-direction:column;background:var(--drawer-color-back);box-shadow:var(--drawer-shadow);container-type:inline-size}.k-drawer[aria-disabled]{display:none;pointer-events:none}.k-dropdown{position:relative}:root{--dropdown-color-bg: var(--color-black);--dropdown-color-text: var(--color-white);--dropdown-color-hr: rgba(255, 255, 255, .25);--dropdown-padding: var(--spacing-2);--dropdown-rounded: var(--rounded);--dropdown-shadow: var(--shadow-xl)}.k-dropdown-content{--dropdown-x: 0;--dropdown-y: 0;position:absolute;inset-block-start:0;inset-inline-start:initial;left:0;width:max-content;padding:var(--dropdown-padding);background:var(--dropdown-color-bg);border-radius:var(--dropdown-rounded);color:var(--dropdown-color-text);box-shadow:var(--dropdown-shadow);text-align:start;transform:translate(var(--dropdown-x),var(--dropdown-y))}.k-dropdown-content::backdrop{background:none}.k-dropdown-content[data-align-x=end]{--dropdown-x: -100%}.k-dropdown-content[data-align-x=center]{--dropdown-x: -50%}.k-dropdown-content[data-align-y=top]{--dropdown-y: -100%}.k-dropdown-content hr{margin:.5rem 0;height:1px;background:var(--dropdown-color-hr)}.k-dropdown-content[data-theme=light]{--dropdown-color-bg: var(--color-white);--dropdown-color-text: var(--color-black);--dropdown-color-hr: rgba(0, 0, 0, .1)}.k-dropdown-item.k-button{--button-align: flex-start;--button-color-text: var(--dropdown-color-text);--button-height: var(--height-sm);--button-rounded: var(--rounded-sm);--button-width: 100%;display:flex;gap:.75rem}.k-dropdown-item.k-button:focus{outline:var(--outline)}.k-dropdown-item.k-button[aria-current]{--button-color-text: var(--color-blue-500)}.k-dropdown-item.k-button:not([aria-disabled]):hover{--button-color-back: var(--dropdown-color-hr)}.k-options-dropdown{display:flex;justify-content:center;align-items:center}:root{--picklist-rounded: var(--rounded-sm);--picklist-highlight: var(--color-yellow-500)}.k-picklist-input{--choice-color-text: currentColor;--button-rounded: var(--picklist-rounded)}.k-picklist-input-header{--input-rounded: var(--picklist-rounded)}.k-picklist-input-search{display:flex;align-items:center;border-radius:var(--picklist-rounded)}.k-picklist-input-search .k-search-input{height:var(--button-height)}.k-picklist-input-search:focus-within{outline:var(--outline)}.k-picklist-dropdown .k-picklist-input-create:focus{outline:0}.k-picklist-dropdown .k-picklist-input-create[aria-disabled=true]{visibility:hidden}.k-picklist-input-options.k-grid{--columns: 1}.k-picklist-input-options li+li{margin-top:var(--spacing-1)}.k-picklist-input-options .k-choice-input{padding-inline:var(--spacing-2)}.k-picklist-input-options .k-choice-input{--choice-color-checked: var(--color-focus)}.k-picklist-input-options .k-choice-input:has(:checked){--choice-color-text: var(--color-focus)}.k-picklist-input-options .k-choice-input[aria-disabled=true]{--choice-color-text: var(--color-text-dimmed)}.k-picklist-input-options .k-choice-input:has(:focus-within){outline:var(--outline)}.k-picklist-input-options .k-choice-input b{font-weight:var(--font-normal);color:var(--picklist-highlight)}.k-picklist-input-more.k-button{--button-width: 100%;--button-align: start;--button-color-text: var(--color-text-dimmed);padding-inline:var(--spacing-2)}.k-picklist-input-more.k-button .k-button-icon{position:relative;inset-inline-start:-1px}.k-picklist-input-empty{height:var(--button-height);line-height:1.25rem;padding:var(--spacing-1) var(--spacing-2);color:var(--color-text-dimmed)}.k-picklist-dropdown{--color-text-dimmed: var(--color-gray-400);padding:0;max-width:30rem;min-width:8rem}.k-picklist-dropdown :where(.k-picklist-input-header,.k-picklist-input-body,.k-picklist-input-footer){padding:var(--dropdown-padding)}.k-picklist-dropdown .k-picklist-input-header{border-bottom:1px solid var(--dropdown-color-hr)}.k-picklist-dropdown .k-picklist-input-search{background:var(--dropdown-color-hr);padding-inline-end:var(--input-padding)}.k-picklist-dropdown .k-picklist-input-create{--button-rounded: 1rem;--button-height: 1.125rem}.k-picklist-dropdown .k-picklist-input-create:focus{--button-color-back: var(--color-blue-500);--button-color-text: var(--color-black)}.k-picklist-dropdown .k-picklist-input-body{max-height:calc(var(--button-height) * 9.5 + 2px * 9 + var(--dropdown-padding));overflow-y:auto;outline-offset:-2px;overscroll-behavior:contain;scroll-padding-top:var(--dropdown-padding);scroll-padding-bottom:var(--dropdown-padding)}.k-picklist-dropdown .k-picklist-input-options .k-choice-input{--choice-color-border: var(--dropdown-color-hr);--choice-color-back: var(--dropdown-color-hr);--choice-color-info: var(--color-text-dimmed);min-height:var(--button-height);border-radius:var(--picklist-rounded);padding-block:.375rem}.k-picklist-dropdown .k-picklist-input-options li+li{margin-top:0}.k-picklist-dropdown .k-picklist-input-options .k-choice-input[aria-disabled=true] input{--choice-color-border: var(--dropdown-color-hr);--choice-color-back: var(--dropdown-color-hr);--choice-color-checked: var(--dropdown-color-hr);opacity:var(--opacity-disabled)}.k-picklist-dropdown .k-picklist-input-options .k-choice-input:not([aria-disabled=true]):hover{background-color:var(--dropdown-color-hr)}.k-picklist-dropdown .k-picklist-input-options .k-choice-input:not([aria-disabled=true]):focus-within{--choice-color-text: var(--color-blue-500)}.k-picklist-dropdown .k-picklist-input-more.k-button:hover{--button-color-back: var(--dropdown-color-hr)}.k-picklist-dropdown .k-picklist-input-body+.k-picklist-input-footer{border-top:1px solid var(--dropdown-color-hr)}.k-counter{font-size:var(--text-xs);color:var(--color-gray-900)}.k-counter[data-invalid=true]{color:var(--color-red-700)}.k-counter-rules{color:var(--color-gray-600);padding-inline-start:.5rem}.k-form-submitter{display:none}.k-field[data-disabled=true]{cursor:not-allowed}.k-field[data-disabled=true] *{pointer-events:none}.k-field[data-disabled=true] .k-text[data-theme=help] *{pointer-events:initial}.k-field-header{display:flex;justify-content:space-between;align-items:center;gap:var(--spacing-6);position:relative;margin-bottom:var(--spacing-2)}.k-field-options{flex-shrink:0}.k-field:focus-within>.k-field-header>.k-field-counter{display:block}.k-field-footer{margin-top:var(--spacing-2)}.k-fieldset{border:0}:root{--input-color-back: var(--color-white);--input-color-border: var(--color-border);--input-color-description: var(--color-text-dimmed);--input-color-icon: currentColor;--input-color-placeholder: var(--color-gray-600);--input-color-text: currentColor;--input-font-family: var(--font-sans);--input-font-size: var(--text-sm);--input-height: 2.25rem;--input-leading: 1;--input-outline-focus: var(--outline);--input-padding: var(--spacing-2);--input-padding-multiline: .475rem var(--input-padding);--input-rounded: var(--rounded);--input-shadow: none}@media (pointer: coarse){:root{--input-font-size: var(--text-md);--input-padding-multiline: .375rem var(--input-padding)}}.k-input{display:flex;align-items:center;line-height:var(--input-leading);border:0;background:var(--input-color-back);border-radius:var(--input-rounded);outline:1px solid var(--input-color-border);color:var(--input-color-text);min-height:var(--input-height);box-shadow:var(--input-shadow);font-family:var(--input-font-family);font-size:var(--input-font-size)}.k-input:focus-within{outline:var(--input-outline-focus)}.k-input-element{flex-grow:1}.k-input-icon{color:var(--input-color-icon);display:flex;justify-content:center;align-items:center;width:var(--input-height)}.k-input-icon-button{width:100%;height:100%;display:flex;align-items:center;justify-content:center;flex-shrink:0}.k-input-description{color:var(--input-color-description);padding-inline:var(--input-padding)}.k-input-before{padding-inline-end:0}.k-input-after{padding-inline-start:0}.k-input :where(.k-input-description,.k-input-icon){align-self:stretch;display:flex;align-items:center;flex-shrink:0}.k-input[data-disabled=true]{--input-color-back: var(--color-background);--input-color-icon: var(--color-gray-600);pointer-events:none}.k-block-title{display:flex;align-items:center;min-width:0;padding-inline-end:.75rem;line-height:1;gap:var(--spacing-2)}.k-block-icon{--icon-color: var(--color-gray-600);width:1rem}.k-block-label{color:var(--color-text-dimmed);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.k-block-type-default .k-block-title{line-height:1.5em}.k-block-options{--toolbar-size: 30px;box-shadow:var(--shadow-toolbar)}.k-block-options>.k-button:not(:last-of-type){border-inline-end:1px solid var(--color-background)}.k-block-options .k-dropdown-content{margin-top:.5rem}.k-block-container{position:relative;padding:.75rem;background:var(--color-white);border-radius:var(--rounded)}.k-block-container:not(:last-of-type){border-bottom:1px dashed rgba(0,0,0,.1)}.k-block-container:focus{outline:0}.k-block-container[data-selected=true]{z-index:2;outline:var(--outline);border-bottom-color:transparent}.k-block-container[data-batched=true]:after{position:absolute;top:0;right:0;bottom:0;left:0;content:"";background:#b1c2d82d;mix-blend-mode:multiply}.k-block-container .k-block-options{display:none;position:absolute;top:0;inset-inline-end:.75rem;margin-top:calc(-1.75rem + 2px)}.k-block-container[data-last-selected=true]>.k-block-options{display:flex}.k-block-container[data-hidden=true] .k-block{opacity:.25}.k-drawer-options .k-drawer-option[data-disabled=true]{vertical-align:middle;display:inline-grid}.k-block-container[data-disabled=true]{background:var(--color-background)}.k-block-container:is(.k-sortable-ghost,.k-sortable-fallback) .k-block{position:relative;max-height:4rem;overflow:hidden}.k-block-container:is(.k-sortable-ghost,.k-sortable-fallback) .k-block:after{position:absolute;bottom:0;content:"";height:2rem;width:100%;background:linear-gradient(to top,var(--color-white),transparent)}.k-blocks{border-radius:var(--rounded)}.k-blocks:not([data-empty=true],[data-disabled=true]){background:var(--color-white);box-shadow:var(--shadow)}.k-blocks[data-disabled=true]:not([data-empty=true]){border:1px solid var(--input-color-border)}.k-blocks-list[data-multi-select-key=true]>.k-block-container *{pointer-events:none}.k-blocks-list[data-multi-select-key=true]>.k-block-container .k-blocks *{pointer-events:all}.k-blocks .k-sortable-ghost{outline:2px solid var(--color-focus);box-shadow:#11111140 0 5px 10px;cursor:grabbing;cursor:-moz-grabbing;cursor:-webkit-grabbing}.k-blocks-list>.k-blocks-empty{display:flex;align-items:center}.k-block-importer .k-dialog-body{padding:0}.k-block-importer label{display:block;padding:var(--spacing-6) var(--spacing-6) 0;color:var(--color-text-dimmed);line-height:var(--leading-normal)}.k-block-importer label small{display:block;font-size:inherit}.k-block-importer textarea{width:100%;height:20rem;background:none;font:inherit;color:var(--color-white);border:0;padding:var(--spacing-6);resize:none}.k-block-importer textarea:focus{outline:0}.k-block-selector .k-headline{margin-bottom:1rem}.k-block-selector details+details{margin-top:var(--spacing-6)}.k-block-selector summary{font-size:var(--text-xs);cursor:pointer;color:var(--color-text-dimmed)}.k-block-selector details:only-of-type summary{pointer-events:none}.k-block-selector summary:focus{outline:0}.k-block-selector summary:focus-visible{color:var(--color-focus)}.k-block-types{display:grid;grid-gap:2px;margin-top:.75rem;grid-template-columns:repeat(1,1fr)}.k-block-types .k-button{--button-color-icon: var(--color-text);--button-color-back: var(--color-white);--button-padding: var(--spacing-3);width:100%;justify-content:start;gap:1rem;box-shadow:var(--shadow)}.k-block-types .k-button[aria-disabled]{opacity:var(--opacity-disabled);--button-color-back: var(--color-gray-200);box-shadow:none}.k-clipboard-hint{padding-top:1.5rem;line-height:var(--leading-normal);font-size:var(--text-xs);color:var(--color-text-dimmed)}.k-clipboard-hint small{display:block;font-size:inherit;color:var(--color-text-dimmed)}.k-block-figure-container:not([data-disabled=true]){cursor:pointer}.k-block-figure iframe{border:0;pointer-events:none;background:var(--color-black)}.k-block-figure figcaption{padding-top:.5rem;color:var(--color-text-dimmed);font-size:var(--text-sm);text-align:center}.k-block-figure-empty{--button-width: 100%;--button-height: 6rem;--button-color-text: var(--color-text-dimmed);--button-color-back: var(--color-gray-200)}.k-block-figure-empty,.k-block-figure-container>*{border-radius:var(--rounded-sm)}.k-block-type-code-editor{position:relative}.k-block-type-code-editor .k-input{--input-color-border: none;--input-color-back: var(--color-black);--input-color-text: var(--color-white);--input-font-family: var(--font-mono);--input-outline-focus: none;--input-padding: var(--spacing-3);--input-padding-multiline: var(--input-padding)}.k-block-type-code-editor .k-input[data-type=textarea]{white-space:pre-wrap}.k-block-type-code-editor-language{--input-font-size: var(--text-xs);position:absolute;inset-inline-end:0;bottom:0}.k-block-type-code-editor-language .k-input-element{padding-inline-start:1.5rem}.k-block-type-code-editor-language .k-input-icon{inset-inline-start:0}.k-block-container.k-block-container-type-fields{padding-block:0}.k-block-container:not([data-hidden=true]) .k-block-type-fields>:not([data-collapsed=true]){padding-bottom:var(--spacing-3)}.k-block-type-fields-header{display:flex;justify-content:space-between}.k-block-type-fields-header .k-block-title{padding-block:var(--spacing-3);cursor:pointer;white-space:nowrap}.k-block-type-fields-form{background-color:var(--color-gray-200);padding:var(--spacing-6) var(--spacing-6) var(--spacing-8);border-radius:var(--rounded-sm);container:column / inline-size}.k-block-container-type-fields[data-hidden=true] :where(.k-drawer-tabs,.k-block-type-fields-form){display:none}.k-block-type-gallery ul{display:grid;grid-gap:.75rem;grid-template-columns:repeat(auto-fit,minmax(6rem,1fr));line-height:0;align-items:center;justify-content:center}.k-block-type-gallery:not([data-disabled=true]) ul{cursor:pointer}.k-block-type-gallery[data-disabled=true] .k-block-type-gallery-placeholder{background:var(--color-gray-250)}.k-block-type-gallery-placeholder{background:var(--color-background)}.k-block-type-gallery figcaption{padding-top:.5rem;color:var(--color-gray-600);font-size:var(--text-sm);text-align:center}.k-block-type-heading-input{display:flex;align-items:center;line-height:1.25em;font-size:var(--text-size);font-weight:var(--font-bold)}.k-block-type-heading-input[data-level=h1]{--text-size: var(--text-3xl);line-height:1.125em}.k-block-type-heading-input[data-level=h2]{--text-size: var(--text-2xl)}.k-block-type-heading-input[data-level=h3]{--text-size: var(--text-xl)}.k-block-type-heading-input[data-level=h4]{--text-size: var(--text-lg)}.k-block-type-heading-input[data-level=h5]{--text-size: var(--text-md);line-height:1.5em}.k-block-type-heading-input[data-level=h6]{--text-size: var(--text-sm);line-height:1.5em}.k-block-type-heading-input .k-writer .ProseMirror strong{font-weight:700}.k-block-type-heading-level{--input-color-back: transparent;--input-color-border: none;--input-color-text: var(--color-gray-600);font-weight:var(--font-bold);text-transform:uppercase}.k-block-type-image .k-block-figure-container{text-align:center;line-height:0}.k-block-type-image-auto{max-width:100%;max-height:30rem;margin-inline:auto}.k-block-type-line hr{margin-block:.75rem;border:0;border-top:1px solid var(--color-border)}.k-block-type-list-input{--input-color-back: transparent;--input-color-border: none;--input-outline-focus: none}.k-block-type-markdown-input{--input-color-back: var(--color-light);--input-color-border: none;--input-outline-focus: none;--input-padding-multiline: var(--spacing-3)}.k-block-type-quote-editor{padding-inline-start:var(--spacing-3);border-inline-start:2px solid var(--color-black)}.k-block-type-quote-text{font-size:var(--text-xl);margin-bottom:var(--spacing-1);line-height:1.25em}.k-block-type-quote-citation{font-style:italic;color:var(--color-text-dimmed)}.k-block-type-table-preview{cursor:pointer;border:1px solid var(--color-gray-300);border-spacing:0;border-radius:var(--rounded-sm)}.k-block-type-table-preview :where(th,td){text-align:start;line-height:1.5em;font-size:var(--text-sm)}.k-block-type-table-preview th{padding:.5rem .75rem}.k-block-type-table-preview td:not(.k-table-index-column){padding:0 .75rem}.k-block-type-table-preview td>*,.k-block-type-table-preview td [class$=-field-preview]{padding:0}.k-block-type-text-input{line-height:1.5;height:100%}.k-block-container.k-block-container-type-text{padding:0}.k-block-type-text-input.k-writer[data-toolbar-inline=true]{padding:var(--spacing-3)}.k-block-type-text-input.k-writer:not([data-toolbar-inline=true])>.ProseMirror,.k-block-type-text-input.k-writer:not([data-toolbar-inline=true])[data-placeholder][data-empty=true]:before{padding:var(--spacing-3) var(--spacing-6)}.k-block-type-video-figure video{pointer-events:none}.k-blocks-field{position:relative}.k-blocks-field>footer{display:flex;justify-content:center;margin-top:var(--spacing-3)}.k-string-input{padding:var(--input-padding);border-radius:var(--input-rounded)}.k-string-input:focus{outline:0}.k-string-input[data-font=monospace]{font-family:var(--font-mono)}.k-color-field{--color-frame-size: calc(var(--input-height) - var(--spacing-2))}.k-color-field .k-input-before{align-items:center;padding-inline-start:var(--spacing-1)}.k-color-field-options{--color-frame-size: var(--input-height)}.k-color-field-picker{padding:var(--spacing-3)}.k-color-field-picker-toggle{--color-frame-rounded: var(--rounded-sm);border-radius:var(--color-frame-rounded)}.k-color-field .k-colorname-input{padding-inline:var(--input-padding)}.k-color-field .k-colorname-input:focus{outline:0}.k-date-input:disabled::placeholder{opacity:0}.k-date-field-body{display:grid;gap:var(--spacing-2)}@container (min-width: 20rem){.k-date-field-body[data-has-time=true]{grid-template-columns:1fr minmax(6rem,9rem)}}.k-text-input{padding:var(--input-padding);border-radius:var(--input-rounded)}.k-text-input:focus{outline:0}.k-text-input[data-font=monospace]{font-family:var(--font-mono)}.k-text-input:disabled::placeholder{opacity:0}.k-models-field[data-disabled=true] .k-item *{pointer-events:all!important}.k-headline-field{position:relative;padding-top:1.5rem}.k-fieldset>.k-grid .k-column:first-child .k-headline-field{padding-top:0}.k-headline-field h2.k-headline{font-weight:var(--font-normal)}.k-headline-field footer{margin-top:var(--spacing-2)}.k-info-field .k-headline{padding-bottom:.75rem;line-height:1.25rem}.k-layout-column{position:relative;height:100%;display:flex;flex-direction:column;background:var(--color-white);min-height:6rem}.k-layout-column:focus{outline:0}.k-layout-column>.k-blocks{background:none;box-shadow:none;padding:0;height:100%;background:var(--color-white);min-height:4rem}.k-layout-column>.k-blocks[data-empty=true]{min-height:6rem}.k-layout-column>.k-blocks>.k-blocks-list{display:flex;flex-direction:column;height:100%}.k-layout-column>.k-blocks>.k-blocks-list>.k-block-container:last-of-type{flex-grow:1}.k-layout-column>.k-blocks>.k-blocks-list>.k-blocks-empty.k-box{--box-color-back: transparent;position:absolute;top:0;right:0;bottom:0;left:0;justify-content:center;opacity:0;transition:opacity .3s;border:0}.k-layout-column>.k-blocks>.k-blocks-list>.k-blocks-empty:hover{opacity:1}.k-layout{--layout-border-color: var(--color-gray-300);--layout-toolbar-width: 2rem;position:relative;padding-inline-end:var(--layout-toolbar-width);background:#fff;box-shadow:var(--shadow)}[data-disabled=true] .k-layout{padding-inline-end:0}.k-layout:not(:last-of-type){margin-bottom:1px}.k-layout:focus{outline:0}.k-layout-toolbar{position:absolute;inset-block:0;inset-inline-end:0;width:var(--layout-toolbar-width);display:flex;flex-direction:column;align-items:center;justify-content:space-between;padding-bottom:var(--spacing-2);font-size:var(--text-sm);background:var(--color-gray-100);border-inline-start:1px solid var(--color-light);color:var(--color-gray-500)}.k-layout-toolbar:hover{color:var(--color-black)}.k-layout-toolbar-button{width:var(--layout-toolbar-width);height:var(--layout-toolbar-width)}.k-layout-columns.k-grid{grid-gap:1px;background:var(--layout-border-color);background:var(--color-gray-300)}.k-layout:not(:first-child) .k-layout-columns.k-grid{border-top:0}.k-layouts .k-sortable-ghost{position:relative;box-shadow:#11111140 0 5px 10px;outline:2px solid var(--color-focus);cursor:grabbing;z-index:1}.k-layout-field>footer{display:flex;justify-content:center;margin-top:var(--spacing-3)}.k-line-field{position:relative;border:0;height:3rem;width:auto}.k-line-field:after{position:absolute;content:"";top:50%;margin-top:-1px;inset-inline:0;height:1px;background:var(--color-border)}.k-link-input-header{display:grid;grid-template-columns:max-content minmax(0,1fr);align-items:center;gap:.25rem;height:var(--input-height);grid-area:header}.k-link-input-toggle.k-button{--button-height: var(--height-sm);--button-rounded: var(--rounded-sm);--button-color-back: var(--color-gray-200);margin-inline-start:.25rem}.k-link-input-model{display:flex;justify-content:space-between;margin-inline-end:var(--spacing-1)}.k-link-input-model-placeholder.k-button{--button-align: flex-start;--button-color-text: var(--color-gray-600);--button-height: var(--height-sm);--button-padding: var(--spacing-2);--button-rounded: var(--rounded-sm);flex-grow:1;overflow:hidden;white-space:nowrap;align-items:center}.k-link-field .k-link-field-preview{--tag-height: var(--height-sm);padding-inline:0}.k-link-field .k-link-field-preview .k-tag:focus{outline:0}.k-link-field .k-link-field-preview .k-tag:focus-visible{outline:var(--outline)}.k-link-field .k-link-field-preview .k-tag-text{font-size:var(--text-sm)}.k-link-input-model-toggle{align-self:center;--button-height: var(--height-sm);--button-width: var(--height-sm);--button-rounded: var(--rounded-sm)}.k-link-input-body{display:grid;overflow:hidden;border-top:1px solid var(--color-gray-300);background:var(--color-gray-100);--tree-color-back: var(--color-gray-100);--tree-color-hover-back: var(--color-gray-200)}.k-link-input-body[data-type=page] .k-page-browser{padding:var(--spacing-2);padding-bottom:calc(var(--spacing-2) - 1px);width:100%;container-type:inline-size;overflow:auto}.k-link-field .k-bubbles-field-preview{--bubble-rounded: var(--rounded-sm);--bubble-size: var(--height-sm);padding-inline:0}.k-link-field .k-bubbles-field-preview .k-bubble{font-size:var(--text-sm)}.k-link-field[data-disabled=true] .k-link-input-model-placeholder{display:none}.k-link-field[data-disabled=true] input::placeholder{opacity:0}.k-writer{position:relative;width:100%;display:grid;grid-template-areas:"content";gap:var(--spacing-1)}.k-writer .ProseMirror{overflow-wrap:break-word;word-wrap:break-word;word-break:break-word;white-space:pre-wrap;font-variant-ligatures:none;grid-area:content;padding:var(--input-padding-multiline)}.k-writer .ProseMirror:focus{outline:0}.k-writer .ProseMirror *{caret-color:currentColor}.k-writer .ProseMirror hr.ProseMirror-selectednode{outline:var(--outline)}.k-writer[data-placeholder][data-empty=true]:before{grid-area:content;content:attr(data-placeholder);color:var(--input-color-placeholder);pointer-events:none;white-space:pre-wrap;word-wrap:break-word;line-height:var(--text-line-height);padding:var(--input-padding-multiline)}.k-list-input.k-writer[data-placeholder][data-empty=true]:before{padding-inline-start:2.5em}.k-list-field .k-list-input .ProseMirror,.k-list-field .k-list-input:before{padding:.475rem .5rem .475rem .75rem}:root{--tags-gap: .375rem}.k-tags{display:inline-flex;gap:var(--tags-gap);align-items:center;flex-wrap:wrap}.k-tags .k-sortable-ghost{outline:var(--outline)}.k-tags[data-layout=list],.k-tags[data-layout=list] .k-tag{width:100%}.k-tags.k-draggable .k-tag-text{cursor:grab}.k-tags.k-draggable .k-tag-text:active{cursor:grabbing}.k-multiselect-input{padding:var(--tags-gap);cursor:pointer}.k-multiselect-input-toggle.k-button{opacity:0}.k-tags-input{padding:var(--tags-gap);cursor:pointer}.k-tags-input-toggle.k-button{--button-color-text: var(--input-color-placeholder);opacity:0}.k-tags-input-toggle.k-button:focus{--button-color-text: var(--input-color-text)}.k-tags-input:focus-within .k-tags-input-toggle{opacity:1}.k-tags-input .k-picklist-dropdown{margin-top:var(--spacing-1)}.k-tags-input .k-picklist-dropdown .k-choice-input{gap:0}.k-tags-input .k-picklist-dropdown .k-choice-input:focus-within{outline:var(--outline)}.k-tags-input .k-picklist-dropdown .k-choice-input input{opacity:0;width:0}.k-number-input{padding:var(--input-padding);border-radius:var(--input-rounded)}.k-number-input:focus{outline:0}.k-table.k-object-field-table{table-layout:auto}.k-table.k-object-field-table tbody td{max-width:0}@container (max-width: 40rem){.k-object-field{overflow:hidden}.k-object-field-table.k-table tbody :where(th):is([data-mobile=true]){width:1px!important;white-space:normal;word-break:normal}}.k-range-input{--range-track-height: 1px;--range-track-back: var(--color-gray-300);--range-tooltip-back: var(--color-black);display:flex;align-items:center;border-radius:var(--range-track-height)}.k-range-input input[type=range]:focus{outline:0}.k-range-input-tooltip{position:relative;display:flex;align-items:center;color:var(--color-white);font-size:var(--text-xs);font-variant-numeric:tabular-nums;line-height:1;text-align:center;border-radius:var(--rounded-sm);background:var(--range-tooltip-back);margin-inline-start:var(--spacing-3);padding:0 var(--spacing-1);white-space:nowrap}.k-range-input-tooltip:after{position:absolute;top:50%;inset-inline-start:-3px;width:0;height:0;transform:translateY(-50%);border-block:3px solid transparent;border-inline-end:3px solid var(--range-tooltip-back);content:""}.k-range-input-tooltip>*{padding:var(--spacing-1)}.k-range-input[data-disabled=true]{--range-tooltip-back: var(--color-gray-600)}.k-input[data-type=range] .k-range-input{padding-inline:var(--input-padding)}.k-select-input{position:relative;display:block;overflow:hidden;padding:var(--input-padding);border-radius:var(--input-rounded)}.k-select-input[data-empty=true]{color:var(--input-color-placeholder)}.k-select-input-native{position:absolute;top:0;right:0;bottom:0;left:0;opacity:0;z-index:1}.k-select-input-native[disabled]{cursor:default}.k-input[data-type=select]{position:relative}.k-input[data-type=select] .k-input-icon{position:absolute;inset-block:0;inset-inline-end:0}.k-structure-field:not([data-disabled=true]) td.k-table-column{cursor:pointer}.k-structure-field .k-table+footer{display:flex;justify-content:center;margin-top:var(--spacing-3)}.k-field-counter{display:none}.k-text-field:focus-within .k-field-counter{display:block}.k-toolbar.k-textarea-toolbar{border-end-start-radius:0;border-end-end-radius:0;border-bottom:1px solid var(--toolbar-border)}.k-toolbar.k-textarea-toolbar>.k-button:first-child{border-end-start-radius:0}.k-toolbar.k-textarea-toolbar>.k-button:last-child{border-end-end-radius:0}.k-textarea-input[data-size=small]{--textarea-size: 7.5rem}.k-textarea-input[data-size=medium]{--textarea-size: 15rem}.k-textarea-input[data-size=large]{--textarea-size: 30rem}.k-textarea-input[data-size=huge]{--textarea-size: 45rem}.k-textarea-input-wrapper{position:relative;display:block}.k-textarea-input-native{resize:none;min-height:var(--textarea-size)}.k-textarea-input-native:focus{outline:0}.k-textarea-input-native[data-font=monospace]{font-family:var(--font-mono)}.k-input[data-type=textarea] .k-input-element{min-width:0}.k-input[data-type=textarea] .k-textarea-input-native{padding:var(--input-padding-multiline)}.k-time-input:disabled::placeholder{opacity:0}.k-input[data-type=toggle]{--input-color-border: transparent;--input-shadow: var(--shadow)}.k-input[data-type=toggle] .k-input-before{padding-inline-end:calc(var(--input-padding) / 2)}.k-input[data-type=toggle] .k-toggle-input{padding-inline-start:var(--input-padding)}.k-input[data-type=toggle][data-disabled]{box-shadow:none;border:1px solid var(--color-border)}.k-input[data-type=toggles]{display:inline-flex}.k-input[data-type=toggles].grow{display:flex}.k-input[data-type=toggles]:has(.k-empty){outline:0;display:flex}.k-toggles-input{display:grid;grid-template-columns:repeat(var(--options),minmax(0,1fr));gap:1px;border-radius:var(--rounded);line-height:1;background:var(--color-border);overflow:hidden}.k-toggles-input li{height:var(--field-input-height);background:var(--color-white)}.k-toggles-input label{align-items:center;background:var(--color-white);cursor:pointer;display:flex;font-size:var(--text-sm);justify-content:center;line-height:1.25;padding:0 var(--spacing-3);height:100%}.k-toggles-input li[data-disabled=true] label{color:var(--color-text-dimmed);background:var(--color-light)}.k-toggles-input .k-icon+.k-toggles-text{margin-inline-start:var(--spacing-2)}.k-toggles-input input:focus:not(:checked)+label{background:var(--color-blue-200)}.k-toggles-input input:checked+label{background:var(--color-black);color:var(--color-white)}.k-alpha-input{--range-track-back: linear-gradient(to right, transparent, currentColor);--range-track-height: var(--range-thumb-size);color:#000;background:var(--color-white) var(--pattern-light)}.k-calendar-input{--button-height: var(--height-sm);--button-width: var(--button-height);--button-padding: 0;padding:var(--spacing-2);width:min-content}.k-calendar-table{table-layout:fixed;min-width:15rem}.k-calendar-input .k-button{justify-content:center}.k-calendar-input>nav{display:flex;direction:ltr;align-items:center;margin-bottom:var(--spacing-2)}.k-calendar-selects{flex-grow:1;display:flex;align-items:center;justify-content:center}[dir=ltr] .k-calendar-selects{direction:ltr}[dir=rtl] .k-calendar-selects{direction:rtl}.k-calendar-selects .k-select-input{display:flex;align-items:center;text-align:center;height:var(--button-height);padding:0 .5rem;border-radius:var(--input-rounded)}.k-calendar-selects .k-select-input:focus-within{outline:var(--outline)}.k-calendar-input th{padding-block:.5rem;color:var(--color-gray-500);font-size:var(--text-xs);text-align:center}.k-calendar-day{padding:2px}.k-calendar-day[aria-current=date] .k-button{text-decoration:underline}.k-calendar-day[aria-selected=date] .k-button,.k-calendar-day[aria-selected=date] .k-button:focus{--button-color-text: var(--color-text);--button-color-back: var(--color-blue-500)}.k-calendar-day[aria-selected=date] .k-button:focus-visible{outline-offset:2px}.k-calendar-today{padding-top:var(--spacing-2);text-align:center}.k-calendar-today .k-button{--button-width: auto;--button-padding: var(--spacing-3);font-size:var(--text-xs);text-decoration:underline}.k-choice-input{display:flex;gap:var(--spacing-3);min-width:0}.k-choice-input input{top:2px}.k-choice-input-label{display:flex;line-height:1.25rem;flex-direction:column;min-width:0;color:var(--choice-color-text)}.k-choice-input-label>*{display:block;overflow:hidden;text-overflow:ellipsis}.k-choice-input-label-info{color:var(--choice-color-info)}.k-choice-input[aria-disabled]{cursor:not-allowed}:where(.k-checkboxes-field,.k-radio-field) .k-choice-input{min-height:var(--input-height);padding-block:var(--spacing-2);padding-inline:var(--spacing-3);border-radius:var(--input-rounded)}:where(.k-checkboxes-field,.k-radio-field) .k-choice-input:not([aria-disabled=true]){background:var(--input-color-back);box-shadow:var(--shadow)}:where(.k-checkboxes-field,.k-radio-field) .k-choice-input[aria-disabled=true]{border:1px solid var(--input-color-border)}.k-coloroptions-input{--color-preview-size: var(--input-height)}.k-coloroptions-input ul{display:grid;grid-template-columns:repeat(auto-fill,var(--color-preview-size));gap:var(--spacing-2)}.k-coloroptions-input input:focus+.k-color-frame{outline:var(--outline)}.k-coloroptions-input[disabled] label{opacity:var(--opacity-disabled);cursor:not-allowed}.k-coloroptions-input input:checked+.k-color-frame{outline:1px solid var(--color-gray-600);outline-offset:2px}.k-colorpicker-input{--h: 0;--s: 0%;--l: 0%;--a: 1;--range-thumb-size: .75rem;--range-track-height: .75rem;display:flex;flex-direction:column;gap:var(--spacing-3);width:max-content}.k-colorpicker-input .k-coords-input{border-radius:var(--rounded-sm);aspect-ratio:1/1;background:linear-gradient(to bottom,transparent,#000),linear-gradient(to right,#fff,hsl(var(--h),100%,50%))}.k-colorpicker-input .k-alpha-input{color:hsl(var(--h),var(--s),var(--l))}.k-colorpicker-input .k-coloroptions-input ul{grid-template-columns:repeat(6,1fr)}.k-coords-input{position:relative;display:block!important}.k-coords-input img{width:100%}.k-coords-input-thumb{position:absolute;aspect-ratio:1/1;width:var(--range-thumb-size);background:var(--range-thumb-color);border-radius:var(--range-thumb-size);box-shadow:var(--range-thumb-shadow);transform:translate(-50%,-50%);cursor:move}.k-coords-input[data-empty] .k-coords-input-thumb{opacity:0}.k-coords-input-thumb:active{cursor:grabbing}.k-coords-input:focus-within{outline:var(--outline)}.k-coords-input[aria-disabled]{pointer-events:none;opacity:var(--opacity-disabled)}.k-coords-input .k-coords-input-thumb:focus{outline:var(--outline)}.k-hue-input{--range-track-back: linear-gradient( to right, hsl(0, 100%, 50%) 0%, hsl(60, 100%, 50%) 16.67%, hsl(120, 100%, 50%) 33.33%, hsl(180, 100%, 50%) 50%, hsl(240, 100%, 50%) 66.67%, hsl(320, 100%, 50%) 83.33%, hsl(360, 100%, 50%) 100% ) no-repeat;--range-track-height: var(--range-thumb-size)}.k-timeoptions-input{--button-height: var(--height-sm);display:grid;grid-template-columns:1fr 1fr;gap:var(--spacing-3)}.k-timeoptions-input h3{display:flex;align-items:center;padding-inline:var(--button-padding);height:var(--button-height);margin-bottom:var(--spacing-1)}.k-timeoptions-input hr{margin:var(--spacing-2) var(--spacing-3)}.k-timeoptions-input .k-button[aria-selected=time]{--button-color-text: var(--color-text);--button-color-back: var(--color-blue-500)}.k-layout-selector h3{margin-top:-.5rem;margin-bottom:var(--spacing-3)}.k-layout-selector-options{display:grid;grid-template-columns:repeat(3,1fr);gap:var(--spacing-6)}@media screen and (min-width: 65em){.k-layout-selector-options{grid-template-columns:repeat(var(--columns),1fr)}}.k-layout-selector-option{--color-border: hsla(var(--color-gray-hs), 0%, 6%);--color-back: var(--color-white);border-radius:var(--rounded)}.k-layout-selector-option:focus-visible{outline:var(--outline);outline-offset:-1px}.k-layout-selector-option .k-grid{border:1px solid var(--color-border);gap:1px;grid-template-columns:repeat(var(--columns),1fr);cursor:pointer;background:var(--color-border);border-radius:var(--rounded);overflow:hidden;box-shadow:var(--shadow);height:5rem}.k-layout-selector-option .k-column{grid-column:span var(--span);background:var(--color-back);height:100%}.k-layout-selector-option:hover{--color-border: var(--color-gray-500);--color-back: var(--color-gray-100)}.k-layout-selector-option[aria-current]{--color-border: var(--color-focus);--color-back: var(--color-blue-300)}.k-bubbles{display:flex;gap:.25rem}.k-bubbles-field-preview{--bubble-back: var(--color-light);--bubble-text: var(--color-black);padding:.375rem var(--table-cell-padding);overflow:hidden}.k-bubbles-field-preview .k-bubbles{gap:.375rem}.k-color-field-preview{--color-frame-rounded: var(--tag-rounded);--color-frame-size: var(--tag-height);padding:.375rem var(--table-cell-padding);display:flex;align-items:center;gap:var(--spacing-2)}.k-text-field-preview{padding:.325rem .75rem;overflow-x:hidden;text-overflow:ellipsis;white-space:nowrap}.k-url-field-preview{padding-inline:var(--table-cell-padding)}.k-url-field-preview[data-link]{color:var(--link-color)}.k-url-field-preview a{display:inline-flex;align-items:center;height:var(--height-xs);padding-inline:var(--spacing-1);margin-inline:calc(var(--spacing-1) * -1);border-radius:var(--rounded);max-width:100%;min-width:0}.k-url-field-preview a>*{overflow:hidden;white-space:nowrap;text-overflow:ellipsis;text-decoration:underline;text-underline-offset:var(--link-underline-offset)}.k-url-field-preview a:hover{color:var(--color-black)}.k-flag-field-preview{--button-height: var(--table-row-height);--button-width: 100%;outline-offset:-2px}.k-html-field-preview{padding:.375rem var(--table-cell-padding);overflow:hidden;text-overflow:ellipsis}.k-image-field-preview{height:100%}.k-link-field-preview{--tag-height: var(--height-xs);--tag-color-back: var(--color-gray-200);--tag-color-text: var(--color-black);--tag-color-toggle: var(--tag-color-text);--tag-color-toggle-border: var(--color-gray-300);--tag-color-focus-back: var(--tag-color-back);--tag-color-focus-text: var(--tag-color-text);padding-inline:var(--table-cell-padding);min-width:0}.k-link-field-preview .k-tag{min-width:0;max-width:100%}.k-link-field-preview .k-tag-text{font-size:var(--text-xs);min-width:0}.k-toggle-field-preview{padding-inline:var(--table-cell-padding)}:root{--toolbar-size: var(--height);--toolbar-text: var(--color-black);--toolbar-back: var(--color-white);--toolbar-hover: rgba(239, 239, 239, .5);--toolbar-border: rgba(0, 0, 0, .1);--toolbar-current: var(--color-focus)}.k-toolbar{display:flex;max-width:100%;height:var(--toolbar-size);align-items:center;overflow-x:auto;overflow-y:hidden;color:var(--toolbar-text);background:var(--toolbar-back);border-radius:var(--rounded)}.k-toolbar[data-theme=dark]{--toolbar-text: var(--color-white);--toolbar-back: var(--color-black);--toolbar-hover: rgba(255, 255, 255, .2);--toolbar-border: var(--color-gray-800)}.k-toolbar>hr{height:var(--toolbar-size);width:1px;border-left:1px solid var(--toolbar-border)}.k-toolbar-button.k-button{--button-width: var(--toolbar-size);--button-height: var(--toolbar-size);--button-rounded: 0;outline-offset:-2px}.k-toolbar-button:hover{--button-color-back: var(--toolbar-hover)}.k-toolbar .k-button[aria-current]{--button-color-text: var(--toolbar-current)}.k-toolbar>.k-button:first-child{border-start-start-radius:var(--rounded);border-end-start-radius:var(--rounded)}.k-toolbar>.k-button:last-child{border-start-end-radius:var(--rounded);border-end-end-radius:var(--rounded)}:where(.k-textarea-input,.k-writer-input):not(:focus-within){--toolbar-text: var(--color-gray-400);--toolbar-border: var(--color-background)}:where(.k-textarea-input,.k-writer-input):focus-within .k-toolbar:not([data-inline=true]){position:sticky;top:var(--header-sticky-offset);inset-inline:0;z-index:1;box-shadow:#0000000d 0 2px 5px}.k-writer:not([data-toolbar-inline=true]):not([data-disabled=true]){grid-template-areas:"topbar" "content";grid-template-rows:var(--toolbar-size) 1fr;gap:0}.k-writer:not(:focus-within){--toolbar-current: currentColor}.k-writer-toolbar[data-inline=true]{position:absolute;z-index:calc(var(--z-dropdown) + 1);max-width:none;box-shadow:var(--shadow-toolbar)}.k-writer-toolbar:not([data-inline=true]){border-end-start-radius:0;border-end-end-radius:0;border-bottom:1px solid var(--toolbar-border)}.k-writer-toolbar:not([data-inline=true])>.k-button:first-child{border-end-start-radius:0}.k-writer-toolbar:not([data-inline=true])>.k-button:last-child{border-end-end-radius:0}.k-aspect-ratio{position:relative;display:block;overflow:hidden;padding-bottom:100%}.k-aspect-ratio>*{position:absolute!important;top:0;right:0;bottom:0;left:0;height:100%;width:100%;object-fit:contain}.k-aspect-ratio[data-cover=true]>*{object-fit:cover}:root{--bar-height: var(--height-xs)}.k-bar{display:flex;align-items:center;gap:var(--spacing-3);height:var(--bar-height);justify-content:space-between}.k-bar:where([data-align=center]){justify-content:center}.k-bar:where([data-align=end]):has(:first-child:last-child){justify-content:end}.k-bar-slot{flex-grow:1}.k-bar-slot[data-position=center]{text-align:center}.k-bar-slot[data-position=right]{text-align:end}:root{--box-height: var( --field-input-height );--box-padding-inline: var(--spacing-2);--box-font-size: var(--text-sm);--box-color-back: none;--box-color-text: currentColor}.k-box{--icon-color: var(--box-color-icon);--text-font-size: var(--box-font-size);display:flex;width:100%;align-items:center;gap:var(--spacing-2);color:var(--box-color-text);background:var(--box-color-back);word-wrap:break-word}.k-box[data-theme]{--box-color-back: var(--theme-color-back);--box-color-text: var(--theme-color-text);--box-color-icon: var(--theme-color-700);min-height:var(--box-height);line-height:1.25;padding:.375rem var(--box-padding-inline);border-radius:var(--rounded)}.k-box[data-theme=text],.k-box[data-theme=white]{box-shadow:var(--shadow)}.k-box[data-theme=text]{padding:var(--spacing-6)}.k-box[data-theme=none]{padding:0}.k-box[data-align=center]{justify-content:center}:root{--bubble-size: 1.525rem;--bubble-back: var(--color-light);--bubble-rounded: var(--rounded-sm);--bubble-text: var(--color-black)}.k-bubble{width:min-content;height:var(--bubble-size);white-space:nowrap;line-height:1.5;background:var(--bubble-back);color:var(--bubble-text);border-radius:var(--bubble-rounded);overflow:hidden}.k-bubble .k-frame{width:var(--bubble-size);height:var(--bubble-size)}.k-bubble[data-has-text=true]{display:flex;gap:var(--spacing-2);align-items:center;padding-inline-end:.5rem;font-size:var(--text-xs)}.k-column{min-width:0}.k-column[data-sticky=true]{align-self:stretch}.k-column[data-sticky=true]>div{position:sticky;top:calc(var(--header-sticky-offset) + 2vh);z-index:2}.k-column[data-disabled=true]{cursor:not-allowed;opacity:.4}.k-column[data-disabled=true] *{pointer-events:none}.k-column[data-disabled=true] .k-text[data-theme=help] *{pointer-events:initial}.k-frame{--fit: contain;--ratio: 1/1;position:relative;display:flex;justify-content:center;align-items:center;aspect-ratio:var(--ratio);background:var(--back);overflow:hidden}.k-frame:where([data-theme]){--back: var(--theme-color-back);color:var(--theme-color-text)}.k-frame *:where(img,video,iframe,button){position:absolute;top:0;right:0;bottom:0;left:0;height:100%;width:100%;object-fit:var(--fit)}.k-frame>*{overflow:hidden;text-overflow:ellipsis;min-width:0;min-height:0}:root{--color-frame-rounded: var(--rounded);--color-frame-size: 100%;--color-frame-darkness: 0%}.k-color-frame.k-frame{background:var(--pattern-light);width:var(--color-frame-size);color:transparent;border-radius:var(--color-frame-rounded);overflow:hidden;background-clip:padding-box}.k-color-frame:after{border-radius:var(--color-frame-rounded);box-shadow:0 0 0 1px inset hsla(0,0%,var(--color-frame-darkness),.175);position:absolute;top:0;right:0;bottom:0;left:0;background-color:currentColor;content:""}.k-dropzone{position:relative}.k-dropzone:after{content:"";position:absolute;top:0;right:0;bottom:0;left:0;display:none;pointer-events:none;z-index:1;border-radius:var(--rounded)}.k-dropzone[data-over=true]:after{display:block;background:hsla(var(--color-blue-hs),var(--color-blue-l-300),.6);outline:var(--outline)}.k-grid{--columns: 12;--grid-inline-gap: 0;--grid-block-gap: 0;display:grid;align-items:start;grid-column-gap:var(--grid-inline-gap);grid-row-gap:var(--grid-block-gap)}.k-grid>*{--width: calc(1 / var(--columns));--span: calc(var(--columns) * var(--width))}@container (min-width: 30rem){.k-grid{grid-template-columns:repeat(var(--columns),1fr)}.k-grid>*{grid-column:span var(--span)}.k-grid[data-gutter=small]{--grid-inline-gap: 1rem;--grid-block-gap: 1rem}.k-grid:where([data-gutter=medium],[data-gutter=large],[data-gutter=huge]){--grid-inline-gap: 1.5rem;--grid-block-gap: 1.5rem}}@container (min-width: 65em){.k-grid[data-gutter=large]{--grid-inline-gap: 3rem}.k-grid[data-gutter=huge]{--grid-inline-gap: 4.5rem}}@container (min-width: 90em){.k-grid[data-gutter=large]{--grid-inline-gap: 4.5rem}.k-grid[data-gutter=huge]{--grid-inline-gap: 6rem}}@container (min-width: 120em){.k-grid[data-gutter=large]{--grid-inline-gap: 6rem}.k-grid[data-gutter=huge]{--grid-inline-gap: 7.5rem}}:root{--columns-inline-gap: clamp(.75rem, 6cqw, 6rem);--columns-block-gap: var(--spacing-8)}.k-grid[data-variant=columns]{--grid-inline-gap: var(--columns-inline-gap);--grid-block-gap: var(--columns-block-gap)}.k-grid:where([data-variant=columns],[data-variant=fields])>*{container:column / inline-size}.k-grid[data-variant=fields]{gap:var(--spacing-8)}.k-grid[data-variant=choices]{align-items:stretch;gap:2px}:root{--header-color-back: var(--color-light);--header-padding-block: var(--spacing-4);--header-sticky-offset: var(--scroll-top)}.k-header{position:relative;display:flex;flex-wrap:wrap;align-items:baseline;justify-content:space-between;border-bottom:1px solid var(--color-border);background:var(--header-color-back);padding-top:var(--header-padding-block);margin-bottom:var(--spacing-12);box-shadow:2px 0 0 0 var(--header-color-back),-2px 0 0 0 var(--header-color-back)}.k-header-title{font-size:var(--text-h1);font-weight:var(--font-h1);line-height:var(--leading-h1);margin-bottom:var(--header-padding-block);min-width:0}.k-header-title-button{display:inline-flex;text-align:start;gap:var(--spacing-2);align-items:baseline;max-width:100%;outline:0}.k-header-title-text{overflow-x:clip;text-overflow:ellipsis}.k-header-title-icon{--icon-color: var(--color-text-dimmed);border-radius:var(--rounded);transition:opacity .2s;display:grid;flex-shrink:0;place-items:center;height:var(--height-sm);width:var(--height-sm);opacity:0}.k-header-title-button:is(:hover,:focus) .k-header-title-icon{opacity:1}.k-header-title-button:is(:focus) .k-header-title-icon{outline:var(--outline)}.k-header-buttons{display:flex;flex-shrink:0;gap:var(--spacing-2);margin-bottom:var(--header-padding-block)}.k-header[data-has-buttons=true]{position:sticky;top:var(--scroll-top);z-index:var(--z-toolbar)}:root:has(.k-header[data-has-buttons=true]){--header-sticky-offset: calc(var(--scroll-top) + 4rem)}:root{--icon-size: 18px;--icon-color: currentColor}.k-icon{width:var(--icon-size);height:var(--icon-size);flex-shrink:0;color:var(--icon-color)}.k-icon[data-type=loader]{animation:Spin 1.5s linear infinite}@media only screen and (-webkit-min-device-pixel-ratio: 2),not all,not all,not all,only screen and (min-resolution: 192dpi),only screen and (min-resolution: 2dppx){.k-button-icon [data-type=emoji]{font-size:1.25em}}.k-icon-frame [data-type=emoji]{overflow:visible}.k-image[data-back=pattern]{--back: var(--color-black) var(--pattern)}.k-image[data-back=black]{--back: var(--color-black)}.k-image[data-back=white]{--back: var(--color-white);color:var(--color-gray-900)}:root{--overlay-color-back: var(--color-backdrop)}.k-overlay[open]{position:fixed;overscroll-behavior:contain;top:0;right:0;bottom:0;left:0;width:100%;height:100vh;height:100dvh;background:none;z-index:var(--z-dialog);transform:translateZ(0);overflow:hidden}.k-overlay[open]::backdrop{background:none}.k-overlay[open]>.k-portal{position:fixed;top:0;right:0;bottom:0;left:0;background:var(--overlay-color-back);overflow:auto}.k-overlay[open][data-type=dialog]>.k-portal{display:inline-flex}.k-overlay[open][data-type=dialog]>.k-portal>*{margin:auto}.k-overlay[open][data-type=drawer]>.k-portal{--overlay-color-back: rgba(0, 0, 0, .2);display:flex;align-items:stretch;justify-content:flex-end}html[data-overlay]{overflow:hidden}html[data-overlay] body{overflow:scroll}:root{--stat-value-text-size: var(--text-2xl);--stat-info-text-color: var(--color-text-dimmed)}.k-stat{display:flex;flex-direction:column;padding:var(--spacing-3) var(--spacing-6);background:var(--color-white);border-radius:var(--rounded);box-shadow:var(--shadow);line-height:var(--leading-normal)}.k-stat.k-link:hover{cursor:pointer;background:var(--color-gray-100)}.k-stat :where(dt,dd){display:block}.k-stat-value{order:1;font-size:var(--stat-value-text-size);margin-bottom:var(--spacing-1)}.k-stat-label{--icon-size: var(--text-sm);order:2;display:flex;justify-content:start;align-items:center;gap:var(--spacing-1);font-size:var(--text-xs)}.k-stat-info{order:3;font-size:var(--text-xs);color:var(--stat-info-text-color)}.k-stat:is([data-theme]) .k-stat-info{--stat-info-text-color: var(--theme-color-700)}.k-stats{display:grid;grid-template-columns:repeat(auto-fit,minmax(14rem,1fr));grid-auto-rows:1fr;grid-gap:var(--spacing-2px)}.k-stats[data-size=small]{--stat-value-text-size: var(--text-md)}.k-stats[data-size=medium]{--stat-value-text-size: var(--text-xl)}.k-stats[data-size=large]{--stat-value-text-size: var(--text-2xl)}.k-stats[data-size=huge]{--stat-value-text-size: var(--text-3xl)}:root{--table-cell-padding: var(--spacing-3);--table-color-back: var(--color-white);--table-color-border: var(--color-background);--table-color-hover: var(--color-gray-100);--table-color-th-back: var(--color-gray-100);--table-color-th-text: var(--color-text-dimmed);--table-row-height: var(--input-height)}.k-table{position:relative;background:var(--table-color-back);box-shadow:var(--shadow);border-radius:var(--rounded)}.k-table table{table-layout:fixed}.k-table th,.k-table td{padding-inline:var(--table-cell-padding);height:var(--table-row-height);overflow:hidden;text-overflow:ellipsis;width:100%;border-inline-end:1px solid var(--table-color-border);line-height:1.25}.k-table tr>*:last-child{border-inline-end:0}.k-table th,.k-table tr:not(:last-child) td{border-block-end:1px solid var(--table-color-border)}.k-table :where(td,th)[data-align]{text-align:var(--align)}.k-table th{padding-inline:var(--table-cell-padding);font-family:var(--font-mono);font-size:var(--text-xs);color:var(--table-color-th-text);background:var(--table-color-th-back)}.k-table th[data-has-button]{padding:0}.k-table th button{padding-inline:var(--table-cell-padding);height:100%;width:100%;border-radius:var(--rounded);text-align:start}.k-table th button:focus-visible{outline-offset:-2px}.k-table thead th:first-child{border-start-start-radius:var(--rounded)}.k-table thead th:last-child{border-start-end-radius:var(--rounded)}.k-table thead th{position:sticky;top:var(--header-sticky-offset);inset-inline:0;z-index:1}.k-table tbody tr:hover td{background:var(--table-color-hover)}.k-table tbody th{width:auto;white-space:nowrap;overflow:visible;border-radius:0}.k-table tbody tr:first-child th{border-start-start-radius:var(--rounded)}.k-table tbody tr:last-child th{border-end-start-radius:var(--rounded);border-block-end:0}.k-table-row-ghost{background:var(--color-white);outline:var(--outline);border-radius:var(--rounded);margin-bottom:2px;cursor:grabbing}.k-table-row-fallback{opacity:0!important}.k-table .k-table-index-column{width:var(--table-row-height);text-align:center}.k-table .k-table-index{font-size:var(--text-xs);color:var(--color-text-dimmed);line-height:1.1em}.k-table .k-table-index-column .k-sort-handle{--button-width: 100%;display:none}.k-table tr:hover .k-table-index-column[data-sortable=true] .k-table-index{display:none}.k-table tr:hover .k-table-index-column[data-sortable=true] .k-sort-handle{display:flex}.k-table .k-table-options-column{padding:0;width:var(--table-row-height);text-align:center}.k-table .k-table-options-column .k-options-dropdown-toggle{--button-width: 100%;--button-height: 100%;outline-offset:-2px}.k-table-empty{color:var(--color-text-dimmed);font-size:var(--text-sm)}.k-table[aria-disabled=true]{--table-color-back: transparent;--table-color-border: var(--color-border);--table-color-hover: transparent;--table-color-th-back: transparent;border:1px solid var(--table-color-border);box-shadow:none}.k-table[aria-disabled=true] thead th{position:static}@container (max-width: 40rem){.k-table{overflow-x:auto}.k-table thead th{position:static}.k-table .k-options-dropdown-toggle{aspect-ratio:auto!important}.k-table :where(th,td):not(.k-table-index-column,.k-table-options-column,[data-column-id=image],[data-column-id=flag]){width:auto!important}.k-table :where(th,td):not([data-mobile=true]){display:none}}.k-table-pagination{border-top:1px solid var(--table-color-border);height:var(--table-row-height);background:var(--table-color-th-back);display:flex;justify-content:center;border-end-start-radius:var(--rounded);border-end-end-radius:var(--rounded)}.k-table-pagination>.k-button{--button-color-back: transparent;border-left:0!important}.k-table .k-table-cell{padding:0}.k-tabs{--button-height: var(--height-md);--button-padding: var(--spacing-2);display:flex;gap:var(--spacing-1);margin-bottom:var(--spacing-12);margin-inline:calc(var(--button-padding) * -1)}.k-tabs-tab{position:relative}.k-tab-button.k-button{margin-block:2px;overflow-x:visible}.k-tab-button[aria-current]:after{position:absolute;content:"";height:2px;inset-inline:var(--button-padding);bottom:-2px;background:currentColor}.k-tabs-badge{position:absolute;top:2px;font-variant-numeric:tabular-nums;inset-inline-end:var(--button-padding);transform:translate(75%);line-height:1.5;padding:0 var(--spacing-1);border-radius:1rem;text-align:center;font-size:10px;box-shadow:var(--shadow-md);background:var(--theme-color-back);border:1px solid var(--theme-color-500);color:var(--theme-color-text);z-index:1}.k-view{padding-inline:1.5rem}@container (min-width: 30rem){.k-view{padding-inline:3rem}}.k-view[data-align=center]{height:100vh;display:flex;align-items:center;justify-content:center;padding:0 3rem;overflow:auto}.k-view[data-align=center]>*{flex-basis:22.5rem}.k-fatal[open]{background:var(--overlay-color-back);padding:var(--spacing-6)}.k-fatal-box{position:relative;width:100%;box-shadow:var(--dialog-shadow);border-radius:var(--dialog-rounded);line-height:1;height:calc(100vh - 3rem);height:calc(100dvh - 3rem);display:flex;flex-direction:column;overflow:hidden}.k-fatal-iframe{border:0;width:100%;flex-grow:1;background:var(--color-white);padding:var(--spacing-3)}.k-icons{position:absolute;width:0;height:0}.k-loader{z-index:1}.k-loader-icon{animation:Spin .9s linear infinite}.k-notification{padding:.75rem 1.5rem;background:var(--color-gray-900);width:100%;line-height:1.25rem;color:var(--color-white);display:flex;flex-shrink:0;align-items:center}.k-notification[data-theme]{background:var(--theme-color-back);color:var(--color-black)}.k-notification p{flex-grow:1;word-wrap:break-word;overflow:hidden}.k-notification .k-button{display:flex;margin-inline-start:1rem}.k-offline-warning{position:fixed;top:0;right:0;bottom:0;left:0;z-index:var(--z-offline);background:var(--color-backdrop);display:flex;align-items:center;justify-content:center;line-height:1}.k-offline-warning p{display:flex;align-items:center;gap:.5rem;background:var(--color-white);box-shadow:var(--shadow);padding:.75rem;border-radius:var(--rounded)}.k-offline-warning p .k-icon{color:var(--color-red-400)}:root{--progress-height: var(--spacing-2);--progress-color-back: var(--color-gray-300);--progress-color-value: var(--color-focus)}progress{display:block;width:100%;height:var(--progress-height);border-radius:var(--progress-height);overflow:hidden;border:0}progress::-webkit-progress-bar{background:var(--progress-color-back)}progress::-webkit-progress-value{background:var(--progress-color-value);border-radius:var(--progress-height)}progress::-moz-progress-bar{background:var(--progress-color-value)}progress:not([value])::-webkit-progress-bar{background:var(--progress-color-value)}progress:not([value])::-moz-progress-bar{background:var(--progress-color-value)}.k-sort-handle{cursor:grab;z-index:1}.k-sort-handle:active{cursor:grabbing}.k-breadcrumb{--breadcrumb-divider: "/";overflow-x:clip;padding:2px}.k-breadcrumb ol{display:none;gap:.125rem;align-items:center}.k-breadcrumb ol li{display:flex;align-items:center;min-width:0}.k-breadcrumb ol li:not(:last-child):after{content:var(--breadcrumb-divider);opacity:.175;flex-shrink:0}.k-breadcrumb ol li{min-width:0;transition:flex-shrink .1s}.k-breadcrumb .k-icon[data-type=loader]{opacity:.5}.k-breadcrumb ol li:is(:hover,:focus-within){flex-shrink:0}.k-button.k-breadcrumb-link{flex-shrink:1;min-width:0;justify-content:flex-start}.k-breadcrumb-dropdown{display:grid}.k-breadcrumb-dropdown .k-dropdown-content{width:15rem}@container (min-width: 40em){.k-breadcrumb ol{display:flex}.k-breadcrumb-dropdown{display:none}}.k-browser{container-type:inline-size;font-size:var(--text-sm)}.k-browser-items{--browser-item-gap: 1px;--browser-item-size: 1fr;--browser-item-height: var(--height-sm);--browser-item-padding: .25rem;--browser-item-rounded: var(--rounded);display:grid;column-gap:var(--browser-item-gap);row-gap:var(--browser-item-gap);grid-template-columns:repeat(auto-fill,minmax(var(--browser-item-size),1fr))}.k-browser-item{display:flex;overflow:hidden;gap:.5rem;align-items:center;flex-shrink:0;height:var(--browser-item-height);padding-inline:calc(var(--browser-item-padding) + 1px);border-radius:var(--browser-item-rounded);white-space:nowrap;cursor:pointer}.k-browser-item-image{height:calc(var(--browser-item-height) - var(--browser-item-padding) * 2);aspect-ratio:1/1;border-radius:var(--rounded-sm);box-shadow:var(--shadow);flex-shrink:0}.k-browser-item-image.k-icon-frame{box-shadow:none;background:var(--color-white)}.k-browser-item-image svg{transform:scale(.8)}.k-browser-item input{position:absolute;box-shadow:var(--shadow);opacity:0;width:0}.k-browser-item[aria-selected]{background:var(--color-blue-300)}:root{--button-align: center;--button-height: var(--height-md);--button-width: auto;--button-color-back: none;--button-color-text: currentColor;--button-color-icon: currentColor;--button-padding: var(--spacing-2);--button-rounded: var(--spacing-1);--button-text-display: block;--button-icon-display: block}.k-button{position:relative;display:inline-flex;align-items:center;justify-content:var(--button-align);gap:.5rem;padding-inline:var(--button-padding);white-space:nowrap;line-height:1;border-radius:var(--button-rounded);background:var(--button-color-back);height:var(--button-height);width:var(--button-width);color:var(--button-color-text);font-variant-numeric:tabular-nums;overflow-x:clip;text-align:var(--button-align);flex-shrink:0}.k-button-icon{--icon-color: var(--button-color-icon);flex-shrink:0;display:var(--button-icon-display)}.k-button-text{text-overflow:ellipsis;overflow-x:clip;display:var(--button-text-display);min-width:0}.k-button:where([data-theme]){--button-color-icon: var(--theme-color-icon);--button-color-text: var(--theme-color-text)}.k-button:where([data-theme$=-icon]){--button-color-text: currentColor}.k-button:where([data-variant=dimmed]){--button-color-icon: var(--color-text);--button-color-text: var(--color-text-dimmed)}.k-button:where([data-variant=dimmed]):not([aria-disabled]):is(:hover,[aria-current]) .k-button-text{filter:brightness(75%)}.k-button:where([data-variant=dimmed][data-theme]){--button-color-icon: var(--theme-color-icon);--button-color-text: var(--theme-color-text-dimmed)}.k-button:where([data-variant=dimmed][data-theme$=-icon]){--button-color-text: var(--color-text-dimmed)}.k-button:where([data-variant=filled]){--button-color-back: var(--color-gray-300)}.k-button:where([data-variant=filled]):not([aria-disabled]):hover{filter:brightness(97%)}.k-button:where([data-variant=filled][data-theme]){--button-color-icon: var(--theme-color-700);--button-color-back: var(--theme-color-back)}.k-button:where([data-theme$=-icon][data-variant=filled]){--button-color-icon: hsl( var(--theme-color-hs), 57% );--button-color-back: var(--color-gray-300)}.k-button:not([data-has-text=true]){--button-padding: 0;aspect-ratio:1/1}@container (max-width: 30rem){.k-button[data-responsive=true][data-has-icon=true]{--button-padding: 0;aspect-ratio:1/1;--button-text-display: none}.k-button[data-responsive=text][data-has-text=true]{--button-icon-display: none}.k-button[data-responsive][data-has-icon=true] .k-button-arrow{display:none}}.k-button:not(button,a,summary,label,.k-link){pointer-events:none}.k-button:where([data-size=xs]){--button-height: var(--height-xs);--button-padding: .325rem}.k-button:where([data-size=sm]){--button-height: var(--height-sm);--button-padding: .5rem}.k-button:where([data-size=lg]){--button-height: var(--height-lg)}.k-button-arrow{--icon-size: 14px;width:max-content;margin-inline-start:-.125rem}.k-button:where([aria-disabled]){cursor:not-allowed}.k-button:where([aria-disabled])>*{opacity:var(--opacity-disabled)}.k-button-group{display:flex;flex-wrap:wrap;gap:.5rem;align-items:center}.k-button-group:where([data-layout=collapsed]){gap:0;flex-wrap:nowrap}.k-button-group[data-layout=collapsed]>.k-button[data-variant=filled]:not(:last-child){border-start-end-radius:0;border-end-end-radius:0}.k-button-group[data-layout=collapsed]>.k-button[data-variant=filled]:not(:first-child){border-start-start-radius:0;border-end-start-radius:0;border-left:1px solid var(--theme-color-500, var(--color-gray-400))}.k-button-group[data-layout=collapsed]>.k-button[data-variant=filled]:focus-visible{z-index:1;border-radius:var(--button-rounded)}.k-file-browser{container-type:inline-size;overflow:hidden}.k-file-browser-layout{display:grid;grid-template-columns:minmax(10rem,15rem) 1fr;grid-template-rows:1fr auto;grid-template-areas:"tree items" "tree pagination"}.k-file-browser-tree{grid-area:tree;padding:var(--spacing-2);border-right:1px solid var(--color-gray-300)}.k-file-browser-items{grid-area:items;padding:var(--spacing-2);background:var(--color-gray-100)}.k-file-browser-back-button{display:none}.k-file-browser-pagination{background:var(--color-gray-100);padding:var(--spacing-2);display:flex;justify-content:end}@container (max-width: 30rem){.k-file-browser-layout{grid-template-columns:minmax(0,1fr);min-height:10rem}.k-file-browser-back-button{width:100%;height:var(--height-sm);display:flex;align-items:center;justify-content:flex-start;padding-inline:.25rem;margin-bottom:.5rem;background:var(--color-gray-200);border-radius:var(--rounded)}.k-file-browser-tree{border-right:0}.k-file-browser-pagination{justify-content:start}.k-file-browser[data-view=files] .k-file-browser-layout{grid-template-rows:1fr auto;grid-template-areas:"items" "pagination"}.k-file-browser[data-view=files] .k-file-browser-tree,.k-file-browser[data-view=tree] .k-file-browser-items,.k-file-browser[data-view=tree] .k-file-browser-pagination{display:none}}:root{--tree-color-back: var(--color-gray-200);--tree-color-hover-back: var(--color-gray-300);--tree-color-selected-back: var(--color-blue-300);--tree-color-selected-text: var(--color-black);--tree-color-text: var(--color-gray-dimmed);--tree-level: 0;--tree-indentation: .6rem}.k-tree-branch{display:flex;align-items:center;padding-inline-start:calc(var(--tree-level) * var(--tree-indentation));margin-bottom:1px}.k-tree-branch[data-has-subtree=true]{inset-block-start:calc(var(--tree-level) * 1.5rem);z-index:calc(100 - var(--tree-level));background:var(--tree-color-back)}.k-tree-branch:hover,li[aria-current]>.k-tree-branch{--tree-color-text: var(--tree-color-selected-text);background:var(--tree-color-hover-back);border-radius:var(--rounded)}li[aria-current]>.k-tree-branch{background:var(--tree-color-selected-back)}.k-tree-toggle{--icon-size: 12px;width:1rem;aspect-ratio:1/1;display:grid;place-items:center;padding:0;border-radius:var(--rounded-sm);margin-inline-start:.25rem;flex-shrink:0}.k-tree-toggle:hover{background:#00000013}.k-tree-toggle[disabled]{visibility:hidden}.k-tree-folder{display:flex;height:var(--height-sm);border-radius:var(--rounded-sm);padding-inline:.25rem;width:100%;align-items:center;gap:.325rem;min-width:3rem;line-height:1.25;font-size:var(--text-sm)}@container (max-width: 15rem){.k-tree{--tree-indentation: .375rem}.k-tree-folder{padding-inline:.125rem}.k-tree-folder .k-icon{display:none}}.k-tree-folder>.k-frame{flex-shrink:0}.k-tree-folder-label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:currentColor}.k-tree-folder[disabled]{opacity:var(--opacity-disabled)}.k-pagination{flex-shrink:0}.k-pagination-details{--button-padding: var(--spacing-3);font-size:var(--text-xs)}.k-pagination-selector{--button-height: var(--height);--dropdown-padding: 0;overflow:visible}.k-pagination-selector form{display:flex;align-items:center;justify-content:space-between}.k-pagination-selector label{display:flex;align-items:center;gap:var(--spacing-2);padding-inline-start:var(--spacing-3)}.k-pagination-selector select{--height: calc(var(--button-height) - .5rem);width:auto;min-width:var(--height);height:var(--height);text-align:center;background:var(--color-gray-800);color:var(--color-white);border-radius:var(--rounded-sm)}.k-prev-next{direction:ltr;flex-shrink:0}:root{--tag-color-back: var(--color-black);--tag-color-text: var(--color-white);--tag-color-toggle: currentColor;--tag-color-disabled-back: var(--color-gray-600);--tag-color-disabled-text: var(--tag-color-text);--tag-height: var(--height-xs);--tag-rounded: var(--rounded-sm)}.k-tag{position:relative;height:var(--tag-height);display:flex;align-items:center;justify-content:space-between;font-size:var(--text-sm);line-height:1;color:var(--tag-color-text);background-color:var(--tag-color-back);border-radius:var(--tag-rounded);cursor:pointer;-webkit-user-select:none;user-select:none}.k-tag:not([aria-disabled]):focus{outline:var(--outline)}.k-tag-image{height:100%;border-radius:var(--rounded-xs);overflow:hidden;flex-shrink:0;border-radius:0;border-start-start-radius:var(--tag-rounded);border-end-start-radius:var(--tag-rounded);background-clip:padding-box}.k-tag-text{padding-inline:var(--spacing-2);line-height:var(--leading-tight);overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.k-tag[data-has-toggle=true] .k-tag-text{padding-inline-end:0}.k-tag-toggle{--icon-size: 14px;width:var(--tag-height);height:var(--tag-height);filter:brightness(70%);flex-shrink:0}.k-tag-toggle:hover{filter:brightness(100%)}.k-tag:where([aria-disabled]){background-color:var(--tag-color-disabled-back);color:var(--tag-color-disabled-text);cursor:not-allowed}.k-button[data-disabled=true]{opacity:.5;pointer-events:none;cursor:default}.k-card-options>.k-button[data-disabled=true]{display:inline-flex}.k-section+.k-section{margin-top:var(--columns-block-gap)}.k-section-header{display:flex;justify-content:space-between;align-items:center;gap:var(--spacing-6);margin-bottom:var(--spacing-2)}.k-section-buttons{flex-shrink:0}.k-fields-section input[type=submit]{display:none}[data-locked=true] .k-fields-section{opacity:.2;pointer-events:none}.k-models-section[data-processing=true]{pointer-events:none}.k-models-section-search.k-input{--input-color-back: var(--color-gray-300);--input-color-border: transparent;margin-bottom:var(--spacing-3)}:root{--code-color-back: var(--color-black);--code-color-icon: var(--color-gray-500);--code-color-text: var(--color-gray-200, white);--code-font-family: var(--font-mono);--code-font-size: 1em;--code-inline-color-back: var(--color-blue-300);--code-inline-color-border: var(--color-blue-400);--code-inline-color-text: var(--color-blue-900);--code-inline-font-size: .9em;--code-padding: var(--spacing-3)}code{font-family:var(--code-font-family);font-size:var(--code-font-size);font-weight:var(--font-normal)}.k-code,.k-text pre{position:relative;display:block;max-width:100%;padding:var(--code-padding);border-radius:var(--rounded, .5rem);background:var(--code-color-back);color:var(--code-color-text);white-space:nowrap;overflow-y:hidden;overflow-x:auto;line-height:1.5;-moz-tab-size:2;tab-size:2}.k-code:not(code),.k-text pre{white-space:pre-wrap}.k-code:before{position:absolute;content:attr(data-language);inset-block-start:0;inset-inline-end:0;padding:.5rem .5rem .25rem .25rem;font-size:calc(.75 * var(--text-xs));background:var(--code-color-back);border-radius:var(--rounded, .5rem)}.k-text>code,.k-text *:not(pre)>code{display:inline-flex;padding-inline:var(--spacing-1);font-size:var(--code-inline-font-size);color:var(--code-inline-color-text);background:var(--code-inline-color-back);border-radius:var(--rounded);outline:1px solid var(--code-inline-color-border);outline-offset:-1px}:root{--text-h1: 2em;--text-h2: 1.75em;--text-h3: 1.5em;--text-h4: 1.25em;--text-h5: 1.125em;--text-h6: 1em;--font-h1: var(--font-semi);--font-h2: var(--font-semi);--font-h3: var(--font-semi);--font-h4: var(--font-semi);--font-h5: var(--font-semi);--font-h6: var(--font-semi);--leading-h1: 1.125;--leading-h2: 1.125;--leading-h3: 1.25;--leading-h4: 1.375;--leading-h5: 1.5;--leading-h6: 1.5}.k-headline{line-height:1.5em;font-weight:var(--font-bold)}.h1,.k-text h1,.k-headline[data-size=huge]{color:var(--color-h1, var(--color-h));font-family:var(--font-family-h1);font-size:var(--text-h1);font-weight:var(--font-h1);line-height:var(--leading-h1)}.h2,.k-text h2,.k-headline[data-size=large]{color:var(--color-h2, var(--color-h));font-family:var(--font-family-h2);font-size:var(--text-h2);font-weight:var(--font-h2);line-height:var(--leading-h2)}.h3,.k-text h3{color:var(--color-h3, var(--color-h));font-family:var(--font-family-h3);font-size:var(--text-h3);font-weight:var(--font-h3);line-height:var(--leading-h3)}.h4,.k-text h4,.k-headline[data-size=small]{color:var(--color-h4, var(--color-h));font-family:var(--font-family-h4);font-size:var(--text-h4);font-weight:var(--font-h4);line-height:var(--leading-h4)}.h5,.k-text h5{color:var(--color-h5, var(--color-h));font-family:var(--font-family-h5);font-size:var(--text-h5);font-weight:var(--font-h5);line-height:var(--leading-h5)}.h6,.k-text h6{color:var(--color-h6, var(--color-h));font-family:var(--font-family-h6);font-size:var(--text-h6);font-weight:var(--font-h6);line-height:var(--leading-h6)}.k-text>*+h6{margin-block-start:calc(var(--text-line-height) * 1.5em)}.k-headline[data-theme]{color:var(--theme)}.k-label{position:relative;display:flex;align-items:center;height:var(--height-xs);font-weight:var(--font-semi);min-width:0;flex:1}[aria-disabled] .k-label{opacity:var(--opacity-disabled);cursor:not-allowed}.k-label>a{display:inline-flex;height:var(--height-xs);align-items:center;padding-inline:var(--spacing-2);margin-inline-start:calc(-1 * var(--spacing-2));border-radius:var(--rounded);min-width:0}.k-label-text{text-overflow:ellipsis;white-space:nowrap;overflow-x:clip;min-width:0}.k-label abbr{font-size:var(--text-xs);color:var(--color-gray-500);margin-inline-start:var(--spacing-1)}.k-label abbr.k-label-invalid{display:none;color:var(--color-red-700)}:where(.k-field:has([data-invalid]),.k-section:has([data-invalid]))>header>.k-label abbr.k-label-invalid{display:inline-block}.k-field:has([data-invalid])>.k-field-header>.k-label abbr:has(+abbr.k-label-invalid){display:none}:root{--text-font-size: 1em;--text-line-height: 1.5;--link-color: var(--color-blue-800);--link-underline-offset: 2px}.k-text{font-size:var(--text-font-size);line-height:var(--text-line-height)}.k-text[data-size=tiny]{--text-font-size: var(--text-xs)}.k-text[data-size=small]{--text-font-size: var(--text-sm)}.k-text[data-size=medium]{--text-font-size: var(--text-md)}.k-text[data-size=large]{--text-font-size: var(--text-xl)}.k-text[data-align]{text-align:var(--align)}.k-text>:where(audio,blockquote,details,div,figure,h1,h2,h3,h4,h5,h6,hr,iframe,img,object,ol,p,picture,pre,table,ul)+*{margin-block-start:calc(var(--text-line-height) * 1em)}.k-text :where(.k-link,a){color:var(--link-color);text-decoration:underline;text-underline-offset:var(--link-underline-offset);border-radius:var(--rounded-xs);outline-offset:2px}.k-text ol,.k-text ul{padding-inline-start:1.75em}.k-text ol{list-style:numeric}.k-text ol>li{list-style:decimal}.k-text ul>li{list-style:disc}.k-text ul ul>li{list-style:circle}.k-text ul ul ul>li{list-style:square}.k-text blockquote{font-size:var(--text-lg);line-height:1.25;padding-inline-start:var(--spacing-4);border-inline-start:2px solid var(--color-black)}.k-text img{border-radius:var(--rounded)}.k-text iframe{width:100%;aspect-ratio:16/9;border-radius:var(--rounded)}.k-text hr{background:var(--color-border);height:1px}.k-help{color:var(--color-text-dimmed)}.k-upload-item-preview{--icon-size: 24px;grid-area:preview;display:flex;aspect-ratio:1/1;width:100%;height:100%;overflow:hidden;border-start-start-radius:var(--rounded);border-end-start-radius:var(--rounded)}.k-upload-item-preview:focus{border-radius:var(--rounded);outline:2px solid var(--color-focus);z-index:1}.k-upload-item{accent-color:var(--color-focus);display:grid;grid-template-areas:"preview input input" "preview body toggle";grid-template-columns:6rem 1fr auto;grid-template-rows:var(--input-height) 1fr;border-radius:var(--rounded);background:var(--color-white);box-shadow:var(--shadow);min-height:6rem}.k-upload-item-body{grid-area:body;display:flex;flex-direction:column;justify-content:space-between;padding:var(--spacing-2) var(--spacing-3);min-width:0}.k-upload-item-input.k-input{--input-color-border: transparent;--input-padding: var(--spacing-2) var(--spacing-3);--input-rounded: 0;grid-area:input;font-size:var(--text-sm);border-bottom:1px solid var(--color-light);border-start-end-radius:var(--rounded)}.k-upload-item-input.k-input:focus-within{outline:2px solid var(--color-focus);z-index:1;border-radius:var(--rounded)}.k-upload-item-input.k-input[data-disabled=true]{--input-color-back: var(--color-white)}.k-upload-item-input .k-input-after{color:var(--color-gray-600)}.k-upload-item-meta{font-size:var(--text-xs);color:var(--color-gray-600)}.k-upload-item-error{font-size:var(--text-xs);margin-top:.25rem;color:var(--color-red-700)}.k-upload-item-progress{--progress-height: .25rem;--progress-color-back: var(--color-light);margin-bottom:.3125rem}.k-upload-item-toggle{grid-area:toggle;align-self:end}.k-upload-item-toggle>*{padding:var(--spacing-3)}.k-upload-item[data-completed] .k-upload-item-progress{--progress-color-value: var(--color-green-400)}.k-upload-items{display:grid;gap:.25rem}.k-activation{position:relative;display:flex;color:var(--dropdown-color-text);background:var(--dropdown-color-bg);border-radius:var(--dropdown-rounded);box-shadow:var(--dropdown-shadow);justify-content:space-between}.k-activation p{padding-inline-start:var(--spacing-3);padding-inline-end:var(--spacing-2);padding-block:.425rem;line-height:1.25}.k-activation p strong{font-weight:var(--font-normal);margin-inline-end:var(--spacing-1)}.k-activation p :where(button,a){color:var(--color-pink-400);text-decoration:underline;text-decoration-color:currentColor;text-underline-offset:2px;border-radius:var(--rounded-sm)}.k-activation-toggle{--button-color-text: var(--color-gray-400);--button-rounded: 0;border-left:1px solid var(--dropdown-color-hr)}.k-activation-toggle:is(:hover,:focus){--button-color-text: var(--color-white)}.k-activation-toggle:focus{--button-rounded: var(--rounded)}:root{--main-padding-inline: clamp(var(--spacing-6), 5cqw, var(--spacing-24))}.k-panel-main{min-height:100vh;min-height:100dvh;padding:var(--spacing-3) var(--main-padding-inline) var(--spacing-24);container:main / inline-size;margin-inline-start:var(--main-start)}.k-panel-notification{--button-height: var(--height-md);--button-color-icon: var(--theme-color-900);--button-color-text: var(--theme-color-900);border:1px solid var(--theme-color-500);position:fixed;inset-block-end:var(--menu-padding);inset-inline-end:var(--menu-padding);box-shadow:var(--dropdown-shadow);z-index:var(--z-notification)}:root{--menu-button-height: var(--height);--menu-button-width: 100%;--menu-color-back: var(--color-gray-250);--menu-color-border: var(--color-gray-300);--menu-display: none;--menu-display-backdrop: block;--menu-padding: var(--spacing-3);--menu-shadow: var(--shadow-xl);--menu-toggle-height: var(--menu-button-height);--menu-toggle-width: 1rem;--menu-width-closed: calc( var(--menu-button-height) + 2 * var(--menu-padding) );--menu-width-open: 12rem;--menu-width: var(--menu-width-open)}.k-panel-menu{position:fixed;inset-inline-start:0;inset-block:0;z-index:var(--z-navigation);display:var(--menu-display);width:var(--menu-width);background-color:var(--menu-color-back);border-right:1px solid var(--menu-color-border);box-shadow:var(--menu-shadow)}.k-panel-menu-body{display:flex;flex-direction:column;gap:var(--spacing-4);padding:var(--menu-padding);overscroll-behavior:contain;overflow-x:hidden;overflow-y:auto;height:100%}.k-panel-menu-search{margin-bottom:var(--spacing-8)}.k-panel-menu-buttons{display:flex;flex-direction:column;width:100%}.k-panel-menu-buttons[data-second-last=true]{flex-grow:1}.k-panel-menu-buttons:last-child{justify-content:flex-end}.k-panel-menu-button{--button-align: flex-start;--button-height: var(--menu-button-height);--button-width: var(--menu-button-width);--button-padding: 7px;flex-shrink:0}.k-panel-menu-button[aria-current]{--button-color-back: var(--color-white);box-shadow:var(--shadow)}.k-panel-menu-button:focus{z-index:1}.k-panel[data-menu=true]{--menu-button-width: 100%;--menu-display: block;--menu-width: var(--menu-width-open)}.k-panel[data-menu=true]:after{content:"";position:fixed;top:0;right:0;bottom:0;left:0;background:var(--color-backdrop);display:var(--menu-display-backdrop);pointer-events:none}.k-panel-menu-toggle{--button-align: flex-start;--button-height: 100%;--button-width: var(--menu-toggle-width);position:absolute;inset-block:0;inset-inline-start:100%;align-items:flex-start;border-radius:0;overflow:visible;opacity:0;transition:opacity .2s}.k-panel-menu-toggle:focus{outline:0}.k-panel-menu-toggle .k-button-icon{display:grid;place-items:center;height:var(--menu-toggle-height);width:var(--menu-toggle-width);margin-top:var(--menu-padding);border-block:1px solid var(--menu-color-border);border-inline-end:1px solid var(--menu-color-border);background:var(--menu-color-back);border-start-end-radius:var(--button-rounded);border-end-end-radius:var(--button-rounded)}@media (max-width: 60rem){.k-panel-menu .k-activation-button{margin-bottom:var(--spacing-3)}.k-panel-menu .k-activation-toggle{display:none}}@media (min-width: 60rem){.k-panel{--menu-display: block;--menu-display-backdrop: none;--menu-shadow: none;--main-start: var(--menu-width)}.k-panel[data-menu=false]{--menu-button-width: var(--menu-button-height);--menu-width: var(--menu-width-closed)}.k-panel-menu-proxy{display:none}.k-panel-menu-toggle:focus-visible,.k-panel-menu[data-hover] .k-panel-menu-toggle{opacity:1}.k-panel-menu-toggle:focus-visible .k-button-icon{outline:var(--outline);border-radius:var(--button-rounded)}.k-panel-menu-search[aria-disabled=true]{opacity:0}.k-panel-menu .k-activation{position:absolute;bottom:var(--menu-padding);inset-inline-start:100%;height:var(--height-md);width:max-content;margin-left:var(--menu-padding)}.k-panel-menu .k-activation:before{position:absolute;content:"";top:50%;left:-4px;margin-top:-4px;border-top:4px solid transparent;border-right:4px solid var(--color-black);border-bottom:4px solid transparent}.k-panel-menu .k-activation p :where(button,a){padding-inline:var(--spacing-1)}.k-panel-menu .k-activation-toggle{border-left:1px solid var(--dropdown-color-hr)}}.k-panel.k-panel-outside{display:grid;grid-template-rows:1fr;place-items:center;min-height:100vh;min-height:100dvh;padding:var(--spacing-6)}:root{--scroll-top: 0rem}html{overflow-x:hidden;overflow-y:scroll;background:var(--color-light)}body{font-size:var(--text-sm)}.k-panel[data-loading=true]{animation:LoadingCursor .5s}.k-panel[data-loading=true]:after,.k-panel[data-dragging=true]{-webkit-user-select:none;user-select:none}.k-topbar{position:relative;margin-inline:calc(var(--button-padding) * -1);margin-bottom:var(--spacing-8);display:flex;align-items:center;gap:var(--spacing-1)}.k-topbar-breadcrumb{margin-inline-start:-2px}.k-topbar-spacer{flex-grow:1}.k-topbar-signals{display:flex;align-items:center}.k-search-view .k-header{margin-bottom:0}.k-header+.k-search-view-results{margin-top:var(--spacing-12)}.k-search-view-input{--input-color-border: transparent;--input-color-back: var(--color-gray-300);--input-height: var(--height-md);width:40cqw}.k-file-view-header,.k-file-view[data-has-tabs=true] .k-file-preview{margin-bottom:0}.k-file-preview{display:grid;align-items:stretch;background:var(--color-gray-900);border-radius:var(--rounded-lg);margin-bottom:var(--spacing-12);overflow:hidden}.k-file-preview-thumb-column{background:var(--pattern);aspect-ratio:1/1}.k-file-preview-thumb{display:flex;align-items:center;justify-content:center;height:100%;padding:var(--spacing-12);container-type:size}.k-file-preview-thumb img{width:auto;max-width:100cqw;max-height:100cqh}.k-file-preview-thumb>.k-icon{--icon-size: 3rem}.k-file-preview-thumb>.k-button{position:absolute;top:var(--spacing-2);inset-inline-start:var(--spacing-2)}.k-file-preview .k-coords-input{--opacity-disabled: 1;--range-thumb-color: hsl(216 60% 60% / .75);--range-thumb-size: 1.25rem;--range-thumb-shadow: none;cursor:crosshair}.k-file-preview .k-coords-input-thumb:after{--size: .4rem;--pos: calc(50% - (var(--size) / 2));position:absolute;top:var(--pos);inset-inline-start:var(--pos);width:var(--size);height:var(--size);content:"";background:var(--color-white);border-radius:50%}.k-file-preview:not([data-has-focus=true]) .k-coords-input-thumb{display:none}.k-file-preview-details{display:grid}.k-file-preview-details dl{display:grid;grid-template-columns:repeat(auto-fill,minmax(14rem,1fr));grid-gap:var(--spacing-6) var(--spacing-12);align-self:center;line-height:1.5em;padding:var(--spacing-6)}.k-file-preview-details dt{font-size:var(--text-sm);font-weight:500;font-weight:var(--font-semi);color:var(--color-gray-500);margin-bottom:var(--spacing-1)}.k-file-preview-details :where(dd,a){font-size:var(--text-xs);color:#ffffff80;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;color:#ffffffbf;font-size:var(--text-sm)}.k-file-preview-focus-info dd{display:flex;align-items:center}.k-file-preview-focus-info .k-button{--button-padding: var(--spacing-2);--button-color-back: var(--color-gray-800)}.k-file-preview[data-has-focus=true] .k-file-preview-focus-info .k-button{flex-direction:row-reverse}@container (min-width: 36rem){.k-file-preview{grid-template-columns:50% auto}.k-file-preview-thumb-column{aspect-ratio:auto}}@container (min-width: 65rem){.k-file-preview{grid-template-columns:33.333% auto}.k-file-preview-thumb-column{aspect-ratio:1/1}}@container (min-width: 90rem){.k-file-preview-layout{grid-template-columns:25% auto}}.k-installation-dialog{--dialog-color-back: var(--color-white);--dialog-shadow: var(--shadow);container-type:inline-size}.k-installation-view .k-button{margin-top:var(--spacing-3);width:100%}.k-installation-view form .k-button{margin-top:var(--spacing-10)}.k-installation-view .k-headline{font-weight:var(--font-semi);margin-top:-.5rem;margin-bottom:.75rem}.k-installation-issues{line-height:1.5em;font-size:var(--text-sm)}.k-installation-issues li{position:relative;padding:var(--spacing-6);background:var(--color-red-300);padding-inline-start:3.5rem;border-radius:var(--rounded)}.k-installation-issues .k-icon{position:absolute;top:calc(1.5rem + 2px);inset-inline-start:1.5rem}.k-installation-issues .k-icon{color:var(--color-red-700)}.k-installation-issues li:not(:last-child){margin-bottom:2px}.k-installation-issues li code{font:inherit;color:var(--color-red-700)}.k-login-code-form .k-user-info{margin-bottom:var(--spacing-6)}.k-login-form{position:relative}.k-login-form label abbr{visibility:hidden}.k-login-toggler{position:absolute;top:-2px;inset-inline-end:calc(var(--spacing-2) * -1);color:var(--link-color);text-decoration:underline;text-decoration-color:var(--link-color);text-underline-offset:1px;height:var(--height-xs);line-height:1;padding-inline:var(--spacing-2);border-radius:var(--rounded);z-index:1}.k-login{--dialog-color-back: var(--color-white);--dialog-shadow: var(--shadow);container-type:inline-size}.k-login-buttons{--button-padding: var(--spacing-3);display:flex;gap:1.5rem;align-items:center;justify-content:space-between;margin-top:var(--spacing-10)}.k-page-view[data-has-tabs=true] .k-page-view-header,.k-site-view[data-has-tabs=true] .k-site-view-header{margin-bottom:0}.k-user-name-placeholder{color:var(--color-gray-500);transition:color .3s}.k-user-view-header[data-editable=true] .k-user-name-placeholder:hover{color:var(--color-gray-900)}.k-user-view-header{margin-bottom:0;border-bottom:0}.k-user-view .k-user-profile{margin-bottom:var(--spacing-12)}.k-user-view[data-has-tabs=true] .k-user-profile{margin-bottom:0}.k-password-reset-view .k-user-info{margin-bottom:var(--spacing-8)}.k-user-view-image{padding:0}.k-user-view-image .k-frame{width:6rem;height:6rem;border-radius:var(--rounded);line-height:0}.k-user-view-image .k-icon-frame{--back: var(--color-black);--icon-color: var(--color-gray-200)}.k-user-info{display:flex;align-items:center;font-size:var(--text-sm);height:var(--height-lg);gap:.75rem;padding-inline:var(--spacing-2);background:var(--color-white);box-shadow:var(--shadow)}.k-user-info :where(.k-image-frame,.k-icon-frame){width:1.5rem;border-radius:var(--rounded-sm)}.k-user-profile{--button-height: auto;padding:var(--spacing-2);background:var(--color-white);border-radius:var(--rounded-lg);display:flex;align-items:center;gap:var(--spacing-3);box-shadow:var(--shadow)}.k-user-profile .k-button-group{display:flex;flex-direction:column;align-items:flex-start}.k-users-view-header{margin-bottom:0}.k-system-info .k-stat-label{color:var(--theme, var(--color-black))}.k-table-update-status-cell{padding:0 .75rem;display:flex;align-items:center;height:100%}.k-table-update-status-cell-version,.k-table-update-status-cell-button{font-variant-numeric:tabular-nums}.k-plugin-info{display:grid;column-gap:var(--spacing-3);row-gap:2px;padding:var(--button-padding)}.k-plugin-info dt{color:var(--color-gray-400)}.k-plugin-info dd[data-theme]{color:var(--theme-color-600)}@container (max-width: 30em){.k-plugin-info dd:not(:last-of-type){margin-bottom:var(--spacing-2)}}@container (min-width: 30em){.k-plugin-info{width:20rem;grid-template-columns:1fr auto}}:root{--color-l-100: 98%;--color-l-200: 94%;--color-l-300: 88%;--color-l-400: 80%;--color-l-500: 70%;--color-l-600: 60%;--color-l-700: 45%;--color-l-800: 30%;--color-l-900: 15%;--color-red-h: 0;--color-red-s: 80%;--color-red-hs: var(--color-red-h), var(--color-red-s);--color-red-boost: 3%;--color-red-l-100: calc(var(--color-l-100) + var(--color-red-boost));--color-red-l-200: calc(var(--color-l-200) + var(--color-red-boost));--color-red-l-300: calc(var(--color-l-300) + var(--color-red-boost));--color-red-l-400: calc(var(--color-l-400) + var(--color-red-boost));--color-red-l-500: calc(var(--color-l-500) + var(--color-red-boost));--color-red-l-600: calc(var(--color-l-600) + var(--color-red-boost));--color-red-l-700: calc(var(--color-l-700) + var(--color-red-boost));--color-red-l-800: calc(var(--color-l-800) + var(--color-red-boost));--color-red-l-900: calc(var(--color-l-900) + var(--color-red-boost));--color-red-100: hsl(var(--color-red-hs), var(--color-red-l-100));--color-red-200: hsl(var(--color-red-hs), var(--color-red-l-200));--color-red-300: hsl(var(--color-red-hs), var(--color-red-l-300));--color-red-400: hsl(var(--color-red-hs), var(--color-red-l-400));--color-red-500: hsl(var(--color-red-hs), var(--color-red-l-500));--color-red-600: hsl(var(--color-red-hs), var(--color-red-l-600));--color-red-700: hsl(var(--color-red-hs), var(--color-red-l-700));--color-red-800: hsl(var(--color-red-hs), var(--color-red-l-800));--color-red-900: hsl(var(--color-red-hs), var(--color-red-l-900));--color-orange-h: 28;--color-orange-s: 80%;--color-orange-hs: var(--color-orange-h), var(--color-orange-s);--color-orange-boost: 2.5%;--color-orange-l-100: calc(var(--color-l-100) + var(--color-orange-boost));--color-orange-l-200: calc(var(--color-l-200) + var(--color-orange-boost));--color-orange-l-300: calc(var(--color-l-300) + var(--color-orange-boost));--color-orange-l-400: calc(var(--color-l-400) + var(--color-orange-boost));--color-orange-l-500: calc(var(--color-l-500) + var(--color-orange-boost));--color-orange-l-600: calc(var(--color-l-600) + var(--color-orange-boost));--color-orange-l-700: calc(var(--color-l-700) + var(--color-orange-boost));--color-orange-l-800: calc(var(--color-l-800) + var(--color-orange-boost));--color-orange-l-900: calc(var(--color-l-900) + var(--color-orange-boost));--color-orange-100: hsl(var(--color-orange-hs), var(--color-orange-l-100));--color-orange-200: hsl(var(--color-orange-hs), var(--color-orange-l-200));--color-orange-300: hsl(var(--color-orange-hs), var(--color-orange-l-300));--color-orange-400: hsl(var(--color-orange-hs), var(--color-orange-l-400));--color-orange-500: hsl(var(--color-orange-hs), var(--color-orange-l-500));--color-orange-600: hsl(var(--color-orange-hs), var(--color-orange-l-600));--color-orange-700: hsl(var(--color-orange-hs), var(--color-orange-l-700));--color-orange-800: hsl(var(--color-orange-hs), var(--color-orange-l-800));--color-orange-900: hsl(var(--color-orange-hs), var(--color-orange-l-900));--color-yellow-h: 47;--color-yellow-s: 80%;--color-yellow-hs: var(--color-yellow-h), var(--color-yellow-s);--color-yellow-boost: 0%;--color-yellow-l-100: calc(var(--color-l-100) + var(--color-yellow-boost));--color-yellow-l-200: calc(var(--color-l-200) + var(--color-yellow-boost));--color-yellow-l-300: calc(var(--color-l-300) + var(--color-yellow-boost));--color-yellow-l-400: calc(var(--color-l-400) + var(--color-yellow-boost));--color-yellow-l-500: calc(var(--color-l-500) + var(--color-yellow-boost));--color-yellow-l-600: calc(var(--color-l-600) + var(--color-yellow-boost));--color-yellow-l-700: calc(var(--color-l-700) + var(--color-yellow-boost));--color-yellow-l-800: calc(var(--color-l-800) + var(--color-yellow-boost));--color-yellow-l-900: calc(var(--color-l-900) + var(--color-yellow-boost));--color-yellow-100: hsl(var(--color-yellow-hs), var(--color-yellow-l-100));--color-yellow-200: hsl(var(--color-yellow-hs), var(--color-yellow-l-200));--color-yellow-300: hsl(var(--color-yellow-hs), var(--color-yellow-l-300));--color-yellow-400: hsl(var(--color-yellow-hs), var(--color-yellow-l-400));--color-yellow-500: hsl(var(--color-yellow-hs), var(--color-yellow-l-500));--color-yellow-600: hsl(var(--color-yellow-hs), var(--color-yellow-l-600));--color-yellow-700: hsl(var(--color-yellow-hs), var(--color-yellow-l-700));--color-yellow-800: hsl(var(--color-yellow-hs), var(--color-yellow-l-800));--color-yellow-900: hsl(var(--color-yellow-hs), var(--color-yellow-l-900));--color-green-h: 80;--color-green-s: 60%;--color-green-hs: var(--color-green-h), var(--color-green-s);--color-green-boost: -2.5%;--color-green-l-100: calc(var(--color-l-100) + var(--color-green-boost));--color-green-l-200: calc(var(--color-l-200) + var(--color-green-boost));--color-green-l-300: calc(var(--color-l-300) + var(--color-green-boost));--color-green-l-400: calc(var(--color-l-400) + var(--color-green-boost));--color-green-l-500: calc(var(--color-l-500) + var(--color-green-boost));--color-green-l-600: calc(var(--color-l-600) + var(--color-green-boost));--color-green-l-700: calc(var(--color-l-700) + var(--color-green-boost));--color-green-l-800: calc(var(--color-l-800) + var(--color-green-boost));--color-green-l-900: calc(var(--color-l-900) + var(--color-green-boost));--color-green-100: hsl(var(--color-green-hs), var(--color-green-l-100));--color-green-200: hsl(var(--color-green-hs), var(--color-green-l-200));--color-green-300: hsl(var(--color-green-hs), var(--color-green-l-300));--color-green-400: hsl(var(--color-green-hs), var(--color-green-l-400));--color-green-500: hsl(var(--color-green-hs), var(--color-green-l-500));--color-green-600: hsl(var(--color-green-hs), var(--color-green-l-600));--color-green-700: hsl(var(--color-green-hs), var(--color-green-l-700));--color-green-800: hsl(var(--color-green-hs), var(--color-green-l-800));--color-green-900: hsl(var(--color-green-hs), var(--color-green-l-900));--color-aqua-h: 180;--color-aqua-s: 50%;--color-aqua-hs: var(--color-aqua-h), var(--color-aqua-s);--color-aqua-boost: 0%;--color-aqua-l-100: calc(var(--color-l-100) + var(--color-aqua-boost));--color-aqua-l-200: calc(var(--color-l-200) + var(--color-aqua-boost));--color-aqua-l-300: calc(var(--color-l-300) + var(--color-aqua-boost));--color-aqua-l-400: calc(var(--color-l-400) + var(--color-aqua-boost));--color-aqua-l-500: calc(var(--color-l-500) + var(--color-aqua-boost));--color-aqua-l-600: calc(var(--color-l-600) + var(--color-aqua-boost));--color-aqua-l-700: calc(var(--color-l-700) + var(--color-aqua-boost));--color-aqua-l-800: calc(var(--color-l-800) + var(--color-aqua-boost));--color-aqua-l-900: calc(var(--color-l-900) + var(--color-aqua-boost));--color-aqua-100: hsl(var(--color-aqua-hs), var(--color-aqua-l-100));--color-aqua-200: hsl(var(--color-aqua-hs), var(--color-aqua-l-200));--color-aqua-300: hsl(var(--color-aqua-hs), var(--color-aqua-l-300));--color-aqua-400: hsl(var(--color-aqua-hs), var(--color-aqua-l-400));--color-aqua-500: hsl(var(--color-aqua-hs), var(--color-aqua-l-500));--color-aqua-600: hsl(var(--color-aqua-hs), var(--color-aqua-l-600));--color-aqua-700: hsl(var(--color-aqua-hs), var(--color-aqua-l-700));--color-aqua-800: hsl(var(--color-aqua-hs), var(--color-aqua-l-800));--color-aqua-900: hsl(var(--color-aqua-hs), var(--color-aqua-l-900));--color-blue-h: 210;--color-blue-s: 65%;--color-blue-hs: var(--color-blue-h), var(--color-blue-s);--color-blue-boost: 3%;--color-blue-l-100: calc(var(--color-l-100) + var(--color-blue-boost));--color-blue-l-200: calc(var(--color-l-200) + var(--color-blue-boost));--color-blue-l-300: calc(var(--color-l-300) + var(--color-blue-boost));--color-blue-l-400: calc(var(--color-l-400) + var(--color-blue-boost));--color-blue-l-500: calc(var(--color-l-500) + var(--color-blue-boost));--color-blue-l-600: calc(var(--color-l-600) + var(--color-blue-boost));--color-blue-l-700: calc(var(--color-l-700) + var(--color-blue-boost));--color-blue-l-800: calc(var(--color-l-800) + var(--color-blue-boost));--color-blue-l-900: calc(var(--color-l-900) + var(--color-blue-boost));--color-blue-100: hsl(var(--color-blue-hs), var(--color-blue-l-100));--color-blue-200: hsl(var(--color-blue-hs), var(--color-blue-l-200));--color-blue-300: hsl(var(--color-blue-hs), var(--color-blue-l-300));--color-blue-400: hsl(var(--color-blue-hs), var(--color-blue-l-400));--color-blue-500: hsl(var(--color-blue-hs), var(--color-blue-l-500));--color-blue-600: hsl(var(--color-blue-hs), var(--color-blue-l-600));--color-blue-700: hsl(var(--color-blue-hs), var(--color-blue-l-700));--color-blue-800: hsl(var(--color-blue-hs), var(--color-blue-l-800));--color-blue-900: hsl(var(--color-blue-hs), var(--color-blue-l-900));--color-purple-h: 275;--color-purple-s: 60%;--color-purple-hs: var(--color-purple-h), var(--color-purple-s);--color-purple-boost: 0%;--color-purple-l-100: calc(var(--color-l-100) + var(--color-purple-boost));--color-purple-l-200: calc(var(--color-l-200) + var(--color-purple-boost));--color-purple-l-300: calc(var(--color-l-300) + var(--color-purple-boost));--color-purple-l-400: calc(var(--color-l-400) + var(--color-purple-boost));--color-purple-l-500: calc(var(--color-l-500) + var(--color-purple-boost));--color-purple-l-600: calc(var(--color-l-600) + var(--color-purple-boost));--color-purple-l-700: calc(var(--color-l-700) + var(--color-purple-boost));--color-purple-l-800: calc(var(--color-l-800) + var(--color-purple-boost));--color-purple-l-900: calc(var(--color-l-900) + var(--color-purple-boost));--color-purple-100: hsl(var(--color-purple-hs), var(--color-purple-l-100));--color-purple-200: hsl(var(--color-purple-hs), var(--color-purple-l-200));--color-purple-300: hsl(var(--color-purple-hs), var(--color-purple-l-300));--color-purple-400: hsl(var(--color-purple-hs), var(--color-purple-l-400));--color-purple-500: hsl(var(--color-purple-hs), var(--color-purple-l-500));--color-purple-600: hsl(var(--color-purple-hs), var(--color-purple-l-600));--color-purple-700: hsl(var(--color-purple-hs), var(--color-purple-l-700));--color-purple-800: hsl(var(--color-purple-hs), var(--color-purple-l-800));--color-purple-900: hsl(var(--color-purple-hs), var(--color-purple-l-900));--color-pink-h: 320;--color-pink-s: 70%;--color-pink-hs: var(--color-pink-h), var(--color-pink-s);--color-pink-boost: 0%;--color-pink-l-100: calc(var(--color-l-100) + var(--color-pink-boost));--color-pink-l-200: calc(var(--color-l-200) + var(--color-pink-boost));--color-pink-l-300: calc(var(--color-l-300) + var(--color-pink-boost));--color-pink-l-400: calc(var(--color-l-400) + var(--color-pink-boost));--color-pink-l-500: calc(var(--color-l-500) + var(--color-pink-boost));--color-pink-l-600: calc(var(--color-l-600) + var(--color-pink-boost));--color-pink-l-700: calc(var(--color-l-700) + var(--color-pink-boost));--color-pink-l-800: calc(var(--color-l-800) + var(--color-pink-boost));--color-pink-l-900: calc(var(--color-l-900) + var(--color-pink-boost));--color-pink-100: hsl(var(--color-pink-hs), var(--color-pink-l-100));--color-pink-200: hsl(var(--color-pink-hs), var(--color-pink-l-200));--color-pink-300: hsl(var(--color-pink-hs), var(--color-pink-l-300));--color-pink-400: hsl(var(--color-pink-hs), var(--color-pink-l-400));--color-pink-500: hsl(var(--color-pink-hs), var(--color-pink-l-500));--color-pink-600: hsl(var(--color-pink-hs), var(--color-pink-l-600));--color-pink-700: hsl(var(--color-pink-hs), var(--color-pink-l-700));--color-pink-800: hsl(var(--color-pink-hs), var(--color-pink-l-800));--color-pink-900: hsl(var(--color-pink-hs), var(--color-pink-l-900));--color-gray-h: 0;--color-gray-s: 0%;--color-gray-hs: var(--color-gray-h), var(--color-gray-s);--color-gray-boost: 0%;--color-gray-l-100: calc(var(--color-l-100) + var(--color-gray-boost));--color-gray-l-200: calc(var(--color-l-200) + var(--color-gray-boost));--color-gray-l-300: calc(var(--color-l-300) + var(--color-gray-boost));--color-gray-l-400: calc(var(--color-l-400) + var(--color-gray-boost));--color-gray-l-500: calc(var(--color-l-500) + var(--color-gray-boost));--color-gray-l-600: calc(var(--color-l-600) + var(--color-gray-boost));--color-gray-l-700: calc(var(--color-l-700) + var(--color-gray-boost));--color-gray-l-800: calc(var(--color-l-800) + var(--color-gray-boost));--color-gray-l-900: calc(var(--color-l-900) + var(--color-gray-boost));--color-gray-100: hsl(var(--color-gray-hs), var(--color-gray-l-100));--color-gray-200: hsl(var(--color-gray-hs), var(--color-gray-l-200));--color-gray-250: #e8e8e8;--color-gray-300: hsl(var(--color-gray-hs), var(--color-gray-l-300));--color-gray-400: hsl(var(--color-gray-hs), var(--color-gray-l-400));--color-gray-500: hsl(var(--color-gray-hs), var(--color-gray-l-500));--color-gray-600: hsl(var(--color-gray-hs), var(--color-gray-l-600));--color-gray-700: hsl(var(--color-gray-hs), var(--color-gray-l-700));--color-gray-800: hsl(var(--color-gray-hs), var(--color-gray-l-800));--color-gray-900: hsl(var(--color-gray-hs), var(--color-gray-l-900));--color-backdrop: rgba(0, 0, 0, .6);--color-black: black;--color-border: var(--color-gray-300);--color-dark: var(--color-gray-900);--color-focus: var(--color-blue-600);--color-light: var(--color-gray-200);--color-text: var(--color-black);--color-text-dimmed: var(--color-gray-700);--color-white: white;--color-background: var(--color-light);--color-gray: var(--color-gray-600);--color-red: var(--color-red-600);--color-orange: var(--color-orange-600);--color-yellow: var(--color-yellow-600);--color-green: var(--color-green-600);--color-aqua: var(--color-aqua-600);--color-blue: var(--color-blue-600);--color-purple: var(--color-purple-600);--color-focus-light: var(--color-focus);--color-focus-outline: var(--color-focus);--color-negative: var(--color-red-700);--color-negative-light: var(--color-red-500);--color-negative-outline: var(--color-red-900);--color-notice: var(--color-orange-700);--color-notice-light: var(--color-orange-500);--color-positive: var(--color-green-700);--color-positive-light: var(--color-green-500);--color-positive-outline: var(--color-green-900);--color-text-light: var(--color-text-dimmed)}:root{--font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";--font-mono: "SFMono-Regular", Consolas, Liberation Mono, Menlo, Courier, monospace}:root{--text-xs: .75rem;--text-sm: .875rem;--text-md: 1rem;--text-lg: 1.125rem;--text-xl: 1.25rem;--text-2xl: 1.5rem;--text-3xl: 1.75rem;--text-4xl: 2.5rem;--text-5xl: 3rem;--text-6xl: 4rem;--text-base: var(--text-md);--font-size-tiny: var(--text-xs);--font-size-small: var(--text-sm);--font-size-medium: var(--text-base);--font-size-large: var(--text-xl);--font-size-huge: var(--text-2xl);--font-size-monster: var(--text-3xl)}:root{--font-thin: 300;--font-normal: 400;--font-semi: 500;--font-bold: 600}:root{--height-xs: 1.5rem;--height-sm: 1.75rem;--height-md: 2rem;--height-lg: 2.25rem;--height-xl: 2.5rem;--height: var(--height-md)}:root{--opacity-disabled: .5}:root{--rounded-xs: 1px;--rounded-sm: .125rem;--rounded-md: .25rem;--rounded-lg: .375rem;--rounded-xl: .5rem;--rounded: var(--rounded-md)}:root{--shadow-sm: 0 1px 3px 0 rgba(0, 0, 0, .05), 0 1px 2px 0 rgba(0, 0, 0, .025);--shadow-md: 0 4px 6px -1px rgba(0, 0, 0, .1), 0 2px 4px -1px rgba(0, 0, 0, .05);--shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, .1), 0 4px 6px -2px rgba(0, 0, 0, .05);--shadow-xl: 0 20px 25px -5px rgba(0, 0, 0, .1), 0 10px 10px -5px rgba(0, 0, 0, .05);--shadow: var(--shadow-sm);--shadow-toolbar: rgba(0, 0, 0, .1) -2px 0 5px, var(--shadow), var(--shadow-xl);--shadow-outline: var(--color-focus, currentColor) 0 0 0 2px;--shadow-inset: inset 0 2px 4px 0 rgba(0, 0, 0, .06);--shadow-sticky: rgba(0, 0, 0, .05) 0 2px 5px;--box-shadow-dropdown: var(--shadow-dropdown);--box-shadow-item: var(--shadow);--box-shadow-focus: var(--shadow-xl);--shadow-dropdown: var(--shadow-lg);--shadow-item: var(--shadow-sm)}:root{--spacing-0: 0;--spacing-1: .25rem;--spacing-2: .5rem;--spacing-3: .75rem;--spacing-4: 1rem;--spacing-6: 1.5rem;--spacing-8: 2rem;--spacing-12: 3rem;--spacing-16: 4rem;--spacing-24: 6rem;--spacing-36: 9rem;--spacing-48: 12rem;--spacing-px: 1px;--spacing-2px: 2px;--spacing-5: 1.25rem;--spacing-10: 2.5rem;--spacing-20: 5rem}:root{--z-offline: 1200;--z-fatal: 1100;--z-loader: 1000;--z-notification: 900;--z-dialog: 800;--z-navigation: 700;--z-dropdown: 600;--z-drawer: 500;--z-dropzone: 400;--z-toolbar: 300;--z-content: 200;--z-background: 100}:root{--pattern-size: 16px;--pattern-light: repeating-conic-gradient( hsl(0, 0%, 100%) 0% 25%, hsl(0, 0%, 90%) 0% 50% ) 50% / var(--pattern-size) var(--pattern-size);--pattern-dark: repeating-conic-gradient( hsla(0, 0%, 15%) 0% 25%, hsl(0, 0%, 22%) 0% 50% ) 50% / var(--pattern-size) var(--pattern-size);--pattern: var(--pattern-dark)}:root{--container: 80rem;--leading-none: 1;--leading-tight: 1.25;--leading-snug: 1.375;--leading-normal: 1.5;--leading-relaxed: 1.625;--leading-loose: 2;--field-input-padding: var(--input-padding);--field-input-height: var(--input-height);--field-input-line-height: var(--input-leading);--field-input-font-size: var(--input-font-size);--bg-pattern: var(--pattern)}:root{--choice-color-back: var(--color-white);--choice-color-border: var(--color-gray-500);--choice-color-checked: var(--color-black);--choice-color-disabled: var(--color-gray-400);--choice-color-icon: var(--color-light);--choice-color-info: var(--color-text-dimmed);--choice-color-text: var(--color-text);--choice-color-toggle: var(--choice-color-disabled);--choice-height: 1rem;--choice-rounded: var(--rounded-sm)}input:where([type=checkbox],[type=radio]){position:relative;cursor:pointer;overflow:hidden;flex-shrink:0;height:var(--choice-height);aspect-ratio:1/1;border:1px solid var(--choice-color-border);-webkit-appearance:none;-moz-appearance:none;appearance:none;border-radius:var(--choice-rounded);background:var(--choice-color-back);box-shadow:var(--shadow-sm)}input:where([type=checkbox],[type=radio]):after{position:absolute;content:"";display:none;place-items:center;text-align:center}input:where([type=checkbox],[type=radio]):focus{outline:var(--outline);outline-offset:-1px;color:var(--color-focus)}input:where([type=checkbox]):checked{border-color:var(--choice-color-checked)}input:where([type=checkbox],[type=radio]):checked:after{background:var(--choice-color-checked);display:grid}input:where([type=checkbox],[type=radio]):checked:focus{--choice-color-checked: var(--color-focus)}input:where([type=checkbox],[type=radio])[disabled]{--choice-color-back: none;--choice-color-border: var(--color-gray-300);--choice-color-checked: var(--choice-color-disabled);box-shadow:none;cursor:not-allowed}input[type=checkbox]:checked:after{content:"✓";top:0;right:0;bottom:0;left:0;font-weight:700;color:var(--choice-color-icon);line-height:1}input[type=radio]{--choice-rounded: 50%}input[type=radio]:after{top:3px;right:3px;bottom:3px;left:3px;font-size:9px;border-radius:var(--choice-rounded)}input[type=checkbox][data-variant=toggle]{--choice-rounded: var(--choice-height);width:calc(var(--choice-height) * 2);aspect-ratio:2/1}input[type=checkbox][data-variant=toggle]:after{background:var(--choice-color-toggle);display:grid;top:1px;right:1px;bottom:1px;left:1px;width:.8rem;font-size:7px;border-radius:var(--choice-rounded);transition:margin-inline-start 75ms ease-in-out,background .1s ease-in-out}input[type=checkbox][data-variant=toggle]:checked{border-color:var(--choice-color-border)}input[type=checkbox][data-variant=toggle]:checked:after{background:var(--choice-color-checked);margin-inline-start:50%}:root{--range-thumb-color: var(--color-white);--range-thumb-focus-outline: var(--outline);--range-thumb-size: 1rem;--range-thumb-shadow: rgba(0, 0, 0, .1) 0 2px 4px 2px, rgba(0, 0, 0, .125) 0 0 0 1px;--range-track-back: var(--color-gray-250);--range-track-height: var(--range-thumb-size)}:where(input[type=range]){display:flex;align-items:center;-webkit-appearance:none;-moz-appearance:none;appearance:none;padding:0;height:var(--range-thumb-size);border-radius:var(--range-track-size);width:100%}:where(input[type=range])::-webkit-slider-thumb{-webkit-appearance:none;-moz-appearance:none;appearance:none;width:var(--range-thumb-size);height:var(--range-thumb-size);border:0;background:var(--range-thumb-color);box-shadow:var(--range-thumb-shadow);transform:translateZ(0);margin-top:calc(((var(--range-thumb-size) - var(--range-track-height)) / 2) * -1);border-radius:50%;z-index:1;cursor:grab}:where(input[type=range])::-moz-range-thumb{-webkit-appearance:none;-moz-appearance:none;appearance:none;width:var(--range-thumb-size);height:var(--range-thumb-size);border:0;background:var(--range-thumb-color);box-shadow:var(--range-thumb-shadow);border-radius:50%;transform:translateZ(0);z-index:1;cursor:grab}:where(input[type=range])::-webkit-slider-thumb:active{cursor:grabbing}:where(input[type=range])::-moz-range-thumb:active{cursor:grabbing}:where(input[type=range])::-webkit-slider-runnable-track{background:var(--range-track-back);height:var(--range-track-height);border-radius:var(--range-track-height)}:where(input[type=range])::-moz-range-track{background:var(--range-track-back);height:var(--range-track-height);border-radius:var(--range-track-height)}:where(input[type=range][disabled]){--range-thumb-color: rgba(255, 255, 255, .2)}:where(input[type=range][disabled])::-webkit-slider-thumb{cursor:not-allowed}:where(input[type=range][disabled])::-moz-range-thumb{cursor:not-allowed}:where(input[type=range]):focus{outline:var(--outline)}:where(input[type=range]):focus::-webkit-slider-thumb{outline:var(--range-thumb-focus-outline)}:where(input[type=range]):focus::-moz-range-thumb{outline:var(--range-thumb-focus-outline)}*,*:before,*:after{margin:0;padding:0;box-sizing:border-box}:where(b,strong){font-weight:var(--font-bold, 600)}:where([hidden]){display:none!important}:where(abbr){text-decoration:none}:where(input,button,textarea,select){border:0;font:inherit;line-height:inherit;color:inherit;background:none}:where(fieldset){border:0}:where(legend){width:100%;float:left}:where(legend+*){clear:both}:where(select){-webkit-appearance:none;-moz-appearance:none;appearance:none;background:var(--color-white);color:var(--color-black);cursor:pointer}:where(textarea,select,input:not([type=checkbox],[type=radio],[type=reset],[type=submit])){width:100%;font-variant-numeric:tabular-nums}:where(textarea){resize:vertical;line-height:1.5}:where(input)::-webkit-calendar-picker-indicator{display:none}:where(input[type=search]){-webkit-appearance:none;-moz-appearance:none;appearance:none}:where(input)::-webkit-search-cancel-button{display:none}:where(button,label,select,summary,[role=button],[role=option]){cursor:pointer}:where(select[multiple]) option{display:flex;align-items:center}:where(input:-webkit-autofill){-webkit-text-fill-color:var(--input-color-text)!important;-webkit-background-clip:text}:where(:disabled){cursor:not-allowed}*::placeholder{color:var(--input-color-placeholder);opacity:1}:where(a){color:currentColor;text-decoration:none;text-underline-offset:.2ex}:where(ul,ol){list-style:none}:where(img,svg,video,canvas,audio,iframe,embed,object){display:block}:where(iframe){border:0}:where(img,picture,svg){max-inline-size:100%;block-size:auto}:where(p,h1,h2,h3,h4,h5,h6){overflow-wrap:break-word}:where(h1,h2,h3,h4,h5,h6){font:inherit}:where(:focus,:focus-visible,:focus-within){outline-color:var(--color-focus, currentColor);outline-offset:0}:where(:focus-visible){outline:var(--outline, 2px solid var(--color-focus, currentColor))}:where(:invalid){box-shadow:none;outline:0}:where(dialog){border:0;max-width:none;max-height:none}:where(hr){border:0}:where(table){font:inherit;width:100%;border-spacing:0;font-variant-numeric:tabular-nums}:where(table th){font:inherit;text-align:start}:where(svg){fill:currentColor}body{font-family:var(--font-sans, sans-serif);font-size:var(--text-sm);line-height:1;position:relative;accent-color:var(--color-focus, currentColor)}:where(sup,sub){position:relative;line-height:0;vertical-align:baseline;font-size:75%}:where(sup){top:-.5em}:where(sub){bottom:-.25em}:where(mark){background:var(--color-yellow-300)}:where(kbd){display:inline-block;padding-inline:var(--spacing-2);border-radius:var(--rounded);background:var(--color-white);box-shadow:var(--shadow)}[data-align=left]{--align: start}[data-align=center]{--align: center}[data-align=right]{--align: end}@keyframes LoadingCursor{to{cursor:progress}}@keyframes Spin{to{transform:rotate(360deg)}}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}[data-theme]{--theme-color-h: 0;--theme-color-s: 0%;--theme-color-hs: var(--theme-color-h), var(--theme-color-s);--theme-color-boost: 3%;--theme-color-l-100: calc(var(--color-l-100) + var(--theme-color-boost));--theme-color-l-200: calc(var(--color-l-200) + var(--theme-color-boost));--theme-color-l-300: calc(var(--color-l-300) + var(--theme-color-boost));--theme-color-l-400: calc(var(--color-l-400) + var(--theme-color-boost));--theme-color-l-500: calc(var(--color-l-500) + var(--theme-color-boost));--theme-color-l-600: calc(var(--color-l-600) + var(--theme-color-boost));--theme-color-l-700: calc(var(--color-l-700) + var(--theme-color-boost));--theme-color-l-800: calc(var(--color-l-800) + var(--theme-color-boost));--theme-color-l-900: calc(var(--color-l-900) + var(--theme-color-boost));--theme-color-100: hsl(var(--theme-color-hs), var(--theme-color-l-100));--theme-color-200: hsl(var(--theme-color-hs), var(--theme-color-l-200));--theme-color-300: hsl(var(--theme-color-hs), var(--theme-color-l-300));--theme-color-400: hsl(var(--theme-color-hs), var(--theme-color-l-400));--theme-color-500: hsl(var(--theme-color-hs), var(--theme-color-l-500));--theme-color-600: hsl(var(--theme-color-hs), var(--theme-color-l-600));--theme-color-700: hsl(var(--theme-color-hs), var(--theme-color-l-700));--theme-color-800: hsl(var(--theme-color-hs), var(--theme-color-l-800));--theme-color-900: hsl(var(--theme-color-hs), var(--theme-color-l-900));--theme-color-text: var(--theme-color-900);--theme-color-text-dimmed: hsl( var(--theme-color-h), calc(var(--theme-color-s) - 60%), 50% );--theme-color-back: var(--theme-color-400);--theme-color-hover: var(--theme-color-500);--theme-color-icon: var(--theme-color-600)}[data-theme^=red],[data-theme^=error],[data-theme^=negative]{--theme-color-h: var(--color-red-h);--theme-color-s: var(--color-red-s);--theme-color-boost: var(--color-red-boost)}[data-theme^=orange],[data-theme^=notice]{--theme-color-h: var(--color-orange-h);--theme-color-s: var(--color-orange-s);--theme-color-boost: var(--color-orange-boost)}[data-theme^=yellow],[data-theme^=warning]{--theme-color-h: var(--color-yellow-h);--theme-color-s: var(--color-yellow-s);--theme-color-boost: var(--color-yellow-boost)}[data-theme^=blue],[data-theme^=info]{--theme-color-h: var(--color-blue-h);--theme-color-s: var(--color-blue-s);--theme-color-boost: var(--color-blue-boost)}[data-theme^=pink],[data-theme^=love]{--theme-color-h: var(--color-pink-h);--theme-color-s: var(--color-pink-s);--theme-color-boost: var(--color-pink-boost)}[data-theme^=green],[data-theme^=positive]{--theme-color-h: var(--color-green-h);--theme-color-s: var(--color-green-s);--theme-color-boost: var(--color-green-boost)}[data-theme^=aqua]{--theme-color-h: var(--color-aqua-h);--theme-color-s: var(--color-aqua-s);--theme-color-boost: var(--color-aqua-boost)}[data-theme^=purple]{--theme-color-h: var(--color-purple-h);--theme-color-s: var(--color-purple-s);--theme-color-boost: var(--color-purple-boost)}[data-theme^=gray],[data-theme^=passive]{--theme-color-h: var(--color-gray-h);--theme-color-s: var(--color-gray-s);--theme-color-boost: 10%}[data-theme^=white],[data-theme^=text]{--theme-color-back: var(--color-white);--theme-color-icon: var(--color-gray-800);--theme-color-text: var(--color-text);--color-h: var(--color-black)}[data-theme^=dark]{--theme-color-h: var(--color-gray-h);--theme-color-s: var(--color-gray-s);--theme-color-boost: var(--color-gray-boost);--theme-color-back: var(--color-gray-800);--theme-color-icon: var(--color-gray-500);--theme-color-text: var(--color-gray-200)}[data-theme=code]{--theme-color-back: var(--code-color-back);--theme-color-hover: var(--color-black);--theme-color-icon: var(--code-color-icon);--theme-color-text: var(--code-color-text);font-family:var(--code-font-family);font-size:var(--code-font-size)}[data-theme=empty]{--theme-color-back: var(--color-light);--theme-color-border: var(--color-gray-400);--theme-color-icon: var(--color-gray-600);--theme-color-text: var(--color-text-dimmed);border:1px dashed var(--theme-color-border)}[data-theme=none]{--theme-color-back: transparent;--theme-color-border: transparent;--theme-color-icon: var(--color-text);--theme-color-text: var(--color-text)}[data-theme]{--theme: var(--theme-color-700);--theme-light: var(--theme-color-500);--theme-bg: var(--theme-color-500)}:root{--outline: 2px solid var(--color-focus, currentColor)}.scroll-x,.scroll-x-auto,.scroll-y,.scroll-y-auto{-webkit-overflow-scrolling:touch;transform:translateZ(0)}.scroll-x{overflow-x:scroll;overflow-y:hidden}.scroll-x-auto{overflow-x:auto;overflow-y:hidden}.scroll-y{overflow-x:hidden;overflow-y:scroll}.scroll-y-auto{overflow-x:hidden;overflow-y:auto}.input-hidden{position:absolute;-webkit-appearance:none;-moz-appearance:none;appearance:none;width:0;height:0;opacity:0}.k-lab-index-view .k-header{margin-bottom:0}.k-lab-index-view .k-panel-main>.k-box{margin-bottom:var(--spacing-8)}.k-lab-index-view .k-list-items{grid-template-columns:repeat(auto-fill,minmax(12rem,1fr))}.k-lab-docs-deprecated .k-box{box-shadow:var(--shadow)}.k-lab-docs-examples .k-code+.k-code{margin-top:var(--spacing-4)}.k-lab-docs-prop-values{font-size:var(--text-xs);border-left:2px solid var(--color-blue-300);padding-inline-start:var(--spacing-2)}.k-lab-docs-prop-values dl{font-weight:var(--font-bold)}.k-lab-docs-prop-values dl+dl{margin-top:var(--spacing-2)}.k-lab-docs-prop-values dd{display:inline-flex;flex-wrap:wrap;gap:var(--spacing-1)}.k-lab-docs-desc-header{display:flex;justify-content:space-between;align-items:center}.k-table .k-lab-docs-deprecated{--box-height: var(--height-xs);--text-font-size: var(--text-xs)}.k-labs-docs-params li{list-style:square;margin-inline-start:var(--spacing-3)}.k-labs-docs-params .k-lab-docs-types{margin-inline:1ch}.k-lab-docs-types{display:inline-flex;flex-wrap:wrap;gap:var(--spacing-1)}.k-lab-docs-types.k-text code{color:var(--color-gray-800);outline-color:var(--color-gray-400);background:var(--color-gray-300)}.k-lab-docs-types code:is([data-type=boolean],[data-type=Boolean]){color:var(--color-purple-800);outline-color:var(--color-purple-400);background:var(--color-purple-300)}.k-lab-docs-types code:is([data-type=string],[data-type=String]){color:var(--color-green-800);outline-color:var(--color-green-500);background:var(--color-green-300)}.k-lab-docs-types code:is([data-type=number],[data-type=Number]){color:var(--color-orange-800);outline-color:var(--color-orange-500);background:var(--color-orange-300)}.k-lab-docs-types code:is([data-type=array],[data-type=Array]){color:var(--color-aqua-800);outline-color:var(--color-aqua-500);background:var(--color-aqua-300)}.k-lab-docs-types code:is([data-type=object],[data-type=Object]){color:var(--color-yellow-800);outline-color:var(--color-yellow-500);background:var(--color-yellow-300)}.k-lab-docs-types code[data-type=func]{color:var(--color-pink-800);outline-color:var(--color-pink-400);background:var(--color-pink-300)}.k-lab-docs-section+.k-lab-docs-section{margin-top:var(--spacing-12)}.k-lab-docs-section .k-headline{margin-bottom:var(--spacing-3)}.k-lab-docs-section .k-table td{padding:.375rem var(--table-cell-padding);vertical-align:top;line-height:1.5;word-break:break-word}.k-lab-docs-description :where(.k-text,.k-box)+:where(.k-text,.k-box){margin-top:var(--spacing-3)}.k-lab-docs-required{margin-inline-start:var(--spacing-1);font-size:.7rem;vertical-align:super;color:var(--color-red-600)}.k-lab-docs-since{margin-top:var(--spacing-1);font-size:var(--text-xs);color:var(--color-gray-600)}.k-lab-example{position:relative;container-type:inline-size;max-width:100%;outline-offset:-2px;border-radius:var(--rounded);border:1px solid var(--color-gray-300)}.k-lab-example+.k-lab-example{margin-top:var(--spacing-12)}.k-lab-example-header{display:flex;justify-content:space-between;align-items:center;height:var(--height-md);padding-block:var(--spacing-3);padding-inline:var(--spacing-2);border-bottom:1px solid var(--color-gray-300)}.k-lab-example-label{font-size:12px;color:var(--color-text-dimmed)}.k-lab-example-canvas,.k-lab-example-code{padding:var(--spacing-16)}.k-lab-example[data-flex] .k-lab-example-canvas{display:flex;align-items:center;gap:var(--spacing-6)}.k-lab-example-inspector{--icon-size: 13px;--button-color-icon: var(--color-gray-500)}.k-lab-example-inspector .k-button:not([data-theme]):hover{--button-color-icon: var(--color-gray-600)}.k-lab-example-inspector .k-button:where([data-theme]){--button-color-icon: var(--color-gray-800)}.k-lab-examples>:where(.k-text,.k-box){margin-bottom:var(--spacing-6)}.k-lab-form>footer{border-top:1px dashed var(--color-border);padding-top:var(--spacing-6)}.k-lab-playground-view[data-has-tabs=true] .k-header{margin-bottom:0}.k-lab-examples h2{margin-bottom:var(--spacing-6)}.k-lab-examples *+h2{margin-top:var(--spacing-12)}.k-lab-input-examples .k-lab-example:has(:invalid){outline:2px solid var(--color-red-500);outline-offset:-2px}.k-lab-input-examples-focus .k-lab-example-canvas>.k-button{margin-top:var(--spacing-6)}.k-lab-helpers-examples .k-lab-example .k-text{margin-bottom:var(--spacing-6)}.k-lab-helpers-examples h2{margin-bottom:var(--spacing-3);font-weight:var(--font-bold)}.token.punctuation,.token.comment,.token.doctype{color:var(--color-gray-500)}.token.tag,.token.markup,.token.variable,.token.this,.token.selector,.token.key,.token.kirbytag-bracket,.token.prolog,.token.delimiter{color:var(--color-red-500)}.token.constant,.token.number,.token.boolean,.token.boolean.important,.token.attr-name,.token.kirbytag-attr,.token.kirbytag-name,.token.entity,.token.bold,.token.bold>.punctuation{color:var(--color-orange-500)}.token.keyword,.token.italic,.token.italic>.punctuation{color:var(--color-purple-500)}.token.function{color:var(--color-blue-500)}.token.operator,.token.title{color:var(--color-aqua-500)}.token.string,.token.attr-value,.token.attr-value .punctuation,.token.list.punctuation{color:var(--color-green-500)}.token.scope,.token.class-name,.token.property,.token.url{color:var(--color-yellow-500)}.token.title,.token.kirbytag-bracket,.token.list.punctuation,.token.bold{font-weight:var(--font-bold)}.token.title .punctuation{color:var(--color-gray-500)}.token.italic{font-style:italic} diff --git a/kirby/panel/dist/favicon-dark.png b/kirby/panel/dist/favicon-dark.png deleted file mode 100644 index dcf5e582e9ad387f5d38ce5ab89e02df74468ec5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 416 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE3?yBabR7dyX#qYVu0Z-f?ZMRfnJa)cDV7BJ z1v4!8!0k{e@ZHL}1%TrB_SaTu*Uf=WI+3e|=x4xgAq}zI7h8_=dtx{Hln$fMo_FIKnB^$48 zbLMw+n!@tI>GxgzpdXhN)#Wn_W$!snDGB1*GSO;}`_mixpXYGZuHo4(v};1d^W`ib z+%FmY;wVeJd*Z;^U-<{@zTa4)_CRUwQ?(~^4qatq2ow-yGGJ@aVdi11%DFdDi#J;5 zW}beV?k5}Z2*K4C@)th%Cp4j)_2=95Y4c~>N<4dVWAW4T^Yr=RZTIcT`8)sT9nk~w T&+k|P{lwtu>gTe~DWM4f__*m5 diff --git a/kirby/panel/dist/img/icons.svg b/kirby/panel/dist/img/icons.svg index 0da75ac..d0eba91 100644 --- a/kirby/panel/dist/img/icons.svg +++ b/kirby/panel/dist/img/icons.svg @@ -1,644 +1,705 @@ - diff --git a/kirby/panel/dist/js/Docs.min.js b/kirby/panel/dist/js/Docs.min.js deleted file mode 100644 index c835a23..0000000 --- a/kirby/panel/dist/js/Docs.min.js +++ /dev/null @@ -1 +0,0 @@ -import{n as t}from"./index.min.js";const e={props:{deprecated:String}};const s=t({mixins:[e]},(function(){var t=this,e=t._self._c;return t.deprecated.length?e("section",{staticClass:"k-lab-docs-section k-lab-docs-deprecated"},[e("k-lab-docs-deprecated",{attrs:{deprecated:t.deprecated}})],1):t._e()}),[],!1,null,null,null,null).exports,l={props:{description:String,since:String}};const a=t({mixins:[l]},(function(){var t,e,s,l=this,a=l._self._c;return(null==(t=l.description)?void 0:t.length)||(null==(e=l.since)?void 0:e.length)?a("section",{staticClass:"k-lab-docs-section"},[a("header",{staticClass:"k-lab-docs-desc-header"},[a("k-headline",{staticClass:"h3"},[l._v("Description")]),(null==(s=l.since)?void 0:s.length)?a("k-text",[l._v(" Since "),a("code",[l._v(l._s(l.since))])]):l._e()],1),a("k-box",{attrs:{theme:"text"}},[a("k-text",{attrs:{html:l.description}})],1)],1):l._e()}),[],!1,null,null,null,null).exports,n={props:{examples:{default:()=>[],type:Array}}};const c=t({mixins:[n]},(function(){var t=this,e=t._self._c;return t.examples.length?e("section",{staticClass:"k-lab-docs-section k-lab-docs-examples"},[e("k-headline",{staticClass:"h3"},[t._v("Examples")]),t._l(t.examples,(function(s,l){return e("k-code",{key:l,attrs:{language:"html"}},[t._v(t._s(s.content))])}))],2):t._e()}),[],!1,null,null,null,null).exports,r={props:{props:{default:()=>[],type:Array}}};const i=t({mixins:[r]},(function(){var t=this,e=t._self._c;return t.props.length?e("section",{staticClass:"k-lab-docs-section"},[e("k-headline",{staticClass:"h3"},[t._v("Props")]),e("div",{staticClass:"k-table"},[e("table",[t._m(0),e("tbody",t._l(t.props,(function(s){var l,a,n,c,r,i,o,d,p;return e("tr",{key:s.name},[e("td",[e("k-text",[e("code",[t._v(t._s(s.name))]),s.required?e("abbr",{staticClass:"k-lab-docs-required"},[t._v("✶")]):t._e(),(null==(l=s.since)?void 0:l.length)?e("div",{staticClass:"k-lab-docs-since"},[t._v(" since "+t._s(s.since)+" ")]):t._e()])],1),e("td",[e("k-lab-docs-types",{attrs:{types:null==(a=s.type)?void 0:a.split("|")}})],1),e("td",[s.default?e("k-text",[e("code",[t._v(t._s(s.default))])]):t._e()],1),e("td",{staticClass:"k-lab-docs-description"},[e("k-lab-docs-deprecated",{attrs:{deprecated:s.deprecated}}),(null==(n=s.description)?void 0:n.length)?e("k-text",{attrs:{html:s.description}}):t._e(),(null==(c=s.value)?void 0:c.length)||(null==(r=s.values)?void 0:r.length)||(null==(i=s.example)?void 0:i.length)?e("k-text",{staticClass:"k-lab-docs-prop-values"},[(null==(o=s.value)?void 0:o.length)?e("dl",[e("dt",[t._v("Value")]),e("dd",[e("code",[t._v(t._s(s.value))])])]):t._e(),(null==(d=s.values)?void 0:d.length)?e("dl",[e("dt",[t._v("Values")]),e("dd",t._l(s.values,(function(s){return e("code",{key:s},[t._v(" "+t._s(s.replaceAll("`",""))+" ")])})),0)]):t._e(),(null==(p=s.example)?void 0:p.length)?e("dl",[e("dt",[t._v("Example")]),e("dd",[e("code",[t._v(t._s(s.example))])])]):t._e()]):t._e()],1)])})),0)])])],1):t._e()}),[function(){var t=this,e=t._self._c;return e("thead",[e("th",{staticStyle:{width:"10rem"}},[t._v("Name")]),e("th",{staticStyle:{width:"10rem"}},[t._v("Type")]),e("th",{staticStyle:{width:"10rem"}},[t._v("Default")]),e("th",[t._v("Description")])])}],!1,null,null,null,null).exports,o={props:{slots:{default:()=>[],type:Array}},computed:{hasBindings(){return this.slots.filter((t=>t.bindings.length)).length}}};const d=t({mixins:[o]},(function(){var t=this,e=t._self._c;return t.slots.length?e("section",{staticClass:"k-lab-docs-section"},[e("k-headline",{staticClass:"h3"},[t._v("Slots")]),e("div",{staticClass:"k-table"},[e("table",[e("thead",[e("th",{staticStyle:{width:"10rem"}},[t._v("Slot")]),e("th",[t._v("Description")]),t.hasBindings?e("th",[t._v("Bindings")]):t._e()]),e("tbody",t._l(t.slots,(function(s){var l;return e("tr",{key:s.name},[e("td",{staticStyle:{width:"12rem"}},[e("k-text",[e("code",[t._v(t._s(s.name))]),(null==(l=s.since)?void 0:l.length)?e("div",{staticClass:"k-lab-docs-since"},[t._v(" since "+t._s(s.since)+" ")]):t._e()])],1),e("td",[e("k-lab-docs-deprecated",{attrs:{deprecated:s.deprecated}}),e("k-text",{attrs:{html:s.description}})],1),t.hasBindings?e("td",[e("k-lab-docs-params",{attrs:{params:s.bindings}})],1):t._e()])})),0)])])],1):t._e()}),[],!1,null,null,null,null).exports,p={props:{events:{default:()=>[],type:Array}},computed:{hasProperties(){return this.events.filter((t=>t.properties.length)).length}}};const u=t({mixins:[p]},(function(){var t=this,e=t._self._c;return t.events.length?e("section",{staticClass:"k-lab-docs-section"},[e("k-headline",{staticClass:"h3"},[t._v("Events")]),e("div",{staticClass:"k-table"},[e("table",[e("thead",[e("th",{staticStyle:{width:"10rem"}},[t._v("Event")]),e("th",[t._v("Description")]),t.hasProperties?e("th",[t._v("Properties")]):t._e()]),e("tbody",t._l(t.events,(function(s){var l;return e("tr",{key:s.name},[e("td",[e("k-text",[e("code",[t._v(t._s(s.name))]),(null==(l=s.since)?void 0:l.length)?e("div",{staticClass:"k-lab-docs-since"},[t._v(" since "+t._s(s.since)+" ")]):t._e()])],1),e("td",[e("k-lab-docs-deprecated",{attrs:{deprecated:s.deprecated}}),e("k-text",{attrs:{html:s.description}})],1),t.hasProperties?e("td",[e("k-lab-docs-params",{attrs:{params:s.properties}})],1):t._e()])})),0)])])],1):t._e()}),[],!1,null,null,null,null).exports,_={props:{methods:{default:()=>[],type:Array}}};const h=t({mixins:[_]},(function(){var t=this,e=t._self._c;return t.methods.length?e("section",{staticClass:"k-lab-docs-section"},[e("k-headline",{staticClass:"h3"},[t._v("Methods")]),e("div",{staticClass:"k-table"},[e("table",[t._m(0),e("tbody",t._l(t.methods,(function(s){var l;return e("tr",{key:s.name},[e("td",[e("k-text",[e("code",[t._v(t._s(s.name))]),(null==(l=s.since)?void 0:l.length)?e("div",{staticClass:"k-lab-docs-since"},[t._v(" since "+t._s(s.since)+" ")]):t._e()])],1),e("td",[e("k-lab-docs-deprecated",{attrs:{deprecated:s.deprecated}}),e("k-text",{attrs:{html:s.description}})],1),e("td",[e("k-lab-docs-params",{attrs:{params:s.params}})],1),e("td",[e("k-lab-docs-types",{attrs:{types:[s.returns]}})],1)])})),0)])])],1):t._e()}),[function(){var t=this,e=t._self._c;return e("thead",[e("th",{staticStyle:{width:"10rem"}},[t._v("Method")]),e("th",[t._v("Description")]),e("th",{staticStyle:{width:"16rem"}},[t._v("Params")]),e("th",{staticStyle:{width:"10rem"}},[t._v("Returns")])])}],!1,null,null,null,null).exports,v={props:{docBlock:String}};const k=t({mixins:[v]},(function(){var t,e=this,s=e._self._c;return(null==(t=e.docBlock)?void 0:t.length)?s("section",{staticClass:"k-lab-docs-section"},[s("header",[s("k-headline",{staticClass:"h3"},[e._v("Further information")])],1),s("k-box",{attrs:{theme:"text"}},[s("k-text",{attrs:{html:e.docBlock}})],1)],1):e._e()}),[],!1,null,null,null,null).exports;const m=t({props:{deprecated:{type:String}}},(function(){var t,e=this,s=e._self._c;return(null==(t=e.deprecated)?void 0:t.length)?s("k-box",{staticClass:"k-lab-docs-deprecated",attrs:{icon:"protected",theme:"warning"}},[s("k-text",{attrs:{html:"Deprecated: "+e.deprecated}})],1):e._e()}),[],!1,null,null,null,null).exports;const b=t({props:{params:{type:Array,default:()=>[]}}},(function(){var t=this,e=t._self._c;return t.params.length?e("ul",{staticClass:"k-labs-docs-params"},t._l(t.params,(function(s){return e("li",{key:s.name},[e("k-text",[e("code",[t._v(t._s(s.name))]),e("k-lab-docs-types",{attrs:{types:[s.type]}}),s.description.length?e("span",{domProps:{innerHTML:t._s(s.description)}}):t._e()],1)],1)})),0):t._e()}),[],!1,null,null,null,null).exports;const x=t({props:{types:{type:Array,default:()=>[]}}},(function(){var t=this,e=t._self._c;return e("k-text",{staticClass:"k-lab-docs-types"},t._l(t.types,(function(s){return e("code",{key:s,attrs:{"data-type":s}},[t._v(" "+t._s(s)+" ")])})),0)}),[],!1,null,null,null,null).exports;Vue.component("k-lab-docs-deprecated",m),Vue.component("k-lab-docs-params",b),Vue.component("k-lab-docs-types",x);const f=t({components:{"k-lab-docs-deprecated":s,"k-lab-docs-description":a,"k-lab-docs-examples":c,"k-lab-docs-props":i,"k-lab-docs-slots":d,"k-lab-docs-events":u,"k-lab-docs-methods":h,"k-lab-docs-docblock":k},mixins:[e,l,n,r,o,p,_,v],props:{component:String}},(function(){var t=this,e=t._self._c;return e("div",{staticClass:"k-lab-docs"},[e("k-lab-docs-deprecated",{attrs:{deprecated:t.deprecated}}),e("k-lab-docs-description",{attrs:{description:t.description,since:t.since}}),e("k-lab-docs-examples",{attrs:{examples:t.examples}}),e("k-lab-docs-props",{attrs:{props:t.props}}),e("k-lab-docs-slots",{attrs:{slots:t.slots}}),e("k-lab-docs-events",{attrs:{events:t.events}}),e("k-lab-docs-methods",{attrs:{methods:t.methods}}),e("k-lab-docs-docblock",{attrs:{"doc-block":t.docBlock}})],1)}),[],!1,null,null,null,null).exports;export{f as D}; diff --git a/kirby/panel/dist/js/DocsView.min.js b/kirby/panel/dist/js/DocsView.min.js deleted file mode 100644 index 1ad9f61..0000000 --- a/kirby/panel/dist/js/DocsView.min.js +++ /dev/null @@ -1 +0,0 @@ -import{D as t}from"./Docs.min.js";import{n as s}from"./index.min.js";import"./vendor.min.js";const o=s({components:{"k-lab-docs":t},props:{component:String,docs:Object,lab:String},mounted(){},methods:{reloadDocs(){this.$panel.view.refresh()}}},(function(){var t=this,s=t._self._c;return s("k-panel-inside",{staticClass:"k-lab-docs-view"},[s("k-header",[t._v(" "+t._s(t.component)+" "),t.docs.github||t.lab?s("k-button-group",{attrs:{slot:"buttons"},slot:"buttons"},[t.lab?s("k-button",{attrs:{icon:"lab",text:"Lab examples",size:"sm",variant:"filled",link:"/lab/"+t.lab}}):t._e(),t.docs.github?s("k-button",{attrs:{icon:"github",size:"sm",variant:"filled",link:t.docs.github,target:"_blank"}}):t._e()],1):t._e()],1),s("k-lab-docs",t._b({},"k-lab-docs",t.docs,!1))],1)}),[],!1,null,null,null,null).exports;export{o as default}; diff --git a/kirby/panel/dist/js/Highlight.min.js b/kirby/panel/dist/js/Highlight.min.js deleted file mode 100644 index f449f19..0000000 --- a/kirby/panel/dist/js/Highlight.min.js +++ /dev/null @@ -1 +0,0 @@ -import{n as e}from"./index.min.js";import"./vendor.min.js";var t=function(e){var t=/(?:^|\s)lang(?:uage)?-([\w-]+)(?=\s|$)/i,n=0,a={},r={manual:e.Prism&&e.Prism.manual,disableWorkerMessageHandler:e.Prism&&e.Prism.disableWorkerMessageHandler,util:{encode:function e(t){return t instanceof i?new i(t.type,e(t.content),t.alias):Array.isArray(t)?t.map(e):t.replace(/&/g,"&").replace(/=c.reach);F+=w.value.length,w=w.next){var A=w.value;if(t.length>e.length)return;if(!(A instanceof i)){var $,_=1;if(y){if(!($=s(x,F,e,m))||$.index>=e.length)break;var z=$.index,S=$.index+$[0].length,j=F;for(j+=w.value.length;z>=j;)j+=(w=w.next).value.length;if(F=j-=w.value.length,w.value instanceof i)continue;for(var E=w;E!==t.tail&&(jc.reach&&(c.reach=L);var C=w.prev;if(O&&(C=u(t,C,O),F+=O.length),d(t,C,_),w=u(t,C,new i(g,h?r.tokenize(P,h):P,k,P)),q&&u(t,w,q),_>1){var T={cause:g+","+f,reach:L};l(e,t,n,w.prev,F,T),c&&T.reach>c.reach&&(c.reach=T.reach)}}}}}}function o(){var e={value:null,prev:null,next:null},t={value:null,prev:e,next:null};e.next=t,this.head=e,this.tail=t,this.length=0}function u(e,t,n){var a=t.next,r={value:n,prev:t,next:a};return t.next=r,a.prev=r,e.length++,r}function d(e,t,n){for(var a=t.next,r=0;r"+i.content+""},!e.document)return e.addEventListener?(r.disableWorkerMessageHandler||e.addEventListener("message",(function(t){var n=JSON.parse(t.data),a=n.language,i=n.code,s=n.immediateClose;e.postMessage(r.highlight(i,r.languages[a],a)),s&&e.close()}),!1),r):r;var c=r.util.currentScript();function g(){r.manual||r.highlightAll()}if(c&&(r.filename=c.src,c.hasAttribute("data-manual")&&(r.manual=!0)),!r.manual){var p=document.readyState;"loading"===p||"interactive"===p&&c&&c.defer?document.addEventListener("DOMContentLoaded",g):window.requestAnimationFrame?window.requestAnimationFrame(g):window.setTimeout(g,16)}return r}("undefined"!=typeof window?window:"undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?self:{});"undefined"!=typeof module&&module.exports&&(module.exports=t),"undefined"!=typeof global&&(global.Prism=t),t.languages.markup={comment:{pattern://,greedy:!0},prolog:{pattern:/<\?[\s\S]+?\?>/,greedy:!0},doctype:{pattern:/"'[\]]|"[^"]*"|'[^']*')+(?:\[(?:[^<"'\]]|"[^"]*"|'[^']*'|<(?!!--)|)*\]\s*)?>/i,greedy:!0,inside:{"internal-subset":{pattern:/(^[^\[]*\[)[\s\S]+(?=\]>$)/,lookbehind:!0,greedy:!0,inside:null},string:{pattern:/"[^"]*"|'[^']*'/,greedy:!0},punctuation:/^$|[[\]]/,"doctype-tag":/^DOCTYPE/i,name:/[^\s<>'"]+/}},cdata:{pattern://i,greedy:!0},tag:{pattern:/<\/?(?!\d)[^\s>\/=$<%]+(?:\s(?:\s*[^\s>\/=]+(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))|(?=[\s/>])))+)?\s*\/?>/,greedy:!0,inside:{tag:{pattern:/^<\/?[^\s>\/]+/,inside:{punctuation:/^<\/?/,namespace:/^[^\s>\/:]+:/}},"special-attr":[],"attr-value":{pattern:/=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+)/,inside:{punctuation:[{pattern:/^=/,alias:"attr-equals"},{pattern:/^(\s*)["']|["']$/,lookbehind:!0}]}},punctuation:/\/?>/,"attr-name":{pattern:/[^\s>\/]+/,inside:{namespace:/^[^\s>\/:]+:/}}}},entity:[{pattern:/&[\da-z]{1,8};/i,alias:"named-entity"},/&#x?[\da-f]{1,8};/i]},t.languages.markup.tag.inside["attr-value"].inside.entity=t.languages.markup.entity,t.languages.markup.doctype.inside["internal-subset"].inside=t.languages.markup,t.hooks.add("wrap",(function(e){"entity"===e.type&&(e.attributes.title=e.content.replace(/&/,"&"))})),Object.defineProperty(t.languages.markup.tag,"addInlined",{value:function(e,n){var a={};a["language-"+n]={pattern:/(^$)/i,lookbehind:!0,inside:t.languages[n]},a.cdata=/^$/i;var r={"included-cdata":{pattern://i,inside:a}};r["language-"+n]={pattern:/[\s\S]+/,inside:t.languages[n]};var i={};i[e]={pattern:RegExp("(<__[^>]*>)(?:))*\\]\\]>|(?!)".replace(/__/g,(function(){return e})),"i"),lookbehind:!0,greedy:!0,inside:r},t.languages.insertBefore("markup","cdata",i)}}),Object.defineProperty(t.languages.markup.tag,"addAttribute",{value:function(e,n){t.languages.markup.tag.inside["special-attr"].push({pattern:RegExp("(^|[\"'\\s])(?:"+e+")\\s*=\\s*(?:\"[^\"]*\"|'[^']*'|[^\\s'\">=]+(?=[\\s>]))","i"),lookbehind:!0,inside:{"attr-name":/^[^\s=]+/,"attr-value":{pattern:/=[\s\S]+/,inside:{value:{pattern:/(^=\s*(["']|(?!["'])))\S[\s\S]*(?=\2$)/,lookbehind:!0,alias:[n,"language-"+n],inside:t.languages[n]},punctuation:[{pattern:/^=/,alias:"attr-equals"},/"|'/]}}}})}}),t.languages.html=t.languages.markup,t.languages.mathml=t.languages.markup,t.languages.svg=t.languages.markup,t.languages.xml=t.languages.extend("markup",{}),t.languages.ssml=t.languages.xml,t.languages.atom=t.languages.xml,t.languages.rss=t.languages.xml,function(e){var t=/(?:"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"|'(?:\\(?:\r\n|[\s\S])|[^'\\\r\n])*')/;e.languages.css={comment:/\/\*[\s\S]*?\*\//,atrule:{pattern:RegExp("@[\\w-](?:[^;{\\s\"']|\\s+(?!\\s)|"+t.source+")*?(?:;|(?=\\s*\\{))"),inside:{rule:/^@[\w-]+/,"selector-function-argument":{pattern:/(\bselector\s*\(\s*(?![\s)]))(?:[^()\s]|\s+(?![\s)])|\((?:[^()]|\([^()]*\))*\))+(?=\s*\))/,lookbehind:!0,alias:"selector"},keyword:{pattern:/(^|[^\w-])(?:and|not|only|or)(?![\w-])/,lookbehind:!0}}},url:{pattern:RegExp("\\burl\\((?:"+t.source+"|(?:[^\\\\\r\n()\"']|\\\\[^])*)\\)","i"),greedy:!0,inside:{function:/^url/i,punctuation:/^\(|\)$/,string:{pattern:RegExp("^"+t.source+"$"),alias:"url"}}},selector:{pattern:RegExp("(^|[{}\\s])[^{}\\s](?:[^{};\"'\\s]|\\s+(?![\\s{])|"+t.source+")*(?=\\s*\\{)"),lookbehind:!0},string:{pattern:t,greedy:!0},property:{pattern:/(^|[^-\w\xA0-\uFFFF])(?!\s)[-_a-z\xA0-\uFFFF](?:(?!\s)[-\w\xA0-\uFFFF])*(?=\s*:)/i,lookbehind:!0},important:/!important\b/i,function:{pattern:/(^|[^-a-z0-9])[-a-z0-9]+(?=\()/i,lookbehind:!0},punctuation:/[(){};:,]/},e.languages.css.atrule.inside.rest=e.languages.css;var n=e.languages.markup;n&&(n.tag.addInlined("style","css"),n.tag.addAttribute("style","css"))}(t),t.languages.clike={comment:[{pattern:/(^|[^\\])\/\*[\s\S]*?(?:\*\/|$)/,lookbehind:!0,greedy:!0},{pattern:/(^|[^\\:])\/\/.*/,lookbehind:!0,greedy:!0}],string:{pattern:/(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,greedy:!0},"class-name":{pattern:/(\b(?:class|extends|implements|instanceof|interface|new|trait)\s+|\bcatch\s+\()[\w.\\]+/i,lookbehind:!0,inside:{punctuation:/[.\\]/}},keyword:/\b(?:break|catch|continue|do|else|finally|for|function|if|in|instanceof|new|null|return|throw|try|while)\b/,boolean:/\b(?:false|true)\b/,function:/\b\w+(?=\()/,number:/\b0x[\da-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[+-]?\d+)?/i,operator:/[<>]=?|[!=]=?=?|--?|\+\+?|&&?|\|\|?|[?*/~^%]/,punctuation:/[{}[\];(),.:]/},t.languages.javascript=t.languages.extend("clike",{"class-name":[t.languages.clike["class-name"],{pattern:/(^|[^$\w\xA0-\uFFFF])(?!\s)[_$A-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\.(?:constructor|prototype))/,lookbehind:!0}],keyword:[{pattern:/((?:^|\})\s*)catch\b/,lookbehind:!0},{pattern:/(^|[^.]|\.\.\.\s*)\b(?:as|assert(?=\s*\{)|async(?=\s*(?:function\b|\(|[$\w\xA0-\uFFFF]|$))|await|break|case|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally(?=\s*(?:\{|$))|for|from(?=\s*(?:['"]|$))|function|(?:get|set)(?=\s*(?:[#\[$\w\xA0-\uFFFF]|$))|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)\b/,lookbehind:!0}],function:/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*(?:\.\s*(?:apply|bind|call)\s*)?\()/,number:{pattern:RegExp("(^|[^\\w$])(?:NaN|Infinity|0[bB][01]+(?:_[01]+)*n?|0[oO][0-7]+(?:_[0-7]+)*n?|0[xX][\\dA-Fa-f]+(?:_[\\dA-Fa-f]+)*n?|\\d+(?:_\\d+)*n|(?:\\d+(?:_\\d+)*(?:\\.(?:\\d+(?:_\\d+)*)?)?|\\.\\d+(?:_\\d+)*)(?:[Ee][+-]?\\d+(?:_\\d+)*)?)(?![\\w$])"),lookbehind:!0},operator:/--|\+\+|\*\*=?|=>|&&=?|\|\|=?|[!=]==|<<=?|>>>?=?|[-+*/%&|^!=<>]=?|\.{3}|\?\?=?|\?\.?|[~:]/}),t.languages.javascript["class-name"][0].pattern=/(\b(?:class|extends|implements|instanceof|interface|new)\s+)[\w.\\]+/,t.languages.insertBefore("javascript","keyword",{regex:{pattern:RegExp("((?:^|[^$\\w\\xA0-\\uFFFF.\"'\\])\\s]|\\b(?:return|yield))\\s*)/(?:(?:\\[(?:[^\\]\\\\\r\n]|\\\\.)*\\]|\\\\.|[^/\\\\\\[\r\n])+/[dgimyus]{0,7}|(?:\\[(?:[^[\\]\\\\\r\n]|\\\\.|\\[(?:[^[\\]\\\\\r\n]|\\\\.|\\[(?:[^[\\]\\\\\r\n]|\\\\.)*\\])*\\])*\\]|\\\\.|[^/\\\\\\[\r\n])+/[dgimyus]{0,7}v[dgimyus]{0,7})(?=(?:\\s|/\\*(?:[^*]|\\*(?!/))*\\*/)*(?:$|[\r\n,.;:})\\]]|//))"),lookbehind:!0,greedy:!0,inside:{"regex-source":{pattern:/^(\/)[\s\S]+(?=\/[a-z]*$)/,lookbehind:!0,alias:"language-regex",inside:t.languages.regex},"regex-delimiter":/^\/|\/$/,"regex-flags":/^[a-z]+$/}},"function-variable":{pattern:/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*[=:]\s*(?:async\s*)?(?:\bfunction\b|(?:\((?:[^()]|\([^()]*\))*\)|(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)\s*=>))/,alias:"function"},parameter:[{pattern:/(function(?:\s+(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)?\s*\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\))/,lookbehind:!0,inside:t.languages.javascript},{pattern:/(^|[^$\w\xA0-\uFFFF])(?!\s)[_$a-z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*=>)/i,lookbehind:!0,inside:t.languages.javascript},{pattern:/(\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\)\s*=>)/,lookbehind:!0,inside:t.languages.javascript},{pattern:/((?:\b|\s|^)(?!(?:as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)(?![$\w\xA0-\uFFFF]))(?:(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*\s*)\(\s*|\]\s*\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\)\s*\{)/,lookbehind:!0,inside:t.languages.javascript}],constant:/\b[A-Z](?:[A-Z_]|\dx?)*\b/}),t.languages.insertBefore("javascript","string",{hashbang:{pattern:/^#!.*/,greedy:!0,alias:"comment"},"template-string":{pattern:/`(?:\\[\s\S]|\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}|(?!\$\{)[^\\`])*`/,greedy:!0,inside:{"template-punctuation":{pattern:/^`|`$/,alias:"string"},interpolation:{pattern:/((?:^|[^\\])(?:\\{2})*)\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}/,lookbehind:!0,inside:{"interpolation-punctuation":{pattern:/^\$\{|\}$/,alias:"punctuation"},rest:t.languages.javascript}},string:/[\s\S]+/}},"string-property":{pattern:/((?:^|[,{])[ \t]*)(["'])(?:\\(?:\r\n|[\s\S])|(?!\2)[^\\\r\n])*\2(?=\s*:)/m,lookbehind:!0,greedy:!0,alias:"property"}}),t.languages.insertBefore("javascript","operator",{"literal-property":{pattern:/((?:^|[,{])[ \t]*)(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*:)/m,lookbehind:!0,alias:"property"}}),t.languages.markup&&(t.languages.markup.tag.addInlined("script","javascript"),t.languages.markup.tag.addAttribute("on(?:abort|blur|change|click|composition(?:end|start|update)|dblclick|error|focus(?:in|out)?|key(?:down|up)|load|mouse(?:down|enter|leave|move|out|over|up)|reset|resize|scroll|select|slotchange|submit|unload|wheel)","javascript")),t.languages.js=t.languages.javascript,function(e){function t(e,t){return"___"+e.toUpperCase()+t+"___"}Object.defineProperties(e.languages["markup-templating"]={},{buildPlaceholders:{value:function(n,a,r,i){if(n.language===a){var s=n.tokenStack=[];n.code=n.code.replace(r,(function(e){if("function"==typeof i&&!i(e))return e;for(var r,l=s.length;-1!==n.code.indexOf(r=t(a,l));)++l;return s[l]=e,r})),n.grammar=e.languages.markup}}},tokenizePlaceholders:{value:function(n,a){if(n.language===a&&n.tokenStack){n.grammar=e.languages[a];var r=0,i=Object.keys(n.tokenStack);!function s(l){for(var o=0;o=i.length);o++){var u=l[o];if("string"==typeof u||u.content&&"string"==typeof u.content){var d=i[r],c=n.tokenStack[d],g="string"==typeof u?u:u.content,p=t(a,d),f=g.indexOf(p);if(f>-1){++r;var b=g.substring(0,f),h=new e.Token(a,e.tokenize(c,n.grammar),"language-"+a,c),m=g.substring(f+p.length),y=[];b&&y.push.apply(y,s([b])),y.push(h),m&&y.push.apply(y,s([m])),"string"==typeof u?l.splice.apply(l,[o,1].concat(y)):u.content=y}}else u.content&&s(u.content)}return l}(n.tokens)}}}})}(t),function(e){var t=/\/\*[\s\S]*?\*\/|\/\/.*|#(?!\[).*/,n=[{pattern:/\b(?:false|true)\b/i,alias:"boolean"},{pattern:/(::\s*)\b[a-z_]\w*\b(?!\s*\()/i,greedy:!0,lookbehind:!0},{pattern:/(\b(?:case|const)\s+)\b[a-z_]\w*(?=\s*[;=])/i,greedy:!0,lookbehind:!0},/\b(?:null)\b/i,/\b[A-Z_][A-Z0-9_]*\b(?!\s*\()/],a=/\b0b[01]+(?:_[01]+)*\b|\b0o[0-7]+(?:_[0-7]+)*\b|\b0x[\da-f]+(?:_[\da-f]+)*\b|(?:\b\d+(?:_\d+)*\.?(?:\d+(?:_\d+)*)?|\B\.\d+)(?:e[+-]?\d+)?/i,r=/|\?\?=?|\.{3}|\??->|[!=]=?=?|::|\*\*=?|--|\+\+|&&|\|\||<<|>>|[?~]|[/^|%*&<>.+-]=?/,i=/[{}\[\](),:;]/;e.languages.php={delimiter:{pattern:/\?>$|^<\?(?:php(?=\s)|=)?/i,alias:"important"},comment:t,variable:/\$+(?:\w+\b|(?=\{))/,package:{pattern:/(namespace\s+|use\s+(?:function\s+)?)(?:\\?\b[a-z_]\w*)+\b(?!\\)/i,lookbehind:!0,inside:{punctuation:/\\/}},"class-name-definition":{pattern:/(\b(?:class|enum|interface|trait)\s+)\b[a-z_]\w*(?!\\)\b/i,lookbehind:!0,alias:"class-name"},"function-definition":{pattern:/(\bfunction\s+)[a-z_]\w*(?=\s*\()/i,lookbehind:!0,alias:"function"},keyword:[{pattern:/(\(\s*)\b(?:array|bool|boolean|float|int|integer|object|string)\b(?=\s*\))/i,alias:"type-casting",greedy:!0,lookbehind:!0},{pattern:/([(,?]\s*)\b(?:array(?!\s*\()|bool|callable|(?:false|null)(?=\s*\|)|float|int|iterable|mixed|object|self|static|string)\b(?=\s*\$)/i,alias:"type-hint",greedy:!0,lookbehind:!0},{pattern:/(\)\s*:\s*(?:\?\s*)?)\b(?:array(?!\s*\()|bool|callable|(?:false|null)(?=\s*\|)|float|int|iterable|mixed|never|object|self|static|string|void)\b/i,alias:"return-type",greedy:!0,lookbehind:!0},{pattern:/\b(?:array(?!\s*\()|bool|float|int|iterable|mixed|object|string|void)\b/i,alias:"type-declaration",greedy:!0},{pattern:/(\|\s*)(?:false|null)\b|\b(?:false|null)(?=\s*\|)/i,alias:"type-declaration",greedy:!0,lookbehind:!0},{pattern:/\b(?:parent|self|static)(?=\s*::)/i,alias:"static-context",greedy:!0},{pattern:/(\byield\s+)from\b/i,lookbehind:!0},/\bclass\b/i,{pattern:/((?:^|[^\s>:]|(?:^|[^-])>|(?:^|[^:]):)\s*)\b(?:abstract|and|array|as|break|callable|case|catch|clone|const|continue|declare|default|die|do|echo|else|elseif|empty|enddeclare|endfor|endforeach|endif|endswitch|endwhile|enum|eval|exit|extends|final|finally|fn|for|foreach|function|global|goto|if|implements|include|include_once|instanceof|insteadof|interface|isset|list|match|namespace|never|new|or|parent|print|private|protected|public|readonly|require|require_once|return|self|static|switch|throw|trait|try|unset|use|var|while|xor|yield|__halt_compiler)\b/i,lookbehind:!0}],"argument-name":{pattern:/([(,]\s*)\b[a-z_]\w*(?=\s*:(?!:))/i,lookbehind:!0},"class-name":[{pattern:/(\b(?:extends|implements|instanceof|new(?!\s+self|\s+static))\s+|\bcatch\s*\()\b[a-z_]\w*(?!\\)\b/i,greedy:!0,lookbehind:!0},{pattern:/(\|\s*)\b[a-z_]\w*(?!\\)\b/i,greedy:!0,lookbehind:!0},{pattern:/\b[a-z_]\w*(?!\\)\b(?=\s*\|)/i,greedy:!0},{pattern:/(\|\s*)(?:\\?\b[a-z_]\w*)+\b/i,alias:"class-name-fully-qualified",greedy:!0,lookbehind:!0,inside:{punctuation:/\\/}},{pattern:/(?:\\?\b[a-z_]\w*)+\b(?=\s*\|)/i,alias:"class-name-fully-qualified",greedy:!0,inside:{punctuation:/\\/}},{pattern:/(\b(?:extends|implements|instanceof|new(?!\s+self\b|\s+static\b))\s+|\bcatch\s*\()(?:\\?\b[a-z_]\w*)+\b(?!\\)/i,alias:"class-name-fully-qualified",greedy:!0,lookbehind:!0,inside:{punctuation:/\\/}},{pattern:/\b[a-z_]\w*(?=\s*\$)/i,alias:"type-declaration",greedy:!0},{pattern:/(?:\\?\b[a-z_]\w*)+(?=\s*\$)/i,alias:["class-name-fully-qualified","type-declaration"],greedy:!0,inside:{punctuation:/\\/}},{pattern:/\b[a-z_]\w*(?=\s*::)/i,alias:"static-context",greedy:!0},{pattern:/(?:\\?\b[a-z_]\w*)+(?=\s*::)/i,alias:["class-name-fully-qualified","static-context"],greedy:!0,inside:{punctuation:/\\/}},{pattern:/([(,?]\s*)[a-z_]\w*(?=\s*\$)/i,alias:"type-hint",greedy:!0,lookbehind:!0},{pattern:/([(,?]\s*)(?:\\?\b[a-z_]\w*)+(?=\s*\$)/i,alias:["class-name-fully-qualified","type-hint"],greedy:!0,lookbehind:!0,inside:{punctuation:/\\/}},{pattern:/(\)\s*:\s*(?:\?\s*)?)\b[a-z_]\w*(?!\\)\b/i,alias:"return-type",greedy:!0,lookbehind:!0},{pattern:/(\)\s*:\s*(?:\?\s*)?)(?:\\?\b[a-z_]\w*)+\b(?!\\)/i,alias:["class-name-fully-qualified","return-type"],greedy:!0,lookbehind:!0,inside:{punctuation:/\\/}}],constant:n,function:{pattern:/(^|[^\\\w])\\?[a-z_](?:[\w\\]*\w)?(?=\s*\()/i,lookbehind:!0,inside:{punctuation:/\\/}},property:{pattern:/(->\s*)\w+/,lookbehind:!0},number:a,operator:r,punctuation:i};var s={pattern:/\{\$(?:\{(?:\{[^{}]+\}|[^{}]+)\}|[^{}])+\}|(^|[^\\{])\$+(?:\w+(?:\[[^\r\n\[\]]+\]|->\w+)?)/,lookbehind:!0,inside:e.languages.php},l=[{pattern:/<<<'([^']+)'[\r\n](?:.*[\r\n])*?\1;/,alias:"nowdoc-string",greedy:!0,inside:{delimiter:{pattern:/^<<<'[^']+'|[a-z_]\w*;$/i,alias:"symbol",inside:{punctuation:/^<<<'?|[';]$/}}}},{pattern:/<<<(?:"([^"]+)"[\r\n](?:.*[\r\n])*?\1;|([a-z_]\w*)[\r\n](?:.*[\r\n])*?\2;)/i,alias:"heredoc-string",greedy:!0,inside:{delimiter:{pattern:/^<<<(?:"[^"]+"|[a-z_]\w*)|[a-z_]\w*;$/i,alias:"symbol",inside:{punctuation:/^<<<"?|[";]$/}},interpolation:s}},{pattern:/`(?:\\[\s\S]|[^\\`])*`/,alias:"backtick-quoted-string",greedy:!0},{pattern:/'(?:\\[\s\S]|[^\\'])*'/,alias:"single-quoted-string",greedy:!0},{pattern:/"(?:\\[\s\S]|[^\\"])*"/,alias:"double-quoted-string",greedy:!0,inside:{interpolation:s}}];e.languages.insertBefore("php","variable",{string:l,attribute:{pattern:/#\[(?:[^"'\/#]|\/(?![*/])|\/\/.*$|#(?!\[).*$|\/\*(?:[^*]|\*(?!\/))*\*\/|"(?:\\[\s\S]|[^\\"])*"|'(?:\\[\s\S]|[^\\'])*')+\](?=\s*[a-z$#])/im,greedy:!0,inside:{"attribute-content":{pattern:/^(#\[)[\s\S]+(?=\]$)/,lookbehind:!0,inside:{comment:t,string:l,"attribute-class-name":[{pattern:/([^:]|^)\b[a-z_]\w*(?!\\)\b/i,alias:"class-name",greedy:!0,lookbehind:!0},{pattern:/([^:]|^)(?:\\?\b[a-z_]\w*)+/i,alias:["class-name","class-name-fully-qualified"],greedy:!0,lookbehind:!0,inside:{punctuation:/\\/}}],constant:n,number:a,operator:r,punctuation:i}},delimiter:{pattern:/^#\[|\]$/,alias:"punctuation"}}}}),e.hooks.add("before-tokenize",(function(t){/<\?/.test(t.code)&&e.languages["markup-templating"].buildPlaceholders(t,"php",/<\?(?:[^"'/#]|\/(?![*/])|("|')(?:\\[\s\S]|(?!\1)[^\\])*\1|(?:\/\/|#(?!\[))(?:[^?\n\r]|\?(?!>))*(?=$|\?>|[\r\n])|#\[|\/\*(?:[^*]|\*(?!\/))*(?:\*\/|$))*?(?:\?>|$)/g)})),e.hooks.add("after-tokenize",(function(t){e.languages["markup-templating"].tokenizePlaceholders(t,"php")}))}(t),function(e){var t=/[*&][^\s[\]{},]+/,n=/!(?:<[\w\-%#;/?:@&=+$,.!~*'()[\]]+>|(?:[a-zA-Z\d-]*!)?[\w\-%#;/?:@&=+$.~*'()]+)?/,a="(?:"+n.source+"(?:[ \t]+"+t.source+")?|"+t.source+"(?:[ \t]+"+n.source+")?)",r="(?:[^\\s\\x00-\\x08\\x0e-\\x1f!\"#%&'*,\\-:>?@[\\]`{|}\\x7f-\\x84\\x86-\\x9f\\ud800-\\udfff\\ufffe\\uffff]|[?:-])(?:[ \t]*(?:(?![#:])|:))*".replace(//g,(function(){return"[^\\s\\x00-\\x08\\x0e-\\x1f,[\\]{}\\x7f-\\x84\\x86-\\x9f\\ud800-\\udfff\\ufffe\\uffff]"})),i="\"(?:[^\"\\\\\r\n]|\\\\.)*\"|'(?:[^'\\\\\r\n]|\\\\.)*'";function s(e,t){t=(t||"").replace(/m/g,"")+"m";var n="([:\\-,[{]\\s*(?:\\s<>[ \t]+)?)(?:<>)(?=[ \t]*(?:$|,|\\]|\\}|(?:[\r\n]\\s*)?#))".replace(/<>/g,(function(){return a})).replace(/<>/g,(function(){return e}));return RegExp(n,t)}e.languages.yaml={scalar:{pattern:RegExp("([\\-:]\\s*(?:\\s<>[ \t]+)?[|>])[ \t]*(?:((?:\r?\n|\r)[ \t]+)\\S[^\r\n]*(?:\\2[^\r\n]+)*)".replace(/<>/g,(function(){return a}))),lookbehind:!0,alias:"string"},comment:/#.*/,key:{pattern:RegExp("((?:^|[:\\-,[{\r\n?])[ \t]*(?:<>[ \t]+)?)<>(?=\\s*:\\s)".replace(/<>/g,(function(){return a})).replace(/<>/g,(function(){return"(?:"+r+"|"+i+")"}))),lookbehind:!0,greedy:!0,alias:"atrule"},directive:{pattern:/(^[ \t]*)%.+/m,lookbehind:!0,alias:"important"},datetime:{pattern:s("\\d{4}-\\d\\d?-\\d\\d?(?:[tT]|[ \t]+)\\d\\d?:\\d{2}:\\d{2}(?:\\.\\d*)?(?:[ \t]*(?:Z|[-+]\\d\\d?(?::\\d{2})?))?|\\d{4}-\\d{2}-\\d{2}|\\d\\d?:\\d{2}(?::\\d{2}(?:\\.\\d*)?)?"),lookbehind:!0,alias:"number"},boolean:{pattern:s("false|true","i"),lookbehind:!0,alias:"important"},null:{pattern:s("null|~","i"),lookbehind:!0,alias:"important"},string:{pattern:s(i),lookbehind:!0,greedy:!0},number:{pattern:s("[+-]?(?:0x[\\da-f]+|0o[0-7]+|(?:\\d+(?:\\.\\d*)?|\\.\\d+)(?:e[+-]?\\d+)?|\\.inf|\\.nan)","i"),lookbehind:!0},tag:n,important:t,punctuation:/---|[:[\]{}\-,|>?]|\.\.\./},e.languages.yml=e.languages.yaml}(t),t.manual=!0;const n=e({mounted(){t.highlightAll(this.$el)},updated(){t.highlightAll(this.$el)},render(){return this.$scopedSlots.default({})}},null,null,!1,null,null,null,null).exports;export{n as default}; diff --git a/kirby/panel/dist/js/IndexView.min.js b/kirby/panel/dist/js/IndexView.min.js deleted file mode 100644 index b6a13b3..0000000 --- a/kirby/panel/dist/js/IndexView.min.js +++ /dev/null @@ -1 +0,0 @@ -import{n as e}from"./index.min.js";import"./vendor.min.js";const t=e({props:{categories:Array,info:String,tab:String}},(function(){var e=this,t=e._self._c;return t("k-panel-inside",{staticClass:"k-lab-index-view"},[t("k-header",[e._v("Lab")]),t("k-tabs",{attrs:{tab:e.tab,tabs:[{name:"examples",label:"Examples",link:"/lab"},{name:"docs",label:"Docs",link:"/lab/docs"}]}}),e.info?t("k-box",{attrs:{icon:"question",theme:"info",text:e.info,html:!0}}):e._e(),e._l(e.categories,(function(e){return t("k-section",{key:e.name,attrs:{headline:e.name}},[t("k-collection",{attrs:{items:e.examples,empty:{icon:e.icon,text:"Add examples to "+e.path}}})],1)}))],2)}),[],!1,null,null,null,null).exports;export{t as default}; diff --git a/kirby/panel/dist/js/PlaygroundView.min.js b/kirby/panel/dist/js/PlaygroundView.min.js deleted file mode 100644 index 0254521..0000000 --- a/kirby/panel/dist/js/PlaygroundView.min.js +++ /dev/null @@ -1 +0,0 @@ -import{D as t}from"./Docs.min.js";import{n as e}from"./index.min.js";import"./vendor.min.js";const n=e({props:{docs:Object},emits:["cancel"],computed:{options(){const t=[{icon:"expand",link:"lab/docs/"+this.docs.component}];return this.docs.github&&t.unshift({icon:"github",link:this.docs.github,target:"_blank"}),t}}},(function(){var t=this,e=t._self._c;return e("k-drawer",t._b({ref:"drawer",staticClass:"k-form-drawer",attrs:{options:t.options},on:{submit:function(e){return t.$emit("cancel")}}},"k-drawer",t.$attrs,!1),[e("k-lab-docs",t._b({},"k-lab-docs",t.docs,!1))],1)}),[],!1,null,null,null,null).exports;const l=e({props:{code:{type:Boolean,default:!0},label:String,flex:Boolean},data:()=>({mode:"preview"}),computed:{component(){return window.UiExamples[this.label]}}},(function(){var t=this,e=t._self._c;return e("div",{staticClass:"k-lab-example",attrs:{"data-flex":t.flex,tabindex:"0"}},[e("header",{staticClass:"k-lab-example-header"},[e("h3",{staticClass:"k-lab-example-label"},[t._v(t._s(t.label))]),t.code?e("k-button-group",{staticClass:"k-lab-example-inspector",attrs:{layout:"collapsed"}},[e("k-button",{attrs:{theme:"preview"===t.mode?"info":null,icon:"preview",size:"xs",title:"Preview"},on:{click:function(e){t.mode="preview"}}}),e("k-button",{attrs:{theme:"inspect"===t.mode?"info":null,icon:"code",size:"xs",title:"Vue code"},on:{click:function(e){t.mode="inspect"}}})],1):t._e()],1),"preview"===t.mode?e("div",{staticClass:"k-lab-example-canvas"},[t._t("default")],2):t._e(),"inspect"===t.mode?e("div",{staticClass:"k-lab-example-code"},[e("k-code",{attrs:{language:"html"}},[t._v(t._s(t.component))])],1):t._e()])}),[],!1,null,null,null,null).exports;const a=e({},(function(){return(0,this._self._c)("div",{staticClass:"k-lab-examples"},[this._t("default")],2)}),[],!1,null,null,null,null).exports;const o=e({methods:{submit(t){const e=Object.fromEntries(new FormData(t));this.$panel.dialog.open({component:"k-lab-output-dialog",props:{code:JSON.stringify(e,null,2)}})}}},(function(){var t=this,e=t._self._c;return e("form",{staticClass:"k-lab-form",on:{submit:function(e){return e.preventDefault(),t.submit(e.target)}}},[t._t("default"),e("footer",[e("k-button",{attrs:{type:"submit",icon:"check",theme:"positive",variant:"filled"}},[t._v(" Submit ")])],1)],2)}),[],!1,null,null,null,null).exports;const s=e({props:{code:String,language:{default:"js",type:String}},emits:["cancel"]},(function(){var t=this,e=t._self._c;return e("k-dialog",t._b({attrs:{size:"large","cancel-button":!1,"submit-button":!1},on:{cancel:function(e){return t.$emit("cancel")}}},"k-dialog",t.$attrs,!1),[e("k-code",{attrs:{language:t.language}},[t._v(t._s(t.code))])],1)}),[],!1,null,null,null,null).exports;const i=e({},(function(){var t=this._self._c;return t("div",{staticClass:"k-table"},[t("table",[t("tbody",[t("tr",[t("td",{staticClass:"k-table-cell",attrs:{"data-mobile":"true"}},[this._t("default")],2)])])])])}),[],!1,null,null,null,null).exports;Vue.component("k-lab-docs",t),Vue.component("k-lab-docs-drawer",n),Vue.component("k-lab-example",l),Vue.component("k-lab-examples",a),Vue.component("k-lab-form",o),Vue.component("k-lab-output-dialog",s),Vue.component("k-lab-table-cell",i);const r=e({props:{docs:String,examples:[Object,Array],file:String,github:String,props:[Object,Array],styles:String,tab:String,tabs:{type:Array,default:()=>[]},template:String,title:String},data:()=>({component:null}),watch:{tab:{handler(){this.createComponent()},immediate:!0}},mounted(){this.$panel.view.path.replace(/lab\//,"")},methods:{async createComponent(){if(!this.file)return;const{default:t}=await import(this.$panel.url(this.file)+"?cache="+Date.now());t.template=this.template,this.component={...t},window.UiExamples=this.examples},openDocs(){this.$panel.drawer.open(`lab/docs/${this.docs}`)},async reloadComponent(){await this.$panel.view.refresh(),this.createComponent()},reloadDocs(){this.$panel.drawer.isOpen&&this.$panel.drawer.refresh()}}},(function(){var t=this,e=t._self._c;return e("k-panel-inside",{staticClass:"k-lab-playground-view",attrs:{"data-has-tabs":t.tabs.length>1}},[e("k-header",{scopedSlots:t._u([{key:"buttons",fn:function(){return[t.docs||t.github?e("k-button-group",[t.docs?e("k-button",{attrs:{text:t.docs,icon:"book",size:"sm",variant:"filled"},on:{click:t.openDocs}}):t._e(),t.github?e("k-button",{attrs:{link:t.github,icon:"github",size:"sm",target:"_blank",variant:"filled"}}):t._e()],1):t._e()]},proxy:!0}])},[t._v(" "+t._s(t.title)+" ")]),e("k-tabs",{attrs:{tab:t.tab,tabs:t.tabs}}),t.component?e(t.component,t._b({tag:"component"},"component",t.props,!1)):t._e(),t.styles?e("style",{tag:"component",domProps:{innerHTML:t._s(t.styles)}}):t._e()],1)}),[],!1,null,null,null,null).exports;export{r as default}; diff --git a/kirby/panel/dist/js/container-query-polyfill.modern.min.js b/kirby/panel/dist/js/container-query-polyfill.modern.min.js deleted file mode 100644 index ddb773d..0000000 --- a/kirby/panel/dist/js/container-query-polyfill.modern.min.js +++ /dev/null @@ -1 +0,0 @@ -function e(){return e=Object.assign?Object.assign.bind():function(e){for(var t=1;t0?{type:2,value:n/r}:{type:1};case 6:return null!=n&&null!=r?{type:4,value:r>=n?"portrait":"landscape"}:{type:1}}}function n(e,t){switch(e.type){case 1:case 2:case 3:case 4:return i(e,t);case 5:{const n=t.sizeFeatures.get(e.feature);return null==n?{type:1}:n}case 6:return e.value}}function r(e){return{type:5,value:e}}function u(e,t,n){return r(function(e,t,n){switch(n){case 1:return e===t;case 2:return e>t;case 3:return e>=t;case 4:return ee*t))}return null}function c(e,t){switch(e.type){case 2:return 0===e.value?0:null;case 3:return l(e,t)}return null}function i(e,t){switch(e.type){case 4:return function(e,t){const o=n(e.left,t),s=n(e.right,t),l=e.operator;if(4===o.type&&4===s.type||5===o.type&&5===s.type)return i=o,a=s,1===l?r(i.value===a.value):{type:1};var i,a;if(3===o.type||3===s.type){const e=c(o,t),n=c(s,t);if(null!=e&&null!=n)return u(e,n,l)}else if(2===o.type&&2===s.type)return u(o.value,s.value,l);return{type:1}}(e,t);case 2:return function(e,t){const n=i(e.left,t);return 5!==n.type||!0!==n.value?n:i(e.right,t)}(e,t);case 3:return function(e,t){const n=i(e.left,t);return 5===n.type&&!0===n.value?n:i(e.right,t)}(e,t);case 1:{const n=i(e.value,t);return 5===n.type?{type:5,value:!n.value}:{type:1}}case 5:return a(n(e,t));case 6:return a(e.value)}}function a(e){switch(e.type){case 5:return e;case 2:case 3:return{type:5,value:e.value>0}}return{type:1}}const f=Array.from({length:4},(()=>Math.floor(256*Math.random()).toString(16))).join(""),p=S("container"),y=S("container-type"),h=S("container-name"),v=`data-cqs-${f}`,d=`data-cqc-${f}`,m=S("cqw"),w=S("cqh"),g=S("cqi"),b=S("cqb");function S(e){return`--cq-${e}-${f}`}const x=Symbol();function q(e,t){const n={value:t,errorIndices:[],index:-1,at(r){const u=n.index+r;return u>=e.length?t:e[u]},consume:e=>(n.index+=e,n.value=n.at(0),n.value),reconsume(){n.index-=1},error(){n.errorIndices.push(n.index)}};return n}function C(e){return q(e,{type:0})}function*$(e){const t=[];let n=!1;for(const b of e){const e=b.codePointAt(0);n&&10!==e&&(n=!1,t.push(10)),0===e||e>=55296&&e<=57343?t.push(65533):13===e?n=!0:t.push(e)}const r=q(t,-1),{at:u,consume:o,error:s,reconsume:l}=r;function c(){return String.fromCodePoint(r.value)}function i(){return{type:13,value:c()}}function a(){for(;z(u(1));)o(1)}function f(){for(;-1!==r.value;)if(o(1),42===u(0)&&47===u(1))return void o(1);s()}function p(){const[e,t]=function(){let e=0,t="",n=u(1);for(43!==n&&45!==n||(o(1),t+=c());k(u(1));)o(1),t+=c();if(46===u(1)&&k(u(2)))for(e=1,o(1),t+=c();k(u(1));)o(1),t+=c();if(n=u(1),69===n||101===n){const n=u(2);if(k(n))for(e=1,o(1),t+=c();k(u(1));)o(1),t+=c();else if((45===n||43===n)&&k(u(3)))for(e=1,o(1),t+=c(),o(1),t+=c();k(u(1));)o(1),t+=c()}return[t,e]}(),n=u(1);return d(n,u(1),u(2))?{type:15,value:e,flag:t,unit:w()}:37===n?(o(1),{type:16,value:e}):{type:17,value:e,flag:t}}function y(){const e=w();let t=u(1);if("url"===e.toLowerCase()&&40===t){for(o(1);z(u(1))&&z(u(2));)o(1);t=u(1);const n=u(2);return 34===t||39===t?{type:23,value:e}:!z(t)||34!==n&&39!==n?function(){let e="";for(a();;){const n=o(1);if(41===n)return{type:20,value:e};if(-1===n)return s(),{type:20,value:e};if(z(n)){a();const t=u(1);return 41===t||-1===t?(o(1),-1===n&&s(),{type:20,value:e}):(g(),{type:21})}if(34===n||39===n||40===n||(t=n)>=0&&t<=8||11===t||t>=14&&t<=31||127===t)return s(),g(),{type:21};if(92===n){if(!j(n,u(1)))return s(),{type:21};e+=v()}else e+=c()}var t}():{type:23,value:e}}return 40===t?(o(1),{type:23,value:e}):{type:24,value:e}}function h(e){let t="";for(;;){const n=o(1);if(-1===n||n===e)return-1===n&&s(),{type:2,value:t};if(E(n))return s(),l(),{type:3};if(92===n){const e=u(1);if(-1===e)continue;E(e)?o(1):t+=v()}else t+=c()}}function v(){const e=o(1);if(A(e)){const t=[e];for(let e=0;e<5;e++){const e=u(1);if(!A(e))break;t.push(e),o(1)}z(u(1))&&o(1);let n=parseInt(String.fromCodePoint(...t),16);return(0===n||n>=55296&&n<=57343||n>1114111)&&(n=65533),String.fromCodePoint(n)}return-1===e?(s(),String.fromCodePoint(65533)):c()}function d(e,t,n){return 45===e?L(t)||45===t||j(t,n):!!L(e)}function m(e,t,n){return 43===e||45===e?k(t)||46===t&&k(n):!(46!==e||!k(t))||!!k(e)}function w(){let e="";for(;;){const t=o(1);if(M(t))e+=c();else{if(!j(t,u(1)))return l(),e;e+=v()}}}function g(){for(;;){const e=o(1);if(-1===e)return;j(e,u(1))&&v()}}for(;;){const e=o(1);if(47===e&&42===u(1))o(2),f();else if(z(e))a(),yield{type:1};else if(34===e)yield h(e);else if(35===e){const e=u(1);M(e)||j(e,u(2))?yield{type:14,flag:d(u(1),u(2),u(3))?1:0,value:w()}:yield i()}else if(39===e)yield h(e);else if(40===e)yield{type:4};else if(41===e)yield{type:5};else if(43===e)m(e,u(1),u(2))?(l(),yield p()):yield i();else if(44===e)yield{type:6};else if(45===e){const t=u(1),n=u(2);m(e,t,n)?(l(),yield p()):45===t&&62===n?(o(2),yield{type:19}):d(e,t,n)?(l(),yield y()):yield i()}else if(46===e)m(e,u(1),u(2))?(l(),yield p()):yield i();else if(58===e)yield{type:7};else if(59===e)yield{type:8};else if(60===e)33===u(1)&&45===u(2)&&45===u(3)?yield{type:18}:yield i();else if(64===e)if(d(u(1),u(2),u(3))){const e=w();yield{type:22,value:e}}else yield i();else if(91===e)yield{type:9};else if(92===e)j(e,u(1))?(l(),yield y()):(s(),yield i());else if(93===e)yield{type:10};else if(123===e)yield{type:11};else if(125===e)yield{type:12};else if(k(e))l(),yield p();else if(L(e))l(),yield y();else{if(-1===e)return yield{type:0},r.errorIndices;yield{type:13,value:c()}}}}function k(e){return e>=48&&e<=57}function A(e){return k(e)||e>=65&&e<=70||e>=97&&e<=102}function E(e){return 10===e||13===e||12===e}function z(e){return E(e)||9===e||32===e}function L(e){return e>=65&&e<=90||e>=97&&e<=122||e>=128||95===e}function j(e,t){return 92===e&&!E(t)}function M(e){return L(e)||k(e)||45===e}const T={11:12,9:10,4:5};function P(t,n){const r=function(e,t){const n=[];for(;;)switch(e.consume(1).type){case 1:break;case 0:return{type:3,value:n};case 18:case 19:if(!1!==t){e.reconsume();const t=U(e);t!==x&&n.push(t)}break;case 22:e.reconsume(),n.push(F(e));break;default:{e.reconsume();const t=U(e);t!==x&&n.push(t);break}}}(C(t),!0===n);return e({},r,{value:r.value.map((t=>{return 26===t.type?0===(n=t).value.value.type?e({},n,{value:e({},n.value,{value:(r=n.value.value.value,function(e){const t=[],n=[];for(;;){const r=e.consume(1);switch(r.type){case 1:case 8:break;case 0:return{type:1,value:[...n,...t]};case 22:e.reconsume(),t.push(F(e));break;case 24:{const t=[r];let u=e.at(1);for(;8!==u.type&&0!==u.type;)t.push(I(e)),u=e.at(1);const o=R(C(t));o!==x&&n.push(o);break}case 13:if("&"===r.value){e.reconsume();const n=U(e);n!==x&&t.push(n);break}default:{e.error(),e.reconsume();let t=e.at(1);for(;8!==t.type&&0!==t.type;)I(e),t=e.at(1);break}}}}(C(r)))})}):n:t;var n,r}))})}function N(e){const t=C(e),n=[];for(;;){if(0===t.consume(1).type)return n;t.reconsume(),n.push(I(t))}}function O(e){for(;1===e.at(1).type;)e.consume(1)}function F(e){let t=e.consume(1);if(22!==t.type)throw new Error(`Unexpected type ${t.type}`);const n=t.value,r=[];for(;;)switch(t=e.consume(1),t.type){case 8:return{type:25,name:n,prelude:r,value:null};case 0:return e.error(),{type:25,name:n,prelude:r,value:null};case 11:return{type:25,name:n,prelude:r,value:Q(e)};case 28:if(11===t.source.type)return{type:25,name:n,prelude:r,value:t};default:e.reconsume(),r.push(I(e))}}function U(e){let t=e.value;const n=[];for(;;)switch(t=e.consume(1),t.type){case 0:return e.error(),x;case 11:return{type:26,prelude:n,value:Q(e)};case 28:if(11===t.source.type)return{type:26,prelude:n,value:t};default:e.reconsume(),n.push(I(e))}}function R(e){const t=e.consume(1);if(24!==t.type)throw new Error(`Unexpected type ${t.type}`);const n=t.value,r=[];let u=!1;if(O(e),7!==e.at(1).type)return e.error(),x;for(e.consume(1),O(e);0!==e.at(1).type;)r.push(I(e));const o=r[r.length-2],s=r[r.length-1];return o&&13===o.type&&"!"===o.value&&24===s.type&&"important"===s.value.toLowerCase()&&(u=!0,r.splice(r.length-2)),{type:29,name:n,value:r,important:u}}function I(e){const t=e.consume(1);switch(t.type){case 11:case 9:case 4:return Q(e);case 23:return function(e){let t=e.value;if(23!==t.type)throw new Error(`Unexpected type ${t.type}`);const n=t.value,r=[];for(;;)switch(t=e.consume(1),t.type){case 5:return{type:27,name:n,value:r};case 0:return e.error(),{type:27,name:n,value:r};default:e.reconsume(),r.push(I(e))}}(e);default:return t}}function Q(e){let t=e.value;const n=t,r=T[n.type];if(!r)throw new Error(`Unexpected type ${t.type}`);const u=[];for(;;)switch(t=e.consume(1),t.type){case r:return{type:28,source:n,value:{type:0,value:u}};case 0:return e.error(),{type:28,source:n,value:{type:0,value:u}};default:e.reconsume(),u.push(I(e))}}function H(e){return O(e),0===e.at(1).type}const V={11:["{","}"],9:["[","]"],4:["(",")"]};function D(e,t){switch(e.type){case 25:return`@${CSS.escape(e.name)} ${e.prelude.map((e=>D(e))).join("")}${e.value?D(e.value):";"}`;case 26:return`${e.prelude.map((e=>D(e))).join("")}${D(e.value)}`;case 28:{const[t,n]=V[e.source.type];return`${t}${W(e.value)}${n}`}case 27:return`${CSS.escape(e.name)}(${e.value.map((e=>D(e))).join("")})`;case 29:return`${CSS.escape(e.name)}:${e.value.map((e=>D(e))).join("")}${e.important?" !important":""}`;case 1:return" ";case 8:return";";case 7:return":";case 14:return"#"+CSS.escape(e.value);case 24:return CSS.escape(e.value);case 15:return e.value+CSS.escape(e.unit);case 13:case 17:return e.value;case 2:return`"${CSS.escape(e.value)}"`;case 6:return",";case 20:return"url("+CSS.escape(e.value)+")";case 22:return"@"+CSS.escape(e.value);case 16:return e.value+"%";default:throw new Error(`Unsupported token ${e.type}`)}}function W(e,t){return e.value.map((t=>{let n=D(t);return 29===t.type&&0!==e.type&&(n+=";"),n})).join("")}function _(e){return D(e)}function B(e){const t=e.at(1);return 13===t.type&&"="===t.value&&(e.consume(1),!0)}function G(e,t){const n=[];for(;;){const r=e.at(1);if(0===r.type||t&&7===r.type||13===r.type&&(">"===r.value||"<"===r.value||"="===r.value))break;n.push(e.consume(1))}return n}function Y(e){O(e);const t=e.consume(1);return 13!==t.type?x:">"===t.value?B(e)?3:2:"<"===t.value?B(e)?5:4:"="===t.value?1:x}function J(e){return 4===e||5===e}function K(e){return 2===e||3===e}function X(e,t,n){const r=function(e){O(e);const t=e.consume(1);return O(e),24!==t.type||0!==e.at(1).type?x:t.value}(C(e));if(r===x)return x;let u=r.toLowerCase();return u=n?n(u):u,t.has(u)?u:x}function Z(e){return{type:13,value:e}}function ee(e,t){return{type:29,name:e,value:t,important:!1}}function te(e){return{type:24,value:e}}function ne(e,t){return{type:27,name:e,value:t}}function re(e){return ne("var",[te(e)])}function ue(e,t){O(e);let n=!1,r=e.at(1);if(24===r.type){if("not"!==r.value.toLowerCase())return x;e.consume(1),O(e),n=!0}let u=function(e){const t=e.consume(1);switch(t.type){case 28:{if(4!==t.source.type)return x;const e=ue(C(t.value.value),null);return e!==x?e:{type:4,value:t}}case 27:return{type:4,value:t};default:return x}}(e);if(u===x)return x;u=n?{type:1,value:u}:u,O(e),r=e.at(1);const o=24===r.type?r.value.toLowerCase():null;if(null!==o){if(e.consume(1),O(e),"and"!==o&&"or"!==o||null!==t&&o!==t)return x;const n=ue(e,o);return n===x?x:{type:"and"===o?2:3,left:u,right:n}}return H(e)?u:x}function oe(e){return ue(e,null)}function se(e){switch(e.type){case 1:return[te("not"),{type:1},...se(e.value)];case 2:case 3:return[...se(e.left),{type:1},te(2===e.type?"and":"or"),{type:1},...se(e.right)];case 4:return[e.value]}}const le={width:1,height:2,"inline-size":3,"block-size":4,"aspect-ratio":5,orientation:6},ce=new Set(Object.keys(le)),ie=new Set(["none","and","not","or","normal","auto"]),ae=new Set(["initial","inherit","revert","revert-layer","unset"]),fe=new Set(["size","inline-size"]);function pe(e,t,n,r){const u=n();if(u===x)return x;let o=[u,null];O(e);const s=e.at(1);if(13===s.type){if(s.value!==t)return x;e.consume(1),O(e);const n=r();O(e),n!==x&&(o=[u,n])}return H(e)?o:x}function ye(e){const t=e.consume(1);return 17===t.type?parseInt(t.value):x}function he(e){const t=C(e);O(t);const n=t.consume(1);let r=x;switch(n.type){case 17:t.reconsume(),r=function(e){const t=pe(e,"/",(()=>ye(e)),(()=>ye(e)));return t===x?x:{type:2,value:t[0]/(null!==t[1]?t[1]:1)}}(t);break;case 15:r={type:3,value:parseInt(n.value),unit:n.unit.toLowerCase()};break;case 24:{const e=n.value.toLowerCase();switch(e){case"landscape":case"portrait":r={type:4,value:e}}}}return r===x?x:H(t)?{type:6,value:r}:x}function ve(e){return!we(e=e.toLowerCase())&&!ie.has(e)}function de(e,t){const n=[];for(;;){O(e);const r=e.at(1);if(24!==r.type||!t(r.value))return n;e.consume(1),n.push(r.value)}}function me(e){const t=[];for(;;){O(e);const n=e.at(1);if(24!==n.type)break;const r=n.value;if(!ve(r))break;e.consume(1),t.push(r)}return t}function we(e){return ae.has(e)}function ge(e){return e.map((e=>"cq-"+e))}function be(e){const t=de(e,(e=>we(e)));return 1===t.length?ge(t):x}function Se(e,t){const n=de(e,(e=>"none"===e));if(1===n.length)return ge(n);if(0!==n.length)return x;if(t){const t=be(e);if(t!==x)return t}const r=me(e);return r.length>0&&(!t||H(e))?r:x}function xe(e,t){if(t){const t=be(e);if(t!==x)return t}return function(e){const t=de(e,(e=>"normal"===e));if(1===t.length)return ge(t);if(0!==t.length)return x;const n=de(e,(e=>fe.has(e)));return n.length>0&&H(e)?n:x}(e)}function qe(e){const t=C(e),n=be(t);if(n!==x)return[n,n];const r=pe(t,"/",(()=>Se(t,!1)),(()=>xe(t,!1)));return r!==x&&H(t)?[r[0],r[1]||[]]:x}function Ce(e){const t=C(e),n=me(t);if(!n||n.length>1)return x;const r=oe(t);if(r===x)return x;const u={features:new Set},o=$e(r,u);return H(t)?{name:n.length>0?n[0]:null,condition:o,features:u.features}:x}function $e(e,t){switch(e.type){case 1:return{type:1,value:$e(e.value,t)};case 2:case 3:return{type:2===e.type?2:3,left:$e(e.left,t),right:$e(e.right,t)};case 4:if(28===e.value.type){const n=function(e,t){const n=function(e,t){const n=G(e,!0),r=e.at(1);if(0===r.type){const e=X(n,t);return e!==x&&t.has(e)?{type:1,feature:e}:x}if(7===r.type){e.consume(1);const r=G(e,!1);let u=1;const o=X(n,t,(e=>e.startsWith("min-")?(u=3,e.substring(4)):e.startsWith("max-")?(u=5,e.substring(4)):e));return o!==x?{type:2,feature:o,bounds:[null,[u,r]]}:x}const u=Y(e);if(u===x)return x;const o=G(e,!1);if(0===e.at(1).type){const e=X(n,t);if(e!==x)return{type:2,feature:e,bounds:[null,[u,o]]};const r=X(o,t);return r!==x?{type:2,feature:r,bounds:[[u,n],null]}:x}const s=Y(e);if(s===x||!(K(u)&&K(s)||J(u)&&J(s)))return x;const l=G(e,!1),c=X(o,t);return c!==x?{type:2,feature:c,bounds:[[u,n],[s,l]]}:x}(e,ce);if(n===x)return x;const r=le[n.feature];if(null==r)return x;if(t.features.add(r),1===n.type)return{type:5,feature:r};{const e={type:5,feature:r};let t=x;if(null!==n.bounds[0]){const r=he(n.bounds[0][1]);if(r===x)return x;t={type:4,operator:n.bounds[0][0],left:r,right:e}}if(null!==n.bounds[1]){const r=he(n.bounds[1][1]);if(r===x)return x;const u={type:4,operator:n.bounds[1][0],left:e,right:r};t=t!==x?{type:2,left:t,right:u}:u}return t}}(C(e.value.value.value),t);if(n!==x)return n}return{type:6,value:{type:1}}}}let ke=0;const Ae={cqw:m,cqh:w,cqi:g,cqb:b},Ee=CSS.supports("selector(:where(div))"),ze=":not(.container-query-polyfill)";N(Array.from($(ze)));const Le=document.createElement("div"),je=new Set(["before","after","first-line","first-letter"]);function Me(e,t){return ne("calc",[{type:17,flag:e.flag,value:e.value},Z("*"),t])}function Te(t){return t.map((t=>{switch(t.type){case 15:return function(e){const t=e.unit,n=Ae[t];return null!=n?Me(e,re(n)):"cqmin"===t||"cqmax"===t?Me(e,ne(e.unit.slice(2),[re(g),{type:6},re(b)])):e}(t);case 27:return e({},t,{value:Te(t.value)})}return t}))}function Pe(t){switch(t.name){case"container":return qe(t.value)?e({},t,{name:p}):t;case"container-name":return Se(C(t.value),!0)?e({},t,{name:h}):t;case"container-type":return null!=xe(C(t.value),!0)?e({},t,{name:y}):t}return e({},t,{value:Te(t.value)})}function Ne(t,n){return e({},t,{value:t.value.map((t=>{switch(t.type){case 25:return Qe(t,n);case 26:return r=t,(u=n).transformStyleRule(e({},r,{value:Ue(r.value,u)}));default:return t}var r,u}))})}function Oe(e){return 0===e.type||6===e.type}function Fe(e){for(let t=e.length-1;t>=0;t--)if(1!==e[t].type)return e.slice(0,t+1);return e}function Ue(t,n){return function(t,n){const r=[];let u=null,o=null;for(const e of t.value.value)switch(e.type){case 25:{const t=n?n(e):e;t&&r.push(t)}break;case 29:{const t=Pe(e);switch(t.name){case p:{const t=qe(e.value);t!==x&&(u=t[0],o=t[1]);break}case h:{const t=Se(C(e.value),!0);t!==x&&(u=t);break}case y:{const t=xe(C(e.value),!0);t!==x&&(o=t);break}default:r.push(t)}}}return u&&u.length>0&&r.push(ee(h,[te(u.join(" "))])),o&&o.length>0&&r.push(ee(y,[te(o.join(" "))])),e({},t,{value:{type:2,value:r}})}(t,(e=>Qe(e,n)))}function Re(t){if(1===t.type)return e({},t,{value:Re(t.value)});if(2===t.type||3===t.type)return e({},t,{left:Re(t.left),right:Re(t.right)});if(4===t.type&&28===t.value.type){const n=function(e){const t=C(e);return O(t),24!==t.at(1).type?x:R(t)||x}(t.value.value.value);if(n!==x)return e({},t,{value:e({},t.value,{value:{type:0,value:[Pe(n)]}})})}return t}function Ie(t,n){let r=oe(C(t.prelude));return r=r!==x?Re(r):x,e({},t,{prelude:r!==x?se(r):t.prelude,value:t.value?e({},t.value,{value:Ne(P(t.value.value.value),n)}):null})}function Qe(t,n){switch(t.name.toLocaleLowerCase()){case"media":case"layer":return u=n,e({},r=t,{value:r.value?e({},r.value,{value:Ne(P(r.value.value.value),u)}):null});case"keyframes":return function(t,n){let r=null;return t.value&&(r=e({},t.value,{value:{type:3,value:P(t.value.value.value).value.map((t=>{switch(t.type){case 26:return u=n,e({},r=t,{value:Ue(r.value,u)});case 25:return Qe(t,n)}var r,u}))}})),e({},t,{value:r})}(t,n);case"supports":return Ie(t,n);case"container":return function(t,n){if(t.value){const r=Ce(t.prelude);if(r!==x){const u={rule:r,selector:null,parent:n.parent,uid:"c"+ke++},o=new Set,s=[],l=Ne(P(t.value.value.value),{descriptors:n.descriptors,parent:u,transformStyleRule:t=>{const[n,r]=function(e,t,n){const r=C(e),u=[],o=[];for(;;){if(0===r.at(1).type)return[u,o];const n=Math.max(0,r.index);for(;l=r.at(1),c=r.at(2),!(Oe(l)||7===l.type&&(7===c.type||24===c.type&&je.has(c.value.toLowerCase())));)r.consume(1);const i=r.index+1,a=e.slice(n,i),f=a.length>0?Fe(a):[Z("*")];for(;!Oe(r.at(1));)r.consume(1);const p=e.slice(i,Math.max(0,r.index+1));let y=f,h=[{type:28,source:{type:9},value:{type:0,value:[te(p.length>0?v:d),Z("~"),Z("="),{type:2,value:t}]}}];if(Ee)h=[Z(":"),ne("where",h)];else{const e=f.map(_).join("");e.endsWith(ze)?y=N(Array.from($(e.substring(0,e.length-ze.length)))):s.push({actual:e,expected:e+ze})}u.push(...f),o.push(...y),o.push(...h),o.push(...p),r.consume(1)}var l,c}(t.prelude,u.uid);if(s.length>0)return t;const l=n.map(_).join("");try{Le.matches(l),o.add(l)}catch(c){}return e({},t,{prelude:r})}}).value;if(s.length>0){const e=new Set,t=[];let n=0;for(const{actual:u}of s)n=Math.max(n,u.length);const r=Array.from({length:n},(()=>" ")).join("");for(const{actual:u,expected:o}of s)e.has(u)||(t.push(`${u}${r.substring(0,n-u.length)} => ${o}`),e.add(u));console.warn(`The :where() pseudo-class is not supported by this browser. To use the Container Query Polyfill, you must modify the selectors under your @container rules:\n\n${t.join("\n")}`)}return o.size>0&&(u.selector=Array.from(o).join(", ")),n.descriptors.push(u),{type:25,name:"media",prelude:[te("all")],value:e({},t.value,{value:{type:3,value:l}})}}}return t}(t,n)}var r,u;return t}class He{constructor(e){this.value=void 0,this.value=e}}function Ve(e,t){if(e===t)return!0;if(typeof e==typeof t&&null!==e&&null!==t&&"object"==typeof e){if(Array.isArray(e)){if(!Array.isArray(t)||t.length!==e.length)return!1;for(let n=0,r=e.length;nthis.styles.getPropertyValue(e)));this.context.viewportChanged({width:e.width,height:e.height})}}function nt(e){const t=new AbortController;return e(t.signal).catch((e=>{if(!(e instanceof DOMException&&"AbortError"===e.message))throw e})),t}function rt(e){let t=0;if(0===e.length)return t;if(e.startsWith("cq-")&&("normal"===(e=e.substring(3))||we(e)))return t;const n=e.split(" ");for(const r of n)switch(r){case"size":t|=3;break;case"inline-size":t|=1;break;default:return 0}return t}function ut(e){let t=0;return"none"!==e&&(t|=1,"contents"===e||"inline"===e||Je.test(e)||(t|=2)),t}function ot(e,t){return parseFloat(e(t))}function st(e,t){return t.reduce(((t,n)=>t+ot(e,n)),0)}function lt(e){let t=0,n=0;return"border-box"===e("box-sizing")&&(t=st(e,Ge),n=st(e,Ye)),{fontSize:ot(e,"font-size"),width:ot(e,"width")-t,height:ot(e,"height")-n}}function ct(e){return{containerType:rt(e(y).trim()),containerNames:(n=e(h).trim(),n.startsWith("cq-")&&("none"===(n=n.substring(3))||we(n))?new Set([]):new Set(0===n.length?[]:n.split(" "))),writingAxis:(t=e("writing-mode").trim(),Be.has(t)?1:0),displayFlags:ut(e("display").trim())};var t,n}function it(e,t,n){null!=n?n!=e.getPropertyValue(t)&&e.setProperty(t,n):e.removeProperty(t)}function at(e){const t=e[We];return null!=t?t:[]}function ft(e,t){e[We]=t}new Promise((e=>{})),window.CQPolyfill={version:"1.0.2"},"container"in document.documentElement.style||function(n){function r(e){return e[De]||null}const u=document.documentElement;if(r(u))return;const o=document.createElement(`cq-polyfill-${f}`),s=document.createElement("style");new MutationObserver((e=>{for(const t of e){for(const e of t.removedNodes){const t=r(e);null==t||t.disconnect()}t.target.nodeType!==Node.DOCUMENT_NODE&&t.target.nodeType!==Node.DOCUMENT_FRAGMENT_NODE&&null===t.target.parentNode||"attributes"===t.type&&t.attributeName&&(t.attributeName===v||t.attributeName===d||t.target instanceof Element&&t.target.getAttribute(t.attributeName)===t.oldValue)||(A(t.target).mutate(),S())}})).observe(u,{childList:!0,subtree:!0,attributes:!0,attributeOldValue:!0});const l=new ResizeObserver((e=>{for(const t of e)A(t.target).resize();A(u).update(C())})),c=new Ke(u);async function a(e,{source:t,url:n,signal:r}){const o=function(e,t){try{const n=Array.from($(e));if(t)for(let e=0;ee};return{source:W(Ne(P(n,!0),r)),descriptors:r.descriptors}}catch(n){return console.warn("An error occurred while transpiling stylesheet: "+n),{source:e,descriptors:[]}}}(t,n?n.toString():void 0);let s=()=>{},l=()=>{};const c=A(u);let i=!1;return null!=r&&r.aborted||(l=()=>{if(!i){const{sheet:t}=e;null!=t&&(ft(t,o.descriptors),i=!0,s=()=>{ft(t),c.mutate(),S()},c.mutate(),S())}}),{source:o.source,dispose:s,refresh:l}}const p={cqw:null,cqh:null};function y({width:e,height:t}){p.cqw=e,p.cqh=t}function h(e,t,n){if(e instanceof Element&&t){let r="";for(const[n,u]of t.conditions){const t=n.value;null!=t.selector&&null!=u&&!(2&~u)&&e.matches(t.selector)&&(r.length>0&&(r+=" "),r+=t.uid)}r.length>0?e.setAttribute(n,r):e.removeAttribute(n)}}function S(){l.unobserve(u),l.observe(u)}const x=()=>{const e=[];for(const t of document.styleSheets)for(const n of at(t))e.push([new He(n),0]);return e},q=window.getComputedStyle(u),C=()=>{const t=e=>q.getPropertyValue(e),n=ct(t),r=lt(t);return{parentState:null,conditions:x(),context:e({},p,{fontSize:r.fontSize,rootFontSize:r.fontSize,writingAxis:n.writingAxis}),displayFlags:n.displayFlags,isQueryContainer:!1}},k=e=>e;function A(n){let f=r(n);if(!f){let p,S=null,x=!1;n===u?(p=c,S=k):n===o?(x=!0,p=new tt(o,{viewportChanged:y})):p=n===s?new et(s):n instanceof HTMLLinkElement?new Xe(n,{registerStyleSheet:t=>a(n,e({},t))}):n instanceof HTMLStyleElement?new Ze(n,{registerStyleSheet:t=>a(n,e({},t))}):new Ke(n);let q=Symbol();if(null==S&&n instanceof Element){const r=function(n){const r=window.getComputedStyle(n);return function(n){let u=null;return(...n)=>{if(null==u||!Ve(u[0],n)){const o=((n,u)=>{const{context:o,conditions:s}=n,l=e=>r.getPropertyValue(e),c=ct(l),a=e({},o,{writingAxis:c.writingAxis});let f=s,p=!1,y=c.displayFlags;!(1&n.displayFlags)&&(y=0);const{containerType:h,containerNames:v}=c;if(h>0){const e=h>0&&!(2&~y),n=new Map(s.map((e=>[e[0].value,e[1]])));if(f=[],p=!0,e){const e=lt(l);a.fontSize=e.fontSize;const r=function(e,t){const n={value:t.width},r={value:t.height};let u=n,o=r;if(1===e.writingAxis){const e=u;u=o,o=e}return!!(2&~e.containerType)&&(o.value=void 0),{width:n.value,height:r.value,inlineSize:u.value,blockSize:o.value}}(c,e),u={sizeFeatures:r,treeContext:a},p=e=>{const{rule:r}=e,o=r.name,s=null==o||v.has(o)?function(e,n){const r=new Map,u=n.sizeFeatures;for(const s of e.features){const e=t(s,u);if(1===e.type)return null;r.set(s,e)}const o=i(e.condition,{sizeFeatures:r,treeContext:n.treeContext});return 5===o.type?o.value:null}(r,u):null;var l;return null==s?1===((null!=(l=n.get(e))?l:0)&&1):!0===s},y=(e,t)=>{let n=e.get(t);if(null==n){const r=p(t);n=(r?1:0)|(!0!==r||null!=t.parent&&1&~y(e,t.parent)?0:2),e.set(t,n)}return n},h=new Map;for(const t of s)f.push([t[0],y(h,t[0].value)]);a.cqw=null!=r.width?r.width/100:o.cqw,a.cqh=null!=r.height?r.height/100:o.cqh}}return{parentState:new He(n),conditions:f,context:a,displayFlags:y,isQueryContainer:p}})(...n);null!=u&&Ve(u[1],o)||(u=[n,o])}return u[1]}}()}(n);S=e=>r(e,q)}const C=S||k;let $=null;const E=e=>{const t=$,n=C(e);return $=n,[$,$!==t]},z=n instanceof HTMLElement||n instanceof SVGElement?n.style:null;let L=!1;f={connect(){for(let e=n.firstChild;null!=e;e=e.nextSibling)A(e);p.connected()},disconnect(){n instanceof Element&&(l.unobserve(n),n.removeAttribute(v),n.removeAttribute(d)),z&&(z.removeProperty(g),z.removeProperty(b),z.removeProperty(m),z.removeProperty(w));for(let e=n.firstChild;null!=e;e=e.nextSibling){const t=r(e);null==t||t.disconnect()}p.disconnected(),delete n[De]},update(e){const[t,r]=E(e);if(r){if(h(n,e,d),h(n,t,v),n instanceof Element){const e=x||t.isQueryContainer;e&&!L?(l.observe(n),L=!0):!e&&L&&(l.unobserve(n),L=!1)}if(z){const n=t.context,r=n.writingAxis;let u=null,o=null,s=null,l=null;(r!==e.context.writingAxis||t.isQueryContainer)&&(u=`var(${0===r?m:w})`,o=`var(${1===r?m:w})`),e&&!t.isQueryContainer||(n.cqw&&(s=n.cqw+"px"),n.cqh&&(l=n.cqh+"px")),it(z,g,u),it(z,b,o),it(z,m,s),it(z,w,l)}p.updated()}for(let u=n.firstChild;null!=u;u=u.nextSibling)A(u).update(t)},resize(){q=Symbol()},mutate(){q=Symbol();for(let e=n.firstChild;null!=e;e=e.nextSibling)A(e).mutate()}},n[De]=f,f.connect()}return f}u.prepend(s,o),A(u),S()}(); diff --git a/kirby/panel/dist/js/index.js b/kirby/panel/dist/js/index.js new file mode 100644 index 0000000..bb8b1ff --- /dev/null +++ b/kirby/panel/dist/js/index.js @@ -0,0 +1 @@ +import{V as t,a as e,m as s,d as n,c as i,b as o,I as r,P as l,S as a,F as u,N as c,s as d,l as p,w as h,e as m,f,t as g,g as k,h as b,i as y,j as v,k as $,n as _,D as x,o as w,E as S,p as C,q as O,r as A,T,u as I,v as M,x as E,y as L,z as j,A as D,B,C as P,G as N,H as q}from"./vendor.js";const F=t=>({changeName:async(e,s,n)=>t.patch(e+"/files/"+s+"/name",{name:n}),delete:async(e,s)=>t.delete(e+"/files/"+s),async get(e,s,n){let i=await t.get(e+"/files/"+s,n);return!0===Array.isArray(i.content)&&(i.content={}),i},link(t,e,s){return"/"+this.url(t,e,s)},update:async(e,s,n)=>t.patch(e+"/files/"+s,n),url(t,e,s){let n=t+"/files/"+e;return s&&(n+="/"+s),n}}),R=t=>({async blueprint(e){return t.get("pages/"+this.id(e)+"/blueprint")},async blueprints(e,s){return t.get("pages/"+this.id(e)+"/blueprints",{section:s})},async changeSlug(e,s){return t.patch("pages/"+this.id(e)+"/slug",{slug:s})},async changeStatus(e,s,n){return t.patch("pages/"+this.id(e)+"/status",{status:s,position:n})},async changeTemplate(e,s){return t.patch("pages/"+this.id(e)+"/template",{template:s})},async changeTitle(e,s){return t.patch("pages/"+this.id(e)+"/title",{title:s})},async children(e,s){return t.post("pages/"+this.id(e)+"/children/search",s)},async create(e,s){return null===e||"/"===e?t.post("site/children",s):t.post("pages/"+this.id(e)+"/children",s)},async delete(e,s){return t.delete("pages/"+this.id(e),s)},async duplicate(e,s,n){return t.post("pages/"+this.id(e)+"/duplicate",{slug:s,children:n.children||!1,files:n.files||!1})},async get(e,s){let n=await t.get("pages/"+this.id(e),s);return!0===Array.isArray(n.content)&&(n.content={}),n},id:t=>t.replace(/\//g,"+"),async files(e,s){return t.post("pages/"+this.id(e)+"/files/search",s)},link(t){return"/"+this.url(t)},async preview(t){return(await this.get(this.id(t),{select:"previewUrl"})).previewUrl},async search(e,s){return e?t.post("pages/"+this.id(e)+"/children/search?select=id,title,hasChildren",s):t.post("site/children/search?select=id,title,hasChildren",s)},async update(e,s){return t.patch("pages/"+this.id(e),s)},url(t,e){let s=null===t?"pages":"pages/"+String(t).replace(/\//g,"+");return e&&(s+="/"+e),s}});const z=t=>({running:0,async request(e,s,n=!1){s=Object.assign(s||{},{credentials:"same-origin",cache:"no-store",headers:{"x-requested-with":"xmlhttprequest","content-type":"application/json",...s.headers}}),t.methodOverwrite&&"GET"!==s.method&&"POST"!==s.method&&(s.headers["x-http-method-override"]=s.method,s.method="POST"),s=t.onPrepare(s);const i=e+"/"+JSON.stringify(s);t.onStart(i,n),this.running++;const o=await fetch([t.endpoint,e].join(t.endpoint.endsWith("/")||e.startsWith("/")?"":"/"),s);try{const e=await async function(t){const e=await t.text();let s;try{s=JSON.parse(e)}catch(n){return window.panel.$vue.$api.onParserError({html:e}),!1}return s}(o);if(o.status<200||o.status>299)throw e;if("error"===e.status)throw e;let s=e;return e.data&&"model"===e.type&&(s=e.data),this.running--,t.onComplete(i),t.onSuccess(e),s}catch(r){throw this.running--,t.onComplete(i),t.onError(r),r}},async get(t,e,s,n=!1){return e&&(t+="?"+Object.keys(e).filter((t=>void 0!==e[t]&&null!==e[t])).map((t=>t+"="+e[t])).join("&")),this.request(t,Object.assign(s||{},{method:"GET"}),n)},async post(t,e,s,n="POST",i=!1){return this.request(t,Object.assign(s||{},{method:n,body:JSON.stringify(e)}),i)},async patch(t,e,s,n=!1){return this.post(t,e,s,"PATCH",n)},async delete(t,e,s,n=!1){return this.post(t,e,s,"DELETE",n)}}),Y=t=>({blueprint:async e=>t.get("users/"+e+"/blueprint"),blueprints:async(e,s)=>t.get("users/"+e+"/blueprints",{section:s}),changeEmail:async(e,s)=>t.patch("users/"+e+"/email",{email:s}),changeLanguage:async(e,s)=>t.patch("users/"+e+"/language",{language:s}),changeName:async(e,s)=>t.patch("users/"+e+"/name",{name:s}),changePassword:async(e,s)=>t.patch("users/"+e+"/password",{password:s}),changeRole:async(e,s)=>t.patch("users/"+e+"/role",{role:s}),create:async e=>t.post("users",e),delete:async e=>t.delete("users/"+e),deleteAvatar:async e=>t.delete("users/"+e+"/avatar"),link(t,e){return"/"+this.url(t,e)},async list(e){return t.post(this.url(null,"search"),e)},get:async(e,s)=>t.get("users/"+e,s),async roles(e){return(await t.get(this.url(e,"roles"))).data.map((t=>({info:t.description||`(${window.panel.$t("role.description.placeholder")})`,text:t.title,value:t.name})))},search:async e=>t.post("users/search",e),update:async(e,s)=>t.patch("users/"+e,s),url(t,e){let s=t?"users/"+t:"users";return e&&(s+="/"+e),s}}),H={install(t,e){t.prototype.$api=t.$api=((t={})=>{const e={...{endpoint:"/api",methodOverwrite:!0,onPrepare:t=>t,onStart(){},onComplete(){},onSuccess(){},onParserError(){},onError(t){throw window.console.log(t.message),t}},...t.config||{}};let s={...e,...z(e),...t};return s.auth=(t=>({async login(e){const s={long:e.remember||!1,email:e.email,password:e.password};return t.post("auth/login",s)},logout:async()=>t.post("auth/logout"),user:async e=>t.get("auth",e),verifyCode:async e=>t.post("auth/code",{code:e})}))(s),s.files=F(s),s.languages=(t=>({create:async e=>t.post("languages",e),delete:async e=>t.delete("languages/"+e),get:async e=>t.get("languages/"+e),list:async()=>t.get("languages"),update:async(e,s)=>t.patch("languages/"+e,s)}))(s),s.pages=R(s),s.roles=(t=>({list:async e=>t.get("roles",e),get:async e=>t.get("roles/"+e)}))(s),s.system=(t=>({get:async(e={view:"panel"})=>t.get("system",e),install:async e=>(await t.post("system/install",e)).user,register:async e=>t.post("system/register",e)}))(s),s.site=(t=>({blueprint:async()=>t.get("site/blueprint"),blueprints:async()=>t.get("site/blueprints"),changeTitle:async e=>t.patch("site/title",{title:e}),children:async e=>t.post("site/children/search",e),get:async(e={view:"panel"})=>t.get("site",e),update:async e=>t.post("site",e)}))(s),s.translations=(t=>({list:async()=>t.get("translations"),get:async e=>t.get("translations/"+e)}))(s),s.users=Y(s),s})({config:{endpoint:window.panel.$urls.api,onComplete:s=>{t.$api.requests=t.$api.requests.filter((t=>t!==s)),0===t.$api.requests.length&&e.dispatch("isLoading",!1)},onError:e=>{window.panel.$config.debug&&window.console.error(e),403!==e.code||"Unauthenticated"!==e.message&&"access.panel"!==e.key||t.prototype.$go("/logout")},onParserError:({html:t,silent:s})=>{e.dispatch("fatal",{html:t,silent:s})},onPrepare:t=>(window.panel.$language&&(t.headers["x-language"]=window.panel.$language.code),t.headers["x-csrf"]=window.panel.$system.csrf,t),onStart:(s,n=!1)=>{!1===n&&e.dispatch("isLoading",!0),t.$api.requests.push(s)},onSuccess:()=>{clearInterval(t.$api.ping),t.$api.ping=setInterval(t.$api.auth.user,3e5)}},ping:null,requests:[]}),t.$api.ping=setInterval(t.$api.auth.user,3e5)}},U={name:"Fiber",data:()=>({component:null,state:window.fiber,key:null}),created(){this.$fiber.init(this.state,{base:document.querySelector("base").href,headers:()=>({"X-CSRF":this.state.$system.csrf}),onFatal({text:t,options:e}){this.$store.dispatch("fatal",{html:t,silent:e.silent})},onFinish:()=>{0===this.$api.requests.length&&this.$store.dispatch("isLoading",!1)},onPushState:t=>{window.history.pushState(t,"",t.$url)},onReplaceState:t=>{window.history.replaceState(t,"",t.$url)},onStart:({silent:t})=>{!0!==t&&this.$store.dispatch("isLoading",!0)},onSwap:async(t,e)=>{e={navigate:!0,replace:!1,...e},this.setGlobals(t),this.setTitle(t),this.setTranslation(t),this.component=t.$view.component,this.state=t,this.key=!0===e.replace?this.key:t.$view.timestamp,!0===e.navigate&&this.navigate()},query:()=>{var t;return{language:null==(t=this.state.$language)?void 0:t.code}}}),window.addEventListener("popstate",this.$reload)},methods:{navigate(){this.$store.dispatch("navigate")},setGlobals(e){["$config","$direction","$language","$languages","$license","$menu","$multilang","$permissions","$searches","$system","$translation","$urls","$user","$view"].forEach((s=>{void 0!==e[s]?t.prototype[s]=window.panel[s]=e[s]:t.prototype[s]=e[s]=window.panel[s]}))},setTitle(t){t.$view.title?document.title=t.$view.title+" | "+t.$system.title:document.title=t.$system.title},setTranslation(t){t.$translation&&(document.documentElement.lang=t.$translation.code)}},render(t){if(this.component)return t(this.component,{key:this.key,props:this.state.$view.props})}};function K(t){if(void 0!==t)return JSON.parse(JSON.stringify(t))}function G(t,e){for(const s of Object.keys(e))e[s]instanceof Object&&Object.assign(e[s],G(t[s]||{},e[s]));return Object.assign(t||{},e),t}const J={clone:K,isEmpty:function(t){return null==t||""===t||("object"==typeof t&&0===Object.keys(t).length&&t.constructor===Object||void 0!==t.length&&0===t.length)},merge:G},V=(t,e)=>{localStorage.setItem("kirby$content$"+t,JSON.stringify(e))},W={namespaced:!0,state:{current:null,models:{},status:{enabled:!0}},getters:{exists:t=>e=>Object.prototype.hasOwnProperty.call(t.models,e),hasChanges:(t,e)=>t=>{const s=e.model(t).changes;return Object.keys(s).length>0},isCurrent:t=>e=>t.current===e,id:t=>e=>(e=e||t.current,window.panel.$language?e+"?language="+window.panel.$language.code:e),model:(t,e)=>s=>(s=s||t.current,!0===e.exists(s)?t.models[s]:{api:null,originals:{},values:{},changes:{}}),originals:(t,e)=>t=>K(e.model(t).originals),values:(t,e)=>t=>({...e.originals(t),...e.changes(t)}),changes:(t,e)=>t=>K(e.model(t).changes)},mutations:{CLEAR(t){Object.keys(t.models).forEach((e=>{t.models[e].changes={}})),Object.keys(localStorage).forEach((t=>{t.startsWith("kirby$content$")&&localStorage.removeItem(t)}))},CREATE(e,[s,n]){if(!n)return!1;let i=e.models[s]?e.models[s].changes:n.changes;t.set(e.models,s,{api:n.api,originals:n.originals,changes:i||{}})},CURRENT(t,e){t.current=e},MOVE(e,[s,n]){const i=K(e.models[s]);t.delete(e.models,s),t.set(e.models,n,i);const o=localStorage.getItem("kirby$content$"+s);localStorage.removeItem("kirby$content$"+s),localStorage.setItem("kirby$content$"+n,o)},REMOVE(e,s){t.delete(e.models,s),localStorage.removeItem("kirby$content$"+s)},REVERT(e,s){e.models[s]&&(t.set(e.models[s],"changes",{}),localStorage.removeItem("kirby$content$"+s))},STATUS(e,s){t.set(e.status,"enabled",s)},UPDATE(e,[s,n,i]){if(!e.models[s])return!1;void 0===i&&(i=null),i=K(i);const o=JSON.stringify(i);JSON.stringify(e.models[s].originals[n])==o?t.delete(e.models[s].changes,n):t.set(e.models[s].changes,n,i),V(s,{api:e.models[s].api,originals:e.models[s].originals,changes:e.models[s].changes})}},actions:{init(t){Object.keys(localStorage).filter((t=>t.startsWith("kirby$content$"))).map((t=>t.split("kirby$content$")[1])).forEach((e=>{const s=localStorage.getItem("kirby$content$"+e);t.commit("CREATE",[e,JSON.parse(s)])})),Object.keys(localStorage).filter((t=>t.startsWith("kirby$form$"))).map((t=>t.split("kirby$form$")[1])).forEach((e=>{const s=localStorage.getItem("kirby$form$"+e);let n=null;try{n=JSON.parse(s)}catch(o){}if(!n||!n.api)return localStorage.removeItem("kirby$form$"+e),!1;const i={api:n.api,originals:n.originals,changes:n.values};t.commit("CREATE",[e,i]),V(e,i),localStorage.removeItem("kirby$form$"+e)}))},clear(t){t.commit("CLEAR")},create(t,e){const s=K(e.content);Array.isArray(e.ignore)&&e.ignore.forEach((t=>delete s[t])),e.id=t.getters.id(e.id);const n={api:e.api,originals:s,changes:{}};t.commit("CREATE",[e.id,n]),t.dispatch("current",e.id)},current(t,e){t.commit("CURRENT",e)},disable(t){t.commit("STATUS",!1)},enable(t){t.commit("STATUS",!0)},move(t,[e,s]){e=t.getters.id(e),s=t.getters.id(s),t.commit("MOVE",[e,s])},remove(t,e){t.commit("REMOVE",e),t.getters.isCurrent(e)&&t.commit("CURRENT",null)},revert(t,e){e=e||t.state.current,t.commit("REVERT",e)},async save(e,s){if(s=s||e.state.current,e.getters.isCurrent(s)&&!1===e.state.status.enabled)return!1;e.dispatch("disable");const n=e.getters.model(s),i={...n.originals,...n.changes};try{await t.$api.patch(n.api,i),e.commit("CREATE",[s,{...n,originals:i}]),e.dispatch("revert",s)}finally{e.dispatch("enable")}},update(t,[e,s,n]){n=n||t.state.current,t.commit("UPDATE",[n,e,s])}}},X={namespaced:!0,state:{open:[]},mutations:{CLOSE(t,e){t.open=e?t.open.filter((t=>t.id!==e)):[]},GOTO(t,e){t.open=t.open.slice(0,t.open.findIndex((t=>t.id===e))+1)},OPEN(t,e){t.open.push(e)}},actions:{close(t,e){t.commit("CLOSE",e)},goto(t,e){t.commit("GOTO",e)},open(t,e){t.commit("OPEN",e)}}},Z={timer:null,namespaced:!0,state:{type:null,message:null,details:null,timeout:null},mutations:{SET(t,e){t.type=e.type,t.message=e.message,t.details=e.details,t.timeout=e.timeout},UNSET(t){t.type=null,t.message=null,t.details=null,t.timeout=null}},actions:{close(t){clearTimeout(this.timer),t.commit("UNSET")},deprecated(t,e){console.warn("Deprecated: "+e)},error(t,e){let s=e;"string"==typeof e&&(s={message:e}),e instanceof Error&&(s={message:e.message},window.panel.$config.debug&&window.console.error(e)),t.dispatch("dialog",{component:"k-error-dialog",props:s},{root:!0}),t.dispatch("close")},open(t,e){t.dispatch("close"),t.commit("SET",e),e.timeout&&(this.timer=setTimeout((()=>{t.dispatch("close")}),e.timeout))},success(t,e){"string"==typeof e&&(e={message:e}),t.dispatch("open",{type:"success",timeout:4e3,...e})}}};t.use(e);const Q=new e.Store({strict:!1,state:{dialog:null,drag:null,fatal:!1,isLoading:!1},mutations:{SET_DIALOG(t,e){t.dialog=e},SET_DRAG(t,e){t.drag=e},SET_FATAL(t,e){t.fatal=e},SET_LOADING(t,e){t.isLoading=e}},actions:{dialog(t,e){t.commit("SET_DIALOG",e)},drag(t,e){t.commit("SET_DRAG",e)},fatal(t,e){!1!==e?(console.error("The JSON response could not be parsed"),window.panel.$config.debug&&console.info(e.html),e.silent||t.commit("SET_FATAL",e.html)):t.commit("SET_FATAL",!1)},isLoading(t,e){t.commit("SET_LOADING",!0===e)},navigate(t){t.dispatch("dialog",null),t.dispatch("drawers/close")}},modules:{content:W,drawers:X,notification:Z}}),tt={install(t){window.panel=window.panel||{},window.onunhandledrejection=t=>{t.preventDefault(),Q.dispatch("notification/error",t.reason)},window.panel.deprecated=t=>{Q.dispatch("notification/deprecated",t)},window.panel.error=t.config.errorHandler=t=>{Q.dispatch("notification/error",t)}}},et={install(t){const e=s(),n={$on:e.on,$off:e.off,$emit:e.emit,blur(t){n.$emit("blur",t)},click(t){n.$emit("click",t)},copy(t){n.$emit("copy",t)},dragenter(t){n.entered=t.target,n.prevent(t),n.$emit("dragenter",t)},dragleave(t){n.prevent(t),n.entered===t.target&&n.$emit("dragleave",t)},drop(t){n.prevent(t),n.$emit("drop",t)},entered:null,focus(t){n.$emit("focus",t)},keydown(e){let s=["keydown"];(e.metaKey||e.ctrlKey)&&s.push("cmd"),!0===e.altKey&&s.push("alt"),!0===e.shiftKey&&s.push("shift");let i=t.prototype.$helper.string.lcfirst(e.key);const o={escape:"esc",arrowUp:"up",arrowDown:"down",arrowLeft:"left",arrowRight:"right"};o[i]&&(i=o[i]),!1===["alt","control","shift","meta"].includes(i)&&s.push(i),n.$emit(s.join("."),e),n.$emit("keydown",e)},keyup(t){n.$emit("keyup",t)},online(t){n.$emit("online",t)},offline(t){n.$emit("offline",t)},paste(t){n.$emit("paste",t)},prevent(t){t.stopPropagation(),t.preventDefault()}};document.addEventListener("click",n.click,!1),document.addEventListener("copy",n.copy,!0),document.addEventListener("focus",n.focus,!0),document.addEventListener("paste",n.paste,!0),window.addEventListener("blur",n.blur,!1),window.addEventListener("dragenter",n.dragenter,!1),window.addEventListener("dragexit",n.prevent,!1),window.addEventListener("dragleave",n.dragleave,!1),window.addEventListener("drop",n.drop,!1),window.addEventListener("dragover",n.prevent,!1),window.addEventListener("keydown",n.keydown,!1),window.addEventListener("keyup",n.keyup,!1),window.addEventListener("offline",n.offline),window.addEventListener("online",n.online),t.prototype.$events=n}};class st{constructor(t={}){this.options={base:"/",headers:()=>({}),onFatal:()=>{},onFinish:()=>{},onPushState:()=>{},onReplaceState:()=>{},onStart:()=>{},onSwap:()=>{},query:()=>({}),...t},this.state={}}init(t={},e={}){this.options={...this.options,...e},this.setState(t)}arrayToString(t){return!1===Array.isArray(t)?String(t):t.join(",")}body(t){return"object"==typeof t?JSON.stringify(t):t}async fetch(t,e){return fetch(t,e)}async go(t,e){try{const s=await this.request(t,e);return!1!==s&&this.setState(s,e)}catch(s){if(!0!==(null==e?void 0:e.silent))throw s}}query(t={},e={}){let s=new URLSearchParams(e);return"object"!=typeof t&&(t={}),Object.entries(t).forEach((([t,e])=>{null!==e&&s.set(t,e)})),Object.entries(this.options.query()).forEach((([t,e])=>{var n,i;null!==(e=null!=(i=null!=(n=s.get(t))?n:e)?i:null)&&s.set(t,e)})),s}redirect(t){window.location.href=t}reload(t={}){return this.go(window.location.href,{...t,replace:!0})}async request(t="",e={}){var s;const n=!!(e={globals:!1,method:"GET",only:[],query:{},silent:!1,type:"$view",...e}).globals&&this.arrayToString(e.globals),i=this.arrayToString(e.only);this.options.onStart(e);try{const r=this.url(t,e.query);if(new URL(r).origin!==location.origin)return this.redirect(r),!1;const l=await this.fetch(r,{method:e.method,body:this.body(e.body),credentials:"same-origin",cache:"no-store",headers:{...this.options.headers(),"X-Fiber":!0,"X-Fiber-Globals":n,"X-Fiber-Only":i,"X-Fiber-Referrer":(null==(s=this.state.$view)?void 0:s.path)||null,...e.headers}});if(!1===l.headers.has("X-Fiber"))return this.redirect(l.url),!1;const a=await l.text();let u;try{u=JSON.parse(a)}catch(o){return this.options.onFatal({url:r,path:t,options:e,response:l,text:a}),!1}if(!u[e.type])throw Error(`The ${e.type} could not be loaded`);const c=u[e.type];if(c.error)throw Error(c.error);return"$view"===e.type?i.length?G(this.state,u):u:c}finally{this.options.onFinish(e)}}async setState(t,e={}){return"object"==typeof t&&(this.state=K(t),!0===e.replace||this.url(this.state.$url).href===window.location.href?this.options.onReplaceState(this.state,e):this.options.onPushState(this.state,e),this.options.onSwap(this.state,e),this.state)}url(t="",e={}){return(t="string"==typeof t&&null===t.match(/^https?:\/\//)?new URL(this.options.base+t.replace(/^\//,"")):new URL(t)).search=this.query(e,t.search),t}}const nt=async function(t){return{cancel:null,submit:null,props:{},...t}},it=async function(t,e={}){let s=null,n=null;"function"==typeof e?(s=e,e={}):(s=e.submit,n=e.cancel);let i=await this.$fiber.request("dialogs/"+t,{...e,type:"$dialog"});return"object"==typeof i&&(i.submit=s||null,i.cancel=n||null,i)};async function ot(t,e={}){let s=null;if(s="object"==typeof t?await nt.call(this,t):await it.call(this,t,e),!s)return!1;if(!s.component||!1===this.$helper.isComponent(s.component))throw Error("The dialog component does not exist");return s.props=s.props||{},this.$store.dispatch("dialog",s),s}function rt(t,e={}){return async s=>{const n=await this.$fiber.request("dropdowns/"+t,{...e,type:"$dropdown"});if(!n)return!1;if(!1===Array.isArray(n.options)||0===n.options.length)throw Error("The dropdown is empty");n.options.map((t=>(t.dialog&&(t.click=()=>{const e="string"==typeof t.dialog?t.dialog:t.dialog.url,s="object"==typeof t.dialog?t.dialog:{};return this.$dialog(e,s)}),t))),s(n.options)}}async function lt(t,e,s={}){return await this.$fiber.request("search/"+t,{query:{query:e},type:"$search",...s})}const at={install(t){const e=new st;t.prototype.$fiber=window.panel.$fiber=e,t.prototype.$dialog=window.panel.$dialog=ot,t.prototype.$dropdown=window.panel.$dropdown=rt,t.prototype.$go=window.panel.$go=e.go.bind(e),t.prototype.$reload=window.panel.$reload=e.reload.bind(e),t.prototype.$request=window.panel.$request=e.request.bind(e),t.prototype.$search=window.panel.$search=lt,t.prototype.$url=window.panel.$url=e.url.bind(e)}};const ut={read:function(t){if(!t)return null;if("string"==typeof t)return t;if(t instanceof ClipboardEvent){t.preventDefault();const e=t.clipboardData.getData("text/html")||t.clipboardData.getData("text/plain")||null;if(e)return e.replace(/\u00a0/g," ")}return null},write:function(t,e){if("string"!=typeof t&&(t=JSON.stringify(t,null,2)),e&&e instanceof ClipboardEvent)return e.preventDefault(),e.clipboardData.setData("text/plain",t),!0;const s=document.createElement("textarea");if(s.value=t,document.body.append(s),navigator.userAgent.match(/ipad|ipod|iphone/i)){s.contentEditable=!0,s.readOnly=!0;const t=document.createRange();t.selectNodeContents(s);const e=window.getSelection();e.removeAllRanges(),e.addRange(t),s.setSelectionRange(0,999999)}else s.select();return document.execCommand("copy"),s.remove(),!0}};function ct(t){if("string"==typeof t){if("pattern"===(t=t.toLowerCase()))return"var(--color-gray-800) var(--bg-pattern)";if(!1===t.startsWith("#")&&!1===t.startsWith("var(")){const e="--color-"+t;if(window.getComputedStyle(document.documentElement).getPropertyValue(e))return`var(${e})`}return t}}const dt=(t,e)=>{let s=null;return function(){clearTimeout(s),s=setTimeout((()=>t.apply(this,arguments)),e)}};function pt(t,e=!1){if(!t.match("youtu"))return!1;let s=null;try{s=new URL(t)}catch(d){return!1}const n=s.pathname.split("/").filter((t=>""!==t)),i=n[0],o=n[1],r="https://"+(!0===e?"www.youtube-nocookie.com":s.host)+"/embed",l=t=>!!t&&null!==t.match(/^[a-zA-Z0-9_-]+$/);let a=s.searchParams,u=null;switch(n.join("/")){case"embed/videoseries":case"playlist":l(a.get("list"))&&(u=r+"/videoseries");break;case"watch":l(a.get("v"))&&(u=r+"/"+a.get("v"),a.has("t")&&a.set("start",a.get("t")),a.delete("v"),a.delete("t"));break;default:s.host.includes("youtu.be")&&l(i)?(u="https://www.youtube.com/embed/"+i,a.has("t")&&a.set("start",a.get("t")),a.delete("t")):"embed"===i&&l(o)&&(u=r+"/"+o)}if(!u)return!1;const c=a.toString();return c.length&&(u+="?"+c),u}function ht(t,e=!1){let s=null;try{s=new URL(t)}catch(a){return!1}const n=s.pathname.split("/").filter((t=>""!==t));let i=s.searchParams,o=null;switch(!0===e&&i.append("dnt",1),s.host){case"vimeo.com":case"www.vimeo.com":o=n[0];break;case"player.vimeo.com":o=n[1]}if(!o||!o.match(/^[0-9]*$/))return!1;let r="https://player.vimeo.com/video/"+o;const l=i.toString();return l.length&&(r+="?"+l),r}const mt={youtube:pt,vimeo:ht,video:function(t,e=!1){return t.includes("youtu")?pt(t,e):!!t.includes("vimeo")&&ht(t,e)}},ft=e=>void 0!==t.options.components[e],gt=t=>!!t.dataTransfer&&(!!t.dataTransfer.types&&(!0===t.dataTransfer.types.includes("Files")&&!1===t.dataTransfer.types.includes("text/plain")));const kt={metaKey:function(){return window.navigator.userAgent.indexOf("Mac")>-1?"cmd":"ctrl"}},bt=(t="3/2",e="100%",s=!0)=>{const n=String(t).split("/");if(2!==n.length)return e;const i=Number(n[0]),o=Number(n[1]);let r=100;return 0!==i&&0!==o&&(r=s?r/i*o:r/o*i,r=parseFloat(String(r)).toFixed(2)),r+"%"},yt=t=>{var e=(t=t||{}).desc?-1:1,s=-e,n=/^0/,i=/\s+/g,o=/^\s+|\s+$/g,r=/[^\x00-\x80]/,l=/^0x[0-9a-f]+$/i,a=/(0x[\da-fA-F]+|(^[\+\-]?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?(?=\D|\s|$))|\d+)/g,u=/(^([\w ]+,?[\w ]+)?[\w ]+,?[\w ]+\d+:\d+(:\d+)?[\w ]?|^\d{1,4}[\/\-]\d{1,4}[\/\-]\d{1,4}|^\w+, \w+ \d+, \d{4})/,c=t.insensitive?function(t){return function(t){if(t.toLocaleLowerCase)return t.toLocaleLowerCase();return t.toLowerCase()}(""+t).replace(o,"")}:function(t){return(""+t).replace(o,"")};function d(t){return t.replace(a,"\0$1\0").replace(/\0$/,"").replace(/^\0/,"").split("\0")}function p(t,e){return(!t.match(n)||1===e)&&parseFloat(t)||t.replace(i," ").replace(o,"")||0}return function(t,n){var i=c(t),o=c(n);if(!i&&!o)return 0;if(!i&&o)return s;if(i&&!o)return e;var a=d(i),h=d(o),m=parseInt(i.match(l),16)||1!==a.length&&Date.parse(i),f=parseInt(o.match(l),16)||m&&o.match(u)&&Date.parse(o)||null;if(f){if(mf)return e}for(var g=a.length,k=h.length,b=0,y=Math.max(g,k);b0)return e;if(_<0)return s;if(b===y-1)return 0}else{if(v<$)return s;if(v>$)return e}}return 0}};function vt(t){const e={"&":"&","<":"<",">":">",'"':""","'":"'","/":"/","`":"`","=":"="};return String(t).replace(/[&<>"'`=/]/g,(t=>e[t]))}function $t(t,e={}){const s=(t,e={})=>{var n;const i=vt(t.shift()),o=null!=(n=e[i])?n:null;return null===o?Object.prototype.hasOwnProperty.call(e,i)||"…":0===t.length?o:s(t,o)},n="[{]{1,2}[\\s]?",i="[\\s]?[}]{1,2}";return(t=t.replace(new RegExp(`${n}(.*?)${i}`,"gi"),((t,n)=>s(n.split("."),e)))).replace(new RegExp(`${n}.*${i}`,"gi"),"…")}function _t(t){const e=String(t);return e.charAt(0).toUpperCase()+e.slice(1)}RegExp.escape=function(t){return t.replace(new RegExp("[-/\\\\^$*+?.()[\\]{}]","gu"),"\\$&")};const xt={camelToKebab:function(t){return t.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase()},escapeHTML:vt,hasEmoji:function(t){if("string"!=typeof t)return!1;const e=t.match(/(?:[\u2700-\u27bf]|(?:\ud83c[\udde6-\uddff]){2}|[\ud800-\udbff][\udc00-\udfff]|[\u0023-\u0039]\ufe0f?\u20e3|\u3299|\u3297|\u303d|\u3030|\u24c2|\ud83c[\udd70-\udd71]|\ud83c[\udd7e-\udd7f]|\ud83c\udd8e|\ud83c[\udd91-\udd9a]|\ud83c[\udde6-\uddff]|[\ud83c\ude01-\ude02]|\ud83c\ude1a|\ud83c\ude2f|[\ud83c\ude32-\ude3a]|[\ud83c\ude50-\ude51]|\u203c|\u2049|[\u25aa-\u25ab]|\u25b6|\u25c0|[\u25fb-\u25fe]|\u00a9|\u00ae|\u2122|\u2139|\ud83c\udc04|[\u2600-\u26FF]|\u2b05|\u2b06|\u2b07|\u2b1b|\u2b1c|\u2b50|\u2b55|\u231a|\u231b|\u2328|\u23cf|[\u23e9-\u23f3]|[\u23f8-\u23fa]|\ud83c\udccf|\u2934|\u2935|[\u2190-\u21ff])/i);return null!==e&&null!==e.length},lcfirst:function(t){const e=String(t);return e.charAt(0).toLowerCase()+e.slice(1)},pad:function(t,e=2){t=String(t);let s="";for(;s.length]+)>)/gi,"")},template:$t,ucfirst:_t,ucwords:function(t){return String(t).split(/ /g).map((t=>_t(t))).join(" ")},uuid:function(){let t,e,s="";for(t=0;t<32;t++)e=16*Math.random()|0,8!=t&&12!=t&&16!=t&&20!=t||(s+="-"),s+=(12==t?4:16==t?3&e|8:e).toString(16);return s}},wt=(t,e)=>{const s=Object.assign({url:"/",field:"file",method:"POST",attributes:{},complete:function(){},error:function(){},success:function(){},progress:function(){}},e),n=new FormData;n.append(s.field,t,t.name),s.attributes&&Object.keys(s.attributes).forEach((t=>{n.append(t,s.attributes[t])}));const i=new XMLHttpRequest,o=e=>{if(!e.lengthComputable||!s.progress)return;let n=Math.max(0,Math.min(100,e.loaded/e.total*100));s.progress(i,t,Math.ceil(n))};i.upload.addEventListener("loadstart",o),i.upload.addEventListener("progress",o),i.addEventListener("load",(e=>{let n=null;try{n=JSON.parse(e.target.response)}catch(o){n={status:"error",message:"The file could not be uploaded"}}"error"===n.status?s.error(i,t,n):(s.success(i,t,n),s.progress(i,t,100))})),i.addEventListener("error",(e=>{const n=JSON.parse(e.target.response);s.error(i,t,n),s.progress(i,t,100)})),i.open(s.method,s.url,!0),s.headers&&Object.keys(s.headers).forEach((t=>{const e=s.headers[t];i.setRequestHeader(t,e)})),i.send(n)};const St={isUrl:function(t,e){if((t instanceof URL||t instanceof Location)&&(t=t.toString()),"string"!=typeof t)return!1;try{new URL(t,window.location)}catch(s){return!1}if(!0===e){return/^(?:(?:https?|ftp):\/\/)(?:\S+(?::\S*)?@)?(?:(?!10(?:\.\d{1,3}){3})(?!169\.254(?:\.\d{1,3}){2})(?!192\.168(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:localhost)|(?:(?:[a-z\u00a1-\uffff0-9]+-?)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]+-?)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})))(?::\d{2,5})?(?:\/[^\s]*)?$/i.test(t)}return!0}},Ct={install(t){Array.prototype.sortBy=function(e){const s=t.prototype.$helper.sort(),n=e.split(" "),i=n[0],o=n[1]||"asc";return this.sort(((t,e)=>{const n=String(t[i]).toLowerCase(),r=String(e[i]).toLowerCase();return"desc"===o?s(r,n):s(n,r)}))},t.prototype.$helper={clipboard:ut,clone:J.clone,color:ct,embed:mt,isComponent:ft,isUploadEvent:gt,debounce:dt,keyboard:kt,object:J,pad:xt.pad,ratio:bt,slug:xt.slug,sort:yt,string:xt,upload:wt,url:St,uuid:xt.uuid},t.prototype.$esc=xt.escapeHTML}},Ot={install(t){t.$t=t.prototype.$t=window.panel.$t=(t,e,s=null)=>{if("string"!=typeof t)return;const n=window.panel.$translation.data[t]||s;return"string"!=typeof n?n:$t(n,e)},t.directive("direction",{inserted(t,e,s){!0!==s.context.disabled?t.dir=s.context.$direction:t.dir=null}})}};n.extend(i),n.extend(((t,e,s)=>{s.interpret=(t,e="date")=>{const n={date:{"YYYY-MM-DD":!0,"YYYY-MM-D":!0,"YYYY-MM-":!0,"YYYY-MM":!0,"YYYY-M-DD":!0,"YYYY-M-D":!0,"YYYY-M-":!0,"YYYY-M":!0,"YYYY-":!0,YYYYMMDD:!0,"MMM DD YYYY":!1,"MMM D YYYY":!1,"MMM DD YY":!1,"MMM D YY":!1,"MMM DD":!1,"MMM D":!1,"DD MMMM YYYY":!1,"DD MMMM YY":!1,"DD MMMM":!1,"D MMMM YYYY":!1,"D MMMM YY":!1,"D MMMM":!1,"DD MMM YYYY":!1,"D MMM YYYY":!1,"DD MMM YY":!1,"D MMM YY":!1,"DD MMM":!1,"D MMM":!1,"DD MM YYYY":!1,"DD M YYYY":!1,"D MM YYYY":!1,"D M YYYY":!1,"DD MM YY":!1,"D MM YY":!1,"DD M YY":!1,"D M YY":!1,YYYY:!0,MMMM:!0,MMM:!0,"DD MM":!1,"DD M":!1,"D MM":!1,"D M":!1,DD:!1,D:!1},time:{"HH:mm:ss a":!1,"HH:mm:ss":!1,"HH:mm a":!1,"HH:mm":!1,"HH a":!1,HH:!1}};if("string"==typeof t&&""!==t)for(const i in n[e]){const o=s(t,i,n[e][i]);if(!0===o.isValid())return o}return null}})),n.extend(((t,e,s)=>{const n=t=>"date"===t?"YYYY-MM-DD":"time"===t?"HH:mm:ss":"YYYY-MM-DD HH:mm:ss";e.prototype.toISO=function(t="datetime"){return this.format(n(t))},s.iso=function(t,e="datetime"){const i=s(t,n(e));return i&&i.isValid()?i:null}})),n.extend(((t,e)=>{e.prototype.merge=function(t,e="date"){let s=this.clone();if(!t||!t.isValid())return this;if("string"==typeof e){const t={date:["year","month","date"],time:["hour","minute","second"]};if(!1===Object.prototype.hasOwnProperty.call(t,e))throw new Error("Invalid merge unit alias");e=t[e]}for(const n of e)s=s.set(n,t.get(n));return s}})),n.extend(((t,e,s)=>{s.pattern=t=>new class{constructor(t,e){this.dayjs=t,this.pattern=e;const s={year:["YY","YYYY"],month:["M","MM","MMM","MMMM"],day:["D","DD"],hour:["h","hh","H","HH"],minute:["m","mm"],second:["s","ss"],meridiem:["a"]};this.parts=this.pattern.split(/\W/).map(((t,e)=>{const n=this.pattern.indexOf(t);return{index:e,unit:Object.keys(s)[Object.values(s).findIndex((e=>e.includes(t)))],start:n,end:n+(t.length-1)}}))}at(t,e=t){const s=this.parts.filter((s=>s.start<=t&&s.end>=e-1));return s[0]?s[0]:this.parts.filter((e=>e.start<=t)).pop()}format(t){return t&&t.isValid()?t.format(this.pattern):null}}(s,t)})),n.extend(((t,e)=>{e.prototype.round=function(t="date",e=1){const s=["second","minute","hour","date","month","year"];if("day"===t&&(t="date"),!1===s.includes(t))throw new Error("Invalid rounding unit");if(["date","month","year"].includes(t)&&1!==e||"hour"===t&&24%e!=0||["second","minute"].includes(t)&&60%e!=0)throw"Invalid rounding size for "+t;let n=this.clone();const i=s.indexOf(t),o=s.slice(0,i),r=o.pop();if(o.forEach((t=>n=n.startOf(t))),r){const e={month:12,date:n.daysInMonth(),hour:24,minute:60,second:60}[r];Math.round(n.get(r)/e)*e===e&&(n=n.add(1,"date"===t?"day":t)),n=n.startOf(t)}return n=n.set(t,Math.round(n.get(t)/e)*e),n}})),n.extend(((t,e,s)=>{e.prototype.validate=function(t,e,n="day"){if(!this.isValid())return!1;if(!t)return!0;t=s.iso(t);const i={min:"isAfter",max:"isBefore"}[e];return this.isSame(t,n)||this[i](t,n)}}));const At={install(t){t.prototype.$library={autosize:o,dayjs:n}}},Tt={props:{blueprint:String,lock:[Boolean,Object],help:String,name:String,parent:String,timestamp:Number},methods:{load(){return this.$api.get(this.parent+"/sections/"+this.name)}}},It={install(t){const e={...t.options.components},s={section:Tt};for(const[n,i]of Object.entries(window.panel.plugins.components))i.template||i.render||i.extends?("string"==typeof(null==i?void 0:i.extends)&&(e[i.extends]?i.extends=e[i.extends].extend({options:i,components:{...e,...i.components||{}}}):i.extends=null),i.template&&(i.render=null),i.mixins&&(i.mixins=i.mixins.map((t=>"string"==typeof t?s[t]:t))),e[n]&&window.console.warn(`Plugin is replacing "${n}"`),t.component(n,i),e[n]=t.options.components[n]):Q.dispatch("notification/error",`Neither template or render method provided nor extending a component when loading plugin component "${n}". The component has not been registered.`);for(const n of window.panel.plugins.use)t.use(n)}};function Mt(t,e,s,n,i,o,r,l){var a,u="function"==typeof t?t.options:t;if(e&&(u.render=e,u.staticRenderFns=s,u._compiled=!0),n&&(u.functional=!0),o&&(u._scopeId="data-v-"+o),r?(a=function(t){(t=t||this.$vnode&&this.$vnode.ssrContext||this.parent&&this.parent.$vnode&&this.parent.$vnode.ssrContext)||"undefined"==typeof __VUE_SSR_CONTEXT__||(t=__VUE_SSR_CONTEXT__),i&&i.call(this,t),t&&t._registeredComponents&&t._registeredComponents.add(r)},u._ssrRegister=a):i&&(a=l?function(){i.call(this,(u.functional?this.parent:this).$root.$options.shadowRoot)}:i),a)if(u.functional){u._injectStyles=a;var c=u.render;u.render=function(t,e){return a.call(e),c(t,e)}}else{var d=u.beforeCreate;u.beforeCreate=d?[].concat(d,a):[a]}return{exports:t,options:u}}const Et=Mt({props:{autofocus:{type:Boolean,default:!0},cancelButton:{type:[String,Boolean],default:!0},icon:{type:String,default:"check"},size:{type:String,default:"default"},submitButton:{type:[String,Boolean],default:!0},theme:String,visible:Boolean},data:()=>({notification:null}),computed:{buttons(){let t=[];return this.cancelButton&&t.push({icon:"cancel",text:this.cancelButtonLabel,class:"k-dialog-button-cancel",click:this.cancel}),this.submitButtonConfig&&t.push({icon:this.icon,text:this.submitButtonLabel,theme:this.theme,class:"k-dialog-button-submit",click:this.submit}),t},cancelButtonLabel(){return!1!==this.cancelButton&&(!0===this.cancelButton||0===this.cancelButton.length?this.$t("cancel"):this.cancelButton)},submitButtonConfig(){return void 0!==this.$attrs.button?this.$attrs.button:void 0===this.submitButton||this.submitButton},submitButtonLabel(){return!0===this.submitButton||0===this.submitButton.length?this.$t("confirm"):this.submitButton}},created(){this.$events.$on("keydown.esc",this.close,!1)},destroyed(){this.$events.$off("keydown.esc",this.close,!1)},mounted(){this.visible&&this.$nextTick(this.open)},methods:{onOverlayClose(){this.notification=null,this.$emit("close"),this.$events.$off("keydown.esc",this.close),this.$store.dispatch("dialog",!1)},open(){this.$store.state.dialog||this.$store.dispatch("dialog",!0),this.notification=null,this.$refs.overlay.open(),this.$emit("open"),this.$events.$on("keydown.esc",this.close)},close(){this.$refs.overlay&&this.$refs.overlay.close()},cancel(){this.$emit("cancel"),this.close()},focus(){var t;if(null==(t=this.$refs.dialog)?void 0:t.querySelector){const t=this.$refs.dialog.querySelector(".k-dialog-button-cancel");"function"==typeof(null==t?void 0:t.focus)&&t.focus()}},error(t){this.notification={message:t,type:"error"}},submit(){this.$emit("submit")},success(t){this.notification={message:t,type:"success"}}}},(function(){var t=this,e=t._self._c;return e("k-overlay",{ref:"overlay",attrs:{autofocus:t.autofocus,centered:!0},on:{close:t.onOverlayClose,ready:function(e){return t.$emit("ready")}}},[e("div",{ref:"dialog",staticClass:"k-dialog",class:t.$vnode.data.staticClass,attrs:{"data-size":t.size},on:{mousedown:function(t){t.stopPropagation()}}},[t.notification?e("div",{staticClass:"k-dialog-notification",attrs:{"data-theme":t.notification.type}},[e("p",[t._v(t._s(t.notification.message))]),e("k-button",{attrs:{icon:"cancel"},on:{click:function(e){t.notification=null}}})],1):t._e(),e("div",{staticClass:"k-dialog-body scroll-y-auto"},[t._t("default")],2),t.$slots.footer||t.buttons.length?e("footer",{staticClass:"k-dialog-footer"},[t._t("footer",(function(){return[e("k-button-group",{attrs:{buttons:t.buttons}})]}))],2):t._e()])])}),[],!1,null,null,null,null).exports,Lt={props:{autofocus:{type:Boolean,default:!0},cancelButton:{type:[String,Boolean],default:!0},icon:String,submitButton:{type:[String,Boolean],default:!0},size:String,theme:String,visible:Boolean},methods:{close(){this.$refs.dialog.close(),this.$emit("close")},error(t){this.$refs.dialog.error(t)},open(){this.$refs.dialog.open(),this.$emit("open")},success(t){this.$refs.dialog.close(),t.route&&this.$go(t.route),t.message&&this.$store.dispatch("notification/success",t.message),t.event&&("string"==typeof t.event&&(t.event=[t.event]),t.event.forEach((e=>{this.$events.$emit(e,t)}))),!1!==Object.prototype.hasOwnProperty.call(t,"emit")&&!1===t.emit||this.$emit("success")}}};const jt=Mt({mixins:[Lt],props:{details:[Object,Array],message:String,size:{type:String,default:"medium"}},computed:{detailsList(){return Array.isArray(this.details)?this.details:Object.values(this.details||{})}}},(function(){var t=this,e=t._self._c;return e("k-dialog",{ref:"dialog",staticClass:"k-error-dialog",attrs:{"cancel-button":!1,size:t.size,visible:!0},on:{cancel:function(e){return t.$emit("cancel")},close:function(e){return t.$emit("close")},submit:function(e){return t.$refs.dialog.close()}}},[e("k-text",[t._v(t._s(t.message))]),t.detailsList.length?e("dl",{staticClass:"k-error-details"},[t._l(t.detailsList,(function(s,n){return[e("dt",{key:"detail-label-"+n},[t._v(" "+t._s(s.label)+" ")]),e("dd",{key:"detail-message-"+n},["object"==typeof s.message?[e("ul",t._l(s.message,(function(s,n){return e("li",{key:n},[t._v(" "+t._s(s)+" ")])})),0)]:[t._v(" "+t._s(s.message)+" ")]],2)]}))],2):t._e()],1)}),[],!1,null,null,null,null).exports;const Dt=Mt({props:{code:Number,component:String,path:String,props:Object,referrer:String},methods:{close(){this.$refs.dialog.close()},onCancel(){"function"==typeof this.$store.state.dialog.cancel&&this.$store.state.dialog.cancel({dialog:this})},async onSubmit(t){let e=null;try{if("function"==typeof this.$store.state.dialog.submit)e=await this.$store.state.dialog.submit({dialog:this,value:t});else{if(!this.path)throw"The dialog needs a submit action or a dialog route path to be submitted";e=await this.$request(this.path,{body:t,method:"POST",type:"$dialog",headers:{"X-Fiber-Referrer":this.referrer}})}if(!1===e)return!1;this.close(),this.$store.dispatch("notification/success",":)"),e.event&&("string"==typeof e.event&&(e.event=[e.event]),e.event.forEach((t=>{this.$events.$emit(t,e)}))),e.dispatch&&Object.keys(e.dispatch).forEach((t=>{const s=e.dispatch[t];this.$store.dispatch(t,!0===Array.isArray(s)?[...s]:s)})),e.redirect?this.$go(e.redirect):this.$reload(e.reload||{})}catch(s){this.$refs.dialog.error(s)}}}},(function(){var t=this;return(0,t._self._c)(t.component,t._b({ref:"dialog",tag:"component",attrs:{visible:!0},on:{cancel:t.onCancel,submit:t.onSubmit}},"component",t.props,!1))}),[],!1,null,null,null,null).exports,Bt={data:()=>({models:[],issue:null,selected:{},options:{endpoint:null,max:null,multiple:!0,parent:null,selected:[],search:!0},search:null,pagination:{limit:20,page:1,total:0}}),computed:{checkedIcon(){return!0===this.multiple?"check":"circle-filled"},collection(){return{empty:this.emptyProps,items:this.items,link:!1,layout:"list",pagination:{details:!0,dropdown:!1,align:"center",...this.pagination},sortable:!1}},items(){return this.models.map(this.item)},multiple(){return!0===this.options.multiple&&1!==this.options.max}},watch:{search(){this.updateSearch()}},created(){this.updateSearch=dt(this.updateSearch,200)},methods:{async fetch(){const t={page:this.pagination.page,search:this.search,...this.fetchData||{}};try{const e=await this.$api.get(this.options.endpoint,t);this.models=e.data,this.pagination=e.pagination,this.onFetched&&this.onFetched(e)}catch(e){this.models=[],this.issue=e.message}},async open(t,e){this.pagination.page=0,this.search=null;let s=!0;Array.isArray(t)?(this.models=t,s=!1):(this.models=[],e=t),this.options={...this.options,...e},this.selected={},this.options.selected.forEach((t=>{this.$set(this.selected,t,{id:t})})),s&&await this.fetch(),this.$refs.dialog.open()},paginate(t){this.pagination.page=t.page,this.pagination.limit=t.limit,this.fetch()},submit(){this.$emit("submit",Object.values(this.selected)),this.$refs.dialog.close()},isSelected(t){return void 0!==this.selected[t.id]},item:t=>t,toggle(t){!1!==this.options.multiple&&1!==this.options.max||(this.selected={}),!0!==this.isSelected(t)?this.options.max&&this.options.max<=Object.keys(this.selected).length||this.$set(this.selected,t.id,t):this.$delete(this.selected,t.id)},toggleBtn(t){const e=this.isSelected(t);return{icon:e?this.checkedIcon:"circle-outline",tooltip:e?this.$t("remove"):this.$t("select"),theme:e?"positive":null}},updateSearch(){this.pagination.page=0,this.fetch()}}};const Pt=Mt({mixins:[Bt],computed:{emptyProps(){return{icon:"image",text:this.$t("dialog.files.empty")}}}},(function(){var t=this,e=t._self._c;return e("k-dialog",{ref:"dialog",staticClass:"k-files-dialog",attrs:{size:"medium"},on:{cancel:function(e){return t.$emit("cancel")},submit:t.submit}},[t.issue?[e("k-box",{attrs:{text:t.issue,theme:"negative"}})]:[t.options.search?e("k-input",{staticClass:"k-dialog-search",attrs:{autofocus:!0,placeholder:t.$t("search")+" …",type:"text",icon:"search"},model:{value:t.search,callback:function(e){t.search=e},expression:"search"}}):t._e(),e("k-collection",t._b({on:{item:t.toggle,paginate:t.paginate},scopedSlots:t._u([{key:"options",fn:function({item:s}){return[e("k-button",t._b({on:{click:function(e){return t.toggle(s)}}},"k-button",t.toggleBtn(s),!1))]}}])},"k-collection",t.collection,!1))]],2)}),[],!1,null,null,null,null).exports;const Nt=Mt({mixins:[Lt],props:{fields:{type:[Array,Object],default:()=>[]},novalidate:{type:Boolean,default:!0},size:{type:String,default:"medium"},submitButton:{type:[String,Boolean],default:()=>window.panel.$t("save")},text:{type:String},theme:{type:String,default:"positive"},value:{type:Object,default:()=>({})}},data(){return{model:this.value}},computed:{hasFields(){return Object.keys(this.fields).length>0}},watch:{value(t,e){t!==e&&(this.model=t)}}},(function(){var t=this,e=t._self._c;return e("k-dialog",t._b({ref:"dialog",on:{cancel:function(e){return t.$emit("cancel")},close:function(e){return t.$emit("close")},ready:function(e){return t.$emit("ready")},submit:function(e){return t.$refs.form.submit()}}},"k-dialog",t.$props,!1),[t.text?[e("k-text",{attrs:{html:t.text}})]:t._e(),t.hasFields?e("k-form",{ref:"form",attrs:{value:t.model,fields:t.fields,novalidate:t.novalidate},on:{input:function(e){return t.$emit("input",e)},submit:function(e){return t.$emit("submit",e)}}}):e("k-box",{attrs:{theme:"negative"}},[t._v(" This form dialog has no fields ")])],2)}),[],!1,null,null,null,null).exports;const qt=Mt({extends:Nt,watch:{"model.name"(t){this.fields.code.disabled||this.onNameChanges(t)},"model.code"(t){this.fields.code.disabled||(this.model.code=this.$helper.slug(t,[this.$system.ascii]),this.onCodeChanges(this.model.code))}},methods:{onCodeChanges(t){if(!t)return this.model.locale=null;if(t.length>=2)if(-1!==t.indexOf("-")){let e=t.split("-"),s=[e[0],e[1].toUpperCase()];this.model.locale=s.join("_")}else{let e=this.$system.locales||[];(null==e?void 0:e[t])?this.model.locale=e[t]:this.model.locale=null}},onNameChanges(t){this.model.code=this.$helper.slug(t,[this.model.rules,this.$system.ascii]).substr(0,2)}}},null,null,!1,null,null,null,null).exports;const Ft=Mt({mixins:[Bt],data(){const t=Bt.data();return{...t,model:{title:null,parent:null},options:{...t.options,parent:null}}},computed:{emptyProps(){return{icon:"page",text:this.$t("dialog.pages.empty")}},fetchData(){return{parent:this.options.parent}}},methods:{back(){this.options.parent=this.model.parent,this.pagination.page=1,this.fetch()},go(t){this.options.parent=t.id,this.pagination.page=1,this.fetch()},onFetched(t){this.model=t.model}}},(function(){var t=this,e=t._self._c;return e("k-dialog",{ref:"dialog",staticClass:"k-pages-dialog",attrs:{size:"medium"},on:{cancel:function(e){return t.$emit("cancel")},submit:t.submit}},[t.issue?[e("k-box",{attrs:{text:t.issue,theme:"negative"}})]:[t.model?e("header",{staticClass:"k-pages-dialog-navbar"},[e("k-button",{attrs:{disabled:!t.model.id,tooltip:t.$t("back"),icon:"angle-left"},on:{click:t.back}}),e("k-headline",[t._v(t._s(t.model.title))])],1):t._e(),t.options.search?e("k-input",{staticClass:"k-dialog-search",attrs:{autofocus:!0,placeholder:t.$t("search")+" …",type:"text",icon:"search"},model:{value:t.search,callback:function(e){t.search=e},expression:"search"}}):t._e(),e("k-collection",t._b({on:{item:t.toggle,paginate:t.paginate},scopedSlots:t._u([{key:"options",fn:function({item:s}){return[e("k-button",t._b({on:{click:function(e){return t.toggle(s)}}},"k-button",t.toggleBtn(s),!1)),t.model?e("k-button",{attrs:{disabled:!s.hasChildren,tooltip:t.$t("open"),icon:"angle-right"},on:{click:function(e){return e.stopPropagation(),t.go(s)}}}):t._e()]}}])},"k-collection",t.collection,!1))]],2)}),[],!1,null,null,null,null).exports;const Rt=Mt({mixins:[Lt],props:{icon:{type:String,default:"trash"},submitButton:{type:[String,Boolean],default:()=>window.panel.$t("delete")},text:String,theme:{type:String,default:"negative"}}},(function(){var t=this;return(0,t._self._c)("k-text-dialog",t._g(t._b({ref:"dialog"},"k-text-dialog",t.$props,!1),t.$listeners),[t._t("default")],2)}),[],!1,null,null,null,null).exports;const zt=Mt({mixins:[Lt],props:{text:String}},(function(){var t=this,e=t._self._c;return e("k-dialog",t._g(t._b({ref:"dialog"},"k-dialog",t.$props,!1),t.$listeners),[t._t("default",(function(){return[t.text?e("k-text",{attrs:{html:t.text}}):e("k-box",{attrs:{theme:"negative"}},[t._v(" This dialog does not define any text ")])]}))],2)}),[],!1,null,null,null,null).exports;const Yt=Mt({mixins:[Bt],computed:{emptyProps(){return{icon:"users",text:this.$t("dialog.users.empty")}}},methods:{item:t=>({...t,key:t.email,info:t.info!==t.text?t.info:null})}},(function(){var t=this,e=t._self._c;return e("k-dialog",{ref:"dialog",staticClass:"k-users-dialog",attrs:{size:"medium"},on:{cancel:function(e){return t.$emit("cancel")},submit:t.submit}},[t.issue?[e("k-box",{attrs:{text:t.issue,theme:"negative"}})]:[t.options.search?e("k-input",{staticClass:"k-dialog-search",attrs:{autofocus:!0,placeholder:t.$t("search")+" …",type:"text",icon:"search"},model:{value:t.search,callback:function(e){t.search=e},expression:"search"}}):t._e(),e("k-collection",t._b({on:{item:t.toggle,paginate:t.paginate},scopedSlots:t._u([{key:"options",fn:function({item:s}){return[e("k-button",t._b({on:{click:function(e){return t.toggle(s)}}},"k-button",t.toggleBtn(s),!1))]}}])},"k-collection",t.collection,!1))]],2)}),[],!1,null,null,null,null).exports;const Ht=Mt({inheritAttrs:!1,props:{id:String,icon:String,tab:String,tabs:Object,title:String},data:()=>({click:!1}),computed:{breadcrumb(){return this.$store.state.drawers.open},hasTabs(){return this.tabs&&Object.keys(this.tabs).length>1},index(){return this.breadcrumb.findIndex((t=>t.id===this._uid))},nested(){return this.index>0}},watch:{index(){-1===this.index&&this.close()}},destroyed(){this.$store.dispatch("drawers/close",this._uid)},methods:{close(){this.$refs.overlay.close()},goTo(t){if(t===this._uid)return!0;this.$store.dispatch("drawers/goto",t)},mouseup(){!0===this.click&&this.close(),this.click=!1},mousedown(t=!1){this.click=t,!0===this.click&&this.$store.dispatch("drawers/close")},onClose(){this.$store.dispatch("drawers/close",this._uid),this.$emit("close")},onOpen(){this.$store.dispatch("drawers/open",{id:this._uid,icon:this.icon,title:this.title}),this.$emit("open")},open(){this.$refs.overlay.open()}}},(function(){var t=this,e=t._self._c;return e("k-overlay",{ref:"overlay",attrs:{dimmed:!1},on:{close:t.onClose,open:t.onOpen}},[e("div",{staticClass:"k-drawer",attrs:{"data-id":t.id,"data-nested":t.nested},on:{mousedown:function(e){return e.stopPropagation(),t.mousedown(!0)},mouseup:t.mouseup}},[e("div",{staticClass:"k-drawer-box",on:{mousedown:function(e){return e.stopPropagation(),t.mousedown(!1)}}},[e("header",{staticClass:"k-drawer-header"},[1===t.breadcrumb.length?e("h2",{staticClass:"k-drawer-title"},[e("k-icon",{attrs:{type:t.icon}}),t._v(" "+t._s(t.title)+" ")],1):e("ul",{staticClass:"k-drawer-breadcrumb"},t._l(t.breadcrumb,(function(s){return e("li",{key:s.id},[e("k-button",{attrs:{icon:s.icon,text:s.title},on:{click:function(e){return t.goTo(s.id)}}})],1)})),0),t.hasTabs?e("nav",{staticClass:"k-drawer-tabs"},t._l(t.tabs,(function(s){return e("k-button",{key:s.name,staticClass:"k-drawer-tab",attrs:{current:t.tab==s.name,text:s.label},on:{click:function(e){return e.stopPropagation(),t.$emit("tab",s.name)}}})})),1):t._e(),e("nav",{staticClass:"k-drawer-options"},[t._t("options"),e("k-button",{staticClass:"k-drawer-option",attrs:{icon:"check"},on:{click:t.close}})],2)]),e("div",{staticClass:"k-drawer-body scroll-y-auto"},[t._t("default")],2)])])])}),[],!1,null,null,null,null).exports;const Ut=Mt({inheritAttrs:!1,props:{empty:{type:String,default:()=>"Missing field setup"},icon:String,id:String,tabs:Object,title:String,type:String,value:Object},data:()=>({tab:null}),computed:{fields(){const t=this.tab||null;return(this.tabs[t]||this.firstTab).fields||{}},firstTab(){return Object.values(this.tabs)[0]}},methods:{close(){this.$refs.drawer.close()},focus(t){var e;"function"==typeof(null==(e=this.$refs.form)?void 0:e.focus)&&this.$refs.form.focus(t)},open(t,e=!0){this.$refs.drawer.open(),this.tab=t||this.firstTab.name,!1!==e&&setTimeout((()=>{let t=Object.values(this.fields).filter((t=>!0===t.autofocus))[0]||null;this.focus(t)}),1)}}},(function(){var t=this,e=t._self._c;return e("k-drawer",{ref:"drawer",staticClass:"k-form-drawer",attrs:{id:t.id,icon:t.icon,tabs:t.tabs,tab:t.tab,title:t.title},on:{close:function(e){return t.$emit("close")},open:function(e){return t.$emit("open")},tab:function(e){t.tab=e}},scopedSlots:t._u([{key:"options",fn:function(){return[t._t("options")]},proxy:!0},{key:"default",fn:function(){return[0===Object.keys(t.fields).length?e("k-box",{attrs:{theme:"info"}},[t._v(" "+t._s(t.empty)+" ")]):e("k-form",{ref:"form",attrs:{autofocus:!0,fields:t.fields,value:t.$helper.clone(t.value)},on:{input:function(e){return t.$emit("input",e)}}})]},proxy:!0}],null,!0)})}),[],!1,null,null,null,null).exports;const Kt=Mt({props:{html:{type:Boolean,default:!1},limit:{type:Number,default:10},skip:{type:Array,default:()=>[]},options:Array,query:String},data:()=>({matches:[],selected:{text:null}}),methods:{close(){this.$refs.dropdown.close()},onSelect(t){this.$emit("select",t),this.$refs.dropdown.close()},search(t){if(t.length<1)return;const e=new RegExp(RegExp.escape(t),"ig");this.matches=this.options.filter((t=>!!t.text&&(-1===this.skip.indexOf(t.value)&&null!==t.text.match(e)))).slice(0,this.limit),this.$emit("search",t,this.matches),this.$refs.dropdown.open()}}},(function(){var t=this,e=t._self._c;return e("k-dropdown",{staticClass:"k-autocomplete"},[t._t("default"),e("k-dropdown-content",t._g({ref:"dropdown",attrs:{autofocus:!0}},t.$listeners),t._l(t.matches,(function(s,n){return e("k-dropdown-item",t._b({key:n,on:{mousedown:function(e){return t.onSelect(s)},keydown:[function(e){return!e.type.indexOf("key")&&t._k(e.keyCode,"tab",9,e.key,"Tab")?null:(e.preventDefault(),t.onSelect(s))},function(e){return!e.type.indexOf("key")&&t._k(e.keyCode,"enter",13,e.key,"Enter")?null:(e.preventDefault(),t.onSelect(s))},function(e){return!e.type.indexOf("key")&&t._k(e.keyCode,"left",37,e.key,["Left","ArrowLeft"])||"button"in e&&0!==e.button?null:(e.preventDefault(),t.close.apply(null,arguments))},function(e){return!e.type.indexOf("key")&&t._k(e.keyCode,"backspace",void 0,e.key,void 0)?null:(e.preventDefault(),t.close.apply(null,arguments))},function(e){return!e.type.indexOf("key")&&t._k(e.keyCode,"delete",[8,46],e.key,["Backspace","Delete","Del"])?null:(e.preventDefault(),t.close.apply(null,arguments))}]}},"k-dropdown-item",s,!1),[e("span",{domProps:{innerHTML:t._s(t.html?s.text:t.$esc(s.text))}})])})),1),t._v(" "+t._s(t.query)+" ")],2)}),[],!1,null,null,null,null).exports;const Gt=Mt({props:{disabled:Boolean,max:String,min:String,value:String},data(){return this.data(this.value)},computed:{numberOfDays(){return this.toDate().daysInMonth()},firstWeekday(){const t=this.toDate().day();return t>0?t:7},weekdays(){return["mon","tue","wed","thu","fri","sat","sun"].map((t=>this.$t("days."+t)))},weeks(){const t=this.firstWeekday-1;return Math.ceil((this.numberOfDays+t)/7)},monthnames(){return["january","february","march","april","may","june","july","august","september","october","november","december"].map((t=>this.$t("months."+t)))},months(){var t=[];return this.monthnames.forEach(((e,s)=>{const n=this.toDate(1,s);t.push({value:s,text:e,disabled:n.isBefore(this.current.min,"month")||n.isAfter(this.current.max,"month")})})),t},years(){var t,e,s,n;const i=null!=(e=null==(t=this.current.min)?void 0:t.get("year"))?e:this.current.year-20,o=null!=(n=null==(s=this.current.max)?void 0:s.get("year"))?n:this.current.year+20;return this.toOptions(i,o)}},watch:{value(t){const e=this.data(t);this.dt=e.dt,this.current=e.current}},methods:{data(t){const e=this.$library.dayjs.iso(t),s=this.$library.dayjs();return{dt:e,current:{month:(null!=e?e:s).month(),year:(null!=e?e:s).year(),min:this.$library.dayjs.iso(this.min),max:this.$library.dayjs.iso(this.max)}}},days(t){let e=[];const s=7*(t-1)+1,n=s+7;for(let i=s;ithis.numberOfDays;e.push(s?"":t)}return e},isDisabled(t){const e=this.toDate(t);return this.disabled||e.isBefore(this.current.min,"day")||e.isAfter(this.current.max,"day")},isSelected(t){return this.toDate(t).isSame(this.dt,"day")},isToday(t){const e=this.$library.dayjs();return this.toDate(t).isSame(e,"day")},onInput(){var t;this.$emit("input",(null==(t=this.dt)?void 0:t.toISO("date"))||null)},onNext(){const t=this.toDate().add(1,"month");this.show(t)},onPrev(){const t=this.toDate().subtract(1,"month");this.show(t)},select(t){const e="today"===t?this.$library.dayjs().merge(this.toDate(),"time"):this.toDate(t);this.dt=e,this.show(e),this.onInput()},show(t){this.current.year=t.year(),this.current.month=t.month()},toDate(t=1,e=this.current.month){return this.$library.dayjs(`${this.current.year}-${e+1}-${t}`)},toOptions(t,e){for(var s=[],n=t;n<=e;n++)s.push({value:n,text:this.$helper.pad(n)});return s}}},(function(){var t=this,e=t._self._c;return e("div",{staticClass:"k-calendar-input"},[e("nav",[e("k-button",{attrs:{icon:"angle-left"},on:{click:t.onPrev}}),e("span",{staticClass:"k-calendar-selects"},[e("k-select-input",{attrs:{options:t.months,disabled:t.disabled,required:!0},model:{value:t.current.month,callback:function(e){t.$set(t.current,"month",t._n(e))},expression:"current.month"}}),e("k-select-input",{attrs:{options:t.years,disabled:t.disabled,required:!0},model:{value:t.current.year,callback:function(e){t.$set(t.current,"year",t._n(e))},expression:"current.year"}})],1),e("k-button",{attrs:{icon:"angle-right"},on:{click:t.onNext}})],1),e("table",{staticClass:"k-calendar-table"},[e("thead",[e("tr",t._l(t.weekdays,(function(s){return e("th",{key:"weekday_"+s},[t._v(" "+t._s(s)+" ")])})),0)]),e("tbody",t._l(t.weeks,(function(s){return e("tr",{key:"week_"+s},t._l(t.days(s),(function(s,n){return e("td",{key:"day_"+n,staticClass:"k-calendar-day",attrs:{"aria-current":!!t.isToday(s)&&"date","aria-selected":!!t.isSelected(s)&&"date"}},[s?e("k-button",{attrs:{disabled:t.isDisabled(s),text:s},on:{click:function(e){return t.select(s)}}}):t._e()],1)})),0)})),0),e("tfoot",[e("tr",[e("td",{staticClass:"k-calendar-today",attrs:{colspan:"7"}},[e("k-button",{attrs:{text:t.$t("today")},on:{click:function(e){return t.select("today")}}})],1)])])])])}),[],!1,null,null,null,null).exports;const Jt=Mt({props:{count:Number,min:Number,max:Number,required:{type:Boolean,default:!1}},computed:{valid(){return!1===this.required&&0===this.count||(!0!==this.required||0!==this.count)&&(!(this.min&&this.countthis.max))}}},(function(){var t=this,e=t._self._c;return e("span",{staticClass:"k-counter",attrs:{"data-invalid":!t.valid}},[e("span",[t._v(t._s(t.count))]),t.min&&t.max?e("span",{staticClass:"k-counter-rules"},[t._v("("+t._s(t.min)+"–"+t._s(t.max)+")")]):t.min?e("span",{staticClass:"k-counter-rules"},[t._v("≥ "+t._s(t.min))]):t.max?e("span",{staticClass:"k-counter-rules"},[t._v("≤ "+t._s(t.max))]):t._e()])}),[],!1,null,null,null,null).exports;const Vt=Mt({props:{disabled:Boolean,config:Object,fields:{type:[Array,Object],default:()=>({})},novalidate:{type:Boolean,default:!1},value:{type:Object,default:()=>({})}},data(){return{errors:{},listeners:{...this.$listeners,submit:this.onSubmit}}},methods:{focus(t){var e,s;null==(s=null==(e=this.$refs.fields)?void 0:e.focus)||s.call(e,t)},onSubmit(){this.$emit("submit",this.value)},submit(){this.$refs.submitter.click()}}},(function(){var t=this,e=t._self._c;return e("form",{ref:"form",staticClass:"k-form",attrs:{method:"POST",autocomplete:"off",novalidate:""},on:{submit:function(e){return e.preventDefault(),t.onSubmit.apply(null,arguments)}}},[t._t("header"),t._t("default",(function(){return[e("k-fieldset",t._g({ref:"fields",attrs:{disabled:t.disabled,fields:t.fields,novalidate:t.novalidate},model:{value:t.value,callback:function(e){t.value=e},expression:"value"}},t.listeners))]})),t._t("footer"),e("input",{ref:"submitter",staticClass:"k-form-submitter",attrs:{type:"submit"}})],2)}),[],!1,null,null,null,null).exports;const Wt=Mt({props:{lock:[Boolean,Object]},data:()=>({isRefreshing:null,isLocking:null}),computed:{hasChanges(){return this.$store.getters["content/hasChanges"]()},isDisabled(){return!1===this.$store.state.content.status.enabled},isLocked(){return"lock"===this.lockState},isUnlocked(){return"unlock"===this.lockState},mode(){return null!==this.lockState?this.lockState:!0===this.hasChanges?"changes":null},lockState(){return this.supportsLocking&&this.lock?this.lock.state:null},supportsLocking(){return!1!==this.lock},theme(){return"lock"===this.mode?"negative":"unlock"===this.mode?"info":"notice"}},watch:{hasChanges:{handler(t,e){!0===this.supportsLocking&&!1===this.isLocked&&!1===this.isUnlocked&&(!0===t?(this.onLock(),this.isLocking=setInterval(this.onLock,3e4)):e&&(clearInterval(this.isLocking),this.onLock(!1)))},immediate:!0},isLocked(t){!1===t&&this.$events.$emit("model.reload")}},created(){this.supportsLocking&&(this.isRefreshing=setInterval(this.check,1e4)),this.$events.$on("keydown.cmd.s",this.onSave)},destroyed(){clearInterval(this.isRefreshing),clearInterval(this.isLocking),this.$events.$off("keydown.cmd.s",this.onSave)},methods:{check(){this.$reload({navigate:!1,only:"$view.props.lock",silent:!0})},async onLock(t=!0){const e=[this.$view.path+"/lock",null,null,!0];if(!0===t)try{await this.$api.patch(...e)}catch(s){clearInterval(this.isLocking),this.$store.dispatch("content/revert")}else clearInterval(this.isLocking),await this.$api.delete(...e)},onDownload(){let t="";const e=this.$store.getters["content/changes"]();Object.keys(e).forEach((s=>{t+=s+": \n\n"+e[s],t+="\n\n----\n\n"}));let s=document.createElement("a");s.setAttribute("href","data:text/plain;charset=utf-8,"+encodeURIComponent(t)),s.setAttribute("download",this.$view.path+".txt"),s.style.display="none",document.body.appendChild(s),s.click(),document.body.removeChild(s)},async onResolve(){await this.onUnlock(!1),this.$store.dispatch("content/revert")},onRevert(){this.$refs.revert.open()},async onSave(t){if(!t)return!1;t.preventDefault&&t.preventDefault();try{await this.$store.dispatch("content/save"),this.$events.$emit("model.update"),this.$store.dispatch("notification/success",":)")}catch(e){if(403===e.code)return;e.details&&Object.keys(e.details).length>0?this.$store.dispatch("notification/error",{message:this.$t("error.form.incomplete"),details:e.details}):this.$store.dispatch("notification/error",{message:this.$t("error.form.notSaved"),details:[{label:"Exception: "+e.exception,message:e.message}]})}},async onUnlock(t=!0){const e=[this.$view.path+"/unlock",null,null,!0];!0===t?await this.$api.patch(...e):await this.$api.delete(...e),this.$reload({silent:!0})},revert(){this.$store.dispatch("content/revert"),this.$refs.revert.close()}}},(function(){var t=this,e=t._self._c;return e("nav",{staticClass:"k-form-buttons",attrs:{"data-theme":t.theme}},["unlock"===t.mode?e("k-view",[e("p",{staticClass:"k-form-lock-info"},[t._v(" "+t._s(t.$t("lock.isUnlocked"))+" ")]),e("span",{staticClass:"k-form-lock-buttons"},[e("k-button",{staticClass:"k-form-button",attrs:{text:t.$t("download"),icon:"download"},on:{click:t.onDownload}}),e("k-button",{staticClass:"k-form-button",attrs:{text:t.$t("confirm"),icon:"check"},on:{click:t.onResolve}})],1)]):"lock"===t.mode?e("k-view",[e("p",{staticClass:"k-form-lock-info"},[e("k-icon",{attrs:{type:"lock"}}),e("span",{domProps:{innerHTML:t._s(t.$t("lock.isLocked",{email:t.$esc(t.lock.data.email)}))}})],1),t.lock.data.unlockable?e("k-button",{staticClass:"k-form-button",attrs:{text:t.$t("lock.unlock"),icon:"unlock"},on:{click:function(e){return t.onUnlock()}}}):e("k-icon",{staticClass:"k-form-lock-loader",attrs:{type:"loader"}})],1):"changes"===t.mode?e("k-view",[e("k-button",{staticClass:"k-form-button",attrs:{disabled:t.isDisabled,text:t.$t("revert"),icon:"undo"},on:{click:t.onRevert}}),e("k-button",{staticClass:"k-form-button",attrs:{disabled:t.isDisabled,text:t.$t("save"),icon:"check"},on:{click:t.onSave}})],1):t._e(),e("k-dialog",{ref:"revert",attrs:{"submit-button":t.$t("revert"),icon:"undo",theme:"negative"},on:{submit:t.revert}},[e("k-text",{attrs:{html:t.$t("revert.confirm")}})],1)],1)}),[],!1,null,null,null,null).exports;const Xt=Mt({data:()=>({isOpen:!1,options:[]}),computed:{hasChanges(){return this.ids.length>0},ids(){return Object.keys(this.store).filter((t=>{var e;return Object.keys((null==(e=this.store[t])?void 0:e.changes)||{}).length>0}))},store(){return this.$store.state.content.models}},methods:{async toggle(){if(!1===this.$refs.list.isOpen)try{await this.$dropdown("changes",{method:"POST",body:{ids:this.ids}})((t=>{this.options=t}))}catch(t){return this.$store.dispatch("notification/success",this.$t("lock.unsaved.empty")),this.$store.dispatch("content/clear"),!1}this.$refs.list&&this.$refs.list.toggle()}}},(function(){var t=this,e=t._self._c;return t.hasChanges?e("k-dropdown",{staticClass:"k-form-indicator"},[e("k-button",{staticClass:"k-form-indicator-toggle k-topbar-button",attrs:{icon:"edit"},on:{click:t.toggle}}),e("k-dropdown-content",{ref:"list",attrs:{align:"right",theme:"light"}},[e("p",{staticClass:"k-form-indicator-info"},[t._v(t._s(t.$t("lock.unsaved"))+":")]),e("hr"),t._l(t.options,(function(s){return e("k-dropdown-item",t._b({key:s.id},"k-dropdown-item",s,!1),[t._v(" "+t._s(s.text)+" ")])}))],2)],1):t._e()}),[],!1,null,null,null,null).exports,Zt={props:{after:String}},Qt={props:{autofocus:Boolean}},te={props:{before:String}},ee={props:{disabled:Boolean}},se={props:{help:String}},ne={props:{id:{type:[Number,String],default(){return this._uid}}}},ie={props:{invalid:Boolean}},oe={props:{label:String}},re={props:{name:[Number,String]}},le={props:{required:Boolean}},ae={mixins:[ee,se,oe,re,le],props:{counter:[Boolean,Object],endpoints:Object,input:[String,Number],translate:Boolean,type:String}};const ue=Mt({mixins:[ae],inheritAttrs:!1,computed:{labelText(){return this.label||" "}}},(function(){var t=this,e=t._self._c;return e("div",{class:"k-field k-field-name-"+t.name,attrs:{"data-disabled":t.disabled,"data-translate":t.translate},on:{focusin:function(e){return t.$emit("focus",e)},focusout:function(e){return t.$emit("blur",e)}}},[t._t("header",(function(){return[e("header",{staticClass:"k-field-header"},[t._t("label",(function(){return[e("label",{staticClass:"k-field-label",attrs:{for:t.input}},[t._v(" "+t._s(t.labelText)+" "),t.required?e("abbr",{attrs:{title:t.$t("field.required")}},[t._v("*")]):t._e()])]})),t._t("options"),t._t("counter",(function(){return[t.counter?e("k-counter",t._b({staticClass:"k-field-counter",attrs:{required:t.required}},"k-counter",t.counter,!1)):t._e()]}))],2)]})),t._t("default"),t._t("footer",(function(){return[t.help||t.$slots.help?e("footer",{staticClass:"k-field-footer"},[t._t("help",(function(){return[t.help?e("k-text",{staticClass:"k-field-help",attrs:{theme:"help",html:t.help}}):t._e()]}))],2):t._e()]}))],2)}),[],!1,null,null,null,null).exports;const ce=Mt({props:{config:Object,disabled:Boolean,fields:{type:[Array,Object],default:()=>[]},novalidate:{type:Boolean,default:!1},value:{type:Object,default:()=>({})}},data:()=>({errors:{}}),methods:{focus(t){if(t)return void(this.hasField(t)&&"function"==typeof this.$refs[t][0].focus&&this.$refs[t][0].focus());const e=Object.keys(this.$refs)[0];this.focus(e)},hasFieldType(t){return this.$helper.isComponent(`k-${t}-field`)},hasField(t){var e;return null==(e=this.$refs[t])?void 0:e[0]},meetsCondition(t){if(!t.when)return!0;let e=!0;return Object.keys(t.when).forEach((s=>{this.value[s.toLowerCase()]!==t.when[s]&&(e=!1)})),e},onInvalid(t,e,s,n){this.errors[n]=e,this.$emit("invalid",this.errors)},hasErrors(){return Object.keys(this.errors).length}}},(function(){var t=this,e=t._self._c;return e("fieldset",{staticClass:"k-fieldset"},[e("k-grid",[t._l(t.fields,(function(s,n){return["hidden"!==s.type&&t.meetsCondition(s)?e("k-column",{key:s.signature,attrs:{width:s.width}},[e("k-error-boundary",[t.hasFieldType(s.type)?e("k-"+s.type+"-field",t._b({ref:n,refInFor:!0,tag:"component",attrs:{"form-data":t.value,name:n,novalidate:t.novalidate,disabled:t.disabled||s.disabled},on:{input:function(e){return t.$emit("input",t.value,s,n)},focus:function(e){return t.$emit("focus",e,s,n)},invalid:(e,i)=>t.onInvalid(e,i,s,n),submit:function(e){return t.$emit("submit",e,s,n)}},model:{value:t.value[n],callback:function(e){t.$set(t.value,n,e)},expression:"value[fieldName]"}},"component",s,!1)):e("k-box",{attrs:{theme:"negative"}},[e("k-text",{attrs:{size:"small"}},[t._v(" The field type "),e("strong",[t._v('"'+t._s(n)+'"')]),t._v(" does not exist ")])],1)],1)],1):t._e()]}))],2)],1)}),[],!1,null,null,null,null).exports,de={mixins:[Zt,te,ee,ie],props:{autofocus:Boolean,type:String,icon:[String,Boolean],theme:String,novalidate:{type:Boolean,default:!1},value:{type:[String,Boolean,Number,Object,Array],default:null}}};const pe=Mt({mixins:[de],inheritAttrs:!1,data(){return{isInvalid:this.invalid,listeners:{...this.$listeners,invalid:(t,e)=>{this.isInvalid=t,this.$emit("invalid",t,e)}}}},computed:{inputProps(){return{...this.$props,...this.$attrs}}},methods:{blur(t){(null==t?void 0:t.relatedTarget)&&!1===this.$el.contains(t.relatedTarget)&&this.trigger(null,"blur")},focus(t){this.trigger(t,"focus")},select(t){this.trigger(t,"select")},trigger(t,e){var s,n,i;if("INPUT"===(null==(s=null==t?void 0:t.target)?void 0:s.tagName)&&"function"==typeof(null==(n=null==t?void 0:t.target)?void 0:n[e]))return void t.target[e]();if("function"==typeof(null==(i=this.$refs.input)?void 0:i[e]))return void this.$refs.input[e]();const o=this.$el.querySelector("input, select, textarea");"function"==typeof(null==o?void 0:o[e])&&o[e]()}}},(function(){var t=this,e=t._self._c;return e("div",{staticClass:"k-input",attrs:{"data-disabled":t.disabled,"data-invalid":!t.novalidate&&t.isInvalid,"data-theme":t.theme,"data-type":t.type}},[t.$slots.before||t.before?e("span",{staticClass:"k-input-before",on:{click:t.focus}},[t._t("before",(function(){return[t._v(t._s(t.before))]}))],2):t._e(),e("span",{staticClass:"k-input-element",on:{click:function(e){return e.stopPropagation(),t.focus.apply(null,arguments)}}},[t._t("default",(function(){return[e("k-"+t.type+"-input",t._g(t._b({ref:"input",tag:"component",attrs:{value:t.value}},"component",t.inputProps,!1),t.listeners))]}))],2),t.$slots.after||t.after?e("span",{staticClass:"k-input-after",on:{click:t.focus}},[t._t("after",(function(){return[t._v(t._s(t.after))]}))],2):t._e(),t.$slots.icon||t.icon?e("span",{staticClass:"k-input-icon",on:{click:t.focus}},[t._t("icon",(function(){return[e("k-icon",{attrs:{type:t.icon}})]}))],2):t._e()])}),[],!1,null,null,null,null).exports;const he=Mt({props:{methods:Array},data:()=>({currentForm:null,isLoading:!1,issue:"",user:{email:"",password:"",remember:!1}}),computed:{canToggle(){return null!==this.codeMode&&!0===this.methods.includes("password")&&(!0===this.methods.includes("password-reset")||!0===this.methods.includes("code"))},codeMode(){return!0===this.methods.includes("password-reset")?"password-reset":!0===this.methods.includes("code")?"code":null},fields(){let t={email:{autofocus:!0,label:this.$t("email"),type:"email",required:!0,link:!1}};return"email-password"===this.form&&(t.password={label:this.$t("password"),type:"password",minLength:8,required:!0,autocomplete:"current-password",counter:!1}),t},form(){return this.currentForm?this.currentForm:"password"===this.methods[0]?"email-password":"email"},isResetForm(){return"password-reset"===this.codeMode&&"email"===this.form},toggleText(){return this.$t("login.toggleText."+this.codeMode+"."+this.formOpposite(this.form))}},methods:{formOpposite:t=>"email-password"===t?"email":"email-password",async login(){this.issue=null,this.isLoading=!0;let t=Object.assign({},this.user);"email"===this.currentForm&&(t.password=null),!0===this.isResetForm&&(t.remember=!1);try{await this.$api.auth.login(t),this.$reload({globals:["$system","$translation"]})}catch(e){this.issue=e.message}finally{this.isLoading=!1}},toggleForm(){this.currentForm=this.formOpposite(this.form),this.$refs.fieldset.focus("email")}}},(function(){var t=this,e=t._self._c;return e("form",{staticClass:"k-login-form",on:{submit:function(e){return e.preventDefault(),t.login.apply(null,arguments)}}},[e("h1",{staticClass:"sr-only"},[t._v(" "+t._s(t.$t("login"))+" ")]),t.issue?e("k-login-alert",{on:{click:function(e){t.issue=null}}},[t._v(" "+t._s(t.issue)+" ")]):t._e(),e("div",{staticClass:"k-login-fields"},[!0===t.canToggle?e("button",{staticClass:"k-login-toggler",attrs:{type:"button"},on:{click:t.toggleForm}},[t._v(" "+t._s(t.toggleText)+" ")]):t._e(),e("k-fieldset",{ref:"fieldset",attrs:{novalidate:!0,fields:t.fields},model:{value:t.user,callback:function(e){t.user=e},expression:"user"}})],1),e("div",{staticClass:"k-login-buttons"},[!1===t.isResetForm?e("span",{staticClass:"k-login-checkbox"},[e("k-checkbox-input",{attrs:{value:t.user.remember,label:t.$t("login.remember")},on:{input:function(e){t.user.remember=e}}})],1):t._e(),e("k-button",{staticClass:"k-login-button",attrs:{icon:"check",type:"submit"}},[t._v(" "+t._s(t.$t("login"+(t.isResetForm?".reset":"")))+" "),t.isLoading?[t._v(" … ")]:t._e()],2)],1)],1)}),[],!1,null,null,null,null).exports;const me=Mt({props:{methods:Array,pending:Object},data:()=>({code:"",isLoadingBack:!1,isLoadingLogin:!1,issue:""}),computed:{mode(){return!0===this.methods.includes("password-reset")?"password-reset":"login"}},methods:{async back(){this.isLoadingBack=!0,this.$go("/logout")},async login(){this.issue=null,this.isLoadingLogin=!0;try{await this.$api.auth.verifyCode(this.code),this.$store.dispatch("notification/success",this.$t("welcome")),"password-reset"===this.mode?this.$go("reset-password"):this.$reload()}catch(t){this.issue=t.message}finally{this.isLoadingLogin=!1}}}},(function(){var t=this,e=t._self._c;return e("form",{staticClass:"k-login-form k-login-code-form",on:{submit:function(e){return e.preventDefault(),t.login.apply(null,arguments)}}},[e("h1",{staticClass:"sr-only"},[t._v(" "+t._s(t.$t("login"))+" ")]),t.issue?e("k-login-alert",{on:{click:function(e){t.issue=null}}},[t._v(" "+t._s(t.issue)+" ")]):t._e(),e("k-user-info",{attrs:{user:t.pending.email}}),e("k-text-field",{attrs:{autofocus:!0,counter:!1,help:t.$t("login.code.text."+t.pending.challenge),label:t.$t("login.code.label."+t.mode),novalidate:!0,placeholder:t.$t("login.code.placeholder."+t.pending.challenge),required:!0,autocomplete:"one-time-code",icon:"unlock",name:"code"},model:{value:t.code,callback:function(e){t.code=e},expression:"code"}}),e("div",{staticClass:"k-login-buttons"},[e("k-button",{staticClass:"k-login-button k-login-back-button",attrs:{icon:"angle-left"},on:{click:t.back}},[t._v(" "+t._s(t.$t("back"))+" "),t.isLoadingBack?[t._v(" … ")]:t._e()],2),e("k-button",{staticClass:"k-login-button",attrs:{icon:"check",type:"submit"}},[t._v(" "+t._s(t.$t("login"+("password-reset"===t.mode?".reset":"")))+" "),t.isLoadingLogin?[t._v(" … ")]:t._e()],2)],1)],1)}),[],!1,null,null,null,null).exports;const fe=Mt({props:{display:{type:String,default:"HH:mm"},value:String},computed:{day(){return this.formatTimes([6,7,8,9,10,11,"-",12,13,14,15,16,17])},night(){return this.formatTimes([18,19,20,21,22,23,"-",0,1,2,3,4,5])}},methods:{formatTimes(t){return t.map((t=>{if("-"===t)return t;const e=this.$library.dayjs(t+":00","H:mm");return{display:e.format(this.display),select:e.toISO("time")}}))},select(t){this.$emit("input",t)}}},(function(){var t=this,e=t._self._c;return e("div",{staticClass:"k-times"},[e("div",{staticClass:"k-times-slot"},[e("k-icon",{attrs:{type:"sun"}}),e("ul",t._l(t.day,(function(s){return e("li",{key:s.select},["-"===s?e("hr"):e("k-button",{on:{click:function(e){return t.select(s.select)}}},[t._v(t._s(s.display))])],1)})),0)],1),e("div",{staticClass:"k-times-slot"},[e("k-icon",{attrs:{type:"moon"}}),e("ul",t._l(t.night,(function(s){return e("li",{key:s.select},["-"===s?e("hr"):e("k-button",{on:{click:function(e){return t.select(s.select)}}},[t._v(t._s(s.display))])],1)})),0)],1)])}),[],!1,null,null,null,null).exports;const ge=Mt({props:{accept:{type:String,default:"*"},attributes:{type:Object},max:{type:Number},method:{type:String,default:"POST"},multiple:{type:Boolean,default:!0},url:{type:String}},data(){return{options:this.$props,completed:{},errors:[],files:[],total:0}},computed:{limit(){return!1===this.options.multiple?1:this.options.max}},methods:{open(t){this.params(t),setTimeout((()=>{this.$refs.input.click()}),1)},params(t){this.options=Object.assign({},this.$props,t)},select(t){this.upload(t.target.files)},drop(t,e){this.params(e),this.upload(t)},upload(t){this.$refs.dialog.open(),this.files=[...t],this.completed={},this.errors=[],this.hasErrors=!1,this.limit&&(this.files=this.files.slice(0,this.limit)),this.total=this.files.length,this.files.forEach((t=>{var e,s;this.$helper.upload(t,{url:this.options.url,attributes:this.options.attributes,method:this.options.method,headers:{"X-CSRF":window.panel.$system.csrf},progress:(t,e,s)=>{var n,i;null==(i=null==(n=this.$refs[e.name])?void 0:n[0])||i.set(s)},success:(t,e,s)=>{this.complete(e,s.data)},error:(t,e,s)=>{this.errors.push({file:e,message:s.message}),this.complete(e,s.data)}}),void 0!==(null==(s=null==(e=this.options)?void 0:e.attributes)?void 0:s.sort)&&this.options.attributes.sort++}))},complete(t,e){if(this.completed[t.name]=e,Object.keys(this.completed).length==this.total){if(this.$refs.input.value="",this.errors.length>0)return this.$forceUpdate(),void this.$emit("error",this.files);setTimeout((()=>{this.$refs.dialog.close(),this.$emit("success",this.files,Object.values(this.completed))}),250)}}}},(function(){var t=this,e=t._self._c;return e("div",{staticClass:"k-upload"},[e("input",{ref:"input",attrs:{accept:t.options.accept,multiple:t.options.multiple,"aria-hidden":"true",type:"file",tabindex:"-1"},on:{change:t.select,click:function(t){t.stopPropagation()}}}),e("k-dialog",{ref:"dialog",staticClass:"k-upload-dialog",attrs:{"cancel-button":!1,"submit-button":!1,size:"medium"},scopedSlots:t._u([{key:"footer",fn:function(){return[t.errors.length>0?[e("k-button-group",{attrs:{buttons:[{icon:"check",text:t.$t("confirm"),click:()=>t.$refs.dialog.close()}]}})]:t._e()]},proxy:!0}])},[t.errors.length>0?[e("k-headline",[t._v(t._s(t.$t("upload.errors")))]),e("ul",{staticClass:"k-upload-error-list"},t._l(t.errors,(function(s,n){return e("li",{key:"error-"+n},[e("p",{staticClass:"k-upload-error-filename"},[t._v(" "+t._s(s.file.name)+" ")]),e("p",{staticClass:"k-upload-error-message"},[t._v(" "+t._s(s.message)+" ")])])})),0)]:[e("k-headline",[t._v(t._s(t.$t("upload.progress")))]),e("ul",{staticClass:"k-upload-list"},t._l(t.files,(function(s,n){return e("li",{key:"file-"+n},[e("k-progress",{ref:s.name,refInFor:!0}),e("p",{staticClass:"k-upload-list-filename"},[t._v(" "+t._s(s.name)+" ")]),e("p",[t._v(t._s(t.errors[s.name]))])],1)})),0)]],2)],1)}),[],!1,null,null,null,null).exports;const ke=t=>({$from:e})=>((t,e)=>{for(let s=t.depth;s>0;s--){const n=t.node(s);if(e(n))return{pos:s>0?t.before(s):0,start:t.start(s),depth:s,node:n}}})(e,t),be=t=>e=>{if((t=>t instanceof c)(e)){const{node:s,$from:n}=e;if(((t,e)=>Array.isArray(t)&&t.indexOf(e.type)>-1||e.type===t)(t,s))return{node:s,pos:n.pos,depth:n.depth}}},ye=(t,e,s={})=>{const n=be(e)(t.selection)||ke((t=>t.type===e))(t.selection);return Object.keys(s).length&&n?n.node.hasMarkup(e,{...n.node.attrs,...s}):!!n};function ve(t=null,e=null){if(!t||!e)return!1;const s=t.parent.childAfter(t.parentOffset);if(!s.node)return!1;const n=s.node.marks.find((t=>t.type===e));if(!n)return!1;let i=t.index(),o=t.start()+s.offset,r=i+1,l=o+s.node.nodeSize;for(;i>0&&n.isInSet(t.parent.child(i-1).marks);)i-=1,o-=t.parent.child(i).nodeSize;for(;r{i=[...i,...t.marks]}));const o=i.find((t=>t.type.name===e.name));return o?o.attrs:{}},getNodeAttrs:function(t,e){const{from:s,to:n}=t.selection;let i=[];t.doc.nodesBetween(s,n,(t=>{i=[...i,t]}));const o=i.reverse().find((t=>t.type.name===e.name));return o?o.attrs:{}},markInputRule:function(t,e,s){return new r(t,((t,n,i,o)=>{const r=s instanceof Function?s(n):s,{tr:l}=t,a=n.length-1;let u=o,c=i;if(n[a]){const s=i+n[0].indexOf(n[a-1]),r=s+n[a-1].length-1,d=s+n[a-1].lastIndexOf(n[a]),p=d+n[a].length,h=function(t,e,s){let n=[];return s.doc.nodesBetween(t,e,((t,e)=>{n=[...n,...t.marks.map((s=>({start:e,end:e+t.nodeSize,mark:s})))]})),n}(i,o,t).filter((t=>{const{excluded:s}=t.mark.type;return s.find((t=>t.name===e.name))})).filter((t=>t.end>s));if(h.length)return!1;ps&&l.delete(s,d),c=s,u=c+n[a].length}return l.addMark(c,u,e.create(r)),l.removeStoredMark(e),l}))},markIsActive:function(t,e){const{from:s,$from:n,to:i,empty:o}=t.selection;return o?!!e.isInSet(t.storedMarks||n.marks()):!!t.doc.rangeHasMark(s,i,e)},markPasteRule:function(t,e,s){const n=(i,o)=>{const r=[];return i.forEach((i=>{var l;if(i.isText){const{text:n,marks:a}=i;let u,c=0;const d=!!a.filter((t=>"link"===t.type.name))[0];for(;!d&&null!==(u=t.exec(n));)if((null==(l=null==o?void 0:o.type)?void 0:l.allowsMarkType(e))&&u[1]){const t=u.index,n=t+u[0].length,o=t+u[0].indexOf(u[1]),l=o+u[1].length,a=s instanceof Function?s(u):s;t>0&&r.push(i.cut(c,t)),r.push(i.cut(o,l).mark(e.create(a).addToSet(i.marks))),c=n}cnew a(n(t.content),t.openStart,t.openEnd)}})},minMax:function(t=0,e=0,s=0){return Math.min(Math.max(parseInt(t,10),e),s)},nodeIsActive:ye,nodeInputRule:function(t,e,s){return new r(t,((t,n,i,o)=>{const r=s instanceof Function?s(n):s,{tr:l}=t;return n[0]&&l.replaceWith(i-1,o,e.create(r)),l}))},pasteRule:function(t,e,s){const n=i=>{const o=[];return i.forEach((i=>{if(i.isText){const{text:n}=i;let r,l=0;do{if(r=t.exec(n),r){const t=r.index,n=t+r[0].length,a=s instanceof Function?s(r[0]):s;t>0&&o.push(i.cut(l,t)),o.push(i.cut(t,n).mark(e.create(a).addToSet(i.marks))),l=n}}while(r);lnew a(n(t.content),t.openStart,t.openEnd)}})},removeMark:function(t){return(e,s)=>{const{tr:n,selection:i}=e;let{from:o,to:r}=i;const{$from:l,empty:a}=i;if(a){const e=ve(l,t);o=e.from,r=e.to}return n.removeMark(o,r,t),s(n)}},toggleBlockType:function(t,e,s={}){return(n,i,o)=>ye(n,t,s)?d(e)(n,i,o):d(t,s)(n,i,o)},toggleList:function(t,e){return(s,n,i)=>{const{schema:o,selection:r}=s,{$from:l,$to:a}=r,u=l.blockRange(a);if(!u)return!1;const c=ke((t=>$e(t,o)))(r);if(u.depth>=1&&c&&u.depth-c.depth<=1){if(c.node.type===t)return p(e)(s,n,i);if($e(c.node,o)&&t.validContent(c.node.content)){const{tr:e}=s;return e.setNodeMarkup(c.pos,t),n&&n(e),!1}}return h(t)(s,n,i)}},updateMark:function(t,e){return(s,n)=>{const{tr:i,selection:o,doc:r}=s,{ranges:l,empty:a}=o;if(a){const{from:s,to:n}=ve(o.$from,t);r.rangeHasMark(s,n,t)&&i.removeMark(s,n,t),i.addMark(s,n,t.create(e))}else l.forEach((s=>{const{$to:n,$from:o}=s;r.rangeHasMark(o.pos,n.pos,t)&&i.removeMark(o.pos,n.pos,t),i.addMark(o.pos,n.pos,t.create(e))}));return n(i)}}};class xe{constructor(t=[],e){t.forEach((t=>{t.bindEditor(e),t.init()})),this.extensions=t}commands({schema:t,view:e}){return this.extensions.filter((t=>t.commands)).reduce(((s,n)=>{const{name:i,type:o}=n,r={},l=n.commands({schema:t,utils:_e,...["node","mark"].includes(o)?{type:t[`${o}s`][i]}:{}}),a=(t,s)=>{r[t]=t=>{if("function"!=typeof s||!e.editable)return!1;e.focus();const n=s(t);return"function"==typeof n?n(e.state,e.dispatch,e):n}};return"object"==typeof l?Object.entries(l).forEach((([t,e])=>{a(t,e)})):a(i,l),{...s,...r}}),{})}buttons(t="mark"){const e={};return this.extensions.filter((e=>e.type===t)).filter((t=>t.button)).forEach((t=>{Array.isArray(t.button)?t.button.forEach((t=>{e[t.id||t.name]=t})):e[t.name]=t.button})),e}getAllowedExtensions(t){return t instanceof Array||!t?t instanceof Array?this.extensions.filter((e=>!t.includes(e.name))):this.extensions:[]}getFromExtensions(t,e,s=this.extensions){return s.filter((t=>["extension"].includes(t.type))).filter((e=>e[t])).map((s=>s[t]({...e,utils:_e})))}getFromNodesAndMarks(t,e,s=this.extensions){return s.filter((t=>["node","mark"].includes(t.type))).filter((e=>e[t])).map((s=>s[t]({...e,type:e.schema[`${s.type}s`][s.name],utils:_e})))}inputRules({schema:t,excludedExtensions:e}){const s=this.getAllowedExtensions(e);return[...this.getFromExtensions("inputRules",{schema:t},s),...this.getFromNodesAndMarks("inputRules",{schema:t},s)].reduce(((t,e)=>[...t,...e]),[])}keymaps({schema:t}){return[...this.getFromExtensions("keys",{schema:t}),...this.getFromNodesAndMarks("keys",{schema:t})].map((t=>_(t)))}get marks(){return this.extensions.filter((t=>"mark"===t.type)).reduce(((t,{name:e,schema:s})=>({...t,[e]:s})),{})}get nodes(){return this.extensions.filter((t=>"node"===t.type)).reduce(((t,{name:e,schema:s})=>({...t,[e]:s})),{})}get options(){const{view:t}=this;return this.extensions.reduce(((e,s)=>({...e,[s.name]:new Proxy(s.options,{set(e,s,n){const i=e[s]!==n;return Object.assign(e,{[s]:n}),i&&t.updateState(t.state),!0}})})),{})}pasteRules({schema:t,excludedExtensions:e}){const s=this.getAllowedExtensions(e);return[...this.getFromExtensions("pasteRules",{schema:t},s),...this.getFromNodesAndMarks("pasteRules",{schema:t},s)].reduce(((t,e)=>[...t,...e]),[])}plugins({schema:t}){return[...this.getFromExtensions("plugins",{schema:t}),...this.getFromNodesAndMarks("plugins",{schema:t})].reduce(((t,e)=>[...t,...e]),[]).map((t=>t instanceof l?t:new l(t)))}}class we{constructor(t={}){this.options={...this.defaults,...t}}init(){return null}bindEditor(t=null){this.editor=t}get name(){return null}get type(){return"extension"}get defaults(){return{}}plugins(){return[]}inputRules(){return[]}pasteRules(){return[]}keys(){return{}}}class Se extends we{constructor(t={}){super(t)}get type(){return"node"}get schema(){return null}commands(){return{}}}class Ce extends Se{get defaults(){return{inline:!1}}get name(){return"doc"}get schema(){return{content:this.options.inline?"inline*":"block+"}}}class Oe extends Se{get button(){return{id:this.name,icon:"paragraph",label:window.panel.$t("toolbar.button.paragraph"),name:this.name}}commands({utils:t,type:e}){return{paragraph:()=>t.setBlockType(e)}}get schema(){return{content:"inline*",group:"block",draggable:!1,parseDOM:[{tag:"p"}],toDOM:()=>["p",0]}}get name(){return"paragraph"}}class Ae extends Se{get name(){return"text"}get schema(){return{group:"inline"}}}class Te extends class{emit(t,...e){this._callbacks=this._callbacks||{};const s=this._callbacks[t];return s&&s.forEach((t=>t.apply(this,e))),this}off(t,e){if(arguments.length){const s=this._callbacks?this._callbacks[t]:null;s&&(e?this._callbacks[t]=s.filter((t=>t!==e)):delete this._callbacks[t])}else this._callbacks={};return this}on(t,e){return this._callbacks=this._callbacks||{},this._callbacks[t]=this._callbacks[t]||[],this._callbacks[t].push(e),this}}{constructor(t={}){super(),this.defaults={autofocus:!1,content:"",disableInputRules:!1,disablePasteRules:!1,editable:!0,element:null,extensions:[],emptyDocument:{type:"doc",content:[]},events:{},inline:!1,parseOptions:{},topNode:"doc",useBuiltInExtensions:!0},this.init(t)}blur(){this.view.dom.blur()}get builtInExtensions(){return this.options.useBuiltInExtensions?[new Ce({inline:this.options.inline}),new Ae,new Oe]:[]}buttons(t){return this.extensions.buttons(t)}clearContent(t=!1){this.setContent(this.options.emptyDocument,t)}command(t,...e){this.commands[t]&&this.commands[t](...e)}createCommands(){return this.extensions.commands({schema:this.schema,view:this.view})}createDocument(t,e=this.options.parseOptions){if(null===t)return this.schema.nodeFromJSON(this.options.emptyDocument);if("object"==typeof t)try{return this.schema.nodeFromJSON(t)}catch(s){return window.console.warn("Invalid content.","Passed value:",t,"Error:",s),this.schema.nodeFromJSON(this.options.emptyDocument)}if("string"==typeof t){const s=`
${t}
`,n=(new window.DOMParser).parseFromString(s,"text/html").body.firstElementChild;return x.fromSchema(this.schema).parse(n,e)}return!1}createEvents(){const t=this.options.events||{};return Object.entries(t).forEach((([t,e])=>{this.on(t,e)})),t}createExtensions(){return new xe([...this.builtInExtensions,...this.options.extensions],this)}createFocusEvents(){const t=(t,e,s=!0)=>{this.focused=s,this.emit(s?"focus":"blur",{event:e,state:t.state,view:t});const n=this.state.tr.setMeta("focused",s);this.view.dispatch(n)};return new l({props:{attributes:{tabindex:0},handleDOMEvents:{focus:(e,s)=>{t(e,s,!0)},blur:(e,s)=>{t(e,s,!1)}}}})}createInputRules(){return this.extensions.inputRules({schema:this.schema,excludedExtensions:this.options.disableInputRules})}createKeymaps(){return this.extensions.keymaps({schema:this.schema})}createMarks(){return this.extensions.marks}createNodes(){return this.extensions.nodes}createPasteRules(){return this.extensions.pasteRules({schema:this.schema,excludedExtensions:this.options.disablePasteRules})}createPlugins(){return this.extensions.plugins({schema:this.schema})}createSchema(){return new w({topNode:this.options.topNode,nodes:this.nodes,marks:this.marks})}createState(){return S.create({schema:this.schema,doc:this.createDocument(this.options.content),plugins:[...this.plugins,C({rules:this.inputRules}),...this.pasteRules,...this.keymaps,_({Backspace:I}),_(M),this.createFocusEvents()]})}createView(){return new O(this.element,{dispatchTransaction:this.dispatchTransaction.bind(this),editable:()=>this.options.editable,handlePaste:(t,e)=>{if("function"==typeof this.events.paste){const t=e.clipboardData.getData("text/html"),s=e.clipboardData.getData("text/plain");if(!0===this.events.paste(e,t,s))return!0}},handleDrop:(...t)=>{this.emit("drop",...t)},state:this.createState()})}destroy(){this.view&&this.view.destroy()}dispatchTransaction(t){const e=this.state,s=this.state.apply(t);this.view.updateState(s),this.selection={from:this.state.selection.from,to:this.state.selection.to},this.setActiveNodesAndMarks();const n={editor:this,getHTML:this.getHTML.bind(this),getJSON:this.getJSON.bind(this),state:this.state,transaction:t};this.emit("transaction",n),!t.docChanged&&t.getMeta("preventUpdate")||this.emit("update",n);const{from:i,to:o}=this.state.selection,r=!e||!e.selection.eq(s.selection);this.emit(s.selection.empty?"deselect":"select",{...n,from:i,hasChanged:r,to:o})}focus(t=null){if(this.view.focused&&null===t||!1===t)return;const{from:e,to:s}=this.selectionAtPosition(t);this.setSelection(e,s),setTimeout((()=>this.view.focus()),10)}getHTML(){const t=document.createElement("div"),e=A.fromSchema(this.schema).serializeFragment(this.state.doc.content);return t.appendChild(e),this.options.inline&&t.querySelector("p")?t.querySelector("p").innerHTML:t.innerHTML}getJSON(){return this.state.doc.toJSON()}getMarkAttrs(t=null){return this.activeMarkAttrs[t]}getSchemaJSON(){return JSON.parse(JSON.stringify({nodes:this.nodes,marks:this.marks}))}init(t={}){this.options={...this.defaults,...t},this.element=this.options.element,this.focused=!1,this.selection={from:0,to:0},this.events=this.createEvents(),this.extensions=this.createExtensions(),this.nodes=this.createNodes(),this.marks=this.createMarks(),this.schema=this.createSchema(),this.keymaps=this.createKeymaps(),this.inputRules=this.createInputRules(),this.pasteRules=this.createPasteRules(),this.plugins=this.createPlugins(),this.view=this.createView(),this.commands=this.createCommands(),this.setActiveNodesAndMarks(),!1!==this.options.autofocus&&this.focus(this.options.autofocus),this.emit("init",{view:this.view,state:this.state}),this.extensions.view=this.view,this.setContent(this.options.content,!0)}isEditable(){return this.options.editable}isEmpty(){if(this.state)return 0===this.state.doc.textContent.length}get isActive(){return Object.entries({...this.activeMarks,...this.activeNodes}).reduce(((t,[e,s])=>({...t,[e]:(t={})=>s(t)})),{})}removeMark(t){if(this.schema.marks[t])return _e.removeMark(this.schema.marks[t])(this.state,this.view.dispatch)}selectionAtPosition(t=null){if(this.selection&&null===t)return this.selection;if("start"===t||!0===t)return{from:0,to:0};if("end"===t){const{doc:t}=this.state;return{from:t.content.size,to:t.content.size}}return{from:t,to:t}}setActiveNodesAndMarks(){this.activeMarks=Object.values(this.schema.marks).filter((t=>_e.markIsActive(this.state,t))).map((t=>t.name)),this.activeMarkAttrs=Object.entries(this.schema.marks).reduce(((t,[e,s])=>({...t,[e]:_e.getMarkAttrs(this.state,s)})),{}),this.activeNodes=Object.values(this.schema.nodes).filter((t=>_e.nodeIsActive(this.state,t))).map((t=>t.name)),this.activeNodeAttrs=Object.entries(this.schema.nodes).reduce(((t,[e,s])=>({...t,[e]:_e.getNodeAttrs(this.state,s)})),{})}setContent(t={},e=!1,s){const{doc:n,tr:i}=this.state,o=this.createDocument(t,s),r=i.replaceWith(0,n.content.size,o).setMeta("preventUpdate",!e);this.view.dispatch(r)}setSelection(t=0,e=0){const{doc:s,tr:n}=this.state,i=_e.minMax(t,0,s.content.size),o=_e.minMax(e,0,s.content.size),r=T.create(s,i,o),l=n.setSelection(r);this.view.dispatch(l)}get state(){return this.view?this.view.state:null}toggleMark(t){if(this.schema.marks[t])return _e.toggleMark(this.schema.marks[t])(this.state,this.view.dispatch)}updateMark(t,e){if(this.schema.marks[t])return _e.updateMark(this.schema.marks[t],e)(this.state,this.view.dispatch)}}const Ie=Mt({data:()=>({link:{href:null,title:null,target:!1}}),computed:{fields(){return{href:{label:this.$t("url"),type:"text",icon:"url"},title:{label:this.$t("title"),type:"text",icon:"title"},target:{label:this.$t("open.newWindow"),type:"toggle",text:[this.$t("no"),this.$t("yes")]}}}},methods:{open(t){this.link={title:null,target:!1,...t},this.link.target=Boolean(this.link.target),this.$refs.dialog.open()},submit(){this.$emit("submit",{...this.link,target:this.link.target?"_blank":null}),this.$refs.dialog.close()}}},(function(){var t=this;return(0,t._self._c)("k-form-dialog",{ref:"dialog",attrs:{fields:t.fields,"submit-button":t.$t("confirm"),size:"medium"},on:{close:function(e){return t.$emit("close")},submit:t.submit},model:{value:t.link,callback:function(e){t.link=e},expression:"link"}})}),[],!1,null,null,null,null).exports;const Me=Mt({data:()=>({email:{email:null,title:null}}),computed:{fields(){return{href:{label:this.$t("email"),type:"email",icon:"email"},title:{label:this.$t("title"),type:"text",icon:"title"}}}},methods:{open(t){this.email={title:null,...t},this.$refs.dialog.open()},submit(){this.$emit("submit",this.email),this.$refs.dialog.close()}}},(function(){var t=this;return(0,t._self._c)("k-form-dialog",{ref:"dialog",attrs:{fields:t.fields,"submit-button":t.$t("confirm"),size:"medium"},on:{close:function(e){return t.$emit("close")},submit:t.submit},model:{value:t.email,callback:function(e){t.email=e},expression:"email"}})}),[],!1,null,null,null,null).exports;class Ee extends we{constructor(t={}){super(t)}command(){return()=>{}}remove(){this.editor.removeMark(this.name)}get schema(){return null}get type(){return"mark"}toggle(){return this.editor.toggleMark(this.name)}update(t){this.editor.updateMark(this.name,t)}}class Le extends Ee{get button(){return{icon:"code",label:window.panel.$t("toolbar.button.code")}}commands(){return()=>this.toggle()}inputRules({type:t,utils:e}){return[e.markInputRule(/(?:`)([^`]+)(?:`)$/,t)]}keys(){return{"Mod-`":()=>this.toggle()}}get name(){return"code"}pasteRules({type:t,utils:e}){return[e.markPasteRule(/(?:`)([^`]+)(?:`)/g,t)]}get schema(){return{excludes:"_",parseDOM:[{tag:"code"}],toDOM:()=>["code",0]}}}class je extends Ee{get button(){return{icon:"bold",label:window.panel.$t("toolbar.button.bold")}}commands(){return()=>this.toggle()}inputRules({type:t,utils:e}){return[e.markInputRule(/(?:\*\*|__)([^*_]+)(?:\*\*|__)$/,t)]}keys(){return{"Mod-b":()=>this.toggle()}}get name(){return"bold"}pasteRules({type:t,utils:e}){return[e.markPasteRule(/(?:\*\*|__)([^*_]+)(?:\*\*|__)/g,t)]}get schema(){return{parseDOM:[{tag:"strong"},{tag:"b",getAttrs:t=>"normal"!==t.style.fontWeight&&null},{style:"font-weight",getAttrs:t=>/^(bold(er)?|[5-9]\d{2,})$/.test(t)&&null}],toDOM:()=>["strong",0]}}}class De extends Ee{get button(){return{icon:"italic",label:window.panel.$t("toolbar.button.italic")}}commands(){return()=>this.toggle()}inputRules({type:t,utils:e}){return[e.markInputRule(/(?:^|\s)((?:\*)((?:[^*]+))(?:\*))$/,t),e.markInputRule(/(?:^|\s)((?:_)((?:[^_]+))(?:_))$/,t)]}keys(){return{"Mod-i":()=>this.toggle()}}get name(){return"italic"}pasteRules({type:t,utils:e}){return[e.markPasteRule(/_([^_]+)_/g,t),e.markPasteRule(/\*([^*]+)\*/g,t)]}get schema(){return{parseDOM:[{tag:"i"},{tag:"em"},{style:"font-style=italic"}],toDOM:()=>["em",0]}}}class Be extends Ee{get button(){return{icon:"url",label:window.panel.$t("toolbar.button.link")}}commands(){return{link:()=>{this.editor.emit("link",this.editor)},insertLink:(t={})=>{if(t.href)return this.update(t)},removeLink:()=>this.remove(),toggleLink:(t={})=>{var e;(null==(e=t.href)?void 0:e.length)>0?this.editor.command("insertLink",t):this.editor.command("removeLink")}}}get defaults(){return{target:null}}get name(){return"link"}pasteRules({type:t,utils:e}){return[e.pasteRule(/https?:\/\/(www\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z]{2,}\b([-a-zA-Z0-9@:%_+.~#?&//=,]*)/gi,t,(t=>({href:t})))]}plugins(){return[{props:{handleClick:(t,e,s)=>{const n=this.editor.getMarkAttrs("link");n.href&&!0===s.altKey&&s.target instanceof HTMLAnchorElement&&(s.stopPropagation(),window.open(n.href,n.target))}}}]}get schema(){return{attrs:{href:{default:null},target:{default:null},title:{default:null}},inclusive:!1,parseDOM:[{tag:"a[href]:not([href^='mailto:'])",getAttrs:t=>({href:t.getAttribute("href"),target:t.getAttribute("target"),title:t.getAttribute("title")})}],toDOM:t=>["a",{...t.attrs,rel:"noopener noreferrer"},0]}}}class Pe extends Ee{get button(){return{icon:"email",label:"Email"}}commands(){return{email:()=>{this.editor.emit("email")},insertEmail:(t={})=>{if(t.href)return this.update(t)},removeEmail:()=>this.remove(),toggleEmail:(t={})=>{var e;(null==(e=t.href)?void 0:e.length)>0?this.editor.command("insertEmail",t):this.editor.command("removeEmail")}}}get defaults(){return{target:null}}get name(){return"email"}pasteRules({type:t,utils:e}){return[e.pasteRule(/^[\w-.]+@([\w-]+\.)+[\w-]{2,4}$/gi,t,(t=>({href:t})))]}plugins(){return[{props:{handleClick:(t,e,s)=>{const n=this.editor.getMarkAttrs("email");n.href&&!0===s.altKey&&s.target instanceof HTMLAnchorElement&&(s.stopPropagation(),window.open(n.href))}}}]}get schema(){return{attrs:{href:{default:null},title:{default:null}},inclusive:!1,parseDOM:[{tag:"a[href^='mailto:']",getAttrs:t=>({href:t.getAttribute("href").replace("mailto:",""),title:t.getAttribute("title")})}],toDOM:t=>["a",{...t.attrs,href:"mailto:"+t.attrs.href},0]}}}class Ne extends Ee{get button(){return{icon:"strikethrough",label:window.panel.$t("toolbar.button.strike")}}commands(){return()=>this.toggle()}inputRules({type:t,utils:e}){return[e.markInputRule(/~([^~]+)~$/,t)]}keys(){return{"Mod-d":()=>this.toggle()}}get name(){return"strike"}pasteRules({type:t,utils:e}){return[e.markPasteRule(/~([^~]+)~/g,t)]}get schema(){return{parseDOM:[{tag:"s"},{tag:"del"},{tag:"strike"},{style:"text-decoration",getAttrs:t=>"line-through"===t}],toDOM:()=>["s",0]}}}class qe extends Ee{get button(){return{icon:"underline",label:window.panel.$t("toolbar.button.underline")}}commands(){return()=>this.toggle()}keys(){return{"Mod-u":()=>this.toggle()}}get name(){return"underline"}get schema(){return{parseDOM:[{tag:"u"},{style:"text-decoration",getAttrs:t=>"underline"===t}],toDOM:()=>["u",0]}}}class Fe extends Se{get button(){return{id:this.name,icon:"list-bullet",label:window.panel.$t("toolbar.button.ul"),name:this.name,when:["listItem","bulletList","orderedList"]}}commands({type:t,schema:e,utils:s}){return()=>s.toggleList(t,e.nodes.listItem)}inputRules({type:t,utils:e}){return[e.wrappingInputRule(/^\s*([-+*])\s$/,t)]}keys({type:t,schema:e,utils:s}){return{"Shift-Ctrl-8":s.toggleList(t,e.nodes.listItem)}}get name(){return"bulletList"}get schema(){return{content:"listItem+",group:"block",parseDOM:[{tag:"ul"}],toDOM:()=>["ul",0]}}}class Re extends Se{commands({utils:t,type:e}){return()=>this.createHardBreak(t,e)}createHardBreak(t,e){return t.chainCommands(t.exitCode,((t,s)=>(s(t.tr.replaceSelectionWith(e.create()).scrollIntoView()),!0)))}get defaults(){return{enter:!1,text:!1}}keys({utils:t,type:e}){const s=this.createHardBreak(t,e);let n={"Mod-Enter":s,"Shift-Enter":s};return this.options.enter&&(n.Enter=s),n}get name(){return"hardBreak"}get schema(){return{inline:!0,group:"inline",selectable:!1,parseDOM:[{tag:"br"}],toDOM:()=>["br"]}}}class ze extends Se{get button(){return this.options.levels.map((t=>({id:`h${t}`,command:`h${t}`,icon:`h${t}`,label:window.panel.$t("toolbar.button.heading."+t),attrs:{level:t},name:this.name,when:["heading","paragraph"]})))}commands({type:t,schema:e,utils:s}){let n={toggleHeading:n=>s.toggleBlockType(t,e.nodes.paragraph,n)};return this.options.levels.forEach((i=>{n[`h${i}`]=()=>s.toggleBlockType(t,e.nodes.paragraph,{level:i})})),n}get defaults(){return{levels:[1,2,3,4,5,6]}}inputRules({type:t,utils:e}){return this.options.levels.map((s=>e.textblockTypeInputRule(new RegExp(`^(#{1,${s}})\\s$`),t,(()=>({level:s})))))}keys({type:t,utils:e}){return this.options.levels.reduce(((s,n)=>({...s,[`Shift-Ctrl-${n}`]:e.setBlockType(t,{level:n})})),{})}get name(){return"heading"}get schema(){return{attrs:{level:{default:1}},content:"inline*",group:"block",defining:!0,draggable:!1,parseDOM:this.options.levels.map((t=>({tag:`h${t}`,attrs:{level:t}}))),toDOM:t=>[`h${t.attrs.level}`,0]}}}class Ye extends Se{commands({type:t}){return()=>(e,s)=>s(e.tr.replaceSelectionWith(t.create()))}inputRules({type:t,utils:e}){return[e.nodeInputRule(/^(?:---|___\s|\*\*\*\s)$/,t)]}get name(){return"horizontalRule"}get schema(){return{group:"block",parseDOM:[{tag:"hr"}],toDOM:()=>["hr"]}}}class He extends Se{keys({type:t,utils:e}){return{Enter:e.splitListItem(t),"Shift-Tab":e.liftListItem(t),Tab:e.sinkListItem(t)}}get name(){return"listItem"}get schema(){return{content:"paragraph block*",defining:!0,draggable:!1,parseDOM:[{tag:"li"}],toDOM:()=>["li",0]}}}class Ue extends Se{get button(){return{id:this.name,icon:"list-numbers",label:window.panel.$t("toolbar.button.ol"),name:this.name,when:["listItem","bulletList","orderedList"]}}commands({type:t,schema:e,utils:s}){return()=>s.toggleList(t,e.nodes.listItem)}inputRules({type:t,utils:e}){return[e.wrappingInputRule(/^(\d+)\.\s$/,t,(t=>({order:+t[1]})),((t,e)=>e.childCount+e.attrs.order===+t[1]))]}keys({type:t,schema:e,utils:s}){return{"Shift-Ctrl-9":s.toggleList(t,e.nodes.listItem)}}get name(){return"orderedList"}get schema(){return{attrs:{order:{default:1}},content:"listItem+",group:"block",parseDOM:[{tag:"ol",getAttrs:t=>({order:t.hasAttribute("start")?+t.getAttribute("start"):1})}],toDOM:t=>1===t.attrs.order?["ol",0]:["ol",{start:t.attrs.order},0]}}}class Ke extends we{commands(){return{undo:()=>E,redo:()=>L,undoDepth:()=>j,redoDepth:()=>D}}get defaults(){return{depth:"",newGroupDelay:""}}keys(){return{"Mod-z":E,"Mod-y":L,"Shift-Mod-z":L,"Mod-я":E,"Shift-Mod-я":L}}get name(){return"history"}plugins(){return[B({depth:this.options.depth,newGroupDelay:this.options.newGroupDelay})]}}class Ge extends we{commands(){return{insertHtml:t=>(e,s)=>{let n=document.createElement("div");n.innerHTML=t.trim();const i=x.fromSchema(e.schema).parse(n);s(e.tr.replaceSelectionWith(i).scrollIntoView())}}}}class Je extends we{constructor(t={}){super(t)}close(){this.visible=!1,this.emit()}emit(){this.editor.emit("toolbar",{marks:this.marks,nodes:this.nodes,nodeAttrs:this.nodeAttrs,position:this.position,visible:this.visible})}init(){this.position={left:0,bottom:0},this.visible=!1,this.editor.on("blur",(()=>{this.close()})),this.editor.on("deselect",(()=>{this.close()})),this.editor.on("select",(({hasChanged:t})=>{!1!==t?this.open():this.emit()}))}get marks(){return this.editor.activeMarks}get nodes(){return this.editor.activeNodes}get nodeAttrs(){return this.editor.activeNodeAttrs}open(){this.visible=!0,this.reposition(),this.emit()}reposition(){const{from:t,to:e}=this.editor.selection,s=this.editor.view.coordsAtPos(t),n=this.editor.view.coordsAtPos(e,!0),i=this.editor.element.getBoundingClientRect();let o=(s.left+n.left)/2-i.left,r=Math.round(i.bottom-s.top);return this.position={bottom:r,left:o}}get type(){return"toolbar"}}const Ve=Mt({props:{activeMarks:{type:Array,default:()=>[]},activeNodes:{type:Array,default:()=>[]},activeNodeAttrs:{type:[Array,Object],default:()=>[]},editor:{type:Object,required:!0},marks:{type:Array},isParagraphNodeHidden:{type:Boolean,default:!1}},computed:{activeButton(){return Object.values(this.nodeButtons).find((t=>this.isButtonActive(t)))||!1},hasVisibleButtons(){const t=Object.keys(this.nodeButtons);return t.length>1||1===t.length&&!1===t.includes("paragraph")},markButtons(){return this.buttons("mark")},nodeButtons(){let t=this.buttons("node");return!0===this.isParagraphNodeHidden&&t.paragraph&&delete t.paragraph,t}},methods:{buttons(t){const e=this.editor.buttons(t);let s=this.sorting;!1!==s&&!1!==Array.isArray(s)||(s=Object.keys(e));let n={};return s.forEach((t=>{e[t]&&(n[t]=e[t])})),n},command(t,...e){this.$emit("command",t,...e)},isButtonActive(t){if("paragraph"===t.name)return 1===this.activeNodes.length&&this.activeNodes.includes(t.name);let e=!0;if(t.attrs){const s=Object.values(this.activeNodeAttrs).find((e=>JSON.stringify(e)===JSON.stringify(t.attrs)));e=Boolean(s||!1)}return!0===e&&this.activeNodes.includes(t.name)},isButtonCurrent(t){return!!this.activeButton&&this.activeButton.id===t.id},isButtonDisabled(t){var e;if(null==(e=this.activeButton)?void 0:e.when){return!1===this.activeButton.when.includes(t.name)}return!1},needDividerAfterNode(t){let e=["paragraph"],s=Object.keys(this.nodeButtons);return(s.includes("bulletList")||s.includes("orderedList"))&&e.push("h6"),e.includes(t.id)}}},(function(){var t=this,e=t._self._c;return e("div",{staticClass:"k-writer-toolbar"},[t.hasVisibleButtons?e("k-dropdown",{nativeOn:{mousedown:function(t){t.preventDefault()}}},[e("k-button",{class:{"k-writer-toolbar-button k-writer-toolbar-nodes":!0,"k-writer-toolbar-button-active":!!t.activeButton},attrs:{icon:t.activeButton.icon||"title"},on:{click:function(e){return t.$refs.nodes.toggle()}}}),e("k-dropdown-content",{ref:"nodes"},[t._l(t.nodeButtons,(function(s,n){return[e("k-dropdown-item",{key:n,attrs:{current:t.isButtonCurrent(s),disabled:t.isButtonDisabled(s),icon:s.icon},on:{click:function(e){return t.command(s.command||n)}}},[t._v(" "+t._s(s.label)+" ")]),t.needDividerAfterNode(s)?e("hr",{key:n+"-divider"}):t._e()]}))],2)],1):t._e(),t._l(t.markButtons,(function(s,n){return e("k-button",{key:n,class:{"k-writer-toolbar-button":!0,"k-writer-toolbar-button-active":t.activeMarks.includes(n)},attrs:{icon:s.icon,tooltip:s.label},on:{mousedown:function(e){return e.preventDefault(),t.command(s.command||n)}}})}))],2)}),[],!1,null,null,null,null).exports,We={props:{autofocus:Boolean,breaks:Boolean,code:Boolean,disabled:Boolean,emptyDocument:{type:Object,default:()=>({type:"doc",content:[]})},headings:[Array,Boolean],inline:{type:Boolean,default:!1},marks:{type:[Array,Boolean],default:!0},nodes:{type:[Array,Boolean],default:()=>["heading","bulletList","orderedList"]},paste:{type:Function,default:()=>()=>!1},placeholder:String,spellcheck:Boolean,extensions:Array,value:{type:String,default:""}}};const Xe=Mt({components:{"k-writer-email-dialog":Me,"k-writer-link-dialog":Ie,"k-writer-toolbar":Ve},mixins:[We],data(){return{editor:null,json:{},html:this.value,isEmpty:!0,toolbar:!1}},computed:{isParagraphNodeHidden(){return!0===Array.isArray(this.nodes)&&3!==this.nodes.length&&!1===this.nodes.includes("paragraph")}},watch:{value(t,e){t!==e&&t!==this.html&&(this.html=t,this.editor.setContent(this.html))}},mounted(){this.editor=new Te({autofocus:this.autofocus,content:this.value,editable:!this.disabled,element:this.$el,emptyDocument:this.emptyDocument,events:{link:t=>{this.$refs.linkDialog.open(t.getMarkAttrs("link"))},email:()=>{this.$refs.emailDialog.open(this.editor.getMarkAttrs("email"))},paste:this.paste,toolbar:t=>{this.toolbar=t,this.toolbar.visible&&this.$nextTick((()=>{this.onToolbarOpen()}))},update:t=>{if(!this.editor)return;const e=JSON.stringify(this.editor.getJSON());e!==JSON.stringify(this.json)&&(this.json=e,this.isEmpty=t.editor.isEmpty(),this.html=t.editor.getHTML(),this.isEmpty&&(0===t.editor.activeNodes.length||t.editor.activeNodes.includes("paragraph"))&&(this.html=""),this.$emit("input",this.html))}},extensions:[...this.createMarks(),...this.createNodes(),new Ke,new Ge,new Je,...this.extensions||[]],inline:this.inline}),this.isEmpty=this.editor.isEmpty(),this.json=this.editor.getJSON()},beforeDestroy(){this.editor.destroy()},methods:{filterExtensions(t,e,s){!1===e?e=[]:!0!==e&&!1!==Array.isArray(e)||(e=Object.keys(t));let n=[];return e.forEach((e=>{t[e]&&n.push(t[e])})),"function"==typeof s&&(n=s(e,n)),n},command(t,...e){this.editor.command(t,...e)},createMarks(){return this.filterExtensions({bold:new je,italic:new De,strike:new Ne,underline:new qe,code:new Le,link:new Be,email:new Pe},this.marks)},createNodes(){const t=new Re({text:!0,enter:this.inline});return!0===this.inline?[t]:this.filterExtensions({bulletList:new Fe,orderedList:new Ue,heading:new ze,horizontalRule:new Ye,listItem:new He},this.nodes,((e,s)=>((e.includes("bulletList")||e.includes("orderedList"))&&s.push(new He),s.push(t),s)))},getHTML(){return this.editor.getHTML()},focus(){this.editor.focus()},onToolbarOpen(){if(this.$refs.toolbar){const t=this.$el.clientWidth,e=this.$refs.toolbar.$el.clientWidth;let s=this.toolbar.position.left;s-e/2<0&&(s=s+(e/2-s)-20),s+e/2>t&&(s=s-(s+e/2-t)+20),s!==this.toolbar.position.left&&(this.$refs.toolbar.$el.style.left=s+"px")}}}},(function(){var t=this,e=t._self._c;return e("div",{directives:[{name:"direction",rawName:"v-direction"}],ref:"editor",staticClass:"k-writer",attrs:{"data-empty":t.isEmpty,"data-placeholder":t.placeholder,spellcheck:t.spellcheck}},[t.editor?[t.toolbar.visible?e("k-writer-toolbar",{ref:"toolbar",style:{bottom:t.toolbar.position.bottom+"px","inset-inline-start":t.toolbar.position.left+"px"},attrs:{editor:t.editor,"active-marks":t.toolbar.marks,"active-nodes":t.toolbar.nodes,"active-node-attrs":t.toolbar.nodeAttrs,"is-paragraph-node-hidden":t.isParagraphNodeHidden},on:{command:function(e){return t.editor.command(e)}}}):t._e(),e("k-writer-link-dialog",{ref:"linkDialog",on:{close:function(e){return t.editor.focus()},submit:function(e){return t.editor.command("toggleLink",e)}}}),e("k-writer-email-dialog",{ref:"emailDialog",on:{close:function(e){return t.editor.focus()},submit:function(e){return t.editor.command("toggleEmail",e)}}})]:t._e()],2)}),[],!1,null,null,null,null).exports;const Ze=Mt({},(function(){var t=this,e=t._self._c;return e("div",{staticClass:"k-login-alert",on:{click:function(e){return t.$emit("click")}}},[e("span",[t._t("default")],2),e("k-icon",{attrs:{type:"alert"}})],1)}),[],!1,null,null,null,null).exports;const Qe=Mt({props:{fields:Object,index:[Number,String],total:Number,value:Object},mounted(){this.$store.dispatch("content/disable"),this.$events.$on("keydown.cmd.s",this.onSubmit),this.$events.$on("keydown.esc",this.onDiscard)},destroyed(){this.$events.$off("keydown.cmd.s",this.onSubmit),this.$events.$off("keydown.esc",this.onDiscard),this.$store.dispatch("content/enable")},methods:{focus(t){this.$refs.form.focus(t)},onDiscard(){this.$emit("discard")},onInput(t){this.$emit("input",t)},onSubmit(){this.$emit("submit")}}},(function(){var t=this,e=t._self._c;return e("div",{staticClass:"k-structure-form"},[e("div",{staticClass:"k-structure-backdrop",on:{click:t.onDiscard}}),e("section",[e("k-form",{ref:"form",staticClass:"k-structure-form-fields",attrs:{value:t.value,fields:t.fields},on:{input:t.onInput,submit:t.onSubmit}}),e("footer",{staticClass:"k-structure-form-buttons"},[e("k-button",{staticClass:"k-structure-form-cancel-button",attrs:{text:t.$t("cancel"),icon:"cancel"},on:{click:function(e){return t.$emit("close")}}}),"new"!==t.index?e("k-pagination",{attrs:{dropdown:!1,total:t.total,limit:1,page:t.index+1,details:!0},on:{paginate:function(e){return t.$emit("paginate",e)}}}):t._e(),e("k-button",{staticClass:"k-structure-form-submit-button",attrs:{text:t.$t("new"!==t.index?"confirm":"add"),icon:"check"},on:{click:t.onSubmit}})],1)],1)])}),[],!1,null,null,null,null).exports,ts=function(t){this.command("insert",((e,s)=>{let n=[];return s.split("\n").forEach(((e,s)=>{let i="ol"===t?s+1+".":"-";n.push(i+" "+e)})),n.join("\n")}))};const es=Mt({layout:["headlines","bold","italic","|","link","email","file","|","code","ul","ol"],props:{buttons:{type:[Boolean,Array],default:!0},uploads:[Boolean,Object,Array]},data(){let t={},e={},s=[],n=this.commands();return!1===this.buttons?t:(Array.isArray(this.buttons)&&(s=this.buttons),!0!==Array.isArray(this.buttons)&&(s=this.$options.layout),s.forEach(((s,i)=>{if("|"===s)t["divider-"+i]={divider:!0};else if(n[s]){let i=n[s];t[s]=i,i.shortcut&&(e[i.shortcut]=s)}})),{layout:t,shortcuts:e})},methods:{command(t,e){"function"==typeof t?t.apply(this):this.$emit("command",t,e)},close(){Object.keys(this.$refs).forEach((t=>{const e=this.$refs[t][0];"function"==typeof(null==e?void 0:e.close)&&e.close()}))},fileCommandSetup(){let t={label:this.$t("toolbar.button.file"),icon:"attachment"};return!1===this.uploads?t.command="selectFile":t.dropdown={select:{label:this.$t("toolbar.button.file.select"),icon:"check",command:"selectFile"},upload:{label:this.$t("toolbar.button.file.upload"),icon:"upload",command:"uploadFile"}},t},commands(){return{headlines:{label:this.$t("toolbar.button.headings"),icon:"title",dropdown:{h1:{label:this.$t("toolbar.button.heading.1"),icon:"title",command:"prepend",args:"#"},h2:{label:this.$t("toolbar.button.heading.2"),icon:"title",command:"prepend",args:"##"},h3:{label:this.$t("toolbar.button.heading.3"),icon:"title",command:"prepend",args:"###"}}},bold:{label:this.$t("toolbar.button.bold"),icon:"bold",command:"wrap",args:"**",shortcut:"b"},italic:{label:this.$t("toolbar.button.italic"),icon:"italic",command:"wrap",args:"*",shortcut:"i"},link:{label:this.$t("toolbar.button.link"),icon:"url",shortcut:"k",command:"dialog",args:"link"},email:{label:this.$t("toolbar.button.email"),icon:"email",shortcut:"e",command:"dialog",args:"email"},file:this.fileCommandSetup(),code:{label:this.$t("toolbar.button.code"),icon:"code",command:"wrap",args:"`"},ul:{label:this.$t("toolbar.button.ul"),icon:"list-bullet",command(){return ts.apply(this,["ul"])}},ol:{label:this.$t("toolbar.button.ol"),icon:"list-numbers",command(){return ts.apply(this,["ol"])}}}},shortcut(t,e){if(this.shortcuts[t]){const s=this.layout[this.shortcuts[t]];if(!s)return!1;e.preventDefault(),this.command(s.command,s.args)}}}},(function(){var t=this,e=t._self._c;return e("nav",{staticClass:"k-toolbar"},[e("div",{staticClass:"k-toolbar-wrapper"},[e("div",{staticClass:"k-toolbar-buttons"},[t._l(t.layout,(function(s,n){return[s.divider?[e("span",{key:n,staticClass:"k-toolbar-divider"})]:s.dropdown?[e("k-dropdown",{key:n},[e("k-button",{key:n,staticClass:"k-toolbar-button",attrs:{icon:s.icon,tooltip:s.label,tabindex:"-1"},on:{click:function(e){t.$refs[n+"-dropdown"][0].toggle()}}}),e("k-dropdown-content",{ref:n+"-dropdown",refInFor:!0},t._l(s.dropdown,(function(s,n){return e("k-dropdown-item",{key:n,attrs:{icon:s.icon},on:{click:function(e){return t.command(s.command,s.args)}}},[t._v(" "+t._s(s.label)+" ")])})),1)],1)]:[e("k-button",{key:n,staticClass:"k-toolbar-button",attrs:{icon:s.icon,tooltip:s.label,tabindex:"-1"},on:{click:function(e){return t.command(s.command,s.args)}}})]]}))],2)])])}),[],!1,null,null,null,null).exports;const ss=Mt({data(){return{value:{email:null,text:null},fields:{email:{label:this.$t("email"),type:"email"},text:{label:this.$t("link.text"),type:"text"}}}},computed:{kirbytext(){return this.$config.kirbytext}},methods:{open(t,e){this.value.text=e,this.$refs.dialog.open()},cancel(){this.$emit("cancel")},createKirbytext(){var t;const e=this.value.email||"";return(null==(t=this.value.text)?void 0:t.length)>0?`(email: ${e} text: ${this.value.text})`:`(email: ${e})`},createMarkdown(){var t;const e=this.value.email||"";return(null==(t=this.value.text)?void 0:t.length)>0?`[${this.value.text}](mailto:${e})`:`<${e}>`},submit(){this.$emit("submit",this.kirbytext?this.createKirbytext():this.createMarkdown()),this.value={email:null,text:null},this.$refs.dialog.close()}}},(function(){var t=this,e=t._self._c;return e("k-dialog",{ref:"dialog",attrs:{"submit-button":t.$t("insert")},on:{close:t.cancel,submit:function(e){return t.$refs.form.submit()}}},[e("k-form",{ref:"form",attrs:{fields:t.fields},on:{submit:t.submit},model:{value:t.value,callback:function(e){t.value=e},expression:"value"}})],1)}),[],!1,null,null,null,null).exports;const ns=Mt({data(){return{value:{url:null,text:null},fields:{url:{label:this.$t("link"),type:"text",placeholder:this.$t("url.placeholder"),icon:"url"},text:{label:this.$t("link.text"),type:"text"}}}},computed:{kirbytext(){return this.$config.kirbytext}},methods:{open(t,e){this.value.text=e,this.$refs.dialog.open()},cancel(){this.$emit("cancel")},createKirbytext(){return this.value.text.length>0?`(link: ${this.value.url} text: ${this.value.text})`:`(link: ${this.value.url})`},createMarkdown(){return this.value.text.length>0?`[${this.value.text}](${this.value.url})`:`<${this.value.url}>`},submit(){this.$emit("submit",this.kirbytext?this.createKirbytext():this.createMarkdown()),this.value={url:null,text:null},this.$refs.dialog.close()}}},(function(){var t=this,e=t._self._c;return e("k-dialog",{ref:"dialog",attrs:{"submit-button":t.$t("insert")},on:{close:t.cancel,submit:function(e){return t.$refs.form.submit()}}},[e("k-form",{ref:"form",attrs:{fields:t.fields},on:{submit:t.submit},model:{value:t.value,callback:function(e){t.value=e},expression:"value"}})],1)}),[],!1,null,null,null,null).exports;const is=Mt({mixins:[Qt,ee,ne,oe,le],inheritAttrs:!1,props:{value:Boolean},watch:{value(){this.onInvalid()}},mounted(){this.onInvalid(),this.$props.autofocus&&this.focus()},methods:{focus(){this.$refs.input.focus()},onChange(t){this.$emit("input",t)},onInvalid(){this.$emit("invalid",this.$v.$invalid,this.$v)},select(){this.focus()}},validations(){return{value:{required:!this.required||P.required}}}},(function(){var t=this,e=t._self._c;return e("label",{staticClass:"k-checkbox-input",on:{click:function(t){t.stopPropagation()}}},[e("input",{ref:"input",staticClass:"k-checkbox-input-native input-hidden",attrs:{id:t.id,disabled:t.disabled,type:"checkbox"},domProps:{checked:t.value},on:{change:function(e){return t.onChange(e.target.checked)}}}),e("span",{staticClass:"k-checkbox-input-icon",attrs:{"aria-hidden":"true"}},[e("svg",{attrs:{width:"12",height:"10",viewBox:"0 0 12 10",xmlns:"http://www.w3.org/2000/svg"}},[e("path",{attrs:{d:"M1 5l3.3 3L11 1","stroke-width":"2",fill:"none","fill-rule":"evenodd"}})])]),e("span",{staticClass:"k-checkbox-input-label",domProps:{innerHTML:t._s(t.label)}})])}),[],!1,null,null,null,null).exports,os={mixins:[Qt,ee,ne,le],props:{columns:Number,max:Number,min:Number,options:Array,value:{type:[Array,Object],default:()=>[]}}};const rs=Mt({mixins:[os],inheritAttrs:!1,data(){return{selected:this.valueToArray(this.value)}},watch:{value(t){this.selected=this.valueToArray(t)},selected(){this.onInvalid()}},mounted(){this.onInvalid(),this.$props.autofocus&&this.focus()},methods:{focus(){this.$el.querySelector("input").focus()},onInput(t,e){if(!0===e)this.selected.push(t);else{const e=this.selected.indexOf(t);-1!==e&&this.selected.splice(e,1)}this.$emit("input",this.selected)},onInvalid(){this.$emit("invalid",this.$v.$invalid,this.$v)},select(){this.focus()},valueToArray:t=>!0===Array.isArray(t)?t:"string"==typeof t?String(t).split(","):"object"==typeof t?Object.values(t):void 0},validations(){return{selected:{required:!this.required||P.required,min:!this.min||P.minLength(this.min),max:!this.max||P.maxLength(this.max)}}}},(function(){var t=this,e=t._self._c;return e("ul",{staticClass:"k-checkboxes-input",style:"--columns:"+t.columns},t._l(t.options,(function(s,n){return e("li",{key:n},[e("k-checkbox-input",{attrs:{id:t.id+"-"+n,label:s.text,value:-1!==t.selected.indexOf(s.value)},on:{input:function(e){return t.onInput(s.value,e)}}})],1)})),0)}),[],!1,null,null,null,null).exports,ls={mixins:[Qt,ee,ne,le],props:{display:{type:String,default:"DD.MM.YYYY"},max:String,min:String,step:{type:Object,default:()=>({size:1,unit:"day"})},type:{type:String,default:"date"},value:String}};const as=Mt({mixins:[ls],inheritAttrs:!1,data:()=>({dt:null,formatted:null}),computed:{inputType:()=>"date",pattern(){return this.$library.dayjs.pattern(this.display)},rounding(){return{...this.$options.props.step.default(),...this.step}}},watch:{value:{handler(t,e){if(t!==e){const e=this.toDatetime(t);this.commit(e)}},immediate:!0}},created(){this.$events.$on("keydown.cmd.s",this.onBlur)},destroyed(){this.$events.$off("keydown.cmd.s",this.onBlur)},methods:{alter(t){let e=this.parse()||this.round(this.$library.dayjs()),s=this.rounding.unit,n=this.rounding.size;const i=this.selection();null!==i&&("meridiem"===i.unit?(t="pm"===e.format("a")?"subtract":"add",s="hour",n=12):(s=i.unit,s!==this.rounding.unit&&(n=1))),e=e[t](n,s).round(this.rounding.unit,this.rounding.size),this.commit(e),this.emit(e),this.$nextTick((()=>this.select(i)))},commit(t){this.dt=t,this.formatted=this.pattern.format(t),this.$emit("invalid",this.$v.$invalid,this.$v)},emit(t){this.$emit("input",this.toISO(t))},focus(){this.$refs.input.focus()},onArrowDown(){this.alter("subtract")},onArrowUp(){this.alter("add")},onBlur(){const t=this.parse();this.commit(t),this.emit(t)},onEnter(){this.onBlur(),this.$nextTick((()=>this.$emit("submit")))},onInput(t){const e=this.parse(),s=this.pattern.format(e);if(!t||s==t)return this.commit(e),this.emit(e)},onTab(t){""!=this.$refs.input.value&&(this.onBlur(),this.$nextTick((()=>{const e=this.selection();if(this.$refs.input&&e.start===this.$refs.input.selectionStart&&e.end===this.$refs.input.selectionEnd-1)if(t.shiftKey){if(0===e.index)return;this.selectPrev(e.index)}else{if(e.index===this.pattern.parts.length-1)return;this.selectNext(e.index)}else t.shiftKey?this.selectLast():this.selectFirst();t.preventDefault()})))},parse(){let t=this.$refs.input.value;return t=this.$library.dayjs.interpret(t,this.inputType),this.round(t)},round(t){return(null==t?void 0:t.round(this.rounding.unit,this.rounding.size))||null},select(t){var e;t||(t=this.selection()),null==(e=this.$refs.input)||e.setSelectionRange(t.start,t.end+1)},selectFirst(){this.select(this.pattern.parts[0])},selectLast(){this.select(this.pattern.parts[this.pattern.parts.length-1])},selectNext(t){this.select(this.pattern.parts[t+1])},selectPrev(t){this.select(this.pattern.parts[t-1])},selection(){return this.pattern.at(this.$refs.input.selectionStart,this.$refs.input.selectionEnd)},toDatetime(t){return this.round(this.$library.dayjs.iso(t,this.inputType))},toISO(t){return(null==t?void 0:t.toISO(this.inputType))||null}},validations(){return{value:{min:!this.dt||!this.min||(()=>this.dt.validate(this.min,"min",this.rounding.unit)),max:!this.dt||!this.max||(()=>this.dt.validate(this.max,"max",this.rounding.unit)),required:!this.required||(()=>!!this.dt)}}}},(function(){var t=this;return(0,t._self._c)("input",{directives:[{name:"model",rawName:"v-model",value:t.formatted,expression:"formatted"},{name:"direction",rawName:"v-direction"}],ref:"input",class:`k-text-input k-${t.type}-input`,attrs:{id:t.id,autofocus:t.autofocus,disabled:t.disabled,placeholder:t.display,required:t.required,autocomplete:"off",spellcheck:"false",type:"text"},domProps:{value:t.formatted},on:{blur:t.onBlur,focus:function(e){return t.$emit("focus")},input:[function(e){e.target.composing||(t.formatted=e.target.value)},function(e){return t.onInput(e.target.value)}],keydown:[function(e){return!e.type.indexOf("key")&&t._k(e.keyCode,"down",40,e.key,["Down","ArrowDown"])?null:(e.stopPropagation(),e.preventDefault(),t.onArrowDown.apply(null,arguments))},function(e){return!e.type.indexOf("key")&&t._k(e.keyCode,"up",38,e.key,["Up","ArrowUp"])?null:(e.stopPropagation(),e.preventDefault(),t.onArrowUp.apply(null,arguments))},function(e){return!e.type.indexOf("key")&&t._k(e.keyCode,"enter",13,e.key,"Enter")?null:(e.stopPropagation(),e.preventDefault(),t.onEnter.apply(null,arguments))},function(e){return!e.type.indexOf("key")&&t._k(e.keyCode,"tab",9,e.key,"Tab")?null:t.onTab.apply(null,arguments)}]}})}),[],!1,null,null,null,null).exports,us={mixins:[Qt,ee,ne,re,le],props:{autocomplete:{type:[Boolean,String],default:"off"},maxlength:Number,minlength:Number,pattern:String,placeholder:String,preselect:Boolean,spellcheck:{type:[Boolean,String],default:"off"},type:{type:String,default:"text"},value:String}};const cs=Mt({mixins:[us],inheritAttrs:!1,data(){return{listeners:{...this.$listeners,input:t=>this.onInput(t.target.value)}}},watch:{value(){this.onInvalid()}},mounted(){this.onInvalid(),this.$props.autofocus&&this.focus(),this.$props.preselect&&this.select()},methods:{focus(){this.$refs.input.focus()},onInput(t){this.$emit("input",t)},onInvalid(){this.$emit("invalid",this.$v.$invalid,this.$v)},select(){this.$refs.input.select()}},validations(){return{value:{required:!this.required||P.required,minLength:!this.minlength||P.minLength(this.minlength),maxLength:!this.maxlength||P.maxLength(this.maxlength),email:"email"!==this.type||P.email,url:"url"!==this.type||P.url,pattern:!this.pattern||(t=>!this.required&&!t||!this.$refs.input.validity.patternMismatch)}}}},(function(){var t=this;return(0,t._self._c)("input",t._g(t._b({directives:[{name:"direction",rawName:"v-direction"}],ref:"input",staticClass:"k-text-input"},"input",{autocomplete:t.autocomplete,autofocus:t.autofocus,disabled:t.disabled,id:t.id,minlength:t.minlength,name:t.name,pattern:t.pattern,placeholder:t.placeholder,required:t.required,spellcheck:t.spellcheck,type:t.type,value:t.value},!1),t.listeners))}),[],!1,null,null,null,null).exports,ds={mixins:[us],props:{autocomplete:{type:String,default:"email"},placeholder:{type:String,default:()=>window.panel.$t("email.placeholder")},type:{type:String,default:"email"}}};const ps=Mt({extends:cs,mixins:[ds]},null,null,!1,null,null,null,null).exports;class hs extends Ce{get schema(){return{content:"bulletList|orderedList"}}}const ms=Mt({inheritAttrs:!1,props:{autofocus:Boolean,marks:{type:[Array,Boolean],default:!0},value:String},data(){return{list:this.value,html:this.value}},computed:{extensions:()=>[new hs({inline:!0})]},watch:{value(t){t!==this.html&&(this.list=t,this.html=t)}},methods:{focus(){this.$refs.input.focus()},onInput(t){let e=(new DOMParser).parseFromString(t,"text/html").querySelector("ul, ol");e&&0!==e.textContent.trim().length?(this.list=t,this.html=t.replace(/(

|<\/p>)/gi,""),this.$emit("input",this.html)):this.$emit("input",this.list="")}}},(function(){var t=this;return(0,t._self._c)("k-writer",t._b({ref:"input",staticClass:"k-list-input",attrs:{extensions:t.extensions,nodes:["bulletList","orderedList"],value:t.list},on:{input:t.onInput}},"k-writer",t.$props,!1))}),[],!1,null,null,null,null).exports,fs={mixins:[ee,ne,le],props:{max:Number,min:Number,layout:String,options:{type:Array,default:()=>[]},search:[Object,Boolean],separator:{type:String,default:","},sort:Boolean,value:{type:Array,required:!0,default:()=>[]}}};const gs=Mt({mixins:[fs],inheritAttrs:!1,data(){return{state:this.value,q:null,limit:!0,scrollTop:0}},computed:{draggable(){return this.state.length>1&&!this.sort},dragOptions(){return{disabled:!this.draggable,draggable:".k-tag",delay:1}},emptyLabel(){return this.q?this.$t("search.results.none"):this.$t("options.none")},filtered(){var t;return(null==(t=this.q)?void 0:t.length)>=(this.search.min||0)?this.options.filter((t=>this.isFiltered(t))).map((t=>({...t,display:this.toHighlightedString(t.text),info:this.toHighlightedString(t.value)}))):this.options.map((t=>({...t,display:t.text,info:t.value})))},more(){return!this.max||this.state.lengththis.options.findIndex((e=>e.value===t.value));return t.sort(((t,s)=>e(t)-e(s)))},visible(){return this.limit?this.filtered.slice(0,this.search.display||this.filtered.length):this.filtered}},watch:{value(t){this.state=t,this.onInvalid()}},mounted(){this.onInvalid(),this.$events.$on("click",this.close),this.$events.$on("keydown.cmd.s",this.close)},destroyed(){this.$events.$off("click",this.close),this.$events.$off("keydown.cmd.s",this.close)},methods:{add(t){!0===this.more&&(this.state.push(t),this.onInput())},blur(){this.close()},close(){!0===this.$refs.dropdown.isOpen&&(this.$refs.dropdown.close(),this.limit=!0)},escape(){this.q?this.q=null:this.close()},focus(){this.$refs.dropdown.open()},index(t){return this.state.findIndex((e=>e.value===t.value))},isFiltered(t){return String(t.text).match(this.regex)||String(t.value).match(this.regex)},isSelected(t){return-1!==this.index(t)},navigate(t){var e,s,n;"prev"===t&&(t="previous"),null==(n=null==(s=null==(e=document.activeElement)?void 0:e[t+"Sibling"])?void 0:s.focus)||n.call(s)},onClose(){!1===this.$refs.dropdown.isOpen&&(document.activeElement===this.$parent.$el&&(this.q=null),this.$parent.$el.focus())},onInput(){this.$emit("input",this.sorted)},onInvalid(){this.$emit("invalid",this.$v.$invalid,this.$v)},onOpen(){this.$nextTick((()=>{var t,e;null==(e=null==(t=this.$refs.search)?void 0:t.focus)||e.call(t),this.$refs.dropdown.$el.querySelector(".k-multiselect-options").scrollTop=this.scrollTop}))},remove(t){this.state.splice(this.index(t),1),this.onInput()},select(t){this.scrollTop=this.$refs.dropdown.$el.querySelector(".k-multiselect-options").scrollTop,t={text:t.text,value:t.value},this.isSelected(t)?this.remove(t):this.add(t)},toHighlightedString(t){return(t=this.$helper.string.stripHTML(t)).replace(this.regex,"$1")}},validations(){return{state:{required:!this.required||P.required,minLength:!this.min||P.minLength(this.min),maxLength:!this.max||P.maxLength(this.max)}}}},(function(){var t=this,e=t._self._c;return e("k-draggable",{staticClass:"k-multiselect-input",attrs:{list:t.state,options:t.dragOptions,"data-layout":t.layout,element:"k-dropdown"},on:{end:t.onInput},nativeOn:{click:function(e){return t.$refs.dropdown.toggle.apply(null,arguments)}},scopedSlots:t._u([{key:"footer",fn:function(){return[e("k-dropdown-content",{ref:"dropdown",on:{open:t.onOpen,close:t.onClose},nativeOn:{keydown:function(e){return!e.type.indexOf("key")&&t._k(e.keyCode,"esc",27,e.key,["Esc","Escape"])?null:(e.stopPropagation(),t.close.apply(null,arguments))}}},[t.search?e("k-dropdown-item",{staticClass:"k-multiselect-search",attrs:{icon:"search"}},[e("input",{directives:[{name:"model",rawName:"v-model",value:t.q,expression:"q"}],ref:"search",attrs:{placeholder:t.search.min?t.$t("search.min",{min:t.search.min}):t.$t("search")+" …"},domProps:{value:t.q},on:{keydown:function(e){return!e.type.indexOf("key")&&t._k(e.keyCode,"esc",27,e.key,["Esc","Escape"])?null:(e.stopPropagation(),t.escape.apply(null,arguments))},input:function(e){e.target.composing||(t.q=e.target.value)}}})]):t._e(),e("div",{staticClass:"k-multiselect-options scroll-y-auto"},[t._l(t.visible,(function(s){return e("k-dropdown-item",{key:s.value,class:{"k-multiselect-option":!0,selected:t.isSelected(s),disabled:!t.more},attrs:{icon:t.isSelected(s)?"check":"circle-outline"},on:{click:function(e){return e.preventDefault(),t.select(s)}},nativeOn:{keydown:[function(e){return!e.type.indexOf("key")&&t._k(e.keyCode,"enter",13,e.key,"Enter")?null:(e.preventDefault(),e.stopPropagation(),t.select(s))},function(e){return!e.type.indexOf("key")&&t._k(e.keyCode,"space",32,e.key,[" ","Spacebar"])?null:(e.preventDefault(),e.stopPropagation(),t.select(s))}]}},[e("span",{domProps:{innerHTML:t._s(s.display)}}),e("span",{staticClass:"k-multiselect-value",domProps:{innerHTML:t._s(s.info)}})])})),0===t.filtered.length?e("k-dropdown-item",{staticClass:"k-multiselect-option",attrs:{disabled:!0}},[t._v(" "+t._s(t.emptyLabel)+" ")]):t._e()],2),t.visible.lengththis.onInput(t.target.value),blur:this.onBlur}}},watch:{value(t){this.number=t},number:{immediate:!0,handler(){this.onInvalid()}}},mounted(){this.$props.autofocus&&this.focus(),this.$props.preselect&&this.select()},methods:{decimals(){const t=Number(this.step||0);return Math.floor(t)===t?0:-1!==t.toString().indexOf("e")?parseInt(t.toFixed(16).split(".")[1].split("").reverse().join("")).toString().length:t.toString().split(".")[1].length||0},format(t){if(isNaN(t)||""===t)return"";const e=this.decimals();return t=e?parseFloat(t).toFixed(e):Number.isInteger(this.step)?parseInt(t):parseFloat(t)},clean(){this.number=this.format(this.number)},emit(t){t=parseFloat(t),isNaN(t)&&(t=""),t!==this.value&&this.$emit("input",t)},focus(){this.$refs.input.focus()},onInvalid(){this.$emit("invalid",this.$v.$invalid,this.$v)},onInput(t){this.number=t,this.emit(t)},onBlur(){this.clean(),this.emit(this.number)},select(){this.$refs.input.select()}},validations(){return{value:{required:!this.required||P.required,min:!this.min||P.minValue(this.min),max:!this.max||P.maxValue(this.max)}}}},(function(){var t=this;return(0,t._self._c)("input",t._g(t._b({ref:"input",staticClass:"k-number-input",attrs:{step:t.stepNumber,type:"number"},domProps:{value:t.number},on:{keydown:[function(e){return!e.type.indexOf("key")&&t._k(e.keyCode,"s",void 0,e.key,void 0)?null:e.ctrlKey?t.clean.apply(null,arguments):null},function(e){return!e.type.indexOf("key")&&t._k(e.keyCode,"s",void 0,e.key,void 0)?null:e.metaKey?t.clean.apply(null,arguments):null}]}},"input",{autofocus:t.autofocus,disabled:t.disabled,id:t.id,max:t.max,min:t.min,name:t.name,placeholder:t.placeholder,required:t.required},!1),t.listeners))}),[],!1,null,null,null,null).exports,ys={mixins:[us],props:{autocomplete:{type:String,default:"new-password"},type:{type:String,default:"password"}}};const vs=Mt({extends:cs,mixins:[ys]},null,null,!1,null,null,null,null).exports,$s={mixins:[Qt,ee,ne,le],props:{columns:Number,options:Array,value:[String,Number,Boolean]}};const _s=Mt({mixins:[$s],inheritAttrs:!1,watch:{value(){this.onInvalid()}},mounted(){this.onInvalid(),this.$props.autofocus&&this.focus()},methods:{focus(){this.$el.querySelector("input").focus()},onInput(t){this.$emit("input",t)},onInvalid(){this.$emit("invalid",this.$v.$invalid,this.$v)},select(){this.focus()}},validations(){return{value:{required:!this.required||P.required}}}},(function(){var t=this,e=t._self._c;return e("ul",{staticClass:"k-radio-input",style:"--columns:"+t.columns},t._l(t.options,(function(s,n){return e("li",{key:n},[e("input",{staticClass:"k-radio-input-native",attrs:{id:t.id+"-"+n,name:t.id,type:"radio"},domProps:{value:s.value,checked:t.value===s.value},on:{change:function(e){return t.onInput(s.value)}}}),s.info?e("label",{attrs:{for:t.id+"-"+n}},[e("span",{staticClass:"k-radio-input-text",domProps:{innerHTML:t._s(s.text)}}),e("span",{staticClass:"k-radio-input-info",domProps:{innerHTML:t._s(s.info)}})]):e("label",{attrs:{for:t.id+"-"+n},domProps:{innerHTML:t._s(s.text)}}),s.icon?e("k-icon",{attrs:{type:s.icon}}):t._e()],1)})),0)}),[],!1,null,null,null,null).exports,xs={mixins:[Qt,ee,ne,re,le],props:{default:[Number,String],max:{type:Number,default:100},min:{type:Number,default:0},step:{type:Number,default:1},tooltip:{type:[Boolean,Object],default:()=>({before:null,after:null})},value:[Number,String]}};const ws=Mt({mixins:[xs],inheritAttrs:!1,data(){return{listeners:{...this.$listeners,input:t=>this.onInput(t.target.value)}}},computed:{baseline(){return this.min<0?0:this.min},label(){return this.required||this.value||0===this.value?this.format(this.position):"–"},position(){return this.value||0===this.value?this.value:this.default||this.baseline}},watch:{position(){this.onInvalid()}},mounted(){this.onInvalid(),this.$props.autofocus&&this.focus()},methods:{focus(){this.$refs.input.focus()},format(t){const e=document.lang?document.lang.replace("_","-"):"en",s=this.step.toString().split("."),n=s.length>1?s[1].length:0;return new Intl.NumberFormat(e,{minimumFractionDigits:n}).format(t)},onInvalid(){this.$emit("invalid",this.$v.$invalid,this.$v)},onInput(t){this.$emit("input",t)}},validations(){return{position:{required:!this.required||P.required,min:!this.min||P.minValue(this.min),max:!this.max||P.maxValue(this.max)}}}},(function(){var t=this,e=t._self._c;return e("label",{staticClass:"k-range-input"},[e("input",t._g(t._b({ref:"input",staticClass:"k-range-input-native",style:`--min: ${t.min}; --max: ${t.max}; --value: ${t.position}`,attrs:{type:"range"},domProps:{value:t.position}},"input",{autofocus:t.autofocus,disabled:t.disabled,id:t.id,max:t.max,min:t.min,name:t.name,required:t.required,step:t.step},!1),t.listeners)),t.tooltip?e("span",{staticClass:"k-range-input-tooltip"},[t.tooltip.before?e("span",{staticClass:"k-range-input-tooltip-before"},[t._v(t._s(t.tooltip.before))]):t._e(),e("span",{staticClass:"k-range-input-tooltip-text"},[t._v(t._s(t.label))]),t.tooltip.after?e("span",{staticClass:"k-range-input-tooltip-after"},[t._v(t._s(t.tooltip.after))]):t._e()]):t._e()])}),[],!1,null,null,null,null).exports,Ss={mixins:[Qt,ee,ne,re,le],props:{ariaLabel:String,default:String,empty:{type:[Boolean,String],default:!0},placeholder:String,options:{type:Array,default:()=>[]},value:{type:[String,Number,Boolean],default:""}}};const Cs=Mt({mixins:[Ss],inheritAttrs:!1,data(){return{selected:this.value,listeners:{...this.$listeners,click:t=>this.onClick(t),change:t=>this.onInput(t.target.value),input:()=>{}}}},computed:{emptyOption(){return this.placeholder||"—"},hasEmptyOption(){return!1!==this.empty&&!(this.required&&this.default)},label(){const t=this.text(this.selected);return""===this.selected||null===this.selected||null===t?this.emptyOption:t}},watch:{value(t){this.selected=t,this.onInvalid()}},mounted(){this.onInvalid(),this.$props.autofocus&&this.focus()},methods:{focus(){this.$refs.input.focus()},onClick(t){t.stopPropagation(),this.$emit("click",t)},onInvalid(){this.$emit("invalid",this.$v.$invalid,this.$v)},onInput(t){this.selected=t,this.$emit("input",this.selected)},select(){this.focus()},text(t){let e=null;return this.options.forEach((s=>{s.value==t&&(e=s.text)})),e}},validations(){return{selected:{required:!this.required||P.required}}}},(function(){var t=this,e=t._self._c;return e("span",{staticClass:"k-select-input",attrs:{"data-disabled":t.disabled,"data-empty":""===t.selected}},[e("select",t._g({ref:"input",staticClass:"k-select-input-native",attrs:{id:t.id,autofocus:t.autofocus,"aria-label":t.ariaLabel,disabled:t.disabled,name:t.name,required:t.required},domProps:{value:t.selected}},t.listeners),[t.hasEmptyOption?e("option",{attrs:{disabled:t.required,value:""}},[t._v(" "+t._s(t.emptyOption)+" ")]):t._e(),t._l(t.options,(function(s){return e("option",{key:s.value,attrs:{disabled:s.disabled},domProps:{value:s.value}},[t._v(" "+t._s(s.text)+" ")])}))],2),t._v(" "+t._s(t.label)+" ")])}),[],!1,null,null,null,null).exports,Os={mixins:[us],props:{allow:{type:String,default:""},formData:{type:Object,default:()=>({})},sync:{type:String}}};const As=Mt({extends:cs,mixins:[Os],data(){return{slug:this.sluggify(this.value),slugs:this.$language?this.$language.rules:this.$system.slugs,syncValue:null}},watch:{formData:{handler(t){return!this.disabled&&(!(!this.sync||void 0===t[this.sync])&&(t[this.sync]!=this.syncValue&&(this.syncValue=t[this.sync],void this.onInput(this.sluggify(this.syncValue)))))},deep:!0,immediate:!0},value(t){(t=this.sluggify(t))!==this.slug&&(this.slug=t,this.$emit("input",this.slug))}},methods:{sluggify(t){return this.$helper.slug(t,[this.slugs,this.$system.ascii],this.allow)},onInput(t){this.slug=this.sluggify(t),this.$emit("input",this.slug)}}},(function(){var t=this;return(0,t._self._c)("input",t._g(t._b({directives:[{name:"direction",rawName:"v-direction"}],ref:"input",staticClass:"k-text-input",attrs:{autocomplete:"off",spellcheck:"false",type:"text"},domProps:{value:t.slug}},"input",{autofocus:t.autofocus,disabled:t.disabled,id:t.id,minlength:t.minlength,name:t.name,pattern:t.pattern,placeholder:t.placeholder,required:t.required},!1),t.listeners))}),[],!1,null,null,null,null).exports,Ts={mixins:[Qt,ee,ne,re,le],props:{accept:{type:String,default:"all"},icon:{type:[String,Boolean],default:"tag"},layout:String,max:Number,min:Number,options:{type:Array,default:()=>[]},separator:{type:String,default:","},value:{type:Array,default:()=>[]}}};const Is=Mt({mixins:[Ts],inheritAttrs:!1,data(){return{tags:this.prepareTags(this.value),selected:null,newTag:null,tagOptions:this.options.map((t=>{var e;return(null==(e=this.icon)?void 0:e.length)>0&&(t.icon=this.icon),t}),this)}},computed:{dragOptions(){return{delay:1,disabled:!this.draggable,draggable:".k-tag"}},draggable(){return this.tags.length>1},skip(){return this.tags.map((t=>t.value))}},watch:{value(t){this.tags=this.prepareTags(t),this.onInvalid()}},mounted(){this.onInvalid(),this.$props.autofocus&&this.focus()},methods:{addString(t){if(t)if((t=t.trim()).includes(this.separator))t.split(this.separator).forEach((t=>{this.addString(t)}));else if(0!==t.length)if("options"===this.accept){const e=this.options.filter((e=>e.text===t))[0];if(!e)return;this.addTag(e)}else this.addTag({text:t,value:t})},addTag(t){this.addTagToIndex(t),this.$refs.autocomplete.close(),this.$refs.input.focus()},addTagToIndex(t){if("options"===this.accept){if(!this.options.filter((e=>e.value===t.value))[0])return}-1===this.index(t)&&(!this.max||this.tags.length=this.tags.length)return;break;case"first":e=0;break;case"last":e=this.tags.length-1;break;default:e=t}let n=this.tags[e];if(n){let t=this.$refs[n.value];if(null==t?void 0:t[0])return{ref:t[0],tag:n,index:e}}return!1},index(t){return this.tags.findIndex((e=>e.value===t.value))},onInput(){this.$emit("input",this.tags)},onInvalid(){this.$emit("invalid",this.$v.$invalid,this.$v)},leaveInput(t){0===t.target.selectionStart&&t.target.selectionStart===t.target.selectionEnd&&0!==this.tags.length&&(this.$refs.autocomplete.close(),this.navigate("last"),t.preventDefault())},navigate(t){var e=this.get(t);e?(e.ref.focus(),this.selectTag(e.tag)):"next"===t&&(this.$refs.input.focus(),this.selectTag(null))},prepareTags:t=>!1===Array.isArray(t)?[]:t.map((t=>"string"==typeof t?{text:t,value:t}:t)),remove(t){const e=this.get("prev"),s=this.get("next");this.tags.splice(this.index(t),1),this.onInput(),e?(this.selectTag(e.tag),e.ref.focus()):s?this.selectTag(s.tag):(this.selectTag(null),this.$refs.input.focus())},select(){this.focus()},selectTag(t){this.selected=t},tab(t){var e;(null==(e=this.newTag)?void 0:e.length)>0&&(t.preventDefault(),this.addString(this.newTag))},type(t){this.newTag=t,this.$refs.autocomplete.search(t)}},validations(){return{tags:{required:!this.required||P.required,minLength:!this.min||P.minLength(this.min),maxLength:!this.max||P.maxLength(this.max)}}}},(function(){var t=this,e=t._self._c;return e("k-draggable",{directives:[{name:"direction",rawName:"v-direction"}],ref:"box",staticClass:"k-tags-input",attrs:{list:t.tags,"data-layout":t.layout,options:t.dragOptions},on:{end:t.onInput},scopedSlots:t._u([{key:"footer",fn:function(){return[e("span",{staticClass:"k-tags-input-element"},[e("k-autocomplete",{ref:"autocomplete",attrs:{html:!0,options:t.options,skip:t.skip},on:{select:t.addTag,leave:function(e){return t.$refs.input.focus()}}},[e("input",{directives:[{name:"model",rawName:"v-model.trim",value:t.newTag,expression:"newTag",modifiers:{trim:!0}}],ref:"input",attrs:{id:t.id,autofocus:t.autofocus,disabled:t.disabled||t.max&&t.tags.length>=t.max,name:t.name,autocomplete:"off",type:"text"},domProps:{value:t.newTag},on:{input:[function(e){e.target.composing||(t.newTag=e.target.value.trim())},function(e){return t.type(e.target.value)}],blur:[t.blurInput,function(e){return t.$forceUpdate()}],keydown:[function(e){return!e.type.indexOf("key")&&t._k(e.keyCode,"s",void 0,e.key,void 0)?null:e.metaKey?t.blurInput.apply(null,arguments):null},function(e){return!e.type.indexOf("key")&&t._k(e.keyCode,"left",37,e.key,["Left","ArrowLeft"])||"button"in e&&0!==e.button||e.ctrlKey||e.shiftKey||e.altKey||e.metaKey?null:t.leaveInput.apply(null,arguments)},function(e){return!e.type.indexOf("key")&&t._k(e.keyCode,"enter",13,e.key,"Enter")||e.ctrlKey||e.shiftKey||e.altKey||e.metaKey?null:t.enter.apply(null,arguments)},function(e){return!e.type.indexOf("key")&&t._k(e.keyCode,"tab",9,e.key,"Tab")||e.ctrlKey||e.shiftKey||e.altKey||e.metaKey?null:t.tab.apply(null,arguments)},function(e){return!e.type.indexOf("key")&&t._k(e.keyCode,"backspace",void 0,e.key,void 0)||e.ctrlKey||e.shiftKey||e.altKey||e.metaKey?null:t.leaveInput.apply(null,arguments)}]}})])],1)]},proxy:!0}])},t._l(t.tags,(function(s,n){return e("k-tag",{key:n,ref:s.value,refInFor:!0,attrs:{removable:!t.disabled,name:"tag"},on:{remove:function(e){return t.remove(s)}},nativeOn:{click:function(t){t.stopPropagation()},blur:function(e){return t.selectTag(null)},focus:function(e){return t.selectTag(s)},keydown:[function(e){return!e.type.indexOf("key")&&t._k(e.keyCode,"left",37,e.key,["Left","ArrowLeft"])||"button"in e&&0!==e.button?null:t.navigate("prev")},function(e){return!e.type.indexOf("key")&&t._k(e.keyCode,"right",39,e.key,["Right","ArrowRight"])||"button"in e&&2!==e.button?null:t.navigate("next")}],dblclick:function(e){return t.edit(s)}}},[t._v(" "+t._s(s.text)+" ")])})),1)}),[],!1,null,null,null,null).exports,Ms={mixins:[us],props:{autocomplete:{type:String,default:"tel"},type:{type:String,default:"tel"}}};const Es=Mt({extends:cs,mixins:[Ms]},null,null,!1,null,null,null,null).exports,Ls={mixins:[Qt,ee,ne,re,le],props:{buttons:{type:[Boolean,Array],default:!0},endpoints:Object,font:String,maxlength:Number,minlength:Number,placeholder:String,preselect:Boolean,size:String,spellcheck:{type:[Boolean,String],default:"off"},theme:String,uploads:[Boolean,Object,Array],value:String}};const js=Mt({mixins:[Ls],inheritAttrs:!1,data:()=>({over:!1}),watch:{value(){this.onInvalid(),this.$nextTick((()=>{this.resize()}))}},mounted(){this.$nextTick((()=>{this.$library.autosize(this.$refs.input)})),this.onInvalid(),this.$props.autofocus&&this.focus(),this.$props.preselect&&this.select()},methods:{cancel(){this.$refs.input.focus()},dialog(t){if(!this.$refs[t+"Dialog"])throw"Invalid toolbar dialog";this.$refs[t+"Dialog"].open(this.$refs.input,this.selection())},focus(){this.$refs.input.focus()},insert(t){const e=this.$refs.input,s=e.value;setTimeout((()=>{if(e.focus(),document.execCommand("insertText",!1,t),e.value===s){const s=e.value.slice(0,e.selectionStart)+t+e.value.slice(e.selectionEnd);e.value=s,this.$emit("input",s)}})),this.resize()},insertFile(t){(null==t?void 0:t.length)>0&&this.insert(t.map((t=>t.dragText)).join("\n\n"))},insertUpload(t,e){this.insert(e.map((t=>t.dragText)).join("\n\n")),this.$events.$emit("model.update")},onClick(){this.$refs.toolbar&&this.$refs.toolbar.close()},onCommand(t,e){"function"==typeof this[t]?"function"==typeof e?this[t](e(this.$refs.input,this.selection())):this[t](e):window.console.warn(t+" is not a valid command")},onDrop(t){if(this.uploads&&this.$helper.isUploadEvent(t))return this.$refs.fileUpload.drop(t.dataTransfer.files,{url:this.$urls.api+"/"+this.endpoints.field+"/upload",multiple:!1});const e=this.$store.state.drag;"text"===(null==e?void 0:e.type)&&(this.focus(),this.insert(e.data))},onFocus(t){this.$emit("focus",t)},onInput(t){this.$emit("input",t.target.value)},onInvalid(){this.$emit("invalid",this.$v.$invalid,this.$v)},onOut(){this.$refs.input.blur(),this.over=!1},onOver(t){if(this.uploads&&this.$helper.isUploadEvent(t))return t.dataTransfer.dropEffect="copy",this.focus(),void(this.over=!0);const e=this.$store.state.drag;"text"===(null==e?void 0:e.type)&&(t.dataTransfer.dropEffect="copy",this.focus(),this.over=!0)},onShortcut(t){!1!==this.buttons&&"Meta"!==t.key&&"Control"!==t.key&&this.$refs.toolbar&&this.$refs.toolbar.shortcut(t.key,t)},onSubmit(t){return this.$emit("submit",t)},prepend(t){this.insert(t+" "+this.selection())},resize(){this.$library.autosize.update(this.$refs.input)},select(){this.$refs.select()},selectFile(){this.$refs.fileDialog.open({endpoint:this.endpoints.field+"/files",multiple:!1})},selection(){const t=this.$refs.input,e=t.selectionStart,s=t.selectionEnd;return t.value.substring(e,s)},uploadFile(){this.$refs.fileUpload.open({url:this.$urls.api+"/"+this.endpoints.field+"/upload",multiple:!1})},wrap(t){this.insert(t+this.selection()+t)}},validations(){return{value:{required:!this.required||P.required,minLength:!this.minlength||P.minLength(this.minlength),maxLength:!this.maxlength||P.maxLength(this.maxlength)}}}},(function(){var t=this,e=t._self._c;return e("div",{staticClass:"k-textarea-input",attrs:{"data-over":t.over,"data-size":t.size,"data-theme":t.theme}},[e("div",{staticClass:"k-textarea-input-wrapper"},[t.buttons&&!t.disabled?e("k-toolbar",{ref:"toolbar",attrs:{buttons:t.buttons,disabled:t.disabled,uploads:t.uploads},on:{command:t.onCommand},nativeOn:{mousedown:function(t){t.preventDefault()}}}):t._e(),e("textarea",t._b({directives:[{name:"direction",rawName:"v-direction"}],ref:"input",staticClass:"k-textarea-input-native",attrs:{"data-font":t.font},on:{click:t.onClick,focus:t.onFocus,input:t.onInput,keydown:[function(e){return!e.type.indexOf("key")&&t._k(e.keyCode,"enter",13,e.key,"Enter")?null:e.metaKey?t.onSubmit.apply(null,arguments):null},function(e){return!e.type.indexOf("key")&&t._k(e.keyCode,"enter",13,e.key,"Enter")?null:e.ctrlKey?t.onSubmit.apply(null,arguments):null},function(e){return e.metaKey?t.onShortcut.apply(null,arguments):null},function(e){return e.ctrlKey?t.onShortcut.apply(null,arguments):null}],dragover:t.onOver,dragleave:t.onOut,drop:t.onDrop}},"textarea",{autofocus:t.autofocus,disabled:t.disabled,id:t.id,minlength:t.minlength,name:t.name,placeholder:t.placeholder,required:t.required,spellcheck:t.spellcheck,value:t.value},!1))],1),e("k-toolbar-email-dialog",{ref:"emailDialog",on:{cancel:t.cancel,submit:function(e){return t.insert(e)}}}),e("k-toolbar-link-dialog",{ref:"linkDialog",on:{cancel:t.cancel,submit:function(e){return t.insert(e)}}}),e("k-files-dialog",{ref:"fileDialog",on:{cancel:t.cancel,submit:function(e){return t.insertFile(e)}}}),t.uploads?e("k-upload",{ref:"fileUpload",on:{success:t.insertUpload}}):t._e()],1)}),[],!1,null,null,null,null).exports,Ds={props:{display:{type:String,default:"HH:mm"},max:String,min:String,step:{type:Object,default:()=>({size:5,unit:"minute"})},type:{type:String,default:"time"},value:String}};const Bs=Mt({mixins:[as,Ds],computed:{inputType:()=>"time"}},null,null,!1,null,null,null,null).exports,Ps={props:{autofocus:Boolean,disabled:Boolean,id:[Number,String],text:{type:[Array,String]},required:Boolean,value:Boolean}};const Ns=Mt({mixins:[Ps],inheritAttrs:!1,computed:{label(){const t=this.text||[this.$t("off"),this.$t("on")];return Array.isArray(t)?this.value?t[1]:t[0]:t}},watch:{value(){this.onInvalid()}},mounted(){this.onInvalid(),this.$props.autofocus&&this.focus()},methods:{focus(){this.$refs.input.focus()},onEnter(t){"Enter"===t.key&&this.$refs.input.click()},onInput(t){this.$emit("input",t)},onInvalid(){this.$emit("invalid",this.$v.$invalid,this.$v)},select(){this.$refs.input.focus()}},validations(){return{value:{required:!this.required||P.required}}}},(function(){var t=this,e=t._self._c;return e("label",{staticClass:"k-toggle-input",attrs:{"data-disabled":t.disabled}},[e("input",{ref:"input",staticClass:"k-toggle-input-native",attrs:{id:t.id,disabled:t.disabled,type:"checkbox"},domProps:{checked:t.value},on:{change:function(e){return t.onInput(e.target.checked)}}}),e("span",{staticClass:"k-toggle-input-label",domProps:{innerHTML:t._s(t.label)}})])}),[],!1,null,null,null,null).exports,qs={mixins:[Qt,ee,ne,le],props:{columns:Number,grow:Boolean,labels:Boolean,options:Array,reset:Boolean,value:[String,Number,Boolean]}};const Fs=Mt({mixins:[qs],inheritAttrs:!1,watch:{value(){this.onInvalid()}},mounted(){this.onInvalid(),this.$props.autofocus&&this.focus()},methods:{focus(){(this.$el.querySelector("input[checked]")||this.$el.querySelector("input")).focus()},onClick(t){t===this.value&&this.reset&&!this.required&&this.$emit("input","")},onInput(t){this.$emit("input",t)},onInvalid(){this.$emit("invalid",this.$v.$invalid,this.$v)},select(){this.focus()}},validations(){return{value:{required:!this.required||P.required}}}},(function(){var t=this,e=t._self._c;return e("ul",{staticClass:"k-toggles-input",style:"--options:"+(t.columns||t.options.length),attrs:{"data-invalid":t.$v.$invalid,"data-labels":t.labels}},t._l(t.options,(function(s,n){return e("li",{key:n},[e("input",{staticClass:"input-hidden",attrs:{id:t.id+"-"+n,name:t.id,type:"radio"},domProps:{value:s.value,checked:t.value===s.value},on:{click:function(e){return t.onClick(s.value)},change:function(e){return t.onInput(s.value)}}}),e("label",{attrs:{for:t.id+"-"+n,title:s.text}},[s.icon?e("k-icon",{attrs:{type:s.icon}}):t._e(),t.labels?e("span",{staticClass:"k-toggles-text"},[t._v(" "+t._s(s.text)+" ")]):t._e()],1)])})),0)}),[],!1,null,null,null,null).exports,Rs={mixins:[us],props:{autocomplete:{type:String,default:"url"},type:{type:String,default:"url"}}};const zs=Mt({extends:cs,mixins:[Rs]},null,null,!1,null,null,null,null).exports;t.component("k-checkbox-input",is),t.component("k-checkboxes-input",rs),t.component("k-date-input",as),t.component("k-email-input",ps),t.component("k-list-input",ms),t.component("k-multiselect-input",gs),t.component("k-number-input",bs),t.component("k-password-input",vs),t.component("k-radio-input",_s),t.component("k-range-input",ws),t.component("k-select-input",Cs),t.component("k-slug-input",As),t.component("k-tags-input",Is),t.component("k-tel-input",Es),t.component("k-text-input",cs),t.component("k-textarea-input",js),t.component("k-time-input",Bs),t.component("k-toggle-input",Ns),t.component("k-toggles-input",Fs),t.component("k-url-input",zs);const Ys=Mt({mixins:[ae],inheritAttrs:!1,props:{autofocus:Boolean,empty:String,fieldsets:Object,fieldsetGroups:Object,group:String,max:{type:Number,default:null},value:{type:Array,default:()=>[]}},data:()=>({opened:[]}),computed:{hasFieldsets(){return Object.keys(this.fieldsets).length},isEmpty(){return 0===this.value.length},isFull(){return null!==this.max&&this.value.length>=this.max}},methods:{focus(){this.$refs.blocks.focus()}}},(function(){var t=this,e=t._self._c;return e("k-field",t._b({staticClass:"k-blocks-field",scopedSlots:t._u([{key:"options",fn:function(){return[t.hasFieldsets?e("k-dropdown",[e("k-button",{attrs:{icon:"dots"},on:{click:function(e){return t.$refs.options.toggle()}}}),e("k-dropdown-content",{ref:"options",attrs:{align:"right"}},[e("k-dropdown-item",{attrs:{disabled:t.isFull,icon:"add"},on:{click:function(e){return t.$refs.blocks.choose(t.value.length)}}},[t._v(" "+t._s(t.$t("add"))+" ")]),e("hr"),e("k-dropdown-item",{attrs:{disabled:t.isEmpty,icon:"template"},on:{click:function(e){return t.$refs.blocks.copyAll()}}},[t._v(" "+t._s(t.$t("copy.all"))+" ")]),e("k-dropdown-item",{attrs:{disabled:t.isFull,icon:"download"},on:{click:function(e){return t.$refs.blocks.pasteboard()}}},[t._v(" "+t._s(t.$t("paste"))+" ")]),e("hr"),e("k-dropdown-item",{attrs:{disabled:t.isEmpty,icon:"trash"},on:{click:function(e){return t.$refs.blocks.confirmToRemoveAll()}}},[t._v(" "+t._s(t.$t("delete.all"))+" ")])],1)],1):t._e()]},proxy:!0}])},"k-field",t.$props,!1),[e("k-blocks",t._g({ref:"blocks",attrs:{autofocus:t.autofocus,compact:!1,empty:t.empty,endpoints:t.endpoints,fieldsets:t.fieldsets,"fieldset-groups":t.fieldsetGroups,group:t.group,max:t.max,value:t.value},on:{close:function(e){t.opened=e},open:function(e){t.opened=e}}},t.$listeners))],1)}),[],!1,null,null,null,null).exports,Hs={props:{counter:{type:Boolean,default:!0}},computed:{counterOptions(){var t,e;if(null===this.value||this.disabled||!1===this.counter)return!1;let s=0;return this.value&&(s=Array.isArray(this.value)?this.value.length:String(this.value).length),{count:s,min:null!=(t=this.min)?t:this.minlength,max:null!=(e=this.max)?e:this.maxlength}}}};const Us=Mt({mixins:[ae,de,os,Hs],inheritAttrs:!1,methods:{focus(){this.$refs.input.focus()}}},(function(){var t=this,e=t._self._c;return e("k-field",t._b({staticClass:"k-checkboxes-field",attrs:{counter:t.counterOptions}},"k-field",t.$props,!1),[e("k-input",t._g(t._b({ref:"input",attrs:{id:t._uid,theme:"field",type:"checkboxes"}},"k-input",t.$props,!1),t.$listeners))],1)}),[],!1,null,null,null,null).exports;const Ks=Mt({mixins:[ae,de,ls],inheritAttrs:!1,props:{calendar:{type:Boolean,default:!0},icon:{type:String,default:"calendar"},time:{type:[Boolean,Object],default:()=>({})},times:{type:Boolean,default:!0}},data(){return{isInvalid:!1,iso:this.toIso(this.value)}},computed:{isEmpty(){return this.time?null===this.iso.date&&this.iso.time:null===this.iso.date}},watch:{value(t,e){t!==e&&(this.iso=this.toIso(t))}},methods:{focus(){this.$refs.dateInput.focus()},now(){const t=this.$library.dayjs();return{date:t.toISO("date"),time:this.time?t.toISO("time"):"00:00:00"}},onInput(){if(this.isEmpty)return this.$emit("input","");const t=this.$library.dayjs.iso(this.iso.date+" "+this.iso.time);(t||null!==this.iso.date&&null!==this.iso.time)&&this.$emit("input",(null==t?void 0:t.toISO())||"")},onCalendarInput(t){var e;null==(e=this.$refs.calendar)||e.close(),this.onDateInput(t)},onDateInput(t){t&&!this.iso.time&&(this.iso.time=this.now().time),this.iso.date=t,this.onInput()},onDateInvalid(t){this.isInvalid=t},onTimeInput(t){t&&!this.iso.date&&(this.iso.date=this.now().date),this.iso.time=t,this.onInput()},onTimesInput(t){var e;null==(e=this.$refs.times)||e.close(),this.onTimeInput(t+":00")},toIso(t){const e=this.$library.dayjs.iso(t);return{date:(null==e?void 0:e.toISO("date"))||null,time:(null==e?void 0:e.toISO("time"))||null}}}},(function(){var t=this,e=t._self._c;return e("k-field",t._b({staticClass:"k-date-field",attrs:{input:t._uid}},"k-field",t.$props,!1),[e("div",{ref:"body",staticClass:"k-date-field-body",attrs:{"data-invalid":!t.novalidate&&t.isInvalid,"data-theme":"field"}},[e("k-input",t._b({ref:"dateInput",attrs:{id:t._uid,autofocus:t.autofocus,disabled:t.disabled,display:t.display,max:t.max,min:t.min,required:t.required,value:t.value,theme:"field",type:"date"},on:{invalid:t.onDateInvalid,input:t.onDateInput,submit:function(e){return t.$emit("submit")}},scopedSlots:t._u([t.calendar?{key:"icon",fn:function(){return[e("k-dropdown",[e("k-button",{staticClass:"k-input-icon-button",attrs:{icon:t.icon,tooltip:t.$t("date.select")},on:{click:function(e){return t.$refs.calendar.toggle()}}}),e("k-dropdown-content",{ref:"calendar",attrs:{align:"right"}},[e("k-calendar",{attrs:{value:t.value,min:t.min,max:t.max},on:{input:t.onCalendarInput}})],1)],1)]},proxy:!0}:null],null,!0)},"k-input",t.$props,!1)),t.time?e("k-input",{ref:"timeInput",attrs:{disabled:t.disabled,display:t.time.display,required:t.required,step:t.time.step,value:t.iso.time,icon:t.time.icon,theme:"field",type:"time"},on:{input:t.onTimeInput,submit:function(e){return t.$emit("submit")}},scopedSlots:t._u([t.times?{key:"icon",fn:function(){return[e("k-dropdown",[e("k-button",{staticClass:"k-input-icon-button",attrs:{icon:t.time.icon||"clock",tooltip:t.$t("time.select")},on:{click:function(e){return t.$refs.times.toggle()}}}),e("k-dropdown-content",{ref:"times",attrs:{align:"right"}},[e("k-times",{attrs:{display:t.time.display,value:t.value},on:{input:t.onTimesInput}})],1)],1)]},proxy:!0}:null],null,!0)}):t._e()],1)])}),[],!1,null,null,null,null).exports;const Gs=Mt({mixins:[ae,de,ds],inheritAttrs:!1,props:{link:{type:Boolean,default:!0},icon:{type:String,default:"email"}},computed:{mailto(){var t;return(null==(t=this.value)?void 0:t.length)>0?"mailto:"+this.value:null}},methods:{focus(){this.$refs.input.focus()}}},(function(){var t=this,e=t._self._c;return e("k-field",t._b({staticClass:"k-email-field",attrs:{input:t._uid}},"k-field",t.$props,!1),[e("k-input",t._g(t._b({ref:"input",attrs:{id:t._uid,theme:"field",type:"email"},scopedSlots:t._u([{key:"icon",fn:function(){return[t.link?e("k-button",{staticClass:"k-input-icon-button",attrs:{icon:t.icon,link:t.mailto,tooltip:t.$t("open"),tabindex:"-1",target:"_blank"}}):t._e()]},proxy:!0}])},"k-input",t.$props,!1),t.$listeners))],1)}),[],!1,null,null,null,null).exports,Js={mixins:[ae],inheritAttrs:!1,props:{empty:String,info:String,link:Boolean,layout:{type:String,default:"list"},max:Number,multiple:Boolean,parent:String,search:Boolean,size:String,text:String,value:{type:Array,default:()=>[]}},data(){return{selected:this.value}},computed:{btnIcon(){return!this.multiple&&this.selected.length>0?"refresh":"add"},btnLabel(){return!this.multiple&&this.selected.length>0?this.$t("change"):this.$t("add")},collection(){return{empty:this.emptyProps,items:this.selected,layout:this.layout,link:this.link,size:this.size,sortable:!this.disabled&&this.selected.length>1}},isInvalid(){return!(!this.required||0!==this.selected.length)||(!!(this.min&&this.selected.lengththis.max))},items(){return this.models.map(this.item)},more(){return!this.max||this.max>this.selected.length}},watch:{value(t){this.selected=t}},methods:{focus(){},item:t=>t,onInput(){this.$emit("input",this.selected)},open(){if(this.disabled)return!1;this.$refs.selector.open({endpoint:this.endpoints.field,max:this.max,multiple:this.multiple,search:this.search,selected:this.selected.map((t=>t.id))})},remove(t){this.selected.splice(t,1),this.onInput()},removeById(t){this.selected=this.selected.filter((e=>e.id!==t)),this.onInput()},select(t){0!==t.length?(this.selected=this.selected.filter((e=>t.filter((t=>t.id===e.id)).length>0)),t.forEach((t=>{0===this.selected.filter((e=>t.id===e.id)).length&&this.selected.push(t)})),this.onInput()):this.selected=[]}}};const Vs=Mt({mixins:[Js],props:{uploads:[Boolean,Object,Array]},computed:{emptyProps(){return{icon:"image",text:this.empty||this.$t("field.files.empty")}},moreUpload(){return!this.disabled&&this.more&&this.uploads},options(){return this.uploads?{icon:this.btnIcon,text:this.btnLabel,options:[{icon:"check",text:this.$t("select"),click:"open"},{icon:"upload",text:this.$t("upload"),click:"upload"}]}:{options:[{icon:"check",text:this.$t("select"),click:()=>this.open()}]}},uploadParams(){return{accept:this.uploads.accept,max:this.max,multiple:this.multiple,url:this.$urls.api+"/"+this.endpoints.field+"/upload"}}},created(){this.$events.$on("file.delete",this.removeById)},destroyed(){this.$events.$off("file.delete",this.removeById)},methods:{drop(t){return!1!==this.uploads&&this.$refs.fileUpload.drop(t,this.uploadParams)},prompt(){if(this.disabled)return!1;this.moreUpload?this.$refs.options.toggle():this.open()},onAction(t){if(this.moreUpload)switch(t){case"open":return this.open();case"upload":return this.$refs.fileUpload.open(this.uploadParams)}},isSelected(t){return this.selected.find((e=>e.id===t.id))},upload(t,e){!1===this.multiple&&(this.selected=[]),e.forEach((t=>{this.isSelected(t)||this.selected.push(t)})),this.onInput(),this.$events.$emit("model.update")}}},(function(){var t=this,e=t._self._c;return e("k-field",t._b({staticClass:"k-files-field",scopedSlots:t._u([t.more&&!t.disabled?{key:"options",fn:function(){return[e("k-button-group",{staticClass:"k-field-options"},[e("k-options-dropdown",t._b({ref:"options",on:{action:t.onAction}},"k-options-dropdown",t.options,!1))],1)]},proxy:!0}:null],null,!0)},"k-field",t.$props,!1),[e("k-dropzone",{attrs:{disabled:!t.moreUpload},on:{drop:t.drop}},[e("k-collection",t._b({on:{empty:t.prompt,sort:t.onInput,sortChange:function(e){return t.$emit("change",e)}},scopedSlots:t._u([{key:"options",fn:function({index:s}){return[t.disabled?t._e():e("k-button",{attrs:{tooltip:t.$t("remove"),icon:"remove"},on:{click:function(e){return t.remove(s)}}})]}}])},"k-collection",t.collection,!1))],1),e("k-files-dialog",{ref:"selector",on:{submit:t.select}}),e("k-upload",{ref:"fileUpload",on:{success:t.upload}})],1)}),[],!1,null,null,null,null).exports;const Ws=Mt({},(function(){return(0,this._self._c)("div",{staticClass:"k-field k-gap-field"})}),[],!1,null,null,null,null).exports;const Xs=Mt({mixins:[se,oe],props:{numbered:Boolean}},(function(){var t=this,e=t._self._c;return e("div",{staticClass:"k-headline-field"},[e("k-headline",{attrs:{"data-numbered":t.numbered,size:"large"}},[t._v(" "+t._s(t.label)+" ")]),t.help?e("footer",{staticClass:"k-field-footer"},[t.help?e("k-text",{staticClass:"k-field-help",attrs:{theme:"help",html:t.help}}):t._e()],1):t._e()],1)}),[],!1,null,null,null,null).exports;const Zs=Mt({mixins:[se,oe],props:{text:String,theme:{type:String,default:"info"}}},(function(){var t=this,e=t._self._c;return e("div",{staticClass:"k-field k-info-field"},[e("k-headline",[t._v(t._s(t.label))]),e("k-box",{attrs:{theme:t.theme}},[e("k-text",{attrs:{html:t.text}})],1),t.help?e("footer",{staticClass:"k-field-footer"},[t.help?e("k-text",{staticClass:"k-field-help",attrs:{theme:"help",html:t.help}}):t._e()],1):t._e()],1)}),[],!1,null,null,null,null).exports;const Qs=Mt({components:{"k-block-layouts":Mt({components:{"k-layout":Mt({components:{"k-layout-column":Mt({props:{blocks:Array,endpoints:Object,fieldsetGroups:Object,fieldsets:Object,id:String,isSelected:Boolean,width:String}},(function(){var t=this,e=t._self._c;return e("div",{staticClass:"k-column k-layout-column",attrs:{id:t.id,"data-width":t.width,tabindex:"0"},on:{dblclick:function(e){return t.$refs.blocks.choose(t.blocks.length)}}},[e("k-blocks",{ref:"blocks",attrs:{endpoints:t.endpoints,"fieldset-groups":t.fieldsetGroups,fieldsets:t.fieldsets,value:t.blocks,group:"layout"},on:{input:function(e){return t.$emit("input",e)}},nativeOn:{dblclick:function(t){t.stopPropagation()}}})],1)}),[],!1,null,null,null,null).exports},props:{attrs:[Array,Object],columns:Array,disabled:Boolean,endpoints:Object,fieldsetGroups:Object,fieldsets:Object,id:String,isSelected:Boolean,settings:Object},computed:{tabs(){let t=this.settings.tabs;return Object.entries(t).forEach((([e,s])=>{Object.entries(s.fields).forEach((([s])=>{t[e].fields[s].endpoints={field:this.endpoints.field+"/fields/"+s,section:this.endpoints.section,model:this.endpoints.model}}))})),t}}},(function(){var t=this,e=t._self._c;return e("section",{staticClass:"k-layout",attrs:{"data-selected":t.isSelected,tabindex:"0"},on:{click:function(e){return t.$emit("select")}}},[e("k-grid",{staticClass:"k-layout-columns"},t._l(t.columns,(function(s,n){return e("k-layout-column",t._b({key:s.id,attrs:{endpoints:t.endpoints,"fieldset-groups":t.fieldsetGroups,fieldsets:t.fieldsets},on:{input:function(e){return t.$emit("updateColumn",{column:s,columnIndex:n,blocks:e})}}},"k-layout-column",s,!1))})),1),t.disabled?t._e():e("nav",{staticClass:"k-layout-toolbar"},[t.settings?e("k-button",{staticClass:"k-layout-toolbar-button",attrs:{tooltip:t.$t("settings"),icon:"settings"},on:{click:function(e){return t.$refs.drawer.open()}}}):t._e(),e("k-dropdown",[e("k-button",{staticClass:"k-layout-toolbar-button",attrs:{icon:"angle-down"},on:{click:function(e){return t.$refs.options.toggle()}}}),e("k-dropdown-content",{ref:"options",attrs:{align:"right"}},[e("k-dropdown-item",{attrs:{icon:"angle-up"},on:{click:function(e){return t.$emit("prepend")}}},[t._v(" "+t._s(t.$t("insert.before"))+" ")]),e("k-dropdown-item",{attrs:{icon:"angle-down"},on:{click:function(e){return t.$emit("append")}}},[t._v(" "+t._s(t.$t("insert.after"))+" ")]),e("hr"),t.settings?e("k-dropdown-item",{attrs:{icon:"settings"},on:{click:function(e){return t.$refs.drawer.open()}}},[t._v(" "+t._s(t.$t("settings"))+" ")]):t._e(),e("k-dropdown-item",{attrs:{icon:"copy"},on:{click:function(e){return t.$emit("duplicate")}}},[t._v(" "+t._s(t.$t("duplicate"))+" ")]),e("hr"),e("k-dropdown-item",{attrs:{icon:"trash"},on:{click:function(e){return t.$refs.confirmRemoveDialog.open()}}},[t._v(" "+t._s(t.$t("field.layout.delete"))+" ")])],1)],1),e("k-sort-handle")],1),t.settings?e("k-form-drawer",{ref:"drawer",staticClass:"k-layout-drawer",attrs:{tabs:t.tabs,title:t.$t("settings"),value:t.attrs,icon:"settings"},on:{input:function(e){return t.$emit("updateAttrs",e)}}}):t._e(),e("k-remove-dialog",{ref:"confirmRemoveDialog",attrs:{text:t.$t("field.layout.delete.confirm")},on:{submit:function(e){return t.$emit("remove")}}})],1)}),[],!1,null,null,null,null).exports},props:{disabled:Boolean,empty:String,endpoints:Object,fieldsetGroups:Object,fieldsets:Object,layouts:Array,max:Number,settings:Object,value:Array},data(){return{currentLayout:null,nextIndex:null,rows:this.value,selected:null}},computed:{draggableOptions(){return{id:this._uid,handle:!0,list:this.rows}}},watch:{value(){this.rows=this.value}},methods:{async addLayout(t){let e=await this.$api.post(this.endpoints.field+"/layout",{columns:t});this.rows.splice(this.nextIndex,0,e),this.layouts.length>1&&this.$refs.selector.close(),this.save()},duplicateLayout(t,e){let s={...this.$helper.clone(e),id:this.$helper.uuid()};s.columns=s.columns.map((t=>(t.id=this.$helper.uuid(),t.blocks=t.blocks.map((t=>(t.id=this.$helper.uuid(),t))),t))),this.rows.splice(t+1,0,s),this.save()},removeLayout(t){const e=this.rows.findIndex((e=>e.id===t.id));-1!==e&&this.$delete(this.rows,e),this.save()},save(){this.$emit("input",this.rows)},selectLayout(t){this.nextIndex=t,1!==this.layouts.length?this.$refs.selector.open():this.addLayout(this.layouts[0])},updateColumn(t){this.rows[t.layoutIndex].columns[t.columnIndex].blocks=t.blocks,this.save()},updateAttrs(t,e){this.rows[t].attrs=e,this.save()}}},(function(){var t=this,e=t._self._c;return e("div",[t.rows.length?[e("k-draggable",t._b({staticClass:"k-layouts",on:{sort:t.save}},"k-draggable",t.draggableOptions,!1),t._l(t.rows,(function(s,n){return e("k-layout",t._b({key:s.id,attrs:{disabled:t.disabled,endpoints:t.endpoints,"fieldset-groups":t.fieldsetGroups,fieldsets:t.fieldsets,"is-selected":t.selected===s.id,settings:t.settings},on:{append:function(e){return t.selectLayout(n+1)},duplicate:function(e){return t.duplicateLayout(n,s)},prepend:function(e){return t.selectLayout(n)},remove:function(e){return t.removeLayout(s)},select:function(e){t.selected=s.id},updateAttrs:function(e){return t.updateAttrs(n,e)},updateColumn:function(e){return t.updateColumn({layout:s,layoutIndex:n,...e})}}},"k-layout",s,!1))})),1),t.disabled?t._e():e("k-button",{staticClass:"k-layout-add-button",attrs:{icon:"add"},on:{click:function(e){return t.selectLayout(t.rows.length)}}})]:[e("k-empty",{staticClass:"k-layout-empty",attrs:{icon:"dashboard"},on:{click:function(e){return t.selectLayout(0)}}},[t._v(" "+t._s(t.empty||t.$t("field.layout.empty"))+" ")])],e("k-dialog",{ref:"selector",staticClass:"k-layout-selector",attrs:{"cancel-button":!1,"submit-button":!1,size:"medium"}},[e("k-headline",[t._v(t._s(t.$t("field.layout.select")))]),e("ul",t._l(t.layouts,(function(s,n){return e("li",{key:n,staticClass:"k-layout-selector-option"},[e("k-grid",{nativeOn:{click:function(e){return t.addLayout(s)}}},t._l(s,(function(t,s){return e("k-column",{key:s,attrs:{width:t}})})),1)],1)})),0)],1)],2)}),[],!1,null,null,null,null).exports},mixins:[ae],inheritAttrs:!1,props:{empty:String,fieldsetGroups:Object,fieldsets:Object,layouts:{type:Array,default:()=>[["1/1"]]},settings:Object,value:{type:Array,default:()=>[]}}},(function(){var t=this,e=t._self._c;return e("k-field",t._b({staticClass:"k-layout-field"},"k-field",t.$props,!1),[e("k-block-layouts",t._b({on:{input:function(e){return t.$emit("input",e)}}},"k-block-layouts",t.$props,!1))],1)}),[],!1,null,null,null,null).exports;const tn=Mt({},(function(){return(0,this._self._c)("hr",{staticClass:"k-line-field"})}),[],!1,null,null,null,null).exports;const en=Mt({mixins:[ae,de],inheritAttrs:!1,props:{marks:[Array,Boolean],value:String},methods:{focus(){this.$refs.input.focus()}}},(function(){var t=this,e=t._self._c;return e("k-field",t._b({staticClass:"k-list-field",attrs:{input:t._uid,counter:!1}},"k-field",t.$props,!1),[e("k-input",t._b({ref:"input",attrs:{id:t._uid,marks:t.marks,value:t.value,type:"list",theme:"field"},on:{input:function(e){return t.$emit("input",e)}}},"k-input",t.$props,!1))],1)}),[],!1,null,null,null,null).exports;const sn=Mt({mixins:[ae,de,fs,Hs],inheritAttrs:!1,props:{icon:{type:String,default:"angle-down"}},mounted(){this.$refs.input.$el.setAttribute("tabindex",0)},methods:{blur(t){this.$refs.input.blur(t)},focus(){this.$refs.input.focus()}}},(function(){var t=this,e=t._self._c;return e("k-field",t._b({staticClass:"k-multiselect-field",attrs:{input:t._uid,counter:t.counterOptions},on:{blur:t.blur},nativeOn:{keydown:function(e){return!e.type.indexOf("key")&&t._k(e.keyCode,"enter",13,e.key,"Enter")?null:(e.preventDefault(),t.focus.apply(null,arguments))}}},"k-field",t.$props,!1),[e("k-input",t._g(t._b({ref:"input",attrs:{id:t._uid,theme:"field",type:"multiselect"}},"k-input",t.$props,!1),t.$listeners))],1)}),[],!1,null,null,null,null).exports;const nn=Mt({mixins:[ae,de,ks],inheritAttrs:!1,methods:{focus(){this.$refs.input.focus()}}},(function(){var t=this,e=t._self._c;return e("k-field",t._b({staticClass:"k-number-field",attrs:{input:t._uid}},"k-field",t.$props,!1),[e("k-input",t._g(t._b({ref:"input",attrs:{id:t._uid,theme:"field",type:"number"}},"k-input",t.$props,!1),t.$listeners))],1)}),[],!1,null,null,null,null).exports;const on=Mt({mixins:[Js],computed:{emptyProps(){return{icon:"page",text:this.empty||this.$t("field.pages.empty")}}}},(function(){var t=this,e=t._self._c;return e("k-field",t._b({staticClass:"k-pages-field",scopedSlots:t._u([{key:"options",fn:function(){return[e("k-button-group",{staticClass:"k-field-options"},[t.more&&!t.disabled?e("k-button",{staticClass:"k-field-options-button",attrs:{icon:t.btnIcon,text:t.btnLabel},on:{click:t.open}}):t._e()],1)]},proxy:!0}])},"k-field",t.$props,!1),[e("k-collection",t._b({on:{empty:t.open,sort:t.onInput,sortChange:function(e){return t.$emit("change",e)}},scopedSlots:t._u([{key:"options",fn:function({index:s}){return[t.disabled?t._e():e("k-button",{attrs:{tooltip:t.$t("remove"),icon:"remove"},on:{click:function(e){return t.remove(s)}}})]}}])},"k-collection",t.collection,!1)),e("k-pages-dialog",{ref:"selector",on:{submit:t.select}})],1)}),[],!1,null,null,null,null).exports;const rn=Mt({mixins:[ae,de,ys,Hs],inheritAttrs:!1,props:{minlength:{type:Number,default:8},icon:{type:String,default:"key"}},methods:{focus(){this.$refs.input.focus()}}},(function(){var t=this,e=t._self._c;return e("k-field",t._b({staticClass:"k-password-field",attrs:{input:t._uid,counter:t.counterOptions},scopedSlots:t._u([{key:"options",fn:function(){return[t._t("options")]},proxy:!0}],null,!0)},"k-field",t.$props,!1),[e("k-input",t._g(t._b({ref:"input",attrs:{id:t._uid,theme:"field",type:"password"}},"k-input",t.$props,!1),t.$listeners))],1)}),[],!1,null,null,null,null).exports;const ln=Mt({mixins:[ae,de,$s],inheritAttrs:!1,methods:{focus(){this.$refs.input.focus()}}},(function(){var t=this,e=t._self._c;return e("k-field",t._b({staticClass:"k-radio-field"},"k-field",t.$props,!1),[e("k-input",t._g(t._b({ref:"input",attrs:{id:t._uid,theme:"field",type:"radio"}},"k-input",t.$props,!1),t.$listeners))],1)}),[],!1,null,null,null,null).exports;const an=Mt({mixins:[de,ae,xs],inheritAttrs:!1,methods:{focus(){this.$refs.input.focus()}}},(function(){var t=this,e=t._self._c;return e("k-field",t._b({staticClass:"k-range-field",attrs:{input:t._uid}},"k-field",t.$props,!1),[e("k-input",t._g(t._b({ref:"input",attrs:{id:t._uid,theme:"field",type:"range"}},"k-input",t.$props,!1),t.$listeners))],1)}),[],!1,null,null,null,null).exports;const un=Mt({mixins:[ae,de,Ss],inheritAttrs:!1,props:{icon:{type:String,default:"angle-down"}},methods:{focus(){this.$refs.input.focus()}}},(function(){var t=this,e=t._self._c;return e("k-field",t._b({staticClass:"k-select-field",attrs:{input:t._uid}},"k-field",t.$props,!1),[e("k-input",t._g(t._b({ref:"input",attrs:{id:t._uid,theme:"field",type:"select"}},"k-input",t.$props,!1),t.$listeners))],1)}),[],!1,null,null,null,null).exports;const cn=Mt({mixins:[ae,de,Os],inheritAttrs:!1,props:{icon:{type:String,default:"url"},path:{type:String},wizard:{type:[Boolean,Object],default:!1}},data(){return{slug:this.value}},computed:{preview(){return void 0!==this.help?this.help:void 0!==this.path?this.path+this.value:null}},watch:{value(){this.slug=this.value}},methods:{focus(){this.$refs.input.focus()},onWizard(){var t;this.formData[null==(t=this.wizard)?void 0:t.field]&&(this.slug=this.formData[this.wizard.field])}}},(function(){var t=this,e=t._self._c;return e("k-field",t._b({staticClass:"k-slug-field",attrs:{input:t._uid,help:t.preview},scopedSlots:t._u([t.wizard&&t.wizard.text?{key:"options",fn:function(){return[e("k-button",{attrs:{text:t.wizard.text,icon:"wand"},on:{click:t.onWizard}})]},proxy:!0}:null],null,!0)},"k-field",t.$props,!1),[e("k-input",t._g(t._b({ref:"input",attrs:{id:t._uid,value:t.slug,theme:"field",type:"slug"}},"k-input",t.$props,!1),t.$listeners))],1)}),[],!1,null,null,null,null).exports;const dn=Mt({mixins:[ae],inheritAttrs:!1,props:{columns:Object,duplicate:{type:Boolean,default:!0},empty:String,fields:Object,limit:Number,max:Number,min:Number,prepend:{type:Boolean,default:!1},sortable:{type:Boolean,default:!0},sortBy:String,value:{type:Array,default:()=>[]}},data(){return{autofocus:null,items:this.toItems(this.value),currentIndex:null,currentModel:null,trash:null,page:1}},computed:{dragOptions(){return{disabled:!this.isSortable,fallbackClass:"k-sortable-row-fallback"}},form(){let t={};return Object.keys(this.fields).forEach((e=>{let s=this.fields[e];s.section=this.name,s.endpoints={field:this.endpoints.field+"+"+e,section:this.endpoints.section,model:this.endpoints.model},null===this.autofocus&&!0===s.autofocus&&(this.autofocus=e),t[e]=s})),t},index(){return this.limit?(this.page-1)*this.limit:1},more(){return!0!==this.disabled&&!(this.max&&this.items.length>=this.max)},isInvalid(){return!0!==this.disabled&&(!!(this.min&&this.items.lengththis.max))},isSortable(){return!this.sortBy&&(!this.limit&&(!0!==this.disabled&&(!(this.items.length<=1)&&!1!==this.sortable)))},pagination(){let t=0;return this.limit&&(t=(this.page-1)*this.limit),{page:this.page,offset:t,limit:this.limit,total:this.items.length,align:"center",details:!0}},options(){let t=[],e=this.duplicate&&this.more&&null===this.currentIndex;return e&&t.push({icon:"copy",text:this.$t("duplicate"),click:"duplicate"}),t.push({icon:"remove",text:e?this.$t("remove"):null,click:"remove"}),t},paginatedItems(){return this.limit?this.items.slice(this.pagination.offset,this.pagination.offset+this.limit):this.items}},watch:{value(t){t!=this.items&&(this.items=this.toItems(t))}},methods:{add(t){!0===this.prepend?this.items.unshift(t):this.items.push(t)},focus(){var t,e;null==(e=null==(t=this.$refs.add)?void 0:t.focus)||e.call(t)},jump(t,e){this.open(t+this.pagination.offset,e)},onAdd(){if(!0===this.disabled)return!1;if(null!==this.currentIndex)return this.onFormDiscard(),!1;let t={};for(const e in this.fields)t[e]=this.$helper.clone(this.fields[e].default);this.currentIndex="new",this.currentModel=t,this.onFormOpen()},onFormClose(){this.currentIndex=null,this.currentModel=null},onFormDiscard(){if("new"===this.currentIndex){if(0===Object.values(this.currentModel).filter((t=>!1===this.$helper.object.isEmpty(t))).length)return void this.onFormClose()}this.onFormSubmit()},onFormOpen(t=this.autofocus){this.$nextTick((()=>{var e;null==(e=this.$refs.form)||e.focus(t)}))},async onFormPaginate(t){await this.save(),this.open(t)},async onFormSubmit(){try{await this.save(),this.onFormClose()}catch(t){}},onInput(t=this.items){this.$emit("input",t)},onOption(t,e,s){switch(t){case"remove":this.onFormClose(),this.trash=s+this.pagination.offset,this.$refs.remove.open();break;case"duplicate":this.add(this.items[s+this.pagination.offset]),this.onInput()}},onRemove(){if(null===this.trash)return!1;this.items.splice(this.trash,1),this.trash=null,this.$refs.remove.close(),this.onInput(),0===this.paginatedItems.length&&this.page>1&&this.page--,this.items=this.sort(this.items)},open(t,e){this.currentIndex=t,this.currentModel=this.$helper.clone(this.items[t]),this.onFormOpen(e)},paginate({page:t}){this.page=t},sort(t){return this.sortBy?t.sortBy(this.sortBy):t},async save(){if(null!==this.currentIndex&&void 0!==this.currentIndex)try{return await this.validate(this.currentModel),"new"===this.currentIndex?this.add(this.currentModel):this.items[this.currentIndex]=this.currentModel,this.items=this.sort(this.items),this.onInput(),!0}catch(t){throw this.$store.dispatch("notification/error",{message:this.$t("error.form.incomplete"),details:t}),t}},toItems(t){return!1===Array.isArray(t)?[]:this.sort(t)},async validate(t){const e=await this.$api.post(this.endpoints.field+"/validate",t);if(e.length>0)throw e;return!0}}},(function(){var t=this,e=t._self._c;return e("k-field",t._b({staticClass:"k-structure-field",nativeOn:{click:function(t){t.stopPropagation()}},scopedSlots:t._u([{key:"options",fn:function(){return[t.more&&null===t.currentIndex?e("k-button",{ref:"add",attrs:{id:t._uid,text:t.$t("add"),icon:"add"},on:{click:t.onAdd}}):t._e()]},proxy:!0}])},"k-field",t.$props,!1),[null!==t.currentIndex?e("k-structure-form",{ref:"form",attrs:{fields:t.form,index:t.currentIndex,total:t.items.length},on:{close:t.onFormClose,discard:t.onFormDiscard,paginate:function(e){return t.onFormPaginate(e.offset)},submit:t.onFormSubmit},model:{value:t.currentModel,callback:function(e){t.currentModel=e},expression:"currentModel"}}):0===t.items.length?e("k-empty",{attrs:{"data-invalid":t.isInvalid,icon:"list-bullet"},on:{click:t.onAdd}},[t._v(" "+t._s(t.empty||t.$t("field.structure.empty"))+" ")]):[e("k-table",{attrs:{columns:t.columns,disabled:t.disabled,fields:t.fields,empty:t.$t("field.structure.empty"),index:t.index,options:t.options,rows:t.paginatedItems,sortable:t.isSortable,"data-invalid":t.isInvalid},on:{cell:function(e){return t.jump(e.rowIndex,e.columnIndex)},input:t.onInput,option:t.onOption}}),t.limit?e("k-pagination",t._b({on:{paginate:t.paginate}},"k-pagination",t.pagination,!1)):t._e(),t.disabled?t._e():e("k-dialog",{ref:"remove",attrs:{"submit-button":t.$t("delete"),theme:"negative"},on:{submit:t.onRemove}},[e("k-text",[t._v(t._s(t.$t("field.structure.delete.confirm")))])],1)]],2)}),[],!1,null,null,null,null).exports;const pn=Mt({mixins:[ae,de,Ts,Hs],inheritAttrs:!1,methods:{focus(){this.$refs.input.focus()}}},(function(){var t=this,e=t._self._c;return e("k-field",t._b({staticClass:"k-tags-field",attrs:{input:t._uid,counter:t.counterOptions}},"k-field",t.$props,!1),[e("k-input",t._g(t._b({ref:"input",attrs:{id:t._uid,theme:"field",type:"tags"}},"k-input",t.$props,!1),t.$listeners))],1)}),[],!1,null,null,null,null).exports;const hn=Mt({mixins:[ae,de,Ms],inheritAttrs:!1,props:{icon:{type:String,default:"phone"}},methods:{focus(){this.$refs.input.focus()}}},(function(){var t=this,e=t._self._c;return e("k-field",t._b({staticClass:"k-tel-field",attrs:{input:t._uid}},"k-field",t.$props,!1),[e("k-input",t._g(t._b({ref:"input",attrs:{id:t._uid,theme:"field",type:"tel"}},"k-input",t.$props,!1),t.$listeners))],1)}),[],!1,null,null,null,null).exports;const mn=Mt({mixins:[ae,de,us,Hs],inheritAttrs:!1,methods:{focus(){this.$refs.input.focus()},select(){this.$refs.input.select()}}},(function(){var t=this,e=t._self._c;return e("k-field",t._b({staticClass:"k-text-field",attrs:{input:t._uid,counter:t.counterOptions},scopedSlots:t._u([{key:"options",fn:function(){return[t._t("options")]},proxy:!0}],null,!0)},"k-field",t.$props,!1),[e("k-input",t._g(t._b({ref:"input",attrs:{id:t._uid,theme:"field"}},"k-input",t.$props,!1),t.$listeners))],1)}),[],!1,null,null,null,null).exports;const fn=Mt({mixins:[ae,de,Ls,Hs],inheritAttrs:!1,methods:{focus(){this.$refs.input.focus()}}},(function(){var t=this,e=t._self._c;return e("k-field",t._b({staticClass:"k-textarea-field",attrs:{input:t._uid,counter:t.counterOptions}},"k-field",t.$props,!1),[e("k-input",t._g(t._b({ref:"input",attrs:{id:t._uid,type:"textarea",theme:"field"}},"k-input",t.$props,!1),t.$listeners))],1)}),[],!1,null,null,null,null).exports;const gn=Mt({mixins:[ae,de,Ds],inheritAttrs:!1,props:{icon:{type:String,default:"clock"},times:{type:Boolean,default:!0}},methods:{focus(){this.$refs.input.focus()},select(t){var e;this.$emit("input",t),null==(e=this.$refs.times)||e.close()}}},(function(){var t=this,e=t._self._c;return e("k-field",t._b({staticClass:"k-time-field",attrs:{input:t._uid}},"k-field",t.$props,!1),[e("k-input",t._b({ref:"input",attrs:{id:t._uid,theme:"field",type:"time"},on:{input:function(e){return t.$emit("input",e||"")}},scopedSlots:t._u([t.times?{key:"icon",fn:function(){return[e("k-dropdown",[e("k-button",{staticClass:"k-input-icon-button",attrs:{icon:t.icon||"clock",tooltip:t.$t("time.select")},on:{click:function(e){return t.$refs.times.toggle()}}}),e("k-dropdown-content",{ref:"times",attrs:{align:"right"}},[e("k-times",{attrs:{display:t.display,value:t.value},on:{input:t.select}})],1)],1)]},proxy:!0}:null],null,!0)},"k-input",t.$props,!1))],1)}),[],!1,null,null,null,null).exports;const kn=Mt({mixins:[ae,de,Ps],inheritAttrs:!1,methods:{focus(){this.$refs.input.focus()}}},(function(){var t=this,e=t._self._c;return e("k-field",t._b({staticClass:"k-toggle-field",attrs:{input:t._uid}},"k-field",t.$props,!1),[e("k-input",t._g(t._b({ref:"input",attrs:{id:t._uid,theme:"field",type:"toggle"}},"k-input",t.$props,!1),t.$listeners))],1)}),[],!1,null,null,null,null).exports;const bn=Mt({mixins:[ae,de,qs],inheritAttrs:!1,methods:{focus(){this.$refs.input.focus()},onInput(t){this.$emit("input",t)}}},(function(){var t=this,e=t._self._c;return e("k-field",t._b({staticClass:"k-toggles-field"},"k-field",t.$props,!1),[e("k-input",t._g(t._b({ref:"input",class:{grow:t.grow},attrs:{id:t._uid,theme:"field",type:"toggles"}},"k-input",t.$props,!1),t.$listeners))],1)}),[],!1,null,null,null,null).exports;const yn=Mt({mixins:[ae,de,Rs],inheritAttrs:!1,props:{link:{type:Boolean,default:!0},icon:{type:String,default:"url"}},computed:{isValidUrl(){return""!==this.value&&!0===this.$helper.url.isUrl(this.value,!0)}},methods:{focus(){this.$refs.input.focus()}}},(function(){var t=this,e=t._self._c;return e("k-field",t._b({staticClass:"k-url-field",attrs:{input:t._uid}},"k-field",t.$props,!1),[e("k-input",t._g(t._b({ref:"input",attrs:{id:t._uid,theme:"field",type:"url"},scopedSlots:t._u([{key:"icon",fn:function(){return[t.link&&t.isValidUrl?e("k-button",{staticClass:"k-input-icon-button",attrs:{icon:t.icon,link:t.value,tooltip:t.$t("open"),tabindex:"-1",target:"_blank"}}):t._e()]},proxy:!0}])},"k-input",t.$props,!1),t.$listeners))],1)}),[],!1,null,null,null,null).exports;const vn=Mt({mixins:[Js],computed:{emptyProps(){return{icon:"users",text:this.empty||this.$t("field.users.empty")}}}},(function(){var t=this,e=t._self._c;return e("k-field",t._b({staticClass:"k-users-field",scopedSlots:t._u([{key:"options",fn:function(){return[e("k-button-group",{staticClass:"k-field-options"},[t.more&&!t.disabled?e("k-button",{staticClass:"k-field-options-button",attrs:{icon:t.btnIcon,text:t.btnLabel},on:{click:t.open}}):t._e()],1)]},proxy:!0}])},"k-field",t.$props,!1),[e("k-collection",t._b({on:{empty:t.open,sort:t.onInput,sortChange:function(e){return t.$emit("change",e)}},scopedSlots:t._u([{key:"options",fn:function({index:s}){return[t.disabled?t._e():e("k-button",{attrs:{tooltip:t.$t("remove"),icon:"remove"},on:{click:function(e){return t.remove(s)}}})]}}])},"k-collection",t.collection,!1)),e("k-users-dialog",{ref:"selector",on:{submit:t.select}})],1)}),[],!1,null,null,null,null).exports;const $n=Mt({mixins:[ae,de,We],inheritAttrs:!1,methods:{focus(){this.$refs.input.focus()}}},(function(){var t=this,e=t._self._c;return e("k-field",t._b({staticClass:"k-writer-field",attrs:{input:t._uid,counter:!1}},"k-field",t.$props,!1),[e("k-input",t._b({attrs:{after:t.after,before:t.before,icon:t.icon,theme:"field"}},"k-input",t.$props,!1),[e("k-writer",t._b({ref:"input",staticClass:"k-writer-field-input",attrs:{value:t.value},on:{input:function(e){return t.$emit("input",e)}}},"k-writer",t.$props,!1))],1)],1)}),[],!1,null,null,null,null).exports;t.component("k-blocks-field",Ys),t.component("k-checkboxes-field",Us),t.component("k-date-field",Ks),t.component("k-email-field",Gs),t.component("k-files-field",Vs),t.component("k-gap-field",Ws),t.component("k-headline-field",Xs),t.component("k-info-field",Zs),t.component("k-layout-field",Qs),t.component("k-line-field",tn),t.component("k-list-field",en),t.component("k-multiselect-field",sn),t.component("k-number-field",nn),t.component("k-pages-field",on),t.component("k-password-field",rn),t.component("k-radio-field",ln),t.component("k-range-field",an),t.component("k-select-field",un),t.component("k-slug-field",cn),t.component("k-structure-field",dn),t.component("k-tags-field",pn),t.component("k-text-field",mn),t.component("k-textarea-field",fn),t.component("k-tel-field",hn),t.component("k-time-field",gn),t.component("k-toggle-field",kn),t.component("k-toggles-field",bn),t.component("k-url-field",yn),t.component("k-users-field",vn),t.component("k-writer-field",$n);const _n=Mt({props:{cover:Boolean,ratio:String},computed:{ratioPadding(){return this.$helper.ratio(this.ratio)}}},(function(){var t=this;return(0,t._self._c)("span",{staticClass:"k-aspect-ratio",style:{"padding-bottom":t.ratioPadding},attrs:{"data-cover":t.cover}},[t._t("default")],2)}),[],!1,null,null,null,null).exports;const xn=Mt({},(function(){var t=this,e=t._self._c;return e("div",{staticClass:"k-bar"},[t.$slots.left?e("div",{staticClass:"k-bar-slot",attrs:{"data-position":"left"}},[t._t("left")],2):t._e(),t.$slots.center?e("div",{staticClass:"k-bar-slot",attrs:{"data-position":"center"}},[t._t("center")],2):t._e(),t.$slots.right?e("div",{staticClass:"k-bar-slot",attrs:{"data-position":"right"}},[t._t("right")],2):t._e()])}),[],!1,null,null,null,null).exports;const wn=Mt({props:{theme:{type:String,default:"none"},text:String,html:{type:Boolean,default:!1}}},(function(){var t=this,e=t._self._c;return e("div",t._g({staticClass:"k-box",attrs:{"data-theme":t.theme}},t.$listeners),[t._t("default",(function(){return[t.html?e("k-text",{attrs:{html:t.text}}):e("k-text",[t._v(" "+t._s(t.text)+" ")])]}))],2)}),[],!1,null,null,null,null).exports;const Sn=Mt({inheritAttrs:!1,props:{back:String,color:String,element:{type:String,default:"li"},image:Object,link:String,text:String}},(function(){var t=this,e=t._self._c;return e(t.link?"k-link":"p",{tag:"component",staticClass:"k-bubble",style:{color:t.$helper.color(t.color),background:t.$helper.color(t.back)},attrs:{to:t.link},nativeOn:{click:function(t){t.stopPropagation()}}},[t.image?e("k-item-image",{attrs:{image:t.image,layout:"list"}}):t._e(),t._v(" "+t._s(t.text)+" ")],1)}),[],!1,null,null,null,null).exports;const Cn=Mt({inheritAttrs:!1,props:{bubbles:Array},computed:{items(){let t=this.bubbles;return"string"==typeof t&&(t=t.split(",")),t.map((t=>"string"==typeof t?{text:t}:t))}}},(function(){var t=this,e=t._self._c;return e("ul",{staticClass:"k-bubbles"},t._l(t.items,(function(s,n){return e("li",{key:n},[e("k-bubble",t._b({},"k-bubble",s,!1))],1)})),0)}),[],!1,null,null,null,null).exports;const On=Mt({props:{columns:{type:[Object,Array],default:()=>({})},empty:Object,help:String,items:{type:[Array,Object],default:()=>[]},layout:{type:String,default:"list"},link:{type:Boolean,default:!0},size:String,sortable:Boolean,pagination:{type:[Boolean,Object],default:()=>!1}},computed:{hasPagination(){return!1!==this.pagination&&(!0!==this.paginationOptions.hide&&!(this.pagination.total<=this.pagination.limit))},hasFooter(){return!(!this.hasPagination&&!this.help)},paginationOptions(){return{limit:10,details:!0,keys:!1,total:0,hide:!1,..."object"!=typeof this.pagination?{}:this.pagination}}},watch:{$props(){this.$forceUpdate()}},methods:{onEmpty(t){t.stopPropagation(),this.$emit("empty")},onOption(...t){this.$emit("action",...t),this.$emit("option",...t)}}},(function(){var t=this,e=t._self._c;return e("div",{staticClass:"k-collection"},[t.items.length?e("k-items",{attrs:{columns:t.columns,items:t.items,layout:t.layout,link:t.link,size:t.size,sortable:t.sortable},on:{change:function(e){return t.$emit("change",e)},item:function(e){return t.$emit("item",e)},option:t.onOption,sort:function(e){return t.$emit("sort",e)}},scopedSlots:t._u([{key:"options",fn:function({item:e,itemIndex:s}){return[t._t("options",null,null,{item:e,index:s})]}}],null,!0)}):e("k-empty",t._g(t._b({attrs:{layout:t.layout}},"k-empty",t.empty,!1),t.$listeners.empty?{click:t.onEmpty}:{})),t.hasFooter?e("footer",{staticClass:"k-collection-footer"},[t.help?e("k-text",{staticClass:"k-collection-help",attrs:{theme:"help",html:t.help}}):t._e(),e("div",{staticClass:"k-collection-pagination"},[t.hasPagination?e("k-pagination",t._b({on:{paginate:function(e){return t.$emit("paginate",e)}}},"k-pagination",t.paginationOptions,!1)):t._e()],1)],1):t._e()],1)}),[],!1,null,null,null,null).exports;const An=Mt({props:{width:String,sticky:Boolean}},(function(){var t=this,e=t._self._c;return e("div",{staticClass:"k-column",attrs:{"data-width":t.width,"data-sticky":t.sticky}},[e("div",[t._t("default")],2)])}),[],!1,null,null,null,null).exports;const Tn=Mt({props:{disabled:{type:Boolean,default:!1}},data:()=>({files:[],dragging:!1,over:!1}),methods:{cancel(){this.reset()},reset(){this.dragging=!1,this.over=!1},onDrop(t){return!0===this.disabled||!1===this.$helper.isUploadEvent(t)?this.reset():(this.$events.$emit("dropzone.drop"),this.files=t.dataTransfer.files,this.$emit("drop",this.files),void this.reset())},onEnter(t){!1===this.disabled&&this.$helper.isUploadEvent(t)&&(this.dragging=!0)},onLeave(){this.reset()},onOver(t){!1===this.disabled&&this.$helper.isUploadEvent(t)&&(t.dataTransfer.dropEffect="copy",this.over=!0)}}},(function(){var t=this;return(0,t._self._c)("div",{staticClass:"k-dropzone",attrs:{"data-dragging":t.dragging,"data-over":t.over},on:{dragenter:t.onEnter,dragleave:t.onLeave,dragover:t.onOver,drop:t.onDrop}},[t._t("default")],2)}),[],!1,null,null,null,null).exports;const In=Mt({props:{text:String,icon:String,layout:{type:String,default:"list"}},computed:{element(){return void 0!==this.$listeners.click?"button":"div"}}},(function(){var t=this,e=t._self._c;return e(t.element,t._g({tag:"component",staticClass:"k-empty",attrs:{"data-layout":t.layout,type:"button"===t.element&&"button"}},t.$listeners),[t.icon?e("k-icon",{attrs:{type:t.icon}}):t._e(),e("p",[t._t("default",(function(){return[t._v(t._s(t.text))]}))],2)],1)}),[],!1,null,null,null,null).exports;const Mn=Mt({props:{details:Array,image:Object,url:String}},(function(){var t=this,e=t._self._c;return e("div",{staticClass:"k-file-preview"},[e("k-view",{staticClass:"k-file-preview-layout"},[e("div",{staticClass:"k-file-preview-image"},[e("k-link",{staticClass:"k-file-preview-image-link",attrs:{to:t.url,title:t.$t("open"),target:"_blank"}},[e("k-item-image",{attrs:{image:t.image,layout:"cards"}})],1)],1),e("div",{staticClass:"k-file-preview-details"},[e("ul",t._l(t.details,(function(s){return e("li",{key:s.title},[e("h3",[t._v(t._s(s.title))]),e("p",[s.link?e("k-link",{attrs:{to:s.link,tabindex:"-1",target:"_blank"}},[t._v(" /"+t._s(s.text)+" ")]):[t._v(" "+t._s(s.text)+" ")]],2)])})),0)])])],1)}),[],!1,null,null,null,null).exports;const En=Mt({props:{gutter:String}},(function(){var t=this;return(0,t._self._c)("div",{staticClass:"k-grid",attrs:{"data-gutter":t.gutter}},[t._t("default")],2)}),[],!1,null,null,null,null).exports;const Ln=Mt({props:{editable:Boolean,tab:String,tabs:{type:Array,default:()=>[]}},computed:{tabsWithBadges(){const t=Object.keys(this.$store.getters["content/changes"]());return this.tabs.map((e=>{let s=[];return Object.values(e.columns).forEach((t=>{Object.values(t.sections).forEach((t=>{"fields"===t.type&&Object.keys(t.fields).forEach((t=>{s.push(t)}))}))})),e.badge=s.filter((e=>t.includes(e.toLowerCase()))).length,e}))}}},(function(){var t=this,e=t._self._c;return e("header",{staticClass:"k-header",attrs:{"data-editable":t.editable,"data-tabs":t.tabsWithBadges.length>1}},[e("k-headline",{attrs:{tag:"h1",size:"huge"}},[t.editable&&t.$listeners.edit?e("span",{staticClass:"k-headline-editable",on:{click:function(e){return t.$emit("edit")}}},[t._t("default"),e("k-icon",{attrs:{type:"edit"}})],2):t._t("default")],2),t.$slots.left||t.$slots.right?e("k-bar",{staticClass:"k-header-buttons",scopedSlots:t._u([{key:"left",fn:function(){return[t._t("left")]},proxy:!0},{key:"right",fn:function(){return[t._t("right")]},proxy:!0}],null,!0)}):t._e(),e("k-tabs",{attrs:{tab:t.tab,tabs:t.tabsWithBadges,theme:"notice"}})],1)}),[],!1,null,null,null,null).exports;const jn=Mt({inheritAttrs:!1},(function(){var t=this,e=t._self._c;return e("k-panel",{staticClass:"k-panel-inside",attrs:{tabindex:"0"}},[e("header",{staticClass:"k-panel-header"},[e("k-topbar",{attrs:{breadcrumb:t.$view.breadcrumb,license:t.$license,menu:t.$menu,view:t.$view}})],1),e("main",{staticClass:"k-panel-view scroll-y"},[t._t("default")],2),t._t("footer")],2)}),[],!1,null,null,null,null).exports;const Dn=Mt({inheritAttrs:!1,props:{data:Object,flag:Object,image:[Object,Boolean],info:String,layout:{type:String,default:"list"},link:{type:[Boolean,String,Function]},options:{type:[Array,Function,String]},sortable:Boolean,target:String,text:String,width:String},computed:{hasFigure(){return!1!==this.image&&Object.keys(this.image).length>0},title(){return this.text||"-"}},methods:{onOption(t){this.$emit("action",t),this.$emit("option",t)}}},(function(){var t=this,e=t._self._c;return e("article",t._b({staticClass:"k-item",class:!!t.layout&&"k-"+t.layout+"-item",attrs:{"data-has-figure":t.hasFigure,"data-has-flag":Boolean(t.flag),"data-has-info":Boolean(t.info),"data-has-options":Boolean(t.options),tabindex:"-1"},on:{click:function(e){return t.$emit("click",e)},dragstart:function(e){return t.$emit("drag",e)}}},"article",t.data,!1),[t._t("image",(function(){return[t.hasFigure?e("k-item-image",{attrs:{image:t.image,layout:t.layout,width:t.width}}):t._e()]})),t.sortable?e("k-sort-handle",{staticClass:"k-item-sort-handle"}):t._e(),e("header",{staticClass:"k-item-content"},[t._t("default",(function(){return[e("h3",{staticClass:"k-item-title"},[!1!==t.link?e("k-link",{staticClass:"k-item-title-link",attrs:{target:t.target,to:t.link}},[e("span",{domProps:{innerHTML:t._s(t.title)}})]):e("span",{domProps:{innerHTML:t._s(t.title)}})],1),t.info?e("p",{staticClass:"k-item-info",domProps:{innerHTML:t._s(t.info)}}):t._e()]}))],2),t.flag||t.options||t.$slots.options?e("footer",{staticClass:"k-item-footer"},[e("nav",{staticClass:"k-item-buttons",on:{click:function(t){t.stopPropagation()}}},[t.flag?e("k-status-icon",t._b({},"k-status-icon",t.flag,!1)):t._e(),t._t("options",(function(){return[t.options?e("k-options-dropdown",{staticClass:"k-item-options-dropdown",attrs:{options:t.options},on:{option:t.onOption}}):t._e()]}))],2)]):t._e()],2)}),[],!1,null,null,null,null).exports;const Bn=Mt({inheritAttrs:!1,props:{image:[Object,Boolean],layout:{type:String,default:"list"},width:String},computed:{back(){return this.image.back||"black"},ratio(){return"cards"===this.layout&&this.image.ratio||"1/1"},size(){switch(this.layout){case"cards":return"large";case"cardlets":return"medium";default:return"regular"}},sizes(){switch(this.width){case"1/2":case"2/4":return"(min-width: 30em) and (max-width: 65em) 59em, (min-width: 65em) 44em, 27em";case"1/3":return"(min-width: 30em) and (max-width: 65em) 59em, (min-width: 65em) 29.333em, 27em";case"1/4":return"(min-width: 30em) and (max-width: 65em) 59em, (min-width: 65em) 22em, 27em";case"2/3":return"(min-width: 30em) and (max-width: 65em) 59em, (min-width: 65em) 27em, 27em";case"3/4":return"(min-width: 30em) and (max-width: 65em) 59em, (min-width: 65em) 66em, 27em";default:return"(min-width: 30em) and (max-width: 65em) 59em, (min-width: 65em) 88em, 27em"}}}},(function(){var t=this,e=t._self._c;return t.image?e("div",{staticClass:"k-item-figure",style:{background:t.$helper.color(t.back)}},[t.image.src?e("k-image",{staticClass:"k-item-image",attrs:{cover:t.image.cover,ratio:t.ratio,sizes:t.sizes,src:t.image.src,srcset:t.image.srcset}}):e("k-aspect-ratio",{attrs:{ratio:t.ratio}},[e("k-icon",{staticClass:"k-item-icon",attrs:{color:t.$helper.color(t.image.color),type:t.image.icon}})],1)],1):t._e()}),[],!1,null,null,null,null).exports;const Pn=Mt({inheritAttrs:!1,props:{columns:{type:[Object,Array],default:()=>({})},items:{type:Array,default:()=>[]},layout:{type:String,default:"list"},link:{type:Boolean,default:!0},image:{type:[Object,Boolean],default:()=>({})},sortable:Boolean,empty:{type:[String,Object]},size:{type:String,default:"default"}},computed:{dragOptions(){return{sort:this.sortable,disabled:!1===this.sortable,draggable:".k-draggable-item"}},table(){return{columns:this.columns,rows:this.items,sortable:this.sortable}}},methods:{onDragStart(t,e){this.$store.dispatch("drag",{type:"text",data:e})},onOption(t,e,s){this.$emit("option",t,e,s)},imageOptions(t){let e=this.image,s=t.image;return!1!==e&&!1!==s&&("object"!=typeof e&&(e={}),"object"!=typeof s&&(s={}),{...s,...e})}}},(function(){var t=this,e=t._self._c;return"table"===t.layout?e("k-table",t._b({on:{change:function(e){return t.$emit("change",e)},sort:function(e){return t.$emit("sort",e)},option:t.onOption}},"k-table",t.table,!1)):e("k-draggable",{staticClass:"k-items",class:"k-"+t.layout+"-items",attrs:{handle:!0,options:t.dragOptions,"data-layout":t.layout,"data-size":t.size,list:t.items},on:{change:function(e){return t.$emit("change",e)},end:function(e){return t.$emit("sort",t.items,e)}}},t._l(t.items,(function(s,n){return e("k-item",t._b({key:s.id||n,class:{"k-draggable-item":t.sortable&&s.sortable},attrs:{image:t.imageOptions(s),layout:t.layout,link:!!t.link&&s.link,sortable:t.sortable&&s.sortable,width:s.column},on:{click:function(e){return t.$emit("item",s,n)},drag:function(e){return t.onDragStart(e,s.dragText)},option:function(e){return t.onOption(e,s,n)}},nativeOn:{mouseover:function(e){return t.$emit("hover",e,s,n)}},scopedSlots:t._u([{key:"options",fn:function(){return[t._t("options",null,null,{item:s,itemIndex:n})]},proxy:!0}],null,!0)},"k-item",s,!1))})),1)}),[],!1,null,null,null,null).exports;const Nn=Mt({inheritAttrs:!0,props:{autofocus:{type:Boolean,default:!0},centered:{type:Boolean,default:!1},dimmed:{type:Boolean,default:!0},loading:{type:Boolean,default:!1}},data:()=>({isOpen:!1,scrollTop:0}),methods:{close(){!1!==this.isOpen&&(this.isOpen=!1,this.$emit("close"),this.restoreScrollPosition(),this.$events.$off("keydown.esc",this.close))},focus(){var t,e;let s=this.$refs.overlay.querySelector("\n [autofocus],\n [data-autofocus]\n ");return null===s&&(s=this.$refs.overlay.querySelector("\n input,\n textarea,\n select,\n button\n ")),"function"==typeof(null==s?void 0:s.focus)?s.focus():"function"==typeof(null==(e=null==(t=this.$slots.default[0])?void 0:t.context)?void 0:e.focus)?this.$slots.default[0].context.focus():void 0},open(){!0!==this.isOpen&&(this.storeScrollPosition(),this.isOpen=!0,this.$emit("open"),this.$events.$on("keydown.esc",this.close),setTimeout((()=>{!0===this.autofocus&&this.focus(),document.querySelector(".k-overlay > *").addEventListener("mousedown",(t=>t.stopPropagation())),this.$emit("ready")}),1))},restoreScrollPosition(){const t=document.querySelector(".k-panel-view");(null==t?void 0:t.scrollTop)&&(t.scrollTop=this.scrollTop)},storeScrollPosition(){const t=document.querySelector(".k-panel-view");(null==t?void 0:t.scrollTop)?this.scrollTop=t.scrollTop:this.scrollTop=0}}},(function(){var t=this,e=t._self._c;return t.isOpen?e("portal",[e("div",t._g({ref:"overlay",staticClass:"k-overlay",class:t.$vnode.data.staticClass,attrs:{"data-centered":t.loading||t.centered,"data-dimmed":t.dimmed,"data-loading":t.loading,dir:t.$translation.direction},on:{mousedown:t.close}},t.$listeners),[t.loading?e("k-loader",{staticClass:"k-overlay-loader"}):t._t("default",null,{close:t.close,isOpen:t.isOpen})],2)]):t._e()}),[],!1,null,null,null,null).exports;const qn=Mt({computed:{defaultLanguage(){return!!this.$language&&this.$language.default},dialog(){return this.$helper.clone(this.$store.state.dialog)},dir(){return this.$translation.direction},language(){return this.$language?this.$language.code:null},role(){return this.$user?this.$user.role:null},user(){return this.$user?this.$user.id:null}},watch:{dir:{handler(){document.body.dir=this.dir},immediate:!0}},created(){this.$events.$on("drop",this.drop)},destroyed(){this.$events.$off("drop",this.drop)},methods:{drop(){this.$store.dispatch("drag",null)}}},(function(){var t=this,e=t._self._c;return e("div",{staticClass:"k-panel",attrs:{"data-dragging":t.$store.state.drag,"data-loading":t.$store.state.isLoading,"data-language":t.language,"data-language-default":t.defaultLanguage,"data-role":t.role,"data-translation":t.$translation.code,"data-user":t.user,dir:t.dir}},[t._t("default"),t.$store.state.dialog&&t.$store.state.dialog.props?[e("k-fiber-dialog",t._b({},"k-fiber-dialog",t.dialog,!1))]:t._e(),!1!==t.$store.state.fatal?e("k-fatal",{attrs:{html:t.$store.state.fatal}}):t._e(),!1===t.$system.isLocal?e("k-offline-warning"):t._e(),e("k-icons")],2)}),[],!1,null,null,null,null).exports;const Fn=Mt({props:{reports:Array,size:{type:String,default:"large"}}},(function(){var t=this,e=t._self._c;return e("dl",{staticClass:"k-stats",attrs:{"data-size":t.size}},t._l(t.reports,(function(s,n){return e(s.link?"k-link":"div",{key:n,tag:"component",staticClass:"k-stat",attrs:{"data-theme":s.theme,"data-click":!!s.click,to:s.link},on:{click:function(t){s.click&&s.click()}}},[e("dt",{staticClass:"k-stat-label"},[t._v(t._s(s.label))]),e("dd",{staticClass:"k-stat-value"},[t._v(t._s(s.value))]),e("dd",{staticClass:"k-stat-info"},[t._v(t._s(s.info))])])})),1)}),[],!1,null,null,null,null).exports;const Rn=Mt({inheritAttrs:!1,props:{columns:Object,disabled:Boolean,fields:{type:Object,default:()=>({})},empty:String,index:{type:[Number,Boolean],default:1},rows:Array,options:[Array,Function],sortable:Boolean},data(){return{values:this.rows}},computed:{columnsCount(){return Object.keys(this.columns).length},dragOptions(){return{disabled:!this.sortable,fallbackClass:"k-table-row-fallback",ghostClass:"k-table-row-ghost"}},hasIndexColumn(){return this.sortable||!1!==this.index},hasOptions(){return this.options||Object.values(this.values).filter((t=>t.options)).length>0}},watch:{rows(){this.values=this.rows}},methods:{isColumnEmpty(t){return 0===this.rows.filter((e=>!1===this.$helper.object.isEmpty(e[t]))).length},label(t,e){return t.label||this.$helper.string.ucfirst(e)},onChange(t){this.$emit("change",t)},onCell(t){this.$emit("cell",t)},onCellUpdate({columnIndex:t,rowIndex:e,value:s}){this.values[e][t]=s,this.$emit("input",this.values)},onHeader(t){this.$emit("header",t)},onOption(t,e,s){this.$emit("option",t,e,s)},onSort(){this.$emit("input",this.values),this.$emit("sort",this.values)},width(t){return"string"!=typeof t?"auto":!1===t.includes("/")?t:this.$helper.ratio(t,"auto",!1)}}},(function(){var t=this,e=t._self._c;return e("table",{staticClass:"k-table",attrs:{"data-disabled":t.disabled,"data-indexed":t.hasIndexColumn}},[e("thead",[e("tr",[t.hasIndexColumn?e("th",{staticClass:"k-table-index-column",attrs:{"data-mobile":""}},[t._v(" # ")]):t._e(),t._l(t.columns,(function(s,n){return e("th",{key:n+"-header",staticClass:"k-table-column",style:"width:"+t.width(s.width),attrs:{"data-mobile":s.mobile},on:{click:function(e){return t.onHeader({column:s,columnIndex:n})}}},[t._t("header",(function(){return[t._v(" "+t._s(t.label(s,n))+" ")]}),null,{column:s,columnIndex:n,label:t.label(s,n)})],2)})),t.hasOptions?e("th",{staticClass:"k-table-options-column",attrs:{"data-mobile":""}}):t._e()],2)]),e("k-draggable",{attrs:{list:t.values,options:t.dragOptions,handle:!0,element:"tbody"},on:{change:t.onChange,end:t.onSort}},[0===t.rows.length?e("tr",[e("td",{staticClass:"k-table-empty",attrs:{colspan:t.columnsCount}},[t._v(" "+t._s(t.empty)+" ")])]):t._l(t.values,(function(s,n){return e("tr",{key:n},[t.hasIndexColumn?e("td",{staticClass:"k-table-index-column",attrs:{"data-sortable":t.sortable&&!1!==s.sortable,"data-mobile":""}},[t._t("index",(function(){return[e("div",{staticClass:"k-table-index",domProps:{textContent:t._s(t.index+n)}})]}),null,{row:s,rowIndex:n}),t.sortable&&!1!==s.sortable?e("k-sort-handle",{staticClass:"k-table-sort-handle"}):t._e()],2):t._e(),t._l(t.columns,(function(i,o){return e("k-table-cell",{key:n+"-"+o,staticClass:"k-table-column",style:"width:"+t.width(i.width),attrs:{column:i,field:t.fields[o],row:s,mobile:i.mobile,value:s[o]},on:{input:function(e){return t.onCellUpdate({columnIndex:o,rowIndex:n,value:e})}},nativeOn:{click:function(e){return t.onCell({row:s,rowIndex:n,column:i,columnIndex:o})}}})})),t.hasOptions?e("td",{staticClass:"k-table-options-column",attrs:{"data-mobile":""}},[t._t("options",(function(){return[e("k-options-dropdown",{attrs:{options:s.options||t.options,text:(s.options||t.options).length>1},on:{option:function(e){return t.onOption(e,s,n)}}})]}),null,{row:s,rowIndex:n,options:t.options})],2):t._e()],2)}))],2)],1)}),[],!1,null,null,null,null).exports;const zn=Mt({inheritAttrs:!1,props:{column:Object,field:Object,mobile:{type:Boolean,default:!1},row:Object,value:{default:""}},computed:{component(){return this.$helper.isComponent(`k-${this.type}-field-preview`)?`k-${this.type}-field-preview`:this.$helper.isComponent(`k-table-${this.type}-cell`)?`k-table-${this.type}-cell`:Array.isArray(this.value)?"k-array-field-preview":"k-text-field-preview"},type(){var t;return this.column.type||(null==(t=this.field)?void 0:t.type)}}},(function(){var t=this,e=t._self._c;return e("td",{attrs:{"data-align":t.column.align,"data-mobile":t.mobile}},[!1===t.$helper.object.isEmpty(t.value)?[e(t.component,{tag:"component",attrs:{column:t.column,field:t.field,row:t.row,value:t.value},on:{input:function(e){return t.$emit("input",e)}}})]:t._e()],2)}),[],!1,null,null,null,null).exports;const Yn=Mt({props:{tab:String,tabs:Array,theme:String},data(){return{size:null,visibleTabs:this.tabs,invisibleTabs:[]}},computed:{current(){return(this.tabs.find((t=>t.name===this.tab))||this.tabs[0]||{}).name}},watch:{tabs:{handler(t){this.visibleTabs=t,this.invisibleTabs=[],this.resize(!0)},immediate:!0}},created(){window.addEventListener("resize",this.resize)},destroyed(){window.removeEventListener("resize",this.resize)},methods:{resize(t){if(this.tabs&&!(this.tabs.length<=1)){if(this.tabs.length<=3)return this.visibleTabs=this.tabs,void(this.invisibleTabs=[]);if(window.innerWidth>=700){if("large"===this.size&&!t)return;this.visibleTabs=this.tabs,this.invisibleTabs=[],this.size="large"}else{if("small"===this.size&&!t)return;this.visibleTabs=this.tabs.slice(0,2),this.invisibleTabs=this.tabs.slice(2),this.size="small"}}}}},(function(){var t=this,e=t._self._c;return t.tabs&&t.tabs.length>1?e("div",{staticClass:"k-tabs",attrs:{"data-theme":t.theme}},[e("nav",[t._l(t.visibleTabs,(function(s){return e("k-button",{key:s.name,staticClass:"k-tab-button",attrs:{link:s.link,current:t.current===s.name,icon:s.icon,tooltip:s.label}},[t._v(" "+t._s(s.label||s.text||s.name)+" "),s.badge?e("span",{staticClass:"k-tabs-badge"},[t._v(" "+t._s(s.badge)+" ")]):t._e()])})),t.invisibleTabs.length?e("k-button",{staticClass:"k-tab-button k-tabs-dropdown-button",attrs:{text:t.$t("more"),icon:"dots"},on:{click:function(e){return e.stopPropagation(),t.$refs.more.toggle()}}}):t._e()],2),t.invisibleTabs.length?e("k-dropdown-content",{ref:"more",staticClass:"k-tabs-dropdown",attrs:{align:"right"}},t._l(t.invisibleTabs,(function(s){return e("k-dropdown-item",{key:"more-"+s.name,attrs:{link:s.link,current:t.tab===s.name,icon:s.icon,tooltip:s.label}},[t._v(" "+t._s(s.label||s.text||s.name)+" ")])})),1):t._e()],1):t._e()}),[],!1,null,null,null,null).exports;const Hn=Mt({props:{align:String}},(function(){var t=this;return(0,t._self._c)("div",{staticClass:"k-view",attrs:{"data-align":t.align}},[t._t("default")],2)}),[],!1,null,null,null,null).exports,Un={};const Kn=Mt({components:{draggable:()=>{return t=()=>import("./vuedraggable.js"),(e=[])&&0!==e.length?Promise.all(e.map((t=>{if((t=function(t){return"/"+t}(t))in Un)return;Un[t]=!0;const e=t.endsWith(".css"),s=e?'[rel="stylesheet"]':"";if(document.querySelector(`link[href="${t}"]${s}`))return;const n=document.createElement("link");return n.rel=e?"stylesheet":"modulepreload",e||(n.as="script",n.crossOrigin=""),n.href=t,document.head.appendChild(n),e?new Promise(((e,s)=>{n.addEventListener("load",e),n.addEventListener("error",(()=>s(new Error(`Unable to preload CSS for ${t}`))))})):void 0}))).then((()=>t())):t();var t,e}},props:{data:Object,element:String,handle:[String,Boolean],list:[Array,Object],move:Function,options:Object},data(){return{listeners:{...this.$listeners,start:t=>{this.$store.dispatch("drag",{}),this.$listeners.start&&this.$listeners.start(t)},end:t=>{this.$store.dispatch("drag",null),this.$listeners.end&&this.$listeners.end(t)}}}},computed:{dragOptions(){let t=!1;return t=!0===this.handle?".k-sort-handle":this.handle,{fallbackClass:"k-sortable-fallback",fallbackOnBody:!0,forceFallback:!0,ghostClass:"k-sortable-ghost",handle:t,scroll:document.querySelector(".k-panel-view"),...this.options}}}},(function(){var t=this;return(0,t._self._c)("draggable",t._g(t._b({staticClass:"k-draggable",attrs:{"component-data":t.data,tag:t.element,list:t.list,move:t.move},scopedSlots:t._u([{key:"footer",fn:function(){return[t._t("footer")]},proxy:!0}],null,!0)},"draggable",t.dragOptions,!1),t.listeners),[t._t("default")],2)}),[],!1,null,null,null,null).exports;const Gn=Mt({data:()=>({error:null}),errorCaptured(t){return this.$config.debug&&window.console.warn(t),this.error=t,!1},render(t){return this.error?this.$slots.error?this.$slots.error[0]:this.$scopedSlots.error?this.$scopedSlots.error({error:this.error}):t("k-box",{attrs:{theme:"negative"}},this.error.message||this.error):this.$slots.default[0]}},null,null,!1,null,null,null,null).exports;const Jn=Mt({props:{html:String},mounted(){try{let t=this.$refs.iframe.contentWindow.document;t.open(),t.write(this.html),t.close()}catch(t){console.error(t)}}},(function(){var t=this,e=t._self._c;return e("div",{staticClass:"k-fatal"},[e("div",{staticClass:"k-fatal-box"},[e("k-bar",{scopedSlots:t._u([{key:"left",fn:function(){return[e("k-headline",[t._v(" The JSON response could not be parsed ")])]},proxy:!0},{key:"right",fn:function(){return[e("k-button",{attrs:{icon:"cancel",text:"Close"},on:{click:function(e){return t.$store.dispatch("fatal",!1)}}})]},proxy:!0}])}),e("iframe",{ref:"iframe",staticClass:"k-fatal-iframe"})],1)])}),[],!1,null,null,null,null).exports;const Vn=Mt({props:{link:String,size:{type:String},tag:{type:String,default:"h2"},theme:{type:String}}},(function(){var t=this,e=t._self._c;return e(t.tag,t._g({tag:"component",staticClass:"k-headline",attrs:{"data-theme":t.theme,"data-size":t.size}},t.$listeners),[t.link?e("k-link",{attrs:{to:t.link}},[t._t("default")],2):t._t("default")],2)}),[],!1,null,null,null,null).exports;const Wn=Mt({props:{alt:String,color:String,back:String,size:String,type:String},computed:{isEmoji(){return this.$helper.string.hasEmoji(this.type)}}},(function(){var t=this,e=t._self._c;return e("span",{class:"k-icon k-icon-"+t.type,style:{background:t.$helper.color(t.back)},attrs:{"aria-label":t.alt,role:t.alt?"img":null,"aria-hidden":!t.alt,"data-back":t.back,"data-size":t.size}},[t.isEmoji?e("span",{staticClass:"k-icon-emoji"},[t._v(t._s(t.type))]):e("svg",{style:{color:t.$helper.color(t.color)},attrs:{viewBox:"0 0 16 16"}},[e("use",{attrs:{"xlink:href":"#icon-"+t.type}})])])}),[],!1,null,null,null,null).exports;const Xn=Mt({icons:window.panel.plugins.icons},(function(){var t=this,e=t._self._c;return e("svg",{staticClass:"k-icons",attrs:{"aria-hidden":"true",xmlns:"http://www.w3.org/2000/svg",overflow:"hidden"}},[e("defs",t._l(t.$options.icons,(function(s,n){return e("symbol",{key:n,attrs:{id:"icon-"+n,viewBox:"0 0 16 16"},domProps:{innerHTML:t._s(s)}})})),0)])}),[],!1,null,null,null,null).exports;const Zn=Mt({props:{alt:String,back:String,cover:Boolean,ratio:String,sizes:String,src:String,srcset:String},data:()=>({loaded:{type:Boolean,default:!1},error:{type:Boolean,default:!1}}),computed:{ratioPadding(){return this.$helper.ratio(this.ratio||"1/1")}},created(){let t=new Image;t.onload=()=>{this.loaded=!0,this.$emit("load")},t.onerror=()=>{this.error=!0,this.$emit("error")},t.src=this.src}},(function(){var t=this,e=t._self._c;return e("span",t._g({staticClass:"k-image",attrs:{"data-ratio":t.ratio,"data-back":t.back,"data-cover":t.cover}},t.$listeners),[e("span",{style:"padding-bottom:"+t.ratioPadding},[t.loaded?e("img",{key:t.src,attrs:{alt:t.alt||"",src:t.src,srcset:t.srcset,sizes:t.sizes},on:{dragstart:function(t){t.preventDefault()}}}):t._e(),t.loaded||t.error?t._e():e("k-loader",{attrs:{position:"center",theme:"light"}}),!t.loaded&&t.error?e("k-icon",{staticClass:"k-image-error",attrs:{type:"cancel"}}):t._e()],1)])}),[],!1,null,null,null,null).exports;const Qn=Mt({},(function(){var t=this._self._c;return t("span",{staticClass:"k-loader"},[t("k-icon",{staticClass:"k-loader-icon",attrs:{type:"loader"}})],1)}),[],!1,null,null,null,null).exports;const ti=Mt({data:()=>({offline:!1}),created(){this.$events.$on("offline",this.isOffline),this.$events.$on("online",this.isOnline)},destroyed(){this.$events.$off("offline",this.isOffline),this.$events.$off("online",this.isOnline)},methods:{isOnline(){this.offline=!1},isOffline(){this.offline=!0}}},(function(){var t=this,e=t._self._c;return t.offline?e("div",{staticClass:"k-offline-warning"},[e("p",[e("k-icon",{attrs:{type:"bolt"}}),t._v(" "+t._s(t.$t("error.offline")))],1)]):t._e()}),[],!1,null,null,null,null).exports,ei=(t,e=!1)=>{if(t>=0&&t<=100)return!0;if(e)throw new Error("value has to be between 0 and 100");return!1};const si=Mt({props:{value:{type:Number,default:0,validator:ei}},data(){return{state:this.value}},watch:{value(t){this.state=t}},methods:{set(t){ei(t,!0),this.state=t}}},(function(){var t=this;return(0,t._self._c)("progress",{staticClass:"k-progress",attrs:{max:"100"},domProps:{value:t.state}},[t._v(t._s(t.state)+"%")])}),[],!1,null,null,null,null).exports;const ni=Mt({},(function(){var t=this,e=t._self._c;return e("div",{staticClass:"k-registration"},[e("p",[t._v(t._s(t.$t("license.unregistered")))]),e("k-button",{staticClass:"k-topbar-button",attrs:{responsive:!0,tooltip:t.$t("license.unregistered"),icon:"key"},on:{click:function(e){return t.$dialog("registration")}}},[t._v(" "+t._s(t.$t("license.register"))+" ")]),e("k-button",{staticClass:"k-topbar-button",attrs:{responsive:!0,link:"https://getkirby.com/buy",target:"_blank",icon:"cart"}},[t._v(" "+t._s(t.$t("license.buy"))+" ")])],1)}),[],!1,null,null,null,null).exports;const ii=Mt({props:{icon:{type:String,default:"sort"}}},(function(){return(0,this._self._c)("k-icon",{staticClass:"k-sort-handle",attrs:{type:this.icon,"aria-hidden":"true"}})}),[],!1,null,null,null,null).exports;const oi=Mt({props:{click:{type:Function,default:()=>{}},disabled:Boolean,responsive:Boolean,status:String,text:String,tooltip:String},computed:{icon(){return"draft"===this.status?"circle-outline":"unlisted"===this.status?"circle-half":"circle"},theme(){return"draft"===this.status?"negative":"unlisted"===this.status?"info":"positive"},title(){let t=this.tooltip||this.text;return this.disabled&&(t+=` (${this.$t("disabled")})`),t}},methods:{onClick(){this.click(),this.$emit("click")}}},(function(){var t=this;return(0,t._self._c)("k-button",{class:"k-status-icon k-status-icon-"+t.status,attrs:{disabled:t.disabled,icon:t.icon,responsive:t.responsive,text:t.text,theme:t.theme,tooltip:t.title},on:{click:t.onClick}})}),[],!1,null,null,null,null).exports;const ri=Mt({props:{align:String,html:String,size:String,theme:String},computed:{attrs(){return{class:"k-text","data-align":this.align,"data-size":this.size,"data-theme":this.theme}}}},(function(){var t=this,e=t._self._c;return t.html?e("div",t._b({domProps:{innerHTML:t._s(t.html)}},"div",t.attrs,!1)):e("div",t._b({},"div",t.attrs,!1),[t._t("default")],2)}),[],!1,null,null,null,null).exports;const li=Mt({props:{user:[Object,String]}},(function(){var t=this,e=t._self._c;return e("div",{staticClass:"k-user-info"},[t.user.avatar?e("k-image",{attrs:{cover:!0,src:t.user.avatar.url,ratio:"1/1"}}):e("k-icon",{attrs:{type:"user"}}),t._v(" "+t._s(t.user.name||t.user.email||t.user)+" ")],1)}),[],!1,null,null,null,null).exports;const ai=Mt({props:{crumbs:{type:Array,default:()=>[]},label:{type:String,default:"Breadcrumb"},view:Object},computed:{dropdown(){return this.segments.map((t=>({...t,text:t.label,icon:"angle-right"})))},segments(){return[{link:this.view.link,label:this.view.breadcrumbLabel,icon:this.view.icon,loading:this.$store.state.isLoading},...this.crumbs]}},methods:{isLast(t){return this.crumbs.length-1===t}}},(function(){var t=this,e=t._self._c;return e("nav",{staticClass:"k-breadcrumb",attrs:{"aria-label":t.label}},[e("k-dropdown",{staticClass:"k-breadcrumb-dropdown"},[e("k-button",{attrs:{icon:"road-sign"},on:{click:function(e){return t.$refs.dropdown.toggle()}}}),e("k-dropdown-content",{ref:"dropdown",attrs:{options:t.dropdown,theme:"light"}})],1),e("ol",t._l(t.segments,(function(s,n){return e("li",{key:n},[e("k-link",{staticClass:"k-breadcrumb-link",attrs:{title:s.text||s.label,to:s.link,"aria-current":!!t.isLast(n)&&"page"}},[s.loading?e("k-loader",{staticClass:"k-breadcrumb-icon"}):s.icon?e("k-icon",{staticClass:"k-breadcrumb-icon",attrs:{type:s.icon}}):t._e(),e("span",{staticClass:"k-breadcrumb-link-text"},[t._v(" "+t._s(s.text||s.label)+" ")])],1)],1)})),0)],1)}),[],!1,null,null,null,null).exports;const ui=Mt({inheritAttrs:!1,props:{autofocus:Boolean,click:Function,current:[String,Boolean],disabled:Boolean,icon:String,id:[String,Number],link:String,responsive:Boolean,rel:String,role:String,target:String,tabindex:String,text:[String,Number],theme:String,tooltip:String,type:{type:String,default:"button"}},computed:{component(){return!0===this.disabled?"k-button-disabled":this.link?"k-button-link":"k-button-native"}},methods:{focus(){this.$refs.button.focus&&this.$refs.button.focus()},tab(){this.$refs.button.tab&&this.$refs.button.tab()},untab(){this.$refs.button.untab&&this.$refs.button.untab()}}},(function(){var t=this;return(0,t._self._c)(t.component,t._g(t._b({ref:"button",tag:"component"},"component",t.$props,!1),t.$listeners),[t.text?[t._v(" "+t._s(t.text)+" ")]:t._t("default")],2)}),[],!1,null,null,null,null).exports;const ci=Mt({inheritAttrs:!1,props:{icon:String,id:[String,Number],responsive:Boolean,theme:String,tooltip:String}},(function(){var t=this,e=t._self._c;return e("span",{staticClass:"k-button",attrs:{id:t.id,"data-disabled":!0,"data-responsive":t.responsive,"data-theme":t.theme,title:t.tooltip}},[t.icon?e("k-icon",{staticClass:"k-button-icon",attrs:{type:t.icon,alt:t.tooltip}}):t._e(),t.$slots.default?e("span",{staticClass:"k-button-text"},[t._t("default")],2):t._e()],1)}),[],!1,null,null,null,null).exports;const di=Mt({props:{buttons:Array}},(function(){var t=this,e=t._self._c;return e("div",{staticClass:"k-button-group"},[t.$slots.default?t._t("default"):t._l(t.buttons,(function(s,n){return e("k-button",t._b({key:n},"k-button",s,!1))}))],2)}),[],!1,null,null,null,null).exports;const pi=Mt({inheritAttrs:!1,props:{autofocus:Boolean,current:[String,Boolean],icon:String,id:[String,Number],link:String,rel:String,responsive:Boolean,role:String,target:String,tabindex:String,theme:String,tooltip:String},methods:{focus(){this.$el.focus()}}},(function(){var t=this,e=t._self._c;return e("k-link",t._g({staticClass:"k-button",attrs:{id:t.id,"aria-current":t.current,autofocus:t.autofocus,"data-theme":t.theme,"data-responsive":t.responsive,rel:t.rel,role:t.role,tabindex:t.tabindex,target:t.target,title:t.tooltip,to:t.link}},t.$listeners),[t.icon?e("k-icon",{staticClass:"k-button-icon",attrs:{type:t.icon,alt:t.tooltip}}):t._e(),t.$slots.default?e("span",{staticClass:"k-button-text"},[t._t("default")],2):t._e()],1)}),[],!1,null,null,null,null).exports,hi={mounted(){this.$el.addEventListener("keyup",this.onTab,!0),this.$el.addEventListener("blur",this.onUntab,!0)},destroyed(){this.$el.removeEventListener("keyup",this.onTab,!0),this.$el.removeEventListener("blur",this.onUntab,!0)},methods:{focus(){this.$el.focus&&this.$el.focus()},onTab(t){9===t.keyCode&&this.$el.setAttribute("data-tabbed",!0)},onUntab(){this.$el.removeAttribute("data-tabbed")},tab(){this.$el.focus(),this.$el.setAttribute("data-tabbed",!0)},untab(){this.$el.removeAttribute("data-tabbed")}}};const mi=Mt({mixins:[hi],inheritAttrs:!1,props:{autofocus:Boolean,click:{type:Function,default:()=>{}},current:[String,Boolean],icon:String,id:[String,Number],responsive:Boolean,role:String,tabindex:String,theme:String,tooltip:String,type:{type:String,default:"button"}}},(function(){var t=this,e=t._self._c;return e("button",t._g({staticClass:"k-button",attrs:{id:t.id,"aria-current":t.current,autofocus:t.autofocus,"data-theme":t.theme,"data-responsive":t.responsive,role:t.role,tabindex:t.tabindex,title:t.tooltip,type:t.type},on:{click:t.click}},t.$listeners),[t.icon?e("k-icon",{staticClass:"k-button-icon",attrs:{type:t.icon,alt:t.tooltip}}):t._e(),t.$slots.default?e("span",{staticClass:"k-button-text"},[t._t("default")],2):t._e()],1)}),[],!1,null,null,null,null).exports;const fi=Mt({},(function(){return(0,this._self._c)("span",{staticClass:"k-dropdown",on:{click:function(t){t.stopPropagation()}}},[this._t("default")],2)}),[],!1,null,null,null,null).exports;let gi=null;const ki=Mt({props:{align:{type:String,default:"left"},options:[Array,Function,String],theme:{type:String,default:"dark"}},data:()=>({current:-1,dropup:!1,isOpen:!1,items:[]}),methods:{async fetchOptions(t){if(!this.options)return t(this.items);"string"==typeof this.options?this.$dropdown(this.options)(t):"function"==typeof this.options?this.options(t):Array.isArray(this.options)&&t(this.options)},onOptionClick(t){"function"==typeof t.click?t.click.call(this):t.click&&this.$emit("action",t.click)},open(){this.reset(),gi&&gi!==this&&gi.close(),this.fetchOptions((t=>{this.$events.$on("keydown",this.navigate),this.$events.$on("click",this.close),this.items=t,this.isOpen=!0,gi=this,this.onOpen(),this.$emit("open")}))},reset(){this.current=-1,this.$events.$off("keydown",this.navigate),this.$events.$off("click",this.close)},close(){this.reset(),this.isOpen=gi=!1,this.$emit("close")},toggle(){this.isOpen?this.close():this.open()},focus(t=0){var e;(null==(e=this.$children[t])?void 0:e.focus)&&(this.current=t,this.$children[t].focus())},onOpen(){this.dropup=!1,this.$nextTick((()=>{if(this.$el){let t=window.innerHeight||document.body.clientHeight||document.documentElement.clientHeight,e=50,s=this.$el.getBoundingClientRect().top||0,n=this.$el.clientHeight;s+n>t-e&&n+2*ethis.$children.length-1){const t=this.$children.filter((t=>!1===t.disabled));this.current=this.$children.indexOf(t[t.length-1]);break}if(this.$children[this.current]&&!1===this.$children[this.current].disabled){this.focus(this.current);break}}break;case"Tab":for(;;){if(this.current++,this.current>this.$children.length-1){this.close(),this.$emit("leave",t.code);break}if(this.$children[this.current]&&!1===this.$children[this.current].disabled)break}}}}},(function(){var t=this,e=t._self._c;return t.isOpen?e("div",{staticClass:"k-dropdown-content",attrs:{"data-align":t.align,"data-dropup":t.dropup,"data-theme":t.theme}},[t._t("default",(function(){return[t._l(t.items,(function(s,n){return["-"===s?e("hr",{key:t._uid+"-item-"+n}):e("k-dropdown-item",t._b({key:t._uid+"-item-"+n,ref:t._uid+"-item-"+n,refInFor:!0,on:{click:function(e){return t.onOptionClick(s)}}},"k-dropdown-item",s,!1),[t._v(" "+t._s(s.text)+" ")])]}))]}))],2):t._e()}),[],!1,null,null,null,null).exports;const bi=Mt({inheritAttrs:!1,props:{disabled:Boolean,icon:String,image:[String,Object],link:String,target:String,theme:String,upload:String,current:[String,Boolean]},data(){return{listeners:{...this.$listeners,click:t=>{this.$parent.close(),this.$emit("click",t)}}}},methods:{focus(){this.$refs.button.focus()},tab(){this.$refs.button.tab()}}},(function(){var t=this;return(0,t._self._c)("k-button",t._g(t._b({ref:"button",staticClass:"k-dropdown-item"},"k-button",t.$props,!1),t.listeners),[t._t("default")],2)}),[],!1,null,null,null,null).exports;const yi=Mt({mixins:[hi],props:{disabled:Boolean,rel:String,tabindex:[String,Number],target:String,title:String,to:[String,Function]},data(){return{relAttr:"_blank"===this.target?"noreferrer noopener":this.rel,listeners:{...this.$listeners,click:this.onClick}}},computed:{href(){return"function"==typeof this.to?"":"/"!==this.to[0]||this.target?!0===this.to.includes("@")&&!1===this.to.includes("/")?"mailto:"+this.to:this.to:this.$url(this.to)}},methods:{isRoutable(t){if(t.metaKey||t.altKey||t.ctrlKey||t.shiftKey)return!1;if(t.defaultPrevented)return!1;if(void 0!==t.button&&0!==t.button)return!1;if(this.target)return!1;if("string"==typeof this.href){if(this.href.includes("://")||this.href.startsWith("//"))return!1;if(this.href.includes("mailto:"))return!1}return!0},onClick(t){if(!0===this.disabled)return t.preventDefault(),!1;"function"==typeof this.to&&(t.preventDefault(),this.to()),this.isRoutable(t)&&(t.preventDefault(),this.$go(this.to)),this.$emit("click",t)}}},(function(){var t=this,e=t._self._c;return t.to&&!t.disabled?e("a",t._g({ref:"link",staticClass:"k-link",attrs:{href:t.href,rel:t.relAttr,tabindex:t.tabindex,target:t.target,title:t.title}},t.listeners),[t._t("default")],2):e("span",{staticClass:"k-link",attrs:{title:t.title,"data-disabled":""}},[t._t("default")],2)}),[],!1,null,null,null,null).exports;const vi=Mt({computed:{defaultLanguage(){return this.$languages.find((t=>!0===t.default))},language(){return this.$language},languages(){return this.$languages.filter((t=>!1===t.default))}},methods:{change(t){this.$emit("change",t),this.$go(window.location,{query:{language:t.code}})}}},(function(){var t=this,e=t._self._c;return t.languages.length?e("k-dropdown",{staticClass:"k-languages-dropdown"},[e("k-button",{attrs:{text:t.language.name,responsive:!0,icon:"globe"},on:{click:function(e){return t.$refs.languages.toggle()}}}),t.languages?e("k-dropdown-content",{ref:"languages"},[e("k-dropdown-item",{on:{click:function(e){return t.change(t.defaultLanguage)}}},[t._v(" "+t._s(t.defaultLanguage.name)+" ")]),e("hr"),t._l(t.languages,(function(s){return e("k-dropdown-item",{key:s.code,on:{click:function(e){return t.change(s)}}},[t._v(" "+t._s(s.name)+" ")])}))],2):t._e()],1):t._e()}),[],!1,null,null,null,null).exports;const $i=Mt({props:{align:{type:String,default:"right"},icon:{type:String,default:"dots"},options:{type:[Array,Function,String],default:()=>[]},text:{type:[Boolean,String],default:!0},theme:{type:String,default:"dark"}},computed:{hasSingleOption(){return Array.isArray(this.options)&&1===this.options.length}},methods:{onAction(t,e,s){"function"==typeof t?t.call(this):(this.$emit("action",t,e,s),this.$emit("option",t,e,s))},toggle(){this.$refs.options.toggle()}}},(function(){var t=this,e=t._self._c;return t.hasSingleOption?e("k-button",{staticClass:"k-options-dropdown-toggle",attrs:{icon:t.options[0].icon||t.icon,tooltip:t.options[0].tooltip||t.options[0].text},on:{click:function(e){return t.onAction(t.options[0].option||t.options[0].click,t.options[0],0)}}},[!0===t.text?[t._v(" "+t._s(t.options[0].text)+" ")]:!1!==t.text?[t._v(" "+t._s(t.text)+" ")]:t._e()],2):t.options.length?e("k-dropdown",{staticClass:"k-options-dropdown"},[e("k-button",{staticClass:"k-options-dropdown-toggle",attrs:{icon:t.icon,tooltip:t.$t("options")},on:{click:function(e){return t.$refs.options.toggle()}}},[t.text&&!0!==t.text?[t._v(" "+t._s(t.text)+" ")]:t._e()],2),e("k-dropdown-content",{ref:"options",staticClass:"k-options-dropdown-content",attrs:{align:t.align,options:t.options},on:{action:t.onAction}})],1):t._e()}),[],!1,null,null,null,null).exports;const _i=Mt({props:{align:{type:String,default:"left"},details:{type:Boolean,default:!1},dropdown:{type:Boolean,default:!0},keys:{type:Boolean,default:!1},limit:{type:Number,default:10},page:{type:Number,default:1},pageLabel:{type:String,default:()=>window.panel.$t("pagination.page")},total:{type:Number,default:0},prevLabel:{type:String,default:()=>window.panel.$t("prev")},nextLabel:{type:String,default:()=>window.panel.$t("next")},validate:{type:Function,default:()=>Promise.resolve()}},data(){return{currentPage:this.page}},computed:{show(){return this.pages>1},start(){return(this.currentPage-1)*this.limit+1},end(){let t=this.start-1+this.limit;return t>this.total?this.total:t},detailsText(){return 1===this.limit?this.start+" / ":this.start+"-"+this.end+" / "},pages(){return Math.ceil(this.total/this.limit)},hasPrev(){return this.start>1},hasNext(){return this.endthis.limit},offset(){return this.start-1}},watch:{page(t){this.currentPage=parseInt(t)}},created(){!0===this.keys&&window.addEventListener("keydown",this.navigate,!1)},destroyed(){window.removeEventListener("keydown",this.navigate,!1)},methods:{async goTo(t){try{await this.validate(t),t<1&&(t=1),t>this.pages&&(t=this.pages),this.currentPage=t,this.$refs.dropdown&&this.$refs.dropdown.close(),this.$emit("paginate",{page:this.currentPage,start:this.start,end:this.end,limit:this.limit,offset:this.offset})}catch(e){}},prev(){this.goTo(this.currentPage-1)},next(){this.goTo(this.currentPage+1)},navigate(t){switch(t.code){case"ArrowLeft":this.prev();break;case"ArrowRight":this.next()}}}},(function(){var t=this,e=t._self._c;return t.show?e("nav",{staticClass:"k-pagination",attrs:{"data-align":t.align}},[t.show?e("k-button",{attrs:{disabled:!t.hasPrev,tooltip:t.prevLabel,icon:"angle-left"},on:{click:t.prev}}):t._e(),t.details?[t.dropdown?[e("k-dropdown",[e("k-button",{staticClass:"k-pagination-details",attrs:{disabled:!t.hasPages},on:{click:function(e){return t.$refs.dropdown.toggle()}}},[t.total>1?[t._v(" "+t._s(t.detailsText)+" ")]:t._e(),t._v(" "+t._s(t.total)+" ")],2),e("k-dropdown-content",{ref:"dropdown",staticClass:"k-pagination-selector",on:{open:function(e){t.$nextTick((()=>t.$refs.page.focus()))}}},[e("div",{staticClass:"k-pagination-settings"},[e("label",{attrs:{for:"k-pagination-page"}},[e("span",[t._v(t._s(t.pageLabel)+":")]),e("select",{ref:"page",attrs:{id:"k-pagination-page"}},t._l(t.pages,(function(s){return e("option",{key:s,domProps:{selected:t.page===s,value:s}},[t._v(" "+t._s(s)+" ")])})),0)]),e("k-button",{attrs:{icon:"check"},on:{click:function(e){return t.goTo(t.$refs.page.value)}}})],1)])],1)]:[e("span",{staticClass:"k-pagination-details"},[t.total>1?[t._v(" "+t._s(t.detailsText)+" ")]:t._e(),t._v(" "+t._s(t.total)+" ")],2)]]:t._e(),t.show?e("k-button",{attrs:{disabled:!t.hasNext,tooltip:t.nextLabel,icon:"angle-right"},on:{click:t.next}}):t._e()],2):t._e()}),[],!1,null,null,null,null).exports;const xi=Mt({props:{prev:{type:[Boolean,Object],default:!1},next:{type:[Boolean,Object],default:!1}},computed:{buttons(){return[{...this.button(this.prev),icon:"angle-left"},{...this.button(this.next),icon:"angle-right"}]}},methods:{button:t=>t||{disabled:!0,link:"#"}}},(function(){return(0,this._self._c)("k-button-group",{staticClass:"k-prev-next",attrs:{buttons:this.buttons}})}),[],!1,null,null,null,null).exports;const wi=Mt({props:{types:{type:Object,default:()=>({})},type:String},data(){return{isLoading:!1,hasResults:!0,items:[],currentType:this.getType(this.type),q:null,selected:-1}},watch:{q(t,e){t!==e&&this.search(this.q)},currentType(t,e){t!==e&&this.search(this.q)},type(){this.currentType=this.getType(this.type)}},created(){this.search=dt(this.search,250),this.$events.$on("keydown.cmd.shift.f",this.open)},destroyed(){this.$events.$off("keydown.cmd.shift.f",this.open)},methods:{changeType(t){this.currentType=this.getType(t),this.$nextTick((()=>{this.$refs.input.focus()}))},close(){this.$refs.overlay.close(),this.hasResults=!0,this.items=[],this.q=null},getType(t){return this.types[t]||this.types[Object.keys(this.types)[0]]},navigate(t){this.$go(t.link),this.close()},onDown(){this.selected=0&&this.select(this.selected-1)},open(){this.$refs.overlay.open()},async search(t){this.isLoading=!0,this.$refs.types&&this.$refs.types.close();try{if(null===t||""===t)throw Error("Empty query");const e=await this.$search(this.currentType.id,t);if(!1===e)throw Error("JSON parsing failed");this.items=e.results}catch(e){this.items=[]}finally{this.select(-1),this.isLoading=!1,this.hasResults=this.items.length>0}},select(t){if(this.selected=t,this.$refs.items){const e=this.$refs.items.$el.querySelectorAll(".k-item");[...e].forEach((t=>delete t.dataset.selected)),t>=0&&(e[t].dataset.selected=!0)}}}},(function(){var t=this,e=t._self._c;return e("k-overlay",{ref:"overlay"},[e("div",{staticClass:"k-search",attrs:{role:"search"}},[e("div",{staticClass:"k-search-input"},[e("k-dropdown",{staticClass:"k-search-types"},[e("k-button",{attrs:{icon:t.currentType.icon,text:t.currentType.label},on:{click:function(e){return t.$refs.types.toggle()}}}),e("k-dropdown-content",{ref:"types"},t._l(t.types,(function(s,n){return e("k-dropdown-item",{key:n,attrs:{icon:s.icon},on:{click:function(e){return t.changeType(n)}}},[t._v(" "+t._s(s.label)+" ")])})),1)],1),e("input",{directives:[{name:"model",rawName:"v-model",value:t.q,expression:"q"}],ref:"input",attrs:{placeholder:t.$t("search")+" …","aria-label":t.$t("search"),autofocus:!0,type:"text"},domProps:{value:t.q},on:{input:[function(e){e.target.composing||(t.q=e.target.value)},function(e){t.hasResults=!0}],keydown:[function(e){return!e.type.indexOf("key")&&t._k(e.keyCode,"down",40,e.key,["Down","ArrowDown"])?null:(e.preventDefault(),t.onDown.apply(null,arguments))},function(e){return!e.type.indexOf("key")&&t._k(e.keyCode,"up",38,e.key,["Up","ArrowUp"])?null:(e.preventDefault(),t.onUp.apply(null,arguments))},function(e){return!e.type.indexOf("key")&&t._k(e.keyCode,"tab",9,e.key,"Tab")?null:(e.preventDefault(),t.onTab.apply(null,arguments))},function(e){return!e.type.indexOf("key")&&t._k(e.keyCode,"enter",13,e.key,"Enter")?null:t.onEnter.apply(null,arguments)},function(e){return!e.type.indexOf("key")&&t._k(e.keyCode,"esc",27,e.key,["Esc","Escape"])?null:t.close.apply(null,arguments)}]}}),e("k-button",{staticClass:"k-search-close",attrs:{icon:t.isLoading?"loader":"cancel",tooltip:t.$t("close")},on:{click:t.close}})],1),!t.q||t.hasResults&&!t.items.length?t._e():e("div",{staticClass:"k-search-results"},[t.items.length?e("k-collection",{ref:"items",attrs:{items:t.items},on:{hover:t.onHover},nativeOn:{mouseout:function(e){return t.select(-1)}}}):t.hasResults?t._e():e("p",{staticClass:"k-search-empty"},[t._v(" "+t._s(t.$t("search.results.none"))+" ")])],1)])])}),[],!1,null,null,null,null).exports;const Si=Mt({props:{removable:Boolean},methods:{remove(){this.removable&&this.$emit("remove")},focus(){this.$refs.button.focus()}}},(function(){var t=this,e=t._self._c;return e("span",{ref:"button",staticClass:"k-tag",attrs:{tabindex:"0"},on:{keydown:function(e){return!e.type.indexOf("key")&&t._k(e.keyCode,"delete",[8,46],e.key,["Backspace","Delete","Del"])?null:(e.preventDefault(),t.remove.apply(null,arguments))}}},[e("span",{staticClass:"k-tag-text"},[t._t("default")],2),t.removable?e("k-icon",{staticClass:"k-tag-toggle",attrs:{type:"cancel-small"},nativeOn:{click:function(e){return t.remove.apply(null,arguments)}}}):t._e()],1)}),[],!1,null,null,null,null).exports;const Ci=Mt({props:{breadcrumb:Array,license:Boolean,menu:Array,title:String,view:Object},computed:{notification(){return this.$store.state.notification.type&&"error"!==this.$store.state.notification.type?this.$store.state.notification:null}}},(function(){var t=this,e=t._self._c;return e("div",{staticClass:"k-topbar"},[e("k-view",[e("div",{staticClass:"k-topbar-wrapper"},[e("k-dropdown",{staticClass:"k-topbar-menu"},[e("k-button",{staticClass:"k-topbar-button k-topbar-menu-button",attrs:{tooltip:t.$t("menu"),icon:"bars"},on:{click:function(e){return t.$refs.menu.toggle()}}},[e("k-icon",{attrs:{type:"angle-down"}})],1),e("k-dropdown-content",{ref:"menu",staticClass:"k-topbar-menu",attrs:{options:t.menu,theme:"light"}})],1),e("k-breadcrumb",{staticClass:"k-topbar-breadcrumb",attrs:{crumbs:t.breadcrumb,view:t.view}}),e("div",{staticClass:"k-topbar-signals"},[t.notification?e("k-button",{staticClass:"k-topbar-notification k-topbar-button",attrs:{text:t.notification.message,theme:"positive"},on:{click:function(e){return t.$store.dispatch("notification/close")}}}):t.license?t._e():e("k-registration"),e("k-form-indicator"),e("k-button",{staticClass:"k-topbar-button",attrs:{tooltip:t.$t("search"),icon:"search"},on:{click:function(e){return t.$refs.search.open()}}})],1)],1)]),e("k-search",{ref:"search",attrs:{type:t.$view.search||"pages",types:t.$searches}})],1)}),[],!1,null,null,null,null).exports;const Oi=Mt({props:{empty:String,blueprint:String,lock:[Boolean,Object],parent:String,tab:Object},computed:{content(){return this.$store.getters["content/values"]()}},methods:{exists(t){return this.$helper.isComponent(`k-${t}-section`)},meetsCondition(t){if(!t.when)return!0;let e=!0;return Object.keys(t.when).forEach((s=>{this.content[s.toLowerCase()]!==t.when[s]&&(e=!1)})),e}}},(function(){var t=this,e=t._self._c;return 0===t.tab.columns.length?e("k-box",{attrs:{html:!0,text:t.empty,theme:"info"}}):e("k-grid",{staticClass:"k-sections",attrs:{gutter:"large"}},t._l(t.tab.columns,(function(s,n){return e("k-column",{key:t.parent+"-column-"+n,attrs:{width:s.width,sticky:s.sticky}},[t._l(s.sections,(function(i,o){return[t.meetsCondition(i)?[t.exists(i.type)?e("k-"+i.type+"-section",t._b({key:t.parent+"-column-"+n+"-section-"+o+"-"+t.blueprint,tag:"component",class:"k-section k-section-name-"+i.name,attrs:{column:s.width,lock:t.lock,name:i.name,parent:t.parent,timestamp:t.$view.timestamp},on:{submit:function(e){return t.$emit("submit",e)}}},"component",i,!1)):[e("k-box",{key:t.parent+"-column-"+n+"-section-"+o,attrs:{text:t.$t("error.section.type.invalid",{type:i.type}),theme:"negative"}})]]:t._e()]}))],2)})),1)}),[],!1,null,null,null,null).exports;const Ai=Mt({mixins:[Tt],inheritAttrs:!1,data:()=>({fields:{},isLoading:!0,issue:null}),computed:{values(){return this.$store.getters["content/values"]()}},watch:{timestamp(){this.fetch()}},created(){this.input=dt(this.input,50),this.fetch()},methods:{input(t,e,s){this.$store.dispatch("content/update",[s,t[s]])},async fetch(){try{const t=await this.load();this.fields=t.fields,Object.keys(this.fields).forEach((t=>{this.fields[t].section=this.name,this.fields[t].endpoints={field:this.parent+"/fields/"+t,section:this.parent+"/sections/"+this.name,model:this.parent}}))}catch(t){this.issue=t}finally{this.isLoading=!1}},onSubmit(t){this.$events.$emit("keydown.cmd.s",t)}}},(function(){var t=this,e=t._self._c;return t.isLoading?t._e():e("section",{staticClass:"k-fields-section"},[t.issue?[e("k-headline",{staticClass:"k-fields-issue-headline"},[t._v(" Error ")]),e("k-box",{attrs:{text:t.issue.message,html:!1,theme:"negative"}})]:t._e(),e("k-form",{attrs:{fields:t.fields,validate:!0,value:t.values,disabled:t.lock&&"lock"===t.lock.state},on:{input:t.input,submit:t.onSubmit}})],2)}),[],!1,null,null,null,null).exports;const Ti=Mt({inheritAttrs:!1,props:{blueprint:String,column:String,parent:String,name:String,timestamp:Number},data:()=>({data:[],error:null,isLoading:!1,isProcessing:!1,options:{columns:{},empty:null,headline:null,help:null,layout:"list",link:null,max:null,min:null,size:null,sortable:null},pagination:{page:null},searchterm:null,searching:!1}),computed:{addIcon:()=>"add",buttons(){let t=[];return this.canSearch&&t.push({icon:"filter",text:this.$t("search"),click:this.onSearchToggle,responsive:!0}),this.canAdd&&t.push({icon:this.addIcon,text:this.$t("add"),click:this.onAdd}),t},canAdd:()=>!0,canDrop:()=>!1,canSearch(){return this.options.search},collection(){return{columns:this.options.columns,empty:this.emptyPropsWithSearch,layout:this.options.layout,help:this.options.help,items:this.items,pagination:this.pagination,sortable:!this.isProcessing&&this.options.sortable,size:this.options.size}},emptyProps(){return{icon:"page",text:this.$t("pages.empty")}},emptyPropsWithSearch(){return{...this.emptyProps,text:this.searching?this.$t("search.results.none"):this.options.empty||this.emptyProps.text}},items(){return this.data},isInvalid(){var t;return!((null==(t=this.searchterm)?void 0:t.length)>0)&&(!!(this.options.min&&this.data.lengththis.options.max))},paginationId(){return"kirby$pagination$"+this.parent+"/"+this.name},type:()=>"models"},watch:{searchterm:dt((function(){this.pagination.page=0,this.reload()}),200),timestamp(){this.reload()}},created(){this.load()},methods:{async load(t){t||(this.isLoading=!0),this.isProcessing=!0,null===this.pagination.page&&(this.pagination.page=localStorage.getItem(this.paginationId)||1);try{const t=await this.$api.get(this.parent+"/sections/"+this.name,{page:this.pagination.page,searchterm:this.searchterm});this.options=t.options,this.pagination=t.pagination,this.data=t.data}catch(e){this.error=e.message}finally{this.isProcessing=!1,this.isLoading=!1}},onAction(){},onAdd(){},onChange(){},onDrop(){},onSort(){},onPaginate(t){localStorage.setItem(this.paginationId,t.page),this.pagination=t,this.reload()},onSearchToggle(){this.searching=!this.searching,this.searchterm=null},onUpload(){},async reload(){await this.load(!0)},update(){this.reload(),this.$events.$emit("model.update")}}},(function(){var t=this,e=t._self._c;return!1===t.isLoading?e("section",{class:`k-models-section k-${t.type}-section`,attrs:{"data-processing":t.isProcessing}},[e("header",{staticClass:"k-section-header"},[e("k-headline",{attrs:{link:t.options.link}},[t._v(" "+t._s(t.options.headline||" ")+" "),t.options.min?e("abbr",{attrs:{title:t.$t("section.required")}},[t._v("*")]):t._e()]),e("k-button-group",{attrs:{buttons:t.buttons}})],1),t.error?e("k-box",{attrs:{theme:"negative"}},[e("k-text",{attrs:{size:"small"}},[e("strong",[t._v(" "+t._s(t.$t("error.section.notLoaded",{name:t.name}))+": ")]),t._v(" "+t._s(t.error)+" ")])],1):[e("k-dropzone",{attrs:{disabled:!t.canDrop},on:{drop:t.onDrop}},[t.searching&&t.options.search?e("k-input",{staticClass:"k-models-section-search",attrs:{autofocus:!0,placeholder:t.$t("search")+" …",type:"text"},on:{keydown:function(e){return!e.type.indexOf("key")&&t._k(e.keyCode,"esc",27,e.key,["Esc","Escape"])?null:t.onSearchToggle.apply(null,arguments)}},model:{value:t.searchterm,callback:function(e){t.searchterm=e},expression:"searchterm"}}):t._e(),e("k-collection",t._g(t._b({attrs:{"data-invalid":t.isInvalid},on:{action:t.onAction,change:t.onChange,sort:t.onSort,paginate:t.onPaginate}},"k-collection",t.collection,!1),t.canAdd?{empty:t.onAdd}:{}))],1),e("k-upload",{ref:"upload",on:{success:t.onUpload,error:t.reload}})]],2):t._e()}),[],!1,null,null,null,null).exports;const Ii=Mt({extends:Ti,computed:{addIcon:()=>"upload",canAdd(){return this.$permissions.files.create&&!1!==this.options.upload},canDrop(){return!1!==this.canAdd},emptyProps(){return{icon:"image",text:this.$t("files.empty")}},items(){return this.data.map((t=>(t.sortable=this.options.sortable,t.column=this.column,t.options=this.$dropdown(t.link,{query:{view:"list",update:this.options.sortable,delete:this.data.length>this.options.min}}),t.data={"data-id":t.id,"data-template":t.template},t)))},type:()=>"files",uploadProps(){return{...this.options.upload,url:this.$urls.api+"/"+this.options.upload.api}}},created(){this.load(),this.$events.$on("model.update",this.reload),this.$events.$on("file.sort",this.reload)},destroyed(){this.$events.$off("model.update",this.reload),this.$events.$off("file.sort",this.reload)},methods:{onAction(t,e){"replace"===t&&this.replace(e)},onAdd(){this.canAdd&&this.$refs.upload.open(this.uploadProps)},onDrop(t){this.canAdd&&this.$refs.upload.drop(t,this.uploadProps)},async onSort(t){if(!1===this.options.sortable)return!1;this.isProcessing=!0;try{await this.$api.patch(this.options.apiUrl+"/files/sort",{files:t.map((t=>t.id)),index:this.pagination.offset}),this.$store.dispatch("notification/success",":)"),this.$events.$emit("file.sort")}catch(e){this.reload(),this.$store.dispatch("notification/error",e.message)}finally{this.isProcessing=!1}},onUpload(){this.$events.$emit("file.create"),this.$events.$emit("model.update"),this.$store.dispatch("notification/success",":)")},replace(t){this.$refs.upload.open({url:this.$urls.api+"/"+t.link,accept:"."+t.extension+","+t.mime,multiple:!1})}}},null,null,!1,null,null,null,null).exports;const Mi=Mt({mixins:[Tt],data:()=>({headline:null,text:null,theme:null}),async created(){const t=await this.load();this.headline=t.headline,this.text=t.text,this.theme=t.theme||"info"}},(function(){var t=this,e=t._self._c;return e("section",{staticClass:"k-info-section"},[e("k-headline",{staticClass:"k-info-section-headline"},[t._v(" "+t._s(t.headline)+" ")]),e("k-box",{attrs:{theme:t.theme}},[e("k-text",{attrs:{html:t.text}})],1)],1)}),[],!1,null,null,null,null).exports;const Ei=Mt({extends:Ti,computed:{canAdd(){return this.options.add&&this.$permissions.pages.create},items(){return this.data.map((t=>{const e=!1!==t.permissions.changeStatus;return t.flag={status:t.status,tooltip:this.$t("page.status"),disabled:!e,click:()=>this.$dialog(t.link+"/changeStatus")},t.sortable=t.permissions.sort&&this.options.sortable,t.deletable=this.data.length>this.options.min,t.column=this.column,t.options=this.$dropdown(t.link,{query:{view:"list",delete:t.deletable,sort:t.sortable}}),t.data={"data-id":t.id,"data-status":t.status,"data-template":t.template},t}))}},created(){this.load(),this.$events.$on("page.changeStatus",this.reload),this.$events.$on("page.sort",this.reload)},destroyed(){this.$events.$off("page.changeStatus",this.reload),this.$events.$off("page.sort",this.reload)},methods:{onAdd(){this.canAdd&&this.$dialog("pages/create",{query:{parent:this.options.link||this.parent,view:this.parent,section:this.name}})},async onChange(t){let e=null;if(t.added&&(e="added"),t.moved&&(e="moved"),e){this.isProcessing=!0;const n=t[e].element,i=t[e].newIndex+1+this.pagination.offset;try{await this.$api.pages.changeStatus(n.id,"listed",i),this.$store.dispatch("notification/success",":)"),this.$events.$emit("page.sort",n)}catch(s){this.$store.dispatch("notification/error",{message:s.message,details:s.details}),await this.reload()}finally{this.isProcessing=!1}}}}},null,null,!1,null,null,null,null).exports;const Li=Mt({mixins:[Tt],data:()=>({isLoading:!0,headline:null,reports:null,size:null}),async created(){const t=await this.load();this.isLoading=!1,this.headline=t.headline,this.reports=t.reports,this.size=t.size},methods:{}},(function(){var t=this,e=t._self._c;return!1===t.isLoading?e("section",{staticClass:"k-stats-section"},[e("header",{staticClass:"k-section-header"},[e("k-headline",[t._v(" "+t._s(t.headline)+" ")])],1),t.reports.length>0?e("k-stats",{attrs:{reports:t.reports,size:t.size}}):e("k-empty",{attrs:{icon:"chart"}},[t._v(" "+t._s(t.empty||t.$t("stats.empty")))])],1):t._e()}),[],!1,null,null,null,null).exports;t.component("k-sections",Oi),t.component("k-fields-section",Ai),t.component("k-files-section",Ii),t.component("k-info-section",Mi),t.component("k-pages-section",Ei),t.component("k-stats-section",Li);const ji=Mt({props:{blueprint:String,next:Object,prev:Object,permissions:{type:Object,default:()=>({})},lock:{type:[Boolean,Object]},model:{type:Object,default:()=>({})},tab:{type:Object,default:()=>({columns:[]})},tabs:{type:Array,default:()=>[]}},computed:{id(){return this.model.link},isLocked(){var t;return"lock"===(null==(t=this.lock)?void 0:t.state)},protectedFields:()=>[]},watch:{"model.id":{handler(){this.content()},immediate:!0}},created(){this.$events.$on("model.reload",this.reload),this.$events.$on("keydown.left",this.toPrev),this.$events.$on("keydown.right",this.toNext)},destroyed(){this.$events.$off("model.reload",this.reload),this.$events.$off("keydown.left",this.toPrev),this.$events.$off("keydown.right",this.toNext)},methods:{content(){this.$store.dispatch("content/create",{id:this.id,api:this.id,content:this.model.content,ignore:this.protectedFields})},async reload(){await this.$reload(),this.content()},toPrev(t){this.prev&&"body"===t.target.localName&&this.$go(this.prev.link)},toNext(t){this.next&&"body"===t.target.localName&&this.$go(this.next.link)}}},null,null,!1,null,null,null,null).exports;const Di=Mt({extends:ji,computed:{avatarOptions(){return[{icon:"upload",text:this.$t("change"),click:()=>this.$refs.upload.open()},{icon:"trash",text:this.$t("delete"),click:this.deleteAvatar}]},buttons(){return[{icon:"email",text:`${this.$t("email")}: ${this.model.email}`,disabled:!this.permissions.changeEmail||this.isLocked,click:()=>this.$dialog(this.id+"/changeEmail")},{icon:"bolt",text:`${this.$t("role")}: ${this.model.role}`,disabled:!this.permissions.changeRole||this.isLocked,click:()=>this.$dialog(this.id+"/changeRole")},{icon:"globe",text:`${this.$t("language")}: ${this.model.language}`,disabled:!this.permissions.changeLanguage||this.isLocked,click:()=>this.$dialog(this.id+"/changeLanguage")}]},uploadApi(){return this.$urls.api+"/"+this.id+"/avatar"}},methods:{async deleteAvatar(){await this.$api.users.deleteAvatar(this.model.id),this.avatar=null,this.$store.dispatch("notification/success",":)"),this.$reload()},onAvatar(){this.model.avatar?this.$refs.picture.toggle():this.$refs.upload.open()},uploadedAvatar(){this.$store.dispatch("notification/success",":)"),this.$reload()}}},(function(){var t=this,e=t._self._c;return e("k-inside",{scopedSlots:t._u([{key:"footer",fn:function(){return[e("k-form-buttons",{attrs:{lock:t.lock}})]},proxy:!0}])},[e("div",{staticClass:"k-user-view",attrs:{"data-locked":t.isLocked,"data-id":t.model.id,"data-template":t.blueprint}},[e("div",{staticClass:"k-user-profile"},[e("k-view",[e("k-dropdown",[e("k-button",{staticClass:"k-user-view-image",attrs:{tooltip:t.$t("avatar"),disabled:t.isLocked},on:{click:t.onAvatar}},[t.model.avatar?e("k-image",{attrs:{cover:!0,src:t.model.avatar,ratio:"1/1"}}):e("k-icon",{attrs:{back:"gray-900",color:"gray-200",type:"user"}})],1),t.model.avatar?e("k-dropdown-content",{ref:"picture",attrs:{options:t.avatarOptions}}):t._e()],1),e("k-button-group",{attrs:{buttons:t.buttons}})],1)],1),e("k-view",[e("k-header",{attrs:{editable:t.permissions.changeName&&!t.isLocked,tab:t.tab.name,tabs:t.tabs},on:{edit:function(e){return t.$dialog(t.id+"/changeName")}},scopedSlots:t._u([{key:"left",fn:function(){return[e("k-button-group",[e("k-dropdown",{staticClass:"k-user-view-options"},[e("k-button",{attrs:{disabled:t.isLocked,text:t.$t("settings"),icon:"cog"},on:{click:function(e){return t.$refs.settings.toggle()}}}),e("k-dropdown-content",{ref:"settings",attrs:{options:t.$dropdown(t.id)}})],1),e("k-languages-dropdown")],1)]},proxy:!0},{key:"right",fn:function(){return[t.model.account?t._e():e("k-prev-next",{attrs:{prev:t.prev,next:t.next}})]},proxy:!0}])},[t.model.name&&0!==t.model.name.length?[t._v(" "+t._s(t.model.name)+" ")]:e("span",{staticClass:"k-user-name-placeholder"},[t._v(" "+t._s(t.$t("name"))+" … ")])],2),e("k-sections",{attrs:{blueprint:t.blueprint,empty:t.$t("user.blueprint",{blueprint:t.$esc(t.blueprint)}),lock:t.lock,parent:t.id,tab:t.tab}}),e("k-upload",{ref:"upload",attrs:{url:t.uploadApi,multiple:!1,accept:"image/*"},on:{success:t.uploadedAvatar}})],1)],1)])}),[],!1,null,null,null,null).exports;const Bi=Mt({extends:Di,prevnext:!1},null,null,!1,null,null,null,null).exports;const Pi=Mt({props:{error:String,layout:String}},(function(){var t=this,e=t._self._c;return e(`k-${t.layout}`,{tag:"component"},[e("k-view",{staticClass:"k-error-view"},[e("div",{staticClass:"k-error-view-content"},[e("k-text",[e("p",[e("k-icon",{staticClass:"k-error-view-icon",attrs:{type:"alert"}})],1),t._t("default",(function(){return[e("p",[t._v(" "+t._s(t.error)+" ")])]}))],2)],1)])],1)}),[],!1,null,null,null,null).exports;const Ni=Mt({extends:ji,props:{preview:Object},methods:{action(t){if("replace"===t)this.$refs.upload.open({url:this.$urls.api+"/"+this.id,accept:"."+this.model.extension+","+this.model.mime,multiple:!1})},onUpload(){this.$store.dispatch("notification/success",":)"),this.$reload()}}},(function(){var t=this,e=t._self._c;return e("k-inside",{scopedSlots:t._u([{key:"footer",fn:function(){return[e("k-form-buttons",{attrs:{lock:t.lock}})]},proxy:!0}])},[e("div",{staticClass:"k-file-view",attrs:{"data-locked":t.isLocked,"data-id":t.model.id,"data-template":t.blueprint}},[e("k-file-preview",t._b({},"k-file-preview",t.preview,!1)),e("k-view",{staticClass:"k-file-content"},[e("k-header",{attrs:{editable:t.permissions.changeName&&!t.isLocked,tab:t.tab.name,tabs:t.tabs},on:{edit:function(e){return t.$dialog(t.id+"/changeName")}},scopedSlots:t._u([{key:"left",fn:function(){return[e("k-button-group",[e("k-button",{staticClass:"k-file-view-options",attrs:{link:t.preview.url,responsive:!0,text:t.$t("open"),icon:"open",target:"_blank"}}),e("k-dropdown",{staticClass:"k-file-view-options"},[e("k-button",{attrs:{disabled:t.isLocked,responsive:!0,text:t.$t("settings"),icon:"cog"},on:{click:function(e){return t.$refs.settings.toggle()}}}),e("k-dropdown-content",{ref:"settings",attrs:{options:t.$dropdown(t.id)},on:{action:t.action}})],1),e("k-languages-dropdown")],1)]},proxy:!0},{key:"right",fn:function(){return[e("k-prev-next",{attrs:{prev:t.prev,next:t.next}})]},proxy:!0}])},[t._v(" "+t._s(t.model.filename)+" ")]),e("k-sections",{attrs:{blueprint:t.blueprint,empty:t.$t("file.blueprint",{blueprint:t.$esc(t.blueprint)}),lock:t.lock,parent:t.id,tab:t.tab}}),e("k-upload",{ref:"upload",on:{success:t.onUpload}})],1)],1)])}),[],!1,null,null,null,null).exports;const qi=Mt({props:{isInstallable:Boolean,isInstalled:Boolean,isOk:Boolean,requirements:Object,translations:Array},data(){return{user:{name:"",email:"",language:this.$translation.code,password:"",role:"admin"}}},computed:{fields(){return{email:{label:this.$t("email"),type:"email",link:!1,autofocus:!0,required:!0},password:{label:this.$t("password"),type:"password",placeholder:this.$t("password")+" …",required:!0},language:{label:this.$t("language"),type:"select",options:this.translations,icon:"globe",empty:!1,required:!0}}},isReady(){return this.isOk&&this.isInstallable},isComplete(){return this.isOk&&this.isInstalled}},methods:{async install(){try{await this.$api.system.install(this.user),await this.$reload({globals:["$system","$translation"]}),this.$store.dispatch("notification/success",this.$t("welcome")+"!")}catch(t){this.$store.dispatch("notification/error",t)}}}},(function(){var t=this,e=t._self._c;return e("k-panel",[e("k-view",{staticClass:"k-installation-view",attrs:{align:"center"}},[t.isComplete?e("k-text",[e("k-headline",[t._v(t._s(t.$t("installation.completed")))]),e("k-link",{attrs:{to:"/login"}},[t._v(" "+t._s(t.$t("login"))+" ")])],1):t.isReady?e("form",{on:{submit:function(e){return e.preventDefault(),t.install.apply(null,arguments)}}},[e("h1",{staticClass:"sr-only"},[t._v(" "+t._s(t.$t("installation"))+" ")]),e("k-fieldset",{attrs:{fields:t.fields,novalidate:!0},model:{value:t.user,callback:function(e){t.user=e},expression:"user"}}),e("k-button",{attrs:{text:t.$t("install"),type:"submit",icon:"check"}})],1):e("div",[e("k-headline",[t._v(" "+t._s(t.$t("installation.issues.headline"))+" ")]),e("ul",{staticClass:"k-installation-issues"},[!1===t.isInstallable?e("li",[e("k-icon",{attrs:{type:"alert"}}),e("span",{domProps:{innerHTML:t._s(t.$t("installation.disabled"))}})],1):t._e(),!1===t.requirements.php?e("li",[e("k-icon",{attrs:{type:"alert"}}),e("span",{domProps:{innerHTML:t._s(t.$t("installation.issues.php"))}})],1):t._e(),!1===t.requirements.server?e("li",[e("k-icon",{attrs:{type:"alert"}}),e("span",{domProps:{innerHTML:t._s(t.$t("installation.issues.server"))}})],1):t._e(),!1===t.requirements.mbstring?e("li",[e("k-icon",{attrs:{type:"alert"}}),e("span",{domProps:{innerHTML:t._s(t.$t("installation.issues.mbstring"))}})],1):t._e(),!1===t.requirements.curl?e("li",[e("k-icon",{attrs:{type:"alert"}}),e("span",{domProps:{innerHTML:t._s(t.$t("installation.issues.curl"))}})],1):t._e(),!1===t.requirements.accounts?e("li",[e("k-icon",{attrs:{type:"alert"}}),e("span",{domProps:{innerHTML:t._s(t.$t("installation.issues.accounts"))}})],1):t._e(),!1===t.requirements.content?e("li",[e("k-icon",{attrs:{type:"alert"}}),e("span",{domProps:{innerHTML:t._s(t.$t("installation.issues.content"))}})],1):t._e(),!1===t.requirements.media?e("li",[e("k-icon",{attrs:{type:"alert"}}),e("span",{domProps:{innerHTML:t._s(t.$t("installation.issues.media"))}})],1):t._e(),!1===t.requirements.sessions?e("li",[e("k-icon",{attrs:{type:"alert"}}),e("span",{domProps:{innerHTML:t._s(t.$t("installation.issues.sessions"))}})],1):t._e()]),e("k-button",{attrs:{text:t.$t("retry"),icon:"refresh"},on:{click:t.$reload}})],1)],1)],1)}),[],!1,null,null,null,null).exports;const Fi=Mt({props:{languages:{type:Array,default:()=>[]}},computed:{languagesCollection(){return this.languages.map((t=>({...t,image:{back:"black",color:"gray",icon:"globe"},link:()=>{if(!this.$permissions.languages.update)return null;this.$dialog(`languages/${t.id}/update`)},options:[{icon:"edit",text:this.$t("edit"),disabled:!this.$permissions.languages.update,click(){this.$dialog(`languages/${t.id}/update`)}},{icon:"trash",text:this.$t("delete"),disabled:t.default&&1!==this.languages.length||!this.$permissions.languages.delete,click(){this.$dialog(`languages/${t.id}/delete`)}}]})))},primaryLanguage(){return this.languagesCollection.filter((t=>t.default))},secondaryLanguages(){return this.languagesCollection.filter((t=>!1===t.default))}}},(function(){var t=this,e=t._self._c;return e("k-inside",[e("k-view",{staticClass:"k-languages-view"},[e("k-header",[t._v(" "+t._s(t.$t("view.languages"))+" "),e("k-button-group",{attrs:{slot:"left"},slot:"left"},[e("k-button",{attrs:{text:t.$t("language.create"),disabled:!t.$permissions.languages.create,icon:"add"},on:{click:function(e){return t.$dialog("languages/create")}}})],1)],1),e("section",{staticClass:"k-languages"},[t.languages.length>0?[e("section",{staticClass:"k-languages-view-section"},[e("header",{staticClass:"k-languages-view-section-header"},[e("k-headline",[t._v(t._s(t.$t("languages.default")))])],1),e("k-collection",{attrs:{items:t.primaryLanguage}})],1),e("section",{staticClass:"k-languages-view-section"},[e("header",{staticClass:"k-languages-view-section-header"},[e("k-headline",[t._v(t._s(t.$t("languages.secondary")))])],1),t.secondaryLanguages.length?e("k-collection",{attrs:{items:t.secondaryLanguages}}):e("k-empty",{attrs:{icon:"globe",disabled:!t.$permissions.languages.create},on:{click:function(e){return t.$dialog("languages/create")}}},[t._v(" "+t._s(t.$t("languages.secondary.empty"))+" ")])],1)]:0===t.languages.length?[e("k-empty",{attrs:{icon:"globe",disabled:!t.$permissions.languages.create},on:{click:function(e){return t.$dialog("languages/create")}}},[t._v(" "+t._s(t.$t("languages.empty"))+" ")])]:t._e()],2)],1)],1)}),[],!1,null,null,null,null).exports;const Ri=Mt({components:{"k-login-plugin":window.panel.plugins.login||he},props:{methods:Array,pending:Object},computed:{form(){return this.pending.email?"code":this.$user?null:"login"}},created(){this.$store.dispatch("content/clear")}},(function(){var t=this,e=t._self._c;return e("k-panel",["login"===t.form?e("k-view",{staticClass:"k-login-view",attrs:{align:"center"}},[e("k-login-plugin",{attrs:{methods:t.methods}})],1):"code"===t.form?e("k-view",{staticClass:"k-login-code-view",attrs:{align:"center"}},[e("k-login-code",t._b({},"k-login-code",t.$props,!1))],1):t._e()],1)}),[],!1,null,null,null,null).exports;const zi=Mt({extends:ji,props:{status:Object},computed:{protectedFields:()=>["title"]}},(function(){var t=this,e=t._self._c;return e("k-inside",{scopedSlots:t._u([{key:"footer",fn:function(){return[e("k-form-buttons",{attrs:{lock:t.lock}})]},proxy:!0}])},[e("k-view",{staticClass:"k-page-view",attrs:{"data-locked":t.isLocked,"data-id":t.model.id,"data-template":t.blueprint}},[e("k-header",{attrs:{editable:t.permissions.changeTitle&&!t.isLocked,tab:t.tab.name,tabs:t.tabs},on:{edit:function(e){return t.$dialog(t.id+"/changeTitle")}},scopedSlots:t._u([{key:"left",fn:function(){return[e("k-button-group",[t.permissions.preview&&t.model.previewUrl?e("k-button",{staticClass:"k-page-view-preview",attrs:{link:t.model.previewUrl,responsive:!0,text:t.$t("open"),icon:"open",target:"_blank"}}):t._e(),t.status?e("k-status-icon",{attrs:{status:t.model.status,disabled:!t.permissions.changeStatus||t.isLocked,responsive:!0,text:t.status.label},on:{click:function(e){return t.$dialog(t.id+"/changeStatus")}}}):t._e(),e("k-dropdown",{staticClass:"k-page-view-options"},[e("k-button",{attrs:{disabled:!0===t.isLocked,responsive:!0,text:t.$t("settings"),icon:"cog"},on:{click:function(e){return t.$refs.settings.toggle()}}}),e("k-dropdown-content",{ref:"settings",attrs:{options:t.$dropdown(t.id)}})],1),e("k-languages-dropdown")],1)]},proxy:!0},{key:"right",fn:function(){return[t.model.id?e("k-prev-next",{attrs:{prev:t.prev,next:t.next}}):t._e()]},proxy:!0}])},[t._v(" "+t._s(t.model.title)+" ")]),e("k-sections",{attrs:{blueprint:t.blueprint,empty:t.$t("page.blueprint",{blueprint:t.$esc(t.blueprint)}),lock:t.lock,parent:t.id,tab:t.tab}})],1)],1)}),[],!1,null,null,null,null).exports;const Yi=Mt({props:{id:String},computed:{view(){return"k-"+this.id+"-plugin-view"}}},(function(){var t=this._self._c;return t("k-inside",[t(this.view,{tag:"component"})],1)}),[],!1,null,null,null,null).exports;const Hi=Mt({data:()=>({isLoading:!1,issue:"",values:{password:null,passwordConfirmation:null}}),computed:{fields(){return{password:{autofocus:!0,label:this.$t("user.changePassword.new"),icon:"key",type:"password"},passwordConfirmation:{label:this.$t("user.changePassword.new.confirm"),icon:"key",type:"password"}}}},mounted(){this.$store.dispatch("title",this.$t("view.resetPassword"))},methods:{async submit(){if(!this.values.password||this.values.password.length<8)return this.issue=this.$t("error.user.password.invalid"),!1;if(this.values.password!==this.values.passwordConfirmation)return this.issue=this.$t("error.user.password.notSame"),!1;this.isLoading=!0;try{await this.$api.users.changePassword(this.$user.id,this.values.password),this.$store.dispatch("notification/success",":)"),this.$go("/")}catch(t){this.issue=t.message}finally{this.isLoading=!1}}}},(function(){var t=this,e=t._self._c;return e("k-inside",[e("k-view",{staticClass:"k-password-reset-view",attrs:{align:"center"}},[e("k-form",{attrs:{fields:t.fields,"submit-button":t.$t("change")},on:{submit:t.submit},scopedSlots:t._u([{key:"header",fn:function(){return[e("h1",{staticClass:"sr-only"},[t._v(" "+t._s(t.$t("view.resetPassword"))+" ")]),t.issue?e("k-login-alert",{on:{click:function(e){t.issue=null}}},[t._v(" "+t._s(t.issue)+" ")]):t._e(),e("k-user-info",{attrs:{user:t.$user}})]},proxy:!0},{key:"footer",fn:function(){return[e("div",{staticClass:"k-login-buttons"},[e("k-button",{staticClass:"k-login-button",attrs:{icon:"check",type:"submit"}},[t._v(" "+t._s(t.$t("change"))+" "),t.isLoading?[t._v(" … ")]:t._e()],2)],1)]},proxy:!0}]),model:{value:t.values,callback:function(e){t.values=e},expression:"values"}})],1)],1)}),[],!1,null,null,null,null).exports;const Ui=Mt({extends:ji,computed:{protectedFields:()=>["title"]}},(function(){var t=this,e=t._self._c;return e("k-inside",{scopedSlots:t._u([{key:"footer",fn:function(){return[e("k-form-buttons",{attrs:{lock:t.lock}})]},proxy:!0}])},[e("k-view",{staticClass:"k-site-view",attrs:{"data-locked":t.isLocked,"data-id":"/","data-template":"site"}},[e("k-header",{attrs:{editable:t.permissions.changeTitle&&!t.isLocked,tabs:t.tabs,tab:t.tab.name},on:{edit:function(e){return t.$dialog("site/changeTitle")}},scopedSlots:t._u([{key:"left",fn:function(){return[e("k-button-group",[e("k-button",{staticClass:"k-site-view-preview",attrs:{link:t.model.previewUrl,responsive:!0,text:t.$t("open"),icon:"open",target:"_blank"}}),e("k-languages-dropdown")],1)]},proxy:!0}])},[t._v(" "+t._s(t.model.title)+" ")]),e("k-sections",{attrs:{blueprint:t.blueprint,empty:t.$t("site.blueprint"),lock:t.lock,tab:t.tab,parent:"site"},on:{submit:function(e){return t.$emit("submit",e)}}})],1)],1)}),[],!1,null,null,null,null).exports;const Ki=Mt({props:{debug:Boolean,license:String,php:String,plugins:Array,server:String,https:Boolean,urls:Object,version:String},data:()=>({security:[]}),computed:{environment(){return[{label:this.$t("license"),value:this.license?"Kirby 3":this.$t("license.unregistered.label"),theme:this.license?null:"negative",click:this.license?()=>this.$dialog("license"):()=>this.$dialog("registration")},{label:this.$t("version"),value:this.version,link:"https://github.com/getkirby/kirby/releases/tag/"+this.version},{label:"PHP",value:this.php},{label:this.$t("server"),value:this.server||"?"}]}},async created(){console.info("Running system health checks for the Panel system view; failed requests in the following console output are expected behavior.");let t=(Promise.allSettled||Promise.all).bind(Promise);await t([this.check("content"),this.check("debug"),this.check("git"),this.check("https"),this.check("kirby"),this.check("site")]),console.info("System health checks ended.")},methods:{async check(t){switch(t){case"debug":!0===this.debug&&this.securityIssue(t);break;case"https":!0!==this.https&&this.securityIssue(t);break;default:{const e=this.urls[t];if(!e)return!1;!0===await this.isAccessible(e)&&this.securityIssue(t)}}},securityIssue(t){this.security.push({image:{back:"var(--color-red-200)",icon:"alert",color:"var(--color-red)"},id:t,text:this.$t("system.issues."+t),link:"https://getkirby.com/security/"+t})},isAccessible:async t=>(await fetch(t,{cache:"no-store"})).status<400,retry(){this.$go(window.location.href)}}},(function(){var t=this,e=t._self._c;return e("k-inside",[e("k-view",{staticClass:"k-system-view"},[e("k-header",[t._v(" "+t._s(t.$t("view.system"))+" ")]),e("section",{staticClass:"k-system-view-section"},[e("header",{staticClass:"k-system-view-section-header"},[e("k-headline",[t._v(t._s(t.$t("environment")))])],1),e("k-stats",{staticClass:"k-system-info",attrs:{reports:t.environment,size:"medium"}})],1),t.security.length?e("section",{staticClass:"k-system-view-section"},[e("header",{staticClass:"k-system-view-section-header"},[e("k-headline",[t._v(t._s(t.$t("security")))]),e("k-button",{attrs:{tooltip:t.$t("retry"),icon:"refresh"},on:{click:t.retry}})],1),e("k-items",{attrs:{items:t.security}})],1):t._e(),t.plugins.length?e("section",{staticClass:"k-system-view-section"},[e("header",{staticClass:"k-system-view-section-header"},[e("k-headline",{attrs:{link:"https://getkirby.com/plugins"}},[t._v(" "+t._s(t.$t("plugins"))+" ")])],1),e("k-table",{attrs:{index:!1,columns:{name:{label:t.$t("name"),type:"url",mobile:!0},author:{label:t.$t("author")},license:{label:t.$t("license")},version:{label:t.$t("version"),width:"8rem",mobile:!0}},rows:t.plugins}})],1):t._e()],1)],1)}),[],!1,null,null,null,null).exports;const Gi=Mt({props:{role:Object,roles:Array,search:String,title:String,users:Object},computed:{items(){return this.users.data.map((t=>(t.options=this.$dropdown(t.link),t)))}},methods:{paginate(t){this.$reload({query:{page:t.page}})}}},(function(){var t=this,e=t._self._c;return e("k-inside",[e("k-view",{staticClass:"k-users-view"},[e("k-header",{scopedSlots:t._u([{key:"left",fn:function(){return[e("k-button-group",{attrs:{buttons:[{disabled:!1===t.$permissions.users.create,text:t.$t("user.create"),icon:"add",click:()=>t.$dialog("users/create")}]}})]},proxy:!0},{key:"right",fn:function(){return[e("k-button-group",[e("k-dropdown",[e("k-button",{attrs:{responsive:!0,text:`${t.$t("role")}: ${t.role?t.role.title:t.$t("role.all")}`,icon:"funnel"},on:{click:function(e){return t.$refs.roles.toggle()}}}),e("k-dropdown-content",{ref:"roles",attrs:{align:"right"}},[e("k-dropdown-item",{attrs:{icon:"bolt",link:"/users"}},[t._v(" "+t._s(t.$t("role.all"))+" ")]),e("hr"),t._l(t.roles,(function(s){return e("k-dropdown-item",{key:s.id,attrs:{link:"/users/?role="+s.id,icon:"bolt"}},[t._v(" "+t._s(s.title)+" ")])}))],2)],1)],1)]},proxy:!0}])},[t._v(" "+t._s(t.$t("view.users"))+" ")]),t.users.data.length>0?[e("k-collection",{attrs:{items:t.items,pagination:t.users.pagination},on:{paginate:t.paginate}})]:0===t.users.pagination.total?[e("k-empty",{attrs:{icon:"users"}},[t._v(" "+t._s(t.$t("role.empty"))+" ")])]:t._e()],2)],1)}),[],!1,null,null,null,null).exports;const Ji=Mt({computed:{placeholder(){return this.field("code",{}).placeholder},languages(){return this.field("language",{options:[]}).options}},methods:{focus(){this.$refs.code.focus()}}},(function(){var t=this,e=t._self._c;return e("div",{staticClass:"k-block-type-code-editor"},[e("k-input",{ref:"code",attrs:{buttons:!1,placeholder:t.placeholder,spellcheck:!1,value:t.content.code,type:"textarea"},on:{input:function(e){return t.update({code:e})}}}),t.languages.length?e("div",{staticClass:"k-block-type-code-editor-language"},[e("k-icon",{attrs:{type:"code"}}),e("k-input",{ref:"language",attrs:{empty:!1,options:t.languages,value:t.content.language,type:"select"},on:{input:function(e){return t.update({language:e})}}})],1):t._e()],1)}),[],!1,null,null,null,null).exports,Vi=Object.freeze(Object.defineProperty({__proto__:null,default:Ji},Symbol.toStringTag,{value:"Module"}));const Wi=Mt({},(function(){var t=this;return(0,t._self._c)("k-block-title",{attrs:{content:t.content,fieldset:t.fieldset},on:{dblclick:function(e){return t.$emit("open")}}})}),[],!1,null,null,null,null).exports,Xi=Object.freeze(Object.defineProperty({__proto__:null,default:Wi},Symbol.toStringTag,{value:"Module"}));const Zi=Mt({},(function(){var t=this,e=t._self._c;return e("ul",{on:{dblclick:t.open}},[0===t.content.images.length?[e("li"),e("li"),e("li"),e("li"),e("li")]:t._l(t.content.images,(function(t){return e("li",{key:t.id},[e("img",{attrs:{src:t.url,srcset:t.image.srcset,alt:t.alt}})])}))],2)}),[],!1,null,null,null,null).exports,Qi=Object.freeze(Object.defineProperty({__proto__:null,default:Zi},Symbol.toStringTag,{value:"Module"}));const to=Mt({computed:{textField(){return this.field("text",{marks:!0})}},methods:{focus(){this.$refs.input.focus()}}},(function(){var t=this,e=t._self._c;return e("div",{staticClass:"k-block-type-heading-input",attrs:{"data-level":t.content.level}},[e("k-writer",{ref:"input",attrs:{inline:!0,marks:t.textField.marks,placeholder:t.textField.placeholder,value:t.content.text},on:{input:function(e){return t.update({text:e})}}})],1)}),[],!1,null,null,null,null).exports,eo=Object.freeze(Object.defineProperty({__proto__:null,default:to},Symbol.toStringTag,{value:"Module"}));const so=Mt({computed:{captionMarks(){return this.field("caption",{marks:!0}).marks},crop(){return this.content.crop||!1},src(){var t;return"web"===this.content.location?this.content.src:!!(null==(t=this.content.image[0])?void 0:t.url)&&this.content.image[0].url},ratio(){return this.content.ratio||!1}}},(function(){var t=this,e=t._self._c;return e("k-block-figure",{attrs:{caption:t.content.caption,"caption-marks":t.captionMarks,"empty-text":t.$t("field.blocks.image.placeholder")+" …","is-empty":!t.src,"empty-icon":"image"},on:{open:t.open,update:t.update}},[t.src?[t.ratio?e("k-aspect-ratio",{attrs:{ratio:t.ratio,cover:t.crop}},[e("img",{attrs:{alt:t.content.alt,src:t.src}})]):e("img",{staticClass:"k-block-type-image-auto",attrs:{alt:t.content.alt,src:t.src}})]:t._e()],2)}),[],!1,null,null,null,null).exports,no=Object.freeze(Object.defineProperty({__proto__:null,default:so},Symbol.toStringTag,{value:"Module"}));const io=Mt({},(function(){return this._self._c,this._m(0)}),[function(){var t=this._self._c;return t("div",[t("hr")])}],!1,null,null,null,null).exports,oo=Object.freeze(Object.defineProperty({__proto__:null,default:io},Symbol.toStringTag,{value:"Module"}));const ro=Mt({computed:{marks(){return this.field("text",{}).marks}},methods:{focus(){this.$refs.input.focus()}}},(function(){var t=this;return(0,t._self._c)("k-input",{ref:"input",staticClass:"k-block-type-list-input",attrs:{marks:t.marks,value:t.content.text,type:"list"},on:{input:function(e){return t.update({text:e})}}})}),[],!1,null,null,null,null).exports,lo=Object.freeze(Object.defineProperty({__proto__:null,default:ro},Symbol.toStringTag,{value:"Module"}));const ao=Mt({computed:{placeholder(){return this.field("text",{}).placeholder}},methods:{focus(){this.$refs.input.focus()}}},(function(){var t=this;return(0,t._self._c)("k-input",{ref:"input",staticClass:"k-block-type-markdown-input",attrs:{buttons:!1,placeholder:t.placeholder,spellcheck:!1,value:t.content.text,type:"textarea"},on:{input:function(e){return t.update({text:e})}}})}),[],!1,null,null,null,null).exports,uo=Object.freeze(Object.defineProperty({__proto__:null,default:ao},Symbol.toStringTag,{value:"Module"}));const co=Mt({computed:{citationField(){return this.field("citation",{})},textField(){return this.field("text",{})}},methods:{focus(){this.$refs.text.focus()}}},(function(){var t,e,s=this,n=s._self._c;return n("div",{staticClass:"k-block-type-quote-editor"},[n("k-writer",{ref:"text",staticClass:"k-block-type-quote-text",attrs:{inline:null!=(t=s.textField.inline)&&t,marks:s.textField.marks,placeholder:s.textField.placeholder,value:s.content.text},on:{input:function(t){return s.update({text:t})}}}),n("k-writer",{ref:"citation",staticClass:"k-block-type-quote-citation",attrs:{inline:null==(e=s.citationField.inline)||e,marks:s.citationField.marks,placeholder:s.citationField.placeholder,value:s.content.citation},on:{input:function(t){return s.update({citation:t})}}})],1)}),[],!1,null,null,null,null).exports,po=Object.freeze(Object.defineProperty({__proto__:null,default:co},Symbol.toStringTag,{value:"Module"}));const ho=Mt({inheritAttrs:!1,computed:{columns(){return this.table.columns||this.fields},fields(){return this.table.fields||{}},rows(){return this.content.rows||[]},table(){let t=null;for(const e of Object.values(this.fieldset.tabs))e.fields.rows&&(t=e.fields.rows);return t||{}}}},(function(){var t=this;return(0,t._self._c)("k-table",{staticClass:"k-block-type-table-preview",attrs:{columns:t.columns,empty:t.$t("field.structure.empty"),rows:t.rows},nativeOn:{dblclick:function(e){return t.open.apply(null,arguments)}}})}),[],!1,null,null,null,null).exports,mo=Object.freeze(Object.defineProperty({__proto__:null,default:ho},Symbol.toStringTag,{value:"Module"}));const fo=Mt({computed:{component(){const t="k-"+this.textField.type+"-input";return this.$helper.isComponent(t)?t:"k-writer"},textField(){return this.field("text",{})}},methods:{focus(){this.$refs.input.focus()}}},(function(){var t=this;return(0,t._self._c)(t.component,t._b({ref:"input",tag:"component",staticClass:"k-block-type-text-input",attrs:{value:t.content.text},on:{input:function(e){return t.update({text:e})}}},"component",t.textField,!1))}),[],!1,null,null,null,null).exports,go=Object.freeze(Object.defineProperty({__proto__:null,default:fo},Symbol.toStringTag,{value:"Module"}));const ko=Mt({computed:{captionMarks(){return this.field("caption",{marks:!0}).marks},video(){return this.$helper.embed.video(this.content.url,!0)}}},(function(){var t=this,e=t._self._c;return e("k-block-figure",{attrs:{caption:t.content.caption,"caption-marks":t.captionMarks,"empty-text":t.$t("field.blocks.video.placeholder")+" …","is-empty":!t.video,"empty-icon":"video"},on:{open:t.open,update:t.update}},[e("k-aspect-ratio",{attrs:{ratio:"16/9"}},[t.video?e("iframe",{attrs:{src:t.video,referrerpolicy:"strict-origin-when-cross-origin"}}):t._e()])],1)}),[],!1,null,null,null,null).exports,bo=Object.freeze(Object.defineProperty({__proto__:null,default:ko},Symbol.toStringTag,{value:"Module"}));const yo=Mt({inheritAttrs:!1,props:{attrs:[Array,Object],content:[Array,Object],endpoints:Object,fieldset:Object,id:String,isBatched:Boolean,isFull:Boolean,isHidden:Boolean,isLastInBatch:Boolean,isSelected:Boolean,name:String,next:Object,prev:Object,type:String},data:()=>({skipFocus:!1}),computed:{className(){let t=["k-block-type-"+this.type];return this.fieldset.preview!==this.type&&t.push("k-block-type-"+this.fieldset.preview),!1===this.wysiwyg&&t.push("k-block-type-default"),t},customComponent(){return this.wysiwyg?this.wysiwygComponent:"k-block-type-default"},isEditable(){return!1!==this.fieldset.editable},listeners(){return{...this.$listeners,confirmToRemove:this.confirmToRemove,open:this.open}},tabs(){let t=this.fieldset.tabs;return Object.entries(t).forEach((([e,s])=>{Object.entries(s.fields).forEach((([s])=>{t[e].fields[s].section=this.name,t[e].fields[s].endpoints={field:this.endpoints.field+"/fieldsets/"+this.type+"/fields/"+s,section:this.endpoints.section,model:this.endpoints.model}}))})),t},wysiwyg(){return!1!==this.wysiwygComponent},wysiwygComponent(){if(!1===this.fieldset.preview)return!1;let t;return this.fieldset.preview&&(t="k-block-type-"+this.fieldset.preview,this.$helper.isComponent(t))?t:(t="k-block-type-"+this.type,!!this.$helper.isComponent(t)&&t)}},methods:{close(){this.$refs.drawer.close()},confirmToRemove(){this.$refs.removeDialog.open()},focus(){!0!==this.skipFocus&&("function"==typeof this.$refs.editor.focus?this.$refs.editor.focus():this.$refs.container.focus())},onFocusIn(t){var e,s;(null==(s=null==(e=this.$refs.options)?void 0:e.$el)?void 0:s.contains(t.target))||this.$emit("focus",t)},goTo(t){t&&(this.skipFocus=!0,this.close(),this.$nextTick((()=>{t.$refs.container.focus(),t.open(),this.skipFocus=!1})))},open(){var t;null==(t=this.$refs.drawer)||t.open()},remove(){this.$refs.removeDialog.close(),this.$emit("remove",this.id)}}},(function(){var t=this,e=t._self._c;return e("div",{ref:"container",staticClass:"k-block-container",class:"k-block-container-type-"+t.type,attrs:{"data-batched":t.isBatched,"data-disabled":t.fieldset.disabled,"data-hidden":t.isHidden,"data-id":t.id,"data-last-in-batch":t.isLastInBatch,"data-selected":t.isSelected,"data-translate":t.fieldset.translate,tabindex:"0"},on:{keydown:[function(e){return!e.type.indexOf("key")&&t._k(e.keyCode,"down",40,e.key,["Down","ArrowDown"])?null:e.ctrlKey&&e.shiftKey?(e.preventDefault(),t.$emit("sortDown")):null},function(e){return!e.type.indexOf("key")&&t._k(e.keyCode,"up",38,e.key,["Up","ArrowUp"])?null:e.ctrlKey&&e.shiftKey?(e.preventDefault(),t.$emit("sortUp")):null}],focus:function(e){return t.$emit("focus")},focusin:t.onFocusIn}},[e("div",{staticClass:"k-block",class:t.className},[e(t.customComponent,t._g(t._b({ref:"editor",tag:"component"},"component",t.$props,!1),t.listeners))],1),e("k-block-options",t._g({ref:"options",attrs:{"is-batched":t.isBatched,"is-editable":t.isEditable,"is-full":t.isFull,"is-hidden":t.isHidden}},t.listeners)),t.isEditable&&!t.isBatched?e("k-form-drawer",{ref:"drawer",staticClass:"k-block-drawer",attrs:{id:t.id,icon:t.fieldset.icon||"box",tabs:t.tabs,title:t.fieldset.name,value:t.content},on:{close:function(e){return t.focus()},input:function(e){return t.$emit("update",e)}},scopedSlots:t._u([{key:"options",fn:function(){return[t.isHidden?e("k-button",{staticClass:"k-drawer-option",attrs:{icon:"hidden"},on:{click:function(e){return t.$emit("show")}}}):t._e(),e("k-button",{staticClass:"k-drawer-option",attrs:{disabled:!t.prev,icon:"angle-left"},on:{click:function(e){return e.preventDefault(),e.stopPropagation(),t.goTo(t.prev)}}}),e("k-button",{staticClass:"k-drawer-option",attrs:{disabled:!t.next,icon:"angle-right"},on:{click:function(e){return e.preventDefault(),e.stopPropagation(),t.goTo(t.next)}}}),e("k-button",{staticClass:"k-drawer-option",attrs:{icon:"trash"},on:{click:function(e){return e.preventDefault(),e.stopPropagation(),t.confirmToRemove.apply(null,arguments)}}})]},proxy:!0}],null,!1,2211169536)}):t._e(),e("k-remove-dialog",{ref:"removeDialog",attrs:{text:t.$t("field.blocks.delete.confirm")},on:{submit:t.remove}})],1)}),[],!1,null,null,null,null).exports;const vo=Mt({components:{"k-block-pasteboard":Mt({inheritAttrs:!1,computed:{shortcut(){return this.$helper.keyboard.metaKey()+"+v"}},methods:{close(){this.$refs.dialog.close()},open(){this.$refs.dialog.open()},onPaste(t){this.$emit("paste",t),this.close()}}},(function(){var t=this,e=t._self._c;return e("k-dialog",{ref:"dialog",staticClass:"k-block-importer",attrs:{"cancel-button":!1,"submit-button":!1,size:"large"}},[e("label",{attrs:{for:"pasteboard"},domProps:{innerHTML:t._s(t.$t("field.blocks.fieldsets.paste",{shortcut:t.shortcut}))}}),e("textarea",{attrs:{id:"pasteboard"},on:{paste:function(e){return e.preventDefault(),t.onPaste.apply(null,arguments)}}})])}),[],!1,null,null,null,null).exports},inheritAttrs:!1,props:{autofocus:Boolean,empty:String,endpoints:Object,fieldsets:Object,fieldsetGroups:Object,group:String,max:{type:Number,default:null},value:{type:Array,default:()=>[]}},data(){return{isMultiSelectKey:!1,batch:[],blocks:this.value,current:null,isFocussed:!1}},computed:{draggableOptions(){return{id:this._uid,handle:".k-sort-handle",list:this.blocks,move:this.move,delay:10,data:{fieldsets:this.fieldsets,isFull:this.isFull},options:{group:this.group}}},hasFieldsets(){return Object.keys(this.fieldsets).length},isEditing(){return this.$store.state.dialog||this.$store.state.drawers.open.length>0},isEmpty(){return 0===this.blocks.length},isFull(){return null!==this.max&&this.blocks.length>=this.max},selected(){return this.current},selectedOrBatched(){return this.batch.length>0?this.batch:this.selected?[this.selected]:[]}},watch:{value(){this.blocks=this.value}},created(){this.$events.$on("blur",this.onBlur),this.$events.$on("copy",this.copy),this.$events.$on("focus",this.onOutsideFocus),this.$events.$on("keydown",this.onKey),this.$events.$on("keyup",this.onKey),this.$events.$on("paste",this.onPaste)},destroyed(){this.$events.$off("blur",this.onBlur),this.$events.$off("copy",this.copy),this.$events.$off("focus",this.onOutsideFocus),this.$events.$off("keydown",this.onKey),this.$events.$off("keyup",this.onKey),this.$events.$off("paste",this.onPaste)},mounted(){!0===this.$props.autofocus&&this.focus()},methods:{append(t,e){if("string"!=typeof t){if(Array.isArray(t)){let s=this.$helper.clone(t).map((t=>(t.id=this.$helper.uuid(),t)));const n=Object.keys(this.fieldsets);if(s=s.filter((t=>n.includes(t.type))),this.max){const t=this.max-this.blocks.length;s=s.slice(0,t)}this.blocks.splice(e,0,...s),this.save()}}else this.add(t,e)},async add(t="text",e){const s=await this.$api.get(this.endpoints.field+"/fieldsets/"+t);this.blocks.splice(e,0,s),this.save(),this.$nextTick((()=>{this.focusOrOpen(s)}))},addToBatch(t){null!==this.selected&&!1===this.batch.includes(this.selected)&&(this.batch.push(this.selected),this.current=null),!1===this.batch.includes(t.id)&&this.batch.push(t.id)},choose(t){if(1===Object.keys(this.fieldsets).length){const e=Object.values(this.fieldsets)[0].type;this.add(e,t)}else this.$refs.selector.open(t)},chooseToConvert(t){this.$refs.selector.open(t,{disabled:[t.type],headline:this.$t("field.blocks.changeType"),event:"convert"})},click(t){this.$emit("click",t)},confirmToRemoveAll(){this.$refs.removeAll.open()},confirmToRemoveSelected(){this.$refs.removeSelected.open()},copy(t){if(!0===this.isEditing)return!1;if(0===this.blocks.length)return!1;if(0===this.selectedOrBatched.length)return!1;if(!0===this.isInputEvent(t))return!1;let e=[];if(this.blocks.forEach((t=>{this.selectedOrBatched.includes(t.id)&&e.push(t)})),0===e.length)return!1;this.$helper.clipboard.write(e,t),t instanceof ClipboardEvent==!1&&(this.batch=this.selectedOrBatched),this.$store.dispatch("notification/success",`${e.length} copied!`)},copyAll(){this.selectAll(),this.copy(),this.deselectAll()},async convert(t,e){var s;const n=this.findIndex(e.id);if(-1===n)return!1;const i=t=>{var e;let s={};for(const n of Object.values(null!=(e=null==t?void 0:t.tabs)?e:{}))s={...s,...n.fields};return s},o=this.blocks[n],r=await this.$api.get(this.endpoints.field+"/fieldsets/"+t),l=this.fieldsets[o.type],a=this.fieldsets[t];if(!a)return!1;let u=r.content;const c=i(a),d=i(l);for(const[p,h]of Object.entries(c)){const t=d[p];(null==t?void 0:t.type)===h.type&&(null==(s=null==o?void 0:o.content)?void 0:s[p])&&(u[p]=o.content[p])}this.blocks[n]={...r,id:o.id,content:u},this.save()},deselectAll(){this.batch=[],this.current=null},async duplicate(t,e){const s={...this.$helper.clone(t),id:this.$helper.uuid()};this.blocks.splice(e+1,0,s),this.save()},fieldset(t){return this.fieldsets[t.type]||{icon:"box",name:t.type,tabs:{content:{fields:{}}},type:t.type}},find(t){return this.blocks.find((e=>e.id===t))},findIndex(t){return this.blocks.findIndex((e=>e.id===t))},focus(t){(null==t?void 0:t.id)&&this.$refs["block-"+t.id]?this.$refs["block-"+t.id][0].focus():this.blocks[0]&&this.focus(this.blocks[0])},focusOrOpen(t){this.fieldsets[t.type].wysiwyg?this.focus(t):this.open(t)},hide(t){this.$set(t,"isHidden",!0),this.save()},isBatched(t){return this.batch.includes(t.id)},isInputEvent(){const t=document.querySelector(":focus");return t&&t.matches("input, textarea, [contenteditable], .k-writer")},isLastInBatch(t){const[e]=this.batch.slice(-1);return e&&t.id===e},isOnlyInstance:()=>1===document.querySelectorAll(".k-blocks").length,isSelected(t){return this.selected&&this.selected===t.id},move(t){if(t.from!==t.to){const e=t.draggedContext.element,s=t.relatedContext.component.componentData||t.relatedContext.component.$parent.componentData;if(!1===Object.keys(s.fieldsets).includes(e.type))return!1;if(!0===s.isFull)return!1}return!0},onBlur(){0===this.batch.length&&(this.isMultiSelectKey=!1)},onKey(t){this.isMultiSelectKey=t.metaKey||t.ctrlKey||t.altKey},onOutsideFocus(t){if("function"==typeof t.target.closest&&t.target.closest(".k-dialog"))return;const e=document.querySelector(".k-overlay:last-of-type");if(!1===this.$el.contains(t.target)&&(!e||!1===e.contains(t.target)))return this.select(null);if(e){const e=this.$el.closest(".k-layout-column");if(!1===(null==e?void 0:e.contains(t.target)))return this.select(null)}},onPaste(t){var e;return!0!==this.isInputEvent(t)&&(!0===this.isEditing?!0===(null==(e=this.$refs.selector)?void 0:e.isOpen())&&this.paste(t):(0!==this.selectedOrBatched.length||!0===this.isOnlyInstance())&&this.paste(t))},open(t){this.$refs["block-"+t.id]&&this.$refs["block-"+t.id][0].open()},async paste(t){const e=this.$helper.clipboard.read(t),s=await this.$api.post(this.endpoints.field+"/paste",{html:e});let n=this.selectedOrBatched[this.selectedOrBatched.length-1],i=this.findIndex(n);-1===i&&(i=this.blocks.length),this.append(s,i+1)},pasteboard(){this.$refs.pasteboard.open()},prevNext(t){if(this.blocks[t]){let e=this.blocks[t];if(this.$refs["block-"+e.id])return this.$refs["block-"+e.id][0]}},remove(t){var e;const s=this.findIndex(t.id);-1!==s&&((null==(e=this.selected)?void 0:e.id)===t.id&&this.select(null),this.$delete(this.blocks,s),this.save())},removeAll(){this.batch=[],this.blocks=[],this.save(),this.$refs.removeAll.close()},removeSelected(){this.batch.forEach((t=>{const e=this.findIndex(t);-1!==e&&this.$delete(this.blocks,e)})),this.deselectAll(),this.save(),this.$refs.removeSelected.close()},save(){this.$emit("input",this.blocks)},select(t,e=null){if(e&&this.isMultiSelectKey&&this.onKey(e),t&&this.isMultiSelectKey)return this.addToBatch(t),void(this.current=null);this.batch=[],this.current=t?t.id:null},selectAll(){this.batch=Object.values(this.blocks).map((t=>t.id))},show(t){this.$set(t,"isHidden",!1),this.save()},sort(t,e,s){if(s<0)return;let n=this.$helper.clone(this.blocks);n.splice(e,1),n.splice(s,0,t),this.blocks=n,this.save(),this.$nextTick((()=>{this.focus(t)}))},update(t,e){const s=this.findIndex(t.id);-1!==s&&Object.entries(e).forEach((([t,e])=>{this.$set(this.blocks[s].content,t,e)})),this.save()}}},(function(){var t=this,e=t._self._c;return e("div",{ref:"wrapper",staticClass:"k-blocks",attrs:{"data-empty":0===t.blocks.length,"data-multi-select-key":t.isMultiSelectKey},on:{focusin:function(e){t.focussed=!0},focusout:function(e){t.focussed=!1}}},[t.hasFieldsets?[e("k-draggable",t._b({staticClass:"k-blocks-list",on:{sort:t.save},scopedSlots:t._u([{key:"footer",fn:function(){return[e("k-empty",{staticClass:"k-blocks-empty",attrs:{icon:"box"},on:{click:function(e){return t.choose(t.blocks.length)}}},[t._v(" "+t._s(t.empty||t.$t("field.blocks.empty"))+" ")])]},proxy:!0}],null,!1,2413899928)},"k-draggable",t.draggableOptions,!1),t._l(t.blocks,(function(s,n){return e("k-block",t._b({key:s.id,ref:"block-"+s.id,refInFor:!0,attrs:{endpoints:t.endpoints,fieldset:t.fieldset(s),"is-batched":t.isBatched(s),"is-last-in-batch":t.isLastInBatch(s),"is-full":t.isFull,"is-hidden":!0===s.isHidden,"is-selected":t.isSelected(s),next:t.prevNext(n+1),prev:t.prevNext(n-1)},on:{append:function(e){return t.append(e,n+1)},blur:function(e){return t.select(null)},choose:function(e){return t.choose(e)},chooseToAppend:function(e){return t.choose(n+1)},chooseToConvert:function(e){return t.chooseToConvert(s)},chooseToPrepend:function(e){return t.choose(n)},copy:function(e){return t.copy()},confirmToRemoveSelected:t.confirmToRemoveSelected,duplicate:function(e){return t.duplicate(s,n)},focus:function(e){return t.select(s)},hide:function(e){return t.hide(s)},paste:function(e){return t.pasteboard()},prepend:function(e){return t.add(e,n)},remove:function(e){return t.remove(s)},sortDown:function(e){return t.sort(s,n,n+1)},sortUp:function(e){return t.sort(s,n,n-1)},show:function(e){return t.show(s)},update:function(e){return t.update(s,e)}},nativeOn:{click:function(e){return e.stopPropagation(),t.select(s,e)}}},"k-block",s,!1))})),1),e("k-block-selector",{ref:"selector",attrs:{fieldsets:t.fieldsets,"fieldset-groups":t.fieldsetGroups},on:{add:t.add,convert:t.convert,paste:function(e){return t.paste(e)}}}),e("k-remove-dialog",{ref:"removeAll",attrs:{text:t.$t("field.blocks.delete.confirm.all")},on:{submit:t.removeAll}}),e("k-remove-dialog",{ref:"removeSelected",attrs:{text:t.$t("field.blocks.delete.confirm.selected")},on:{submit:t.removeSelected}}),e("k-block-pasteboard",{ref:"pasteboard",on:{paste:function(e){return t.paste(e)}}})]:[e("k-box",{attrs:{theme:"info"}},[t._v(" No fieldsets yet ")])]],2)}),[],!1,null,null,null,null).exports;const $o=Mt({inheritAttrs:!1,props:{caption:String,captionMarks:[Boolean,Array],cover:{type:Boolean,default:!0},isEmpty:Boolean,emptyIcon:String,emptyText:String,ratio:String},computed:{ratioPadding(){return this.$helper.ratio(this.ratio||"16/9")}}},(function(){var t=this,e=t._self._c;return e("figure",{staticClass:"k-block-figure"},[t.isEmpty?e("k-button",{staticClass:"k-block-figure-empty",attrs:{icon:t.emptyIcon,text:t.emptyText},on:{click:function(e){return t.$emit("open")}}}):e("span",{staticClass:"k-block-figure-container",on:{dblclick:function(e){return t.$emit("open")}}},[t._t("default")],2),t.caption?e("figcaption",[e("k-writer",{attrs:{inline:!0,marks:t.captionMarks,value:t.caption},on:{input:function(e){return t.$emit("update",{caption:e})}}})],1):t._e()],1)}),[],!1,null,null,null,null).exports;const _o=Mt({props:{isBatched:Boolean,isEditable:Boolean,isFull:Boolean,isHidden:Boolean},methods:{open(){this.$refs.options.open()}}},(function(){var t=this,e=t._self._c;return e("k-dropdown",{staticClass:"k-block-options"},[t.isBatched?[e("k-button",{staticClass:"k-block-options-button",attrs:{tooltip:t.$t("copy"),icon:"template"},on:{click:function(e){return e.preventDefault(),t.$emit("copy")}}}),e("k-button",{staticClass:"k-block-options-button",attrs:{tooltip:t.$t("remove"),icon:"trash"},on:{click:function(e){return e.preventDefault(),t.$emit("confirmToRemoveSelected")}}})]:[t.isEditable?e("k-button",{staticClass:"k-block-options-button",attrs:{tooltip:t.$t("edit"),icon:"edit"},on:{click:function(e){return t.$emit("open")}}}):t._e(),e("k-button",{staticClass:"k-block-options-button",attrs:{disabled:t.isFull,tooltip:t.$t("insert.after"),icon:"add"},on:{click:function(e){return t.$emit("chooseToAppend")}}}),e("k-button",{staticClass:"k-block-options-button",attrs:{tooltip:t.$t("delete"),icon:"trash"},on:{click:function(e){return t.$emit("confirmToRemove")}}}),e("k-button",{staticClass:"k-block-options-button",attrs:{tooltip:t.$t("more"),icon:"dots"},on:{click:function(e){return t.$refs.options.toggle()}}}),e("k-button",{staticClass:"k-block-options-button k-sort-handle",attrs:{tooltip:t.$t("sort"),icon:"sort"},on:{keydown:[function(e){return!e.type.indexOf("key")&&t._k(e.keyCode,"up",38,e.key,["Up","ArrowUp"])?null:(e.preventDefault(),t.$emit("sortUp"))},function(e){return!e.type.indexOf("key")&&t._k(e.keyCode,"down",40,e.key,["Down","ArrowDown"])?null:(e.preventDefault(),t.$emit("sortDown"))}]}}),e("k-dropdown-content",{ref:"options",attrs:{align:"right"}},[e("k-dropdown-item",{attrs:{disabled:t.isFull,icon:"angle-up"},on:{click:function(e){return t.$emit("chooseToPrepend")}}},[t._v(" "+t._s(t.$t("insert.before"))+" ")]),e("k-dropdown-item",{attrs:{disabled:t.isFull,icon:"angle-down"},on:{click:function(e){return t.$emit("chooseToAppend")}}},[t._v(" "+t._s(t.$t("insert.after"))+" ")]),e("hr"),t.isEditable?e("k-dropdown-item",{attrs:{icon:"edit"},on:{click:function(e){return t.$emit("open")}}},[t._v(" "+t._s(t.$t("edit"))+" ")]):t._e(),e("k-dropdown-item",{attrs:{icon:"refresh"},on:{click:function(e){return t.$emit("chooseToConvert")}}},[t._v(" "+t._s(t.$t("field.blocks.changeType"))+" ")]),e("hr"),e("k-dropdown-item",{attrs:{icon:"template"},on:{click:function(e){return t.$emit("copy")}}},[t._v(" "+t._s(t.$t("copy"))+" ")]),e("k-dropdown-item",{attrs:{icon:"download"},on:{click:function(e){return t.$emit("paste")}}},[t._v(" "+t._s(t.$t("paste.after"))+" ")]),e("hr"),e("k-dropdown-item",{attrs:{icon:t.isHidden?"preview":"hidden"},on:{click:function(e){return t.$emit(t.isHidden?"show":"hide")}}},[t._v(" "+t._s(!0===t.isHidden?t.$t("show"):t.$t("hide"))+" ")]),e("k-dropdown-item",{attrs:{disabled:t.isFull,icon:"copy"},on:{click:function(e){return t.$emit("duplicate")}}},[t._v(" "+t._s(t.$t("duplicate"))+" ")]),e("hr"),e("k-dropdown-item",{attrs:{icon:"trash"},on:{click:function(e){return t.$emit("confirmToRemove")}}},[t._v(" "+t._s(t.$t("delete"))+" ")])],1)]],2)}),[],!1,null,null,null,null).exports;const xo=Mt({inheritAttrs:!1,props:{endpoint:String,fieldsets:Object,fieldsetGroups:Object},data(){return{dialogIsOpen:!1,disabled:[],headline:null,payload:null,event:"add",groups:this.createGroups()}},computed:{shortcut(){return this.$helper.keyboard.metaKey()+"+v"}},methods:{add(t){this.$emit(this.event,t,this.payload),this.$refs.dialog.close()},close(){this.$refs.dialog.close()},createGroups(){let t={},e=0;const s=this.fieldsetGroups||{blocks:{label:this.$t("field.blocks.fieldsets.label"),sets:Object.keys(this.fieldsets)}};return Object.keys(s).forEach((n=>{let i=s[n];i.open=!1!==i.open,i.fieldsets=i.sets.filter((t=>this.fieldsets[t])).map((t=>(e++,{...this.fieldsets[t],index:e}))),0!==i.fieldsets.length&&(t[n]=i)})),t},isOpen(){return this.dialogIsOpen},navigate(t){var e,s;null==(s=null==(e=this.$refs["fieldset-"+t])?void 0:e[0])||s.focus()},onClose(){this.dialogIsOpen=!1,this.$events.$off("paste",this.close)},onOpen(){this.dialogIsOpen=!0,this.$events.$on("paste",this.close)},open(t,e={}){const s={event:"add",disabled:[],headline:null,...e};this.event=s.event,this.disabled=s.disabled,this.headline=s.headline,this.payload=t,this.$refs.dialog.open()}}},(function(){var t=this,e=t._self._c;return e("k-dialog",{ref:"dialog",staticClass:"k-block-selector",attrs:{"cancel-button":!1,"submit-button":!1,size:"medium"},on:{open:t.onOpen,close:t.onClose}},[t.headline?e("k-headline",[t._v(" "+t._s(t.headline)+" ")]):t._e(),t._l(t.groups,(function(s,n){return e("details",{key:n,attrs:{open:s.open}},[e("summary",[t._v(t._s(s.label))]),e("div",{staticClass:"k-block-types"},t._l(s.fieldsets,(function(s){return e("k-button",{key:s.name,ref:"fieldset-"+s.index,refInFor:!0,attrs:{disabled:t.disabled.includes(s.type),icon:s.icon||"box",text:s.name},on:{keydown:[function(e){return!e.type.indexOf("key")&&t._k(e.keyCode,"up",38,e.key,["Up","ArrowUp"])?null:t.navigate(s.index-1)},function(e){return!e.type.indexOf("key")&&t._k(e.keyCode,"down",40,e.key,["Down","ArrowDown"])?null:t.navigate(s.index+1)}],click:function(e){return t.add(s.type)}}})})),1)])})),e("p",{staticClass:"k-clipboard-hint",domProps:{innerHTML:t._s(t.$t("field.blocks.fieldsets.paste",{shortcut:t.shortcut}))}})],2)}),[],!1,null,null,null,null).exports;const wo=Mt({inheritAttrs:!1,props:{fieldset:Object,content:Object},computed:{icon(){return this.fieldset.icon||"box"},label(){if(!this.fieldset.label||0===this.fieldset.label.length)return!1;if(this.fieldset.label===this.fieldset.name)return!1;const t=this.$helper.string.template(this.fieldset.label,this.content);return"…"!==t&&t},name(){return this.fieldset.name}}},(function(){var t=this,e=t._self._c;return e("div",t._g({staticClass:"k-block-title"},t.$listeners),[e("k-icon",{staticClass:"k-block-icon",attrs:{type:t.icon}}),e("span",{staticClass:"k-block-name"},[t._v(" "+t._s(t.name)+" ")]),t.label?e("span",{staticClass:"k-block-label"},[t._v(" "+t._s(t.label)+" ")]):t._e()],1)}),[],!1,null,null,null,null).exports;const So=Mt({inheritAttrs:!1,props:{content:[Object,Array],fieldset:Object},methods:{field(t,e=null){let s=null;return Object.values(this.fieldset.tabs).forEach((e=>{e.fields[t]&&(s=e.fields[t])})),s||e},open(){this.$emit("open")},update(t){this.$emit("update",{...this.content,...t})}}},null,null,!1,null,null,null,null).exports;t.component("k-block",yo),t.component("k-blocks",vo),t.component("k-block-figure",$o),t.component("k-block-options",_o),t.component("k-block-selector",xo),t.component("k-block-title",wo),t.component("k-block-type",So);const Co=Object.assign({"./Types/Code.vue":Vi,"./Types/Default.vue":Xi,"./Types/Gallery.vue":Qi,"./Types/Heading.vue":eo,"./Types/Image.vue":no,"./Types/Line.vue":oo,"./Types/List.vue":lo,"./Types/Markdown.vue":uo,"./Types/Quote.vue":po,"./Types/Table.vue":mo,"./Types/Text.vue":go,"./Types/Video.vue":bo});Object.keys(Co).map((e=>{const s=e.match(/\/([a-zA-Z]*)\.vue/)[1].toLowerCase();let n=Co[e].default;n.extends=So,t.component("k-block-type-"+s,n)}));const Oo={inheritAttrs:!1,props:{column:{type:Object,default:()=>({})},field:Object,value:{}}};const Ao=Mt({mixins:[Oo],inheritAttrs:!1,props:{value:[Array,String]},computed:{bubbles(){var t,e;let s=this.value;const n=(null==(t=this.column)?void 0:t.options)||(null==(e=this.field)?void 0:e.options)||[];return"string"==typeof s&&(s=s.split(",")),s.map((t=>{"string"==typeof t&&(t={value:t,text:t});for(const e of n)e.value===t.value&&(t.text=e.text);return{back:"light",color:"black",...t}}))}}},(function(){var t=this,e=t._self._c;return e("div",{staticClass:"k-bubbles-field-preview",class:t.$options.class},[e("k-bubbles",{attrs:{bubbles:t.bubbles}})],1)}),[],!1,null,null,null,null).exports;const To=Mt({extends:Ao,inheritAttrs:!1,class:"k-array-field-preview",computed:{bubbles(){return[{text:1===this.value.length?`1 ${this.$t("entry")}`:`${this.value.length} ${this.$t("entries")}`}]}}},null,null,!1,null,null,null,null).exports;const Io=Mt({mixins:[Oo],inheritAttrs:!1,computed:{text(){return this.value}}},(function(){var t=this;return(0,t._self._c)("p",{staticClass:"k-text-field-preview",class:t.$options.class},[t._v(" "+t._s(t.column.before)+" "),t._t("default",(function(){return[t._v(t._s(t.text))]})),t._v(" "+t._s(t.column.after)+" ")],2)}),[],!1,null,null,null,null).exports;const Mo=Mt({extends:Io,inheritAttrs:!1,props:{value:String},class:"k-date-field-preview",computed:{text(){var t,e,s,n,i,o;if("string"!=typeof this.value)return"";const r=this.$library.dayjs(this.value);if(!r)return"";let l=(null==(t=this.column)?void 0:t.display)||(null==(e=this.field)?void 0:e.display)||"YYYY-MM-DD",a=(null==(n=null==(s=this.column)?void 0:s.time)?void 0:n.display)||(null==(o=null==(i=this.field)?void 0:i.time)?void 0:o.display);return a&&(l+=" "+a),r.format(l)}}},null,null,!1,null,null,null,null).exports;const Eo=Mt({mixins:[Oo],props:{value:[String,Object]},computed:{link(){return"object"==typeof this.value?this.value.href:this.value},text(){return"object"==typeof this.value?this.value.text:this.link}}},(function(){var t=this,e=t._self._c;return e("p",{staticClass:"k-url-field-preview",class:t.$options.class},[t._v(" "+t._s(t.column.before)+" "),e("k-link",{attrs:{to:t.link},nativeOn:{click:function(t){t.stopPropagation()}}},[t._v(" "+t._s(t.text)+" ")]),t._v(" "+t._s(t.column.after)+" ")],1)}),[],!1,null,null,null,null).exports;const Lo=Mt({extends:Eo,class:"k-email-field-preview"},null,null,!1,null,null,null,null).exports;const jo=Mt({extends:Ao,inheritAttrs:!1,class:"k-files-field-preview",computed:{bubbles(){return this.value.map((t=>({text:t.filename,link:t.link,image:t.image})))}}},null,null,!1,null,null,null,null).exports;const Do=Mt({mixins:[Oo],inheritAttrs:!1,props:{value:Object}},(function(){var t=this;return(0,t._self._c)("k-status-icon",t._b({staticClass:"k-flag-field-preview"},"k-status-icon",t.value,!1))}),[],!1,null,null,null,null).exports;const Bo=Mt({mixins:[Oo],inheritAttrs:!1,props:{value:String},computed:{html(){return this.value}}},(function(){var t=this,e=t._self._c;return e("div",{staticClass:"k-html-field-preview",class:t.$options.class},[t._v(" "+t._s(t.column.before)+" "),e("div",{domProps:{innerHTML:t._s(t.html)}}),t._v(" "+t._s(t.column.after)+" ")])}),[],!1,null,null,null,null).exports;const Po=Mt({mixins:[Oo],inheritAttrs:!1,props:{value:[Object]}},(function(){return(0,this._self._c)("k-item-image",{staticClass:"k-image-field-preview",attrs:{image:this.value,layout:"list"}})}),[],!1,null,null,null,null).exports;const No=Mt({extends:Ao,inheritAttrs:!1,class:"k-pages-field-preview"},null,null,!1,null,null,null,null).exports;const qo=Mt({extends:Io,inheritAttrs:!1,props:{value:String},class:"k-time-field-preview",computed:{text(){const t=this.$library.dayjs.iso(this.value,"time");return(null==t?void 0:t.format(this.field.display))||""}}},null,null,!1,null,null,null,null).exports;const Fo=Mt({props:{field:Object,value:Boolean,column:Object},computed:{text(){return!1!==this.column.text?this.field.text:null}}},(function(){var t=this;return(0,t._self._c)("k-input",{staticClass:"k-toggle-field-preview",attrs:{text:t.text,value:t.value,type:"toggle"},on:{input:function(e){return t.$emit("input",e)}}})}),[],!1,null,null,null,null).exports;const Ro=Mt({extends:Ao,inheritAttrs:!1,class:"k-users-field-preview",computed:{bubble(){return this.value.map((t=>({text:t.username,link:t.link,image:t.image})))}}},null,null,!1,null,null,null,null).exports;t.component("k-array-field-preview",To),t.component("k-bubbles-field-preview",Ao),t.component("k-date-field-preview",Mo),t.component("k-email-field-preview",Lo),t.component("k-files-field-preview",jo),t.component("k-flag-field-preview",Do),t.component("k-html-field-preview",Bo),t.component("k-image-field-preview",Po),t.component("k-pages-field-preview",No),t.component("k-text-field-preview",Io),t.component("k-toggle-field-preview",Fo),t.component("k-time-field-preview",qo),t.component("k-url-field-preview",Eo),t.component("k-users-field-preview",Ro),t.component("k-list-field-preview",Bo),t.component("k-writer-field-preview",Bo),t.component("k-checkboxes-field-preview",Ao),t.component("k-multiselect-field-preview",Ao),t.component("k-radio-field-preview",Ao),t.component("k-select-field-preview",Ao),t.component("k-tags-field-preview",Ao),t.component("k-toggles-field-preview",Ao),t.component("k-dialog",Et),t.component("k-error-dialog",jt),t.component("k-fiber-dialog",Dt),t.component("k-files-dialog",Pt),t.component("k-form-dialog",Nt),t.component("k-language-dialog",qt),t.component("k-pages-dialog",Ft),t.component("k-remove-dialog",Rt),t.component("k-text-dialog",zt),t.component("k-users-dialog",Yt),t.component("k-drawer",Ht),t.component("k-form-drawer",Ut),t.component("k-calendar",Gt),t.component("k-counter",Jt),t.component("k-autocomplete",Kt),t.component("k-form",Vt),t.component("k-form-buttons",Wt),t.component("k-form-indicator",Xt),t.component("k-field",ue),t.component("k-fieldset",ce),t.component("k-input",pe),t.component("k-login",he),t.component("k-login-code",me),t.component("k-times",fe),t.component("k-upload",ge),t.component("k-writer",Xe),t.component("k-login-alert",Ze),t.component("k-structure-form",Qe),t.component("k-toolbar",es),t.component("k-toolbar-email-dialog",ss),t.component("k-toolbar-link-dialog",ns),t.component("k-aspect-ratio",_n),t.component("k-bar",xn),t.component("k-box",wn),t.component("k-bubble",Sn),t.component("k-bubbles",Cn),t.component("k-collection",On),t.component("k-column",An),t.component("k-dropzone",Tn),t.component("k-empty",In),t.component("k-file-preview",Mn),t.component("k-grid",En),t.component("k-header",Ln),t.component("k-inside",jn),t.component("k-item",Dn),t.component("k-item-image",Bn),t.component("k-items",Pn),t.component("k-overlay",Nn),t.component("k-panel",qn),t.component("k-stats",Fn),t.component("k-table",Rn),t.component("k-table-cell",zn),t.component("k-tabs",Yn),t.component("k-view",Hn),t.component("k-draggable",Kn),t.component("k-error-boundary",Gn),t.component("k-fatal",Jn),t.component("k-headline",Vn),t.component("k-icon",Wn),t.component("k-icons",Xn),t.component("k-image",Zn),t.component("k-loader",Qn),t.component("k-offline-warning",ti),t.component("k-progress",si),t.component("k-registration",ni),t.component("k-status-icon",oi),t.component("k-sort-handle",ii),t.component("k-text",ri),t.component("k-user-info",li),t.component("k-breadcrumb",ai),t.component("k-button",ui),t.component("k-button-disabled",ci),t.component("k-button-group",di),t.component("k-button-link",pi),t.component("k-button-native",mi),t.component("k-dropdown",fi),t.component("k-dropdown-content",ki),t.component("k-dropdown-item",bi),t.component("k-languages-dropdown",vi),t.component("k-link",yi),t.component("k-options-dropdown",$i),t.component("k-pagination",_i),t.component("k-prev-next",xi),t.component("k-search",wi),t.component("k-tag",Si),t.component("k-topbar",Ci),t.component("k-account-view",Bi),t.component("k-error-view",Pi),t.component("k-file-view",Ni),t.component("k-installation-view",qi),t.component("k-languages-view",Fi),t.component("k-login-view",Ri),t.component("k-page-view",zi),t.component("k-plugin-view",Yi),t.component("k-reset-password-view",Hi),t.component("k-site-view",Ui),t.component("k-system-view",Ki),t.component("k-users-view",Gi),t.component("k-user-view",Di);t.config.productionTip=!1,t.config.devtools=!0,t.use(tt),t.use(Ct),t.use(At),t.use(It),t.use(et),t.use(Ot),t.use(at),t.use(H,Q),t.use(N),t.use(q),new t({store:Q,created(){window.panel.$vue=window.panel.app=this,window.panel.plugins.created.forEach((t=>t(this))),this.$store.dispatch("content/init")},render:t=>t(U)}).$mount("#app"); diff --git a/kirby/panel/dist/js/index.min.js b/kirby/panel/dist/js/index.min.js deleted file mode 100644 index c3d944a..0000000 --- a/kirby/panel/dist/js/index.min.js +++ /dev/null @@ -1,2 +0,0 @@ -const __vite__fileDeps=["./IndexView.min.js","./vendor.min.js","./DocsView.min.js","./Docs.min.js","./PlaygroundView.min.js","./Highlight.min.js"],__vite__mapDeps=i=>i.map(i=>__vite__fileDeps[i]); -import{v as t,I as e,P as i,S as n,F as s,N as o,s as l,l as a,w as r,a as u,b as c,c as d,e as p,t as h,d as m,f,g,h as k,i as b,k as v,D as y,j as $,E as w,m as x,n as _,o as C,T as S,u as O,p as M,q as A,r as j,x as I,y as D,z as E,A as T,B as L,C as B,G as q,H as P,V as N,J as z}from"./vendor.min.js";const F={},Y=function(t,e,i){let n=Promise.resolve();if(e&&e.length>0){const t=document.getElementsByTagName("link"),s=document.querySelector("meta[property=csp-nonce]"),o=(null==s?void 0:s.nonce)||(null==s?void 0:s.getAttribute("nonce"));n=Promise.all(e.map((e=>{if(e=function(t,e){return new URL(t,e).href}(e,i),e in F)return;F[e]=!0;const n=e.endsWith(".css"),s=n?'[rel="stylesheet"]':"";if(!!i)for(let i=t.length-1;i>=0;i--){const s=t[i];if(s.href===e&&(!n||"stylesheet"===s.rel))return}else if(document.querySelector(`link[href="${e}"]${s}`))return;const l=document.createElement("link");return l.rel=n?"stylesheet":"modulepreload",n||(l.as="script",l.crossOrigin=""),l.href=e,o&&l.setAttribute("nonce",o),document.head.appendChild(l),n?new Promise(((t,i)=>{l.addEventListener("load",t),l.addEventListener("error",(()=>i(new Error(`Unable to preload CSS for ${e}`))))})):void 0})))}return n.then((()=>t())).catch((t=>{const e=new Event("vite:preloadError",{cancelable:!0});if(e.payload=t,window.dispatchEvent(e),!e.defaultPrevented)throw t}))},R={created(){this.$panel.events.subscribe();for(const t of this.$panel.plugins.created)t(this);this.$panel.events.on("popstate",(()=>{this.$panel.open(window.location.href)})),this.$panel.events.on("drop",(()=>{this.$panel.drag.stop()})),this.$store.dispatch("content/init")},destroyed(){this.$panel.events.unsubscribe()},render(t){if(this.$panel.view.component)return t(this.$panel.view.component,{key:this.$panel.view.component,props:this.$panel.view.props})}},U={props:{after:String}},H={props:{autocomplete:String}},V={props:{autofocus:Boolean}},K={props:{before:String}},W={props:{disabled:Boolean}},J={props:{font:String}},G={props:{help:String}},X={props:{id:{type:[Number,String],default(){return this._uid}}}},Z={props:{invalid:Boolean}},Q={props:{label:String}},tt={props:{layout:{type:String,default:"list"}}},et={props:{maxlength:Number}},it={props:{minlength:Number}},nt={props:{name:[Number,String]}},st={props:{options:{default:()=>[],type:Array}}},ot={props:{pattern:String}},lt={props:{placeholder:[Number,String]}},at={props:{required:Boolean}},rt={props:{spellcheck:{type:Boolean,default:!0}}};function ut(t,e,i,n,s,o,l,a){var r,u="function"==typeof t?t.options:t;if(e&&(u.render=e,u.staticRenderFns=i,u._compiled=!0),n&&(u.functional=!0),o&&(u._scopeId="data-v-"+o),l?(r=function(t){(t=t||this.$vnode&&this.$vnode.ssrContext||this.parent&&this.parent.$vnode&&this.parent.$vnode.ssrContext)||"undefined"==typeof __VUE_SSR_CONTEXT__||(t=__VUE_SSR_CONTEXT__),s&&s.call(this,t),t&&t._registeredComponents&&t._registeredComponents.add(l)},u._ssrRegister=r):s&&(r=a?function(){s.call(this,(u.functional?this.parent:this).$root.$options.shadowRoot)}:s),r)if(u.functional){u._injectStyles=r;var c=u.render;u.render=function(t,e){return r.call(e),c(t,e)}}else{var d=u.beforeCreate;u.beforeCreate=d?[].concat(d,r):[r]}return{exports:t,options:u}}const ct={mixins:[tt],inheritAttrs:!1,props:{columns:{type:[Object,Array],default:()=>({})},fields:{type:Object,default:()=>({})},items:{type:Array,default:()=>[]},link:{type:Boolean,default:!0},sortable:Boolean,size:{type:String,default:"medium"},theme:String}};const dt=ut({mixins:[ct],props:{image:{type:[Object,Boolean],default:()=>({})}},emits:["change","hover","item","option","sort"],computed:{dragOptions(){return{sort:this.sortable,disabled:!1===this.sortable,draggable:".k-draggable-item"}},table(){return{columns:this.columns,fields:this.fields,rows:this.items,sortable:this.sortable}}},methods:{onDragStart(t,e){this.$panel.drag.start("text",e)},onOption(t,e,i){this.$emit("option",t,e,i)},imageOptions(t){let e=this.image,i=t.image;return!1!==e&&!1!==i&&("object"!=typeof e&&(e={}),"object"!=typeof i&&(i={}),{...i,...e})}}},(function(){var t=this,e=t._self._c;return"table"===t.layout?e("k-table",t._b({on:{change:function(e){return t.$emit("change",e)},sort:function(e){return t.$emit("sort",e)},option:t.onOption},scopedSlots:t._u([t.$scopedSlots.options?{key:"options",fn:function({row:e,rowIndex:i}){return[t._t("options",null,null,{item:e,index:i})]}}:null],null,!0)},"k-table",t.table,!1)):e("k-draggable",{staticClass:"k-items",class:"k-"+t.layout+"-items",attrs:{"data-layout":t.layout,"data-size":t.size,handle:!0,list:t.items,options:t.dragOptions},on:{change:function(e){return t.$emit("change",e)},end:function(e){return t.$emit("sort",t.items,e)}}},[t._l(t.items,(function(i,n){return[t._t("default",(function(){return[e("k-item",t._b({key:i.id??n,class:{"k-draggable-item":t.sortable&&i.sortable},attrs:{image:t.imageOptions(i),layout:t.layout,link:!!t.link&&i.link,sortable:t.sortable&&i.sortable,theme:t.theme,width:i.column},on:{click:function(e){return t.$emit("item",i,n)},drag:function(e){return t.onDragStart(e,i.dragText)},option:function(e){return t.onOption(e,i,n)}},nativeOn:{mouseover:function(e){return t.$emit("hover",e,i,n)}},scopedSlots:t._u([{key:"options",fn:function(){return[t._t("options",null,null,{item:i,index:n})]},proxy:!0}],null,!0)},"k-item",i,!1))]}),null,{item:i,itemIndex:n})]}))],2)}),[],!1,null,null,null,null).exports;const pt=ut({mixins:[ct],props:{empty:{type:Object,default:()=>({})},help:String,pagination:{type:[Boolean,Object],default:!1}},emits:["action","change","empty","item","option","paginate","sort"],computed:{hasPagination(){return!1!==this.pagination&&(!0!==this.paginationOptions.hide&&!(this.pagination.total<=this.pagination.limit))},paginationOptions(){return{limit:10,details:!0,keys:!1,total:0,hide:!1,..."object"!=typeof this.pagination?{}:this.pagination}}},watch:{$props(){this.$forceUpdate()}},methods:{onEmpty(t){t.stopPropagation(),this.$emit("empty")},onOption(...t){this.$emit("action",...t),this.$emit("option",...t)}}},(function(){var t=this,e=t._self._c;return e("div",{staticClass:"k-collection"},[0===t.items.length?e("k-empty",t._g(t._b({attrs:{layout:t.layout}},"k-empty",t.empty,!1),t.$listeners.empty?{click:t.onEmpty}:{})):e("k-items",t._b({on:{change:function(e){return t.$emit("change",e)},item:function(e){return t.$emit("item",e)},option:t.onOption,sort:function(e){return t.$emit("sort",e)}},scopedSlots:t._u([{key:"options",fn:function({item:e,index:i}){return[t._t("options",null,null,{item:e,index:i})]}}],null,!0)},"k-items",{columns:t.columns,fields:t.fields,items:t.items,layout:t.layout,link:t.link,size:t.size,sortable:t.sortable,theme:t.theme},!1)),t.help||t.hasPagination?e("footer",{staticClass:"k-collection-footer"},[e("k-text",{staticClass:"k-help k-collection-help",attrs:{html:t.help}}),t.hasPagination?e("k-pagination",t._b({on:{paginate:function(e){return t.$emit("paginate",e)}}},"k-pagination",t.paginationOptions,!1)):t._e()],1):t._e()],1)}),[],!1,null,null,null,null).exports;const ht=ut({mixins:[tt],props:{text:String,icon:String},emits:["click"],computed:{attrs(){const t={button:void 0!==this.$listeners.click,icon:this.icon,theme:"empty"};return"cardlets"!==this.layout&&"cards"!==this.layout||(t.align="center",t.height="var(--item-height-cardlet)"),t}}},(function(){var t=this;return(0,t._self._c)("k-box",t._b({staticClass:"k-empty",nativeOn:{click:function(e){return t.$emit("click",e)}}},"k-box",t.attrs,!1),[t._t("default",(function(){return[t._v(" "+t._s(t.text)+" ")]}))],2)}),[],!1,null,null,null,null).exports,mt={mixins:[tt],props:{image:[Object,Boolean],width:{type:String,default:"1/1"}}};const ft=ut({mixins:[mt],inheritAttrs:!1,computed:{attrs(){return{back:this.image.back??"gray-500",cover:!0,...this.image,ratio:"list"===this.layout?"auto":this.image.ratio,size:this.sizes}},sizes(){switch(this.width){case"1/2":case"2/4":return"(min-width: 30em) and (max-width: 65em) 59em, (min-width: 65em) 44em, 27em";case"1/3":return"(min-width: 30em) and (max-width: 65em) 59em, (min-width: 65em) 29.333em, 27em";case"1/4":return"(min-width: 30em) and (max-width: 65em) 59em, (min-width: 65em) 22em, 27em";case"2/3":return"(min-width: 30em) and (max-width: 65em) 59em, (min-width: 65em) 27em, 27em";case"3/4":return"(min-width: 30em) and (max-width: 65em) 59em, (min-width: 65em) 66em, 27em";default:return"(min-width: 30em) and (max-width: 65em) 59em, (min-width: 65em) 88em, 27em"}}}},(function(){var t=this,e=t._self._c;return t.image.src?e("k-image-frame",t._b({staticClass:"k-item-image"},"k-image-frame",t.attrs,!1)):e("k-icon-frame",t._b({staticClass:"k-item-image"},"k-icon-frame",t.attrs,!1))}),[],!1,null,null,null,null).exports;const gt=ut({mixins:[mt,tt],inheritAttrs:!1,props:{buttons:{type:Array,default:()=>[]},data:Object,info:String,link:{type:[Boolean,String,Function]},options:{type:[Array,Function,String]},sortable:Boolean,target:String,text:String,theme:String},emits:["action","click","drag","option"],computed:{hasFigure(){return!1!==this.image&&this.$helper.object.length(this.image)>0},title(){return this.$helper.string.stripHTML(this.$helper.string.unescapeHTML(this.text)).trim()}},methods:{onOption(t){this.$emit("action",t),this.$emit("option",t)}}},(function(){var t,e=this,i=e._self._c;return i("div",e._b({staticClass:"k-item",class:!!e.layout&&"k-"+e.layout+"-item",attrs:{"data-has-image":e.hasFigure,"data-layout":e.layout,"data-theme":e.theme},on:{click:function(t){return e.$emit("click",t)},dragstart:function(t){return e.$emit("drag",t)}}},"div",e.data,!1),[e._t("image",(function(){return[e.hasFigure?i("k-item-image",{attrs:{image:e.image,layout:e.layout,width:e.width}}):e._e()]})),e.sortable?i("k-sort-handle",{staticClass:"k-item-sort-handle",attrs:{tabindex:"-1"}}):e._e(),i("div",{staticClass:"k-item-content"},[i("h3",{staticClass:"k-item-title",attrs:{title:e.title}},[!1!==e.link?i("k-link",{attrs:{target:e.target,to:e.link}},[i("span",{domProps:{innerHTML:e._s(e.text??"–")}})]):i("span",{domProps:{innerHTML:e._s(e.text??"–")}})],1),e.info?i("p",{staticClass:"k-item-info",domProps:{innerHTML:e._s(e.info)}}):e._e()]),i("div",{staticClass:"k-item-options",attrs:{"data-only-option":!(null==(t=e.buttons)?void 0:t.length)||!e.options&&!e.$slots.options}},[e._l(e.buttons,(function(t,n){return i("k-button",e._b({key:"button-"+n},"k-button",t,!1))})),e._t("options",(function(){return[e.options?i("k-options-dropdown",{staticClass:"k-item-options-dropdown",attrs:{options:e.options},on:{option:e.onOption}}):e._e()]}))],2)],2)}),[],!1,null,null,null,null).exports,kt={install(t){t.component("k-collection",pt),t.component("k-empty",ht),t.component("k-item",gt),t.component("k-item-image",ft),t.component("k-items",dt)}};const bt=ut({},(function(){return(0,this._self._c)("div",{staticClass:"k-dialog-body"},[this._t("default")],2)}),[],!1,null,null,null,null).exports;function vt(t){return"object"==typeof t&&(null==t?void 0:t.constructor)===Object}function yt(t){return Object.keys(t??{}).length}function $t(t){return Object.keys(t).reduce(((e,i)=>(e[i.toLowerCase()]=t[i],e)),{})}const wt={clone:function(t){if(void 0!==t)return structuredClone(t)},isEmpty:function(t){return null==t||""===t||(!(!vt(t)||0!==yt(t))||0===t.length)},isObject:vt,length:yt,merge:function t(e,i={}){for(const n in i)i[n]instanceof Object&&Object.assign(i[n],t(e[n]??{},i[n]));return Object.assign(e??{},i),e},same:function(t,e){return JSON.stringify(t)===JSON.stringify(e)},toLowerKeys:$t},xt={props:{cancelButton:{default:!0,type:[Boolean,String,Object]},disabled:{default:!1,type:Boolean},icon:{default:"check",type:String},submitButton:{type:[Boolean,String,Object],default:!0},theme:{default:"positive",type:String}}};const _t=ut({mixins:[xt],emits:["cancel"],computed:{cancel(){return this.button(this.cancelButton,{click:()=>this.$emit("cancel"),class:"k-dialog-button-cancel",icon:"cancel",text:this.$t("cancel"),variant:"filled"})},submit(){return this.button(this.submitButton,{class:"k-dialog-button-submit",disabled:this.disabled||this.$panel.dialog.isLoading,icon:this.icon,text:this.$t("confirm"),theme:this.theme,type:"submit",variant:"filled"})}},methods:{button:(t,e)=>"string"==typeof t?{...e,text:t}:!1!==t&&(!1===vt(t)?e:{...e,...t})}},(function(){var t=this,e=t._self._c;return e("k-button-group",{staticClass:"k-dialog-buttons"},[t.cancel?e("k-button",t._b({},"k-button",t.cancel,!1)):t._e(),t.submit?e("k-button",t._b({attrs:{icon:t.$panel.dialog.isLoading?"loader":t.submit.icon}},"k-button",t.submit,!1)):t._e()],1)}),[],!1,null,null,null,null).exports,Ct={props:{empty:{default:()=>window.panel.$t("dialog.fields.empty"),type:String},fields:{default:()=>[],type:[Array,Object]},novalidate:{default:!0,type:Boolean},value:{default:()=>({}),type:Object}}};const St=ut({mixins:[Ct],emits:["input","submit"],computed:{hasFields(){return this.$helper.object.length(this.fields)>0}}},(function(){var t=this,e=t._self._c;return t.hasFields?e("k-fieldset",{staticClass:"k-dialog-fields",attrs:{novalidate:t.novalidate,fields:t.fields,value:t.value},on:{input:function(e){return t.$emit("input",e)},submit:function(e){return t.$emit("submit",e)}}}):e("k-box",{attrs:{theme:"info"}},[t._v(t._s(t.empty))])}),[],!1,null,null,null,null).exports;const Ot=ut({},(function(){return(0,this._self._c)("footer",{staticClass:"k-dialog-footer"},[this._t("default")],2)}),[],!1,null,null,null,null).exports;const Mt=ut({},(function(){var t=this,e=t._self._c;return"dialog"===t.$panel.notification.context?e("k-notification",{staticClass:"k-dialog-notification"}):t._e()}),[],!1,null,null,null,null).exports;const At=ut({props:{autofocus:{default:!0,type:Boolean},placeholder:{default:()=>window.panel.$t("search")+" …",type:String},value:{type:String}},emits:["search"]},(function(){var t=this;return(0,t._self._c)("k-input",{staticClass:"k-dialog-search",attrs:{autofocus:t.autofocus,placeholder:t.placeholder,spellcheck:!1,value:t.value,icon:"search",type:"text"},on:{input:function(e){return t.$emit("search",e)}}})}),[],!1,null,null,null,null).exports,jt={props:{empty:{type:String,default:()=>window.panel.$t("dialog.text.empty")},text:{type:String}}};const It=ut({mixins:[jt]},(function(){var t=this,e=t._self._c;return t.text?e("k-text",{attrs:{html:t.text}}):e("k-box",{attrs:{theme:"info"}},[t._v(t._s(t.empty))])}),[],!1,null,null,null,null).exports,Dt={install(t){t.component("k-dialog-body",bt),t.component("k-dialog-buttons",_t),t.component("k-dialog-fields",St),t.component("k-dialog-footer",Ot),t.component("k-dialog-notification",Mt),t.component("k-dialog-search",At),t.component("k-dialog-text",It)}},Et={mixins:[xt],props:{size:{default:"default",type:String},visible:{default:!1,type:Boolean}},emits:["cancel","close","input","submit","success"],methods:{cancel(){this.$emit("cancel")},close(){this.$emit("close")},error(t){this.$panel.notification.error(t)},focus(t){this.$panel.dialog.focus(t)},input(t){this.$emit("input",t)},open(){this.$panel.dialog.open(this)},submit(){this.$emit("submit",this.value)},success(t){this.$emit("success",t)}}};const Tt=ut({mixins:[Et]},(function(){var t=this,e=t._self._c;return t.visible?e("portal",{attrs:{to:"dialog"}},[e("form",{staticClass:"k-dialog",class:t.$vnode.data.staticClass,attrs:{"data-has-footer":t.cancelButton||t.submitButton,"data-size":t.size,method:"dialog"},on:{click:function(t){t.stopPropagation()},submit:function(e){return e.preventDefault(),t.$emit("submit")}}},[t._t("header",(function(){return[e("k-dialog-notification")]})),t.$slots.default?e("k-dialog-body",[t._t("default")],2):t._e(),t._t("footer",(function(){return[t.cancelButton||t.submitButton?e("k-dialog-footer",[e("k-dialog-buttons",{attrs:{"cancel-button":t.cancelButton,disabled:t.disabled,icon:t.icon,"submit-button":t.submitButton,theme:t.theme},on:{cancel:function(e){return t.$emit("cancel")}}})],1):t._e()]}))],2)]):t._e()}),[],!1,null,null,null,null).exports;const Lt=ut({mixins:[Et],props:{cancelButton:{default:!1},changes:{type:Array},loading:{type:Boolean},size:{default:"medium"},submitButton:{default:!1}},computed:{ids(){return Object.keys(this.store).filter((t=>{var e;return this.$helper.object.length(null==(e=this.store[t])?void 0:e.changes)>0}))},store(){return this.$store.state.content.models}},watch:{ids:{handler(t){this.$panel.dialog.refresh({method:"POST",body:{ids:t}})},immediate:!0}}},(function(){var t=this,e=t._self._c;return e("k-dialog",t._b({staticClass:"k-changes-dialog"},"k-dialog",t.$props,!1),[!1===t.loading?[e("k-headline",[t._v(t._s(t.$t("lock.unsaved")))]),t.changes.length?e("k-items",{attrs:{items:t.changes,layout:"list"}}):e("k-empty",{attrs:{icon:"edit-line"}},[t._v(t._s(t.$t("lock.unsaved.empty")))])]:[e("k-icon",{attrs:{type:"loader"}})]],2)}),[],!1,null,null,null,null).exports;const Bt=ut({mixins:[Et,Ct],props:{fields:{default:()=>({href:{label:window.panel.$t("email"),type:"email",icon:"email"},title:{label:window.panel.$t("title"),type:"text",icon:"title"}})},size:{default:"medium"},submitButton:{default:()=>window.panel.$t("insert")}},data(){return{values:{href:"",title:null,...this.value}}},methods:{submit(){this.$emit("submit",this.values)}}},(function(){var t=this;return(0,t._self._c)("k-form-dialog",t._b({attrs:{value:t.values},on:{cancel:function(e){return t.$emit("cancel")},input:function(e){t.values=e},submit:t.submit}},"k-form-dialog",t.$props,!1))}),[],!1,null,null,null,null).exports;const qt=ut({mixins:[Et],props:{details:[Object,Array],message:String,size:{default:"medium",type:String}},emits:["cancel"],computed:{detailsList(){return Array.fromObject(this.details)}}},(function(){var t=this,e=t._self._c;return e("k-dialog",{ref:"dialog",staticClass:"k-error-dialog",attrs:{"cancel-button":!1,"submit-button":!1,size:t.size,visible:t.visible},on:{cancel:function(e){return t.$emit("cancel")}}},[e("k-text",[t._v(t._s(t.message))]),t.detailsList.length?e("dl",{staticClass:"k-error-details"},[t._l(t.detailsList,(function(i,n){return[e("dt",{key:"detail-label-"+n},[t._v(" "+t._s(i.label)+" ")]),e("dd",{key:"detail-message-"+n},["object"==typeof i.message?[e("ul",t._l(i.message,(function(i,n){return e("li",{key:n},[t._v(" "+t._s(i)+" ")])})),0)]:[t._v(" "+t._s(i.message)+" ")]],2)]}))],2):t._e()],1)}),[],!1,null,null,null,null).exports;const Pt=ut({},(function(){var t=this;return(0,t._self._c)(t.$panel.dialog.component,t._g(t._b({key:t.$panel.dialog.timestamp,tag:"component",attrs:{visible:!0}},"component",t.$panel.dialog.props,!1),t.$panel.dialog.listeners()))}),[],!1,null,null,null,null).exports,Nt=(t,e)=>{let i=null;return(...n)=>{clearTimeout(i),i=setTimeout((()=>t.apply(void 0,n)),e)}},zt={props:{delay:{default:200,type:Number},hasSearch:{default:!0,type:Boolean}},data:()=>({query:null}),watch:{query(){!1!==this.hasSearch&&this.search()}},created(){this.search=Nt(this.search,this.delay)},methods:{async search(){console.warn("Search mixin: Please implement a `search` method.")}}},Ft={props:{endpoint:String,empty:Object,fetchParams:Object,item:{type:Function,default:t=>t},max:Number,multiple:{type:Boolean,default:!0},size:{type:String,default:"medium"},value:{type:Array,default:()=>[]}}};const Yt=ut({mixins:[Et,zt,Ft],emits:["cancel","fetched","submit"],data(){return{models:[],selected:this.value.reduce(((t,e)=>({...t,[e]:{id:e}})),{}),pagination:{limit:20,page:1,total:0}}},computed:{items(){return this.models.map(this.item)}},watch:{fetchParams(t,e){!1===this.$helper.object.same(t,e)&&(this.pagination.page=1,this.fetch())}},mounted(){this.fetch()},methods:{async fetch(){const t={page:this.pagination.page,search:this.query,...this.fetchParams};try{this.$panel.dialog.isLoading=!0;const e=await this.$api.get(this.endpoint,t);this.models=e.data,this.pagination=e.pagination,this.$emit("fetched",e)}catch(e){this.$panel.error(e),this.models=[]}finally{this.$panel.dialog.isLoading=!1}},isSelected(t){return void 0!==this.selected[t.id]},paginate(t){this.pagination.page=t.page,this.pagination.limit=t.limit,this.fetch()},submit(){this.$emit("submit",Object.values(this.selected))},async search(){this.pagination.page=0,await this.fetch()},toggle(t){if(!1!==this.multiple&&1!==this.max||(this.selected={}),this.isSelected(t))return Vue.del(this.selected,t.id);this.max&&this.max<=this.$helper.object.length(this.selected)||Vue.set(this.selected,t.id,t)}}},(function(){var t=this,e=t._self._c;return e("k-dialog",t._b({staticClass:"k-models-dialog",on:{cancel:function(e){return t.$emit("cancel")},submit:t.submit}},"k-dialog",t.$props,!1),[t._t("header"),t.hasSearch?e("k-dialog-search",{attrs:{value:t.query},on:{search:function(e){t.query=e}}}):t._e(),e("k-collection",{attrs:{empty:{...t.empty,text:t.$panel.dialog.isLoading?t.$t("loading"):t.empty.text},items:t.items,link:!1,pagination:{details:!0,dropdown:!1,align:"center",...t.pagination},sortable:!1,layout:"list"},on:{item:t.toggle,paginate:t.paginate},scopedSlots:t._u([{key:"options",fn:function({item:i}){return[t.isSelected(i)?e("k-button",{attrs:{icon:t.multiple&&1!==t.max?"check":"circle-nested",title:t.$t("remove"),theme:"info"},on:{click:function(e){return e.stopPropagation(),t.toggle(i)}}}):e("k-button",{attrs:{title:t.$t("select"),icon:"circle-outline"},on:{click:function(e){return e.stopPropagation(),t.toggle(i)}}}),t._t("options",null,null,{item:i})]}}],null,!0)})],2)}),[],!1,null,null,null,null).exports;const Rt=ut({mixins:[Et,Ft],props:{empty:{type:Object,default:()=>({icon:"image",text:window.panel.$t("dialog.files.empty")})}}},(function(){var t=this;return(0,t._self._c)("k-models-dialog",t._b({on:{cancel:function(e){return t.$emit("cancel")},submit:function(e){return t.$emit("submit",e)}}},"k-models-dialog",t.$props,!1))}),[],!1,null,null,null,null).exports;const Ut=ut({mixins:[Et,Ct],props:{size:{default:"medium"},submitButton:{default:()=>window.panel.$t("save")},text:{type:String}},emits:["cancel","input","submit"]},(function(){var t=this,e=t._self._c;return e("k-dialog",t._b({ref:"dialog",on:{cancel:function(e){return t.$emit("cancel")},submit:function(e){return t.$emit("submit",t.value)}}},"k-dialog",t.$props,!1),[t._t("default",(function(){return[t.text?e("k-dialog-text",{attrs:{text:t.text}}):t._e(),e("k-dialog-fields",{attrs:{fields:t.fields,novalidate:t.novalidate,value:t.value},on:{input:function(e){return t.$emit("input",e)},submit:function(e){return t.$emit("submit",e)}}})]}))],2)}),[],!1,null,null,null,null).exports;const Ht=ut({extends:Ut,watch:{"value.name"(t){this.fields.code.disabled||this.onNameChanges(t)},"value.code"(t){this.fields.code.disabled||(this.value.code=this.$helper.slug(t,[this.$panel.system.ascii]),this.onCodeChanges(this.value.code))}},methods:{onCodeChanges(t){if(!t)return this.value.locale=null;if(t.length>=2)if(-1!==t.indexOf("-")){let e=t.split("-"),i=[e[0],e[1].toUpperCase()];this.value.locale=i.join("_")}else{let e=this.$panel.system.locales??[];this.value.locale=null==e?void 0:e[t]}},onNameChanges(t){this.value.code=this.$helper.slug(t,[this.value.rules,this.$panel.system.ascii]).substr(0,2)}}},null,null,!1,null,null,null,null).exports;const Vt=ut({mixins:[{mixins:[Et],props:{license:Object,size:{default:"large"}}}]},(function(){var t=this,e=t._self._c;return e("k-dialog",t._b({ref:"dialog",staticClass:"k-license-dialog",on:{cancel:function(e){return t.$emit("cancel")},submit:function(e){return t.$emit("submit")}}},"k-dialog",t.$props,!1),[e("k-bar",{staticStyle:{"margin-bottom":"var(--spacing-2)"}},[e("h2",{staticClass:"k-headline"},[t._v(" "+t._s(t.$t("license"))+" ")])]),e("div",{staticClass:"k-table"},[e("table",{staticStyle:{"table-layout":"auto"}},[e("tbody",[e("tr",[e("th",{attrs:{"data-mobile":"true"}},[t._v(t._s(t.$t("type")))]),e("td",{attrs:{"data-mobile":"true"}},[t._v(t._s(t.license.type))])]),t.license.code?e("tr",[e("th",{attrs:{"data-mobile":"true"}},[t._v(t._s(t.$t("license.code")))]),e("td",{staticClass:"k-text",attrs:{"data-mobile":"true"}},[e("code",[t._v(t._s(t.license.code))])])]):t._e(),t.license.info?e("tr",[e("th",{attrs:{"data-mobile":"true"}},[t._v(t._s(t.$t("status")))]),e("td",{attrs:{"data-mobile":"true","data-theme":t.license.theme}},[e("p",{staticClass:"k-license-dialog-status"},[e("k-icon",{attrs:{type:t.license.icon}}),t._v(" "+t._s(t.license.info)+" ")],1)])]):t._e()])])])],1)}),[],!1,null,null,null,null).exports;const Kt=ut({mixins:[Et,Ct],props:{fields:{default:()=>({href:{label:window.panel.$t("link"),type:"link",placeholder:window.panel.$t("url.placeholder"),icon:"url"},title:{label:window.panel.$t("title"),type:"text",icon:"title"},target:{label:window.panel.$t("open.newWindow"),type:"toggle",text:[window.panel.$t("no"),window.panel.$t("yes")]}})},size:{default:"medium"},submitButton:{default:()=>window.panel.$t("insert")}},data(){return{values:{href:"",title:null,...this.value,target:Boolean(this.value.target??!1)}}},methods:{submit(){const t=this.values.href.replace("file://","/@/file/").replace("page://","/@/page/");this.$emit("submit",{...this.values,href:t,target:this.values.target?"_blank":null})}}},(function(){var t=this;return(0,t._self._c)("k-form-dialog",t._b({attrs:{value:t.values},on:{cancel:function(e){return t.$emit("cancel")},input:function(e){t.values=e},submit:t.submit}},"k-form-dialog",t.$props,!1))}),[],!1,null,null,null,null).exports;const Wt=ut({mixins:[Ut],props:{blueprints:{type:Array},size:{default:"medium",type:String},submitButton:{type:[String,Boolean],default:()=>window.panel.$t("save")},template:{type:String}},computed:{templates(){return this.blueprints.map((t=>({text:t.title,value:t.name})))}},methods:{pick(t){this.$panel.dialog.reload({query:{...this.$panel.dialog.query,slug:this.value.slug,template:t,title:this.value.title}})}}},(function(){var t=this,e=t._self._c;return e("k-form-dialog",t._b({ref:"dialog",staticClass:"k-page-create-dialog",on:{cancel:function(e){return t.$emit("cancel")},submit:function(e){return t.$emit("submit",t.value)}}},"k-form-dialog",t.$props,!1),[t.templates.length>1?e("k-select-field",{staticClass:"k-page-template-switch",attrs:{empty:!1,label:t.$t("template"),options:t.templates,required:!0,value:t.template},on:{input:function(e){return t.pick(e)}}}):t._e(),e("k-dialog-fields",{attrs:{fields:t.fields,novalidate:t.novalidate,value:t.value},on:{input:function(e){return t.$emit("input",e)},submit:function(e){return t.$emit("submit",e)}}})],1)}),[],!1,null,null,null,null).exports;const Jt=ut({mixins:[Et],props:{value:{default:()=>({}),type:Object}},emits:["cancel","input","submit"],methods:{select(t){this.$emit("input",{...this.value,parent:t.value})}}},(function(){var t=this,e=t._self._c;return e("k-dialog",t._b({ref:"dialog",staticClass:"k-page-move-dialog",attrs:{"submit-button":{icon:"parent",text:t.$t("move")},size:"medium"},on:{cancel:function(e){return t.$emit("cancel")},submit:function(e){return t.$emit("submit",t.value)}}},"k-dialog",t.$props,!1),[e("k-headline",[t._v(t._s(t.$t("page.move")))]),e("div",{staticClass:"k-page-move-parent",attrs:{tabindex:"0","data-autofocus":""}},[e("k-page-tree",{attrs:{current:t.value.parent,move:t.value.move,identifier:"id"},on:{select:t.select}})],1)],1)}),[],!1,null,null,null,null).exports;const Gt=ut({mixins:[Et,Ft],props:{empty:{type:Object,default:()=>({icon:"page",text:window.panel.$t("dialog.pages.empty")})}},data:()=>({model:null,parent:null})},(function(){var t=this,e=t._self._c;return e("k-models-dialog",t._b({attrs:{"fetch-params":{parent:t.parent}},on:{cancel:function(e){return t.$emit("cancel")},fetched:function(e){t.model=e.model},submit:function(e){return t.$emit("submit",e)}},scopedSlots:t._u([t.model?{key:"header",fn:function(){return[e("header",{staticClass:"k-pages-dialog-navbar"},[e("k-button",{attrs:{disabled:!t.model.id,title:t.$t("back"),icon:"angle-left"},on:{click:function(e){t.parent=t.model.parent}}}),e("k-headline",[t._v(t._s(t.model.title))])],1)]},proxy:!0}:null,t.model?{key:"options",fn:function({item:i}){return[e("k-button",{staticClass:"k-pages-dialog-option",attrs:{disabled:!i.hasChildren,title:t.$t("open"),icon:"angle-right"},on:{click:function(e){e.stopPropagation(),t.parent=i.id}}})]}}:null],null,!0)},"k-models-dialog",t.$props,!1))}),[],!1,null,null,null,null).exports;const Xt=ut({mixins:[{mixins:[Et,jt]}]},(function(){var t=this,e=t._self._c;return e("k-dialog",t._b({ref:"dialog",on:{cancel:function(e){return t.$emit("cancel")},submit:function(e){return t.$emit("submit")}}},"k-dialog",t.$props,!1),[t._t("default",(function(){return[e("k-dialog-text",{attrs:{text:t.text}})]}))],2)}),[],!1,null,null,null,null).exports;const Zt=ut({mixins:[Xt],props:{icon:{default:"trash"},submitButton:{default:()=>window.panel.$t("delete")},theme:{default:"negative"}}},(function(){var t=this;return(0,t._self._c)("k-text-dialog",t._b({ref:"dialog",on:{cancel:function(e){return t.$emit("cancel")},submit:function(e){return t.$emit("submit")}}},"k-text-dialog",t.$props,!1),[t._t("default")],2)}),[],!1,null,null,null,null).exports;const Qt=ut({mixins:[Et,zt],props:{type:String},emits:["cancel"],data(){return{isLoading:!1,items:[],pagination:{},selected:-1,current:this.type??(this.$panel.searches[this.$panel.view.search]?this.$panel.view.search:Object.keys(this.$panel.searches)[0])}},computed:{currentType(){return this.$panel.searches[this.current]??this.types[0]},types(){return Object.values(this.$panel.searches).map((t=>({...t,current:this.current===t.id,click:()=>{this.current=t.id,this.focus()}})))}},watch:{current(){this.search()}},methods:{clear(){this.items=[],this.query=null},focus(){var t;null==(t=this.$refs.input)||t.focus()},navigate(t){t&&(this.$go(t.link),this.close())},onDown(){this.selected=0&&this.select(this.selected-1)},async search(){var t,e;this.isLoading=!0,null==(t=this.$refs.types)||t.close(),null==(e=this.select)||e.call(this,-1);try{if(null===this.query||this.query.length<2)throw Error("Empty query");const t=await this.$search(this.current,this.query);this.items=t.results,this.pagination=t.pagination}catch{this.items=[],this.pagination={}}finally{this.isLoading=!1}},select(t){var e;this.selected=t;const i=(null==(e=this.$refs.items)?void 0:e.$el.querySelectorAll(".k-item"))??[];for(const n of i)delete n.dataset.selected;t>=0&&(i[t].dataset.selected=!0)}}},(function(){var t,e=this,i=e._self._c;return i("k-dialog",e._b({staticClass:"k-search-dialog",attrs:{"cancel-button":!1,"submit-button":!1,role:"search",size:"medium"},on:{cancel:function(t){return e.$emit("cancel")},submit:e.submit}},"k-dialog",e.$props,!1),[i("div",{staticClass:"k-search-dialog-input"},[i("k-button",{staticClass:"k-search-dialog-types",attrs:{dropdown:!0,icon:e.currentType.icon,text:e.currentType.label,variant:"dimmed"},on:{click:function(t){return e.$refs.types.toggle()}}}),i("k-dropdown-content",{ref:"types",attrs:{options:e.types}}),i("k-search-input",{ref:"input",attrs:{"aria-label":e.$t("search"),autofocus:!0,value:e.query},on:{input:function(t){e.query=t}},nativeOn:{keydown:[function(t){return!t.type.indexOf("key")&&e._k(t.keyCode,"down",40,t.key,["Down","ArrowDown"])?null:(t.preventDefault(),e.onDown.apply(null,arguments))},function(t){return!t.type.indexOf("key")&&e._k(t.keyCode,"up",38,t.key,["Up","ArrowUp"])?null:(t.preventDefault(),e.onUp.apply(null,arguments))},function(t){return!t.type.indexOf("key")&&e._k(t.keyCode,"enter",13,t.key,"Enter")?null:e.onEnter.apply(null,arguments)}]}}),i("k-button",{staticClass:"k-search-dialog-close",attrs:{icon:e.isLoading?"loader":"cancel",title:e.$t("close")},on:{click:e.close}})],1),(null==(t=e.query)?void 0:t.length)>1?i("div",{staticClass:"k-search-dialog-results"},[e.items.length?i("k-collection",{ref:"items",attrs:{items:e.items},nativeOn:{mouseout:function(t){return e.select(-1)}}}):e._e(),i("footer",{staticClass:"k-search-dialog-footer"},[e.items.length?e.items.length({text:window.panel.$t("activate"),icon:"lock",theme:"notice"})}},emits:["cancel","input","submit"]},(function(){var t=this,e=t._self._c;return e("k-dialog",t._b({ref:"dialog",on:{cancel:function(e){return t.$emit("cancel")},submit:function(e){return t.$emit("submit")}}},"k-dialog",t.$props,!1),[e("k-dialog-text",{staticClass:"k-totp-dialog-intro",attrs:{text:t.$t("login.totp.enable.intro")}}),e("div",{staticClass:"k-totp-dialog-grid"},[e("div",{staticClass:"k-totp-qrcode"},[e("k-info-field",{attrs:{label:t.$t("login.totp.enable.qr.label"),text:t.qr,help:t.$t("login.totp.enable.qr.help",{secret:t.value.secret}),theme:"passive"}})],1),e("k-dialog-fields",{staticClass:"k-totp-dialog-fields",attrs:{fields:{info:{label:t.$t("login.totp.enable.confirm.headline"),type:"info",text:t.$t("login.totp.enable.confirm.text"),theme:"none"},confirm:{label:t.$t("login.totp.enable.confirm.label"),type:"text",counter:!1,font:"monospace",required:!0,placeholder:t.$t("login.code.placeholder.totp"),help:t.$t("login.totp.enable.confirm.help")},secret:{type:"hidden"}},novalidate:!0,value:t.value},on:{input:function(e){return t.$emit("input",e)},submit:function(e){return t.$emit("submit",e)}}})],1)],1)}),[],!1,null,null,null,null).exports;const ee=ut({mixins:[Et],props:{submitButton:{type:[String,Boolean,Object],default:()=>({icon:"upload",text:window.panel.$t("upload")})}}},(function(){var t=this,e=t._self._c;return e("k-dialog",t._b({ref:"dialog",staticClass:"k-upload-dialog",attrs:{disabled:t.disabled||0===t.$panel.upload.files.length},on:{cancel:function(e){return t.$emit("cancel")},submit:function(e){return t.$emit("submit")}}},"k-dialog",t.$props,!1),[e("k-dropzone",{on:{drop:function(e){return t.$panel.upload.select(e)}}},[0===t.$panel.upload.files.length?e("k-empty",{attrs:{icon:"upload",layout:"cards"},on:{click:function(e){return t.$panel.upload.pick()}}},[t._v(" "+t._s(t.$t("files.empty"))+" ")]):e("k-upload-items",{attrs:{items:t.$panel.upload.files},on:{remove:e=>{t.$panel.upload.remove(e.id)},rename:(t,e)=>{t.name=e}}})],1)],1)}),[],!1,null,null,null,null).exports;const ie=ut({extends:ee,props:{original:Object,submitButton:{type:[String,Boolean,Object],default:()=>({icon:"upload",text:window.panel.$t("replace")})}},computed:{file(){return this.$panel.upload.files[0]}}},(function(){var t,e,i,n,s=this,o=s._self._c;return o("k-dialog",s._b({ref:"dialog",staticClass:"k-upload-dialog k-upload-replace-dialog",on:{cancel:function(t){return s.$emit("cancel")},submit:function(t){return s.$emit("submit")}}},"k-dialog",s.$props,!1),[o("ul",{staticClass:"k-upload-items"},[o("li",{staticClass:"k-upload-original"},[o("k-upload-item-preview",{attrs:{color:null==(t=s.original.image)?void 0:t.color,icon:null==(e=s.original.image)?void 0:e.icon,url:s.original.url,type:s.original.mime}})],1),o("li",[s._v("←")]),o("k-upload-item",s._b({attrs:{color:null==(i=s.original.image)?void 0:i.color,editable:!1,icon:null==(n=s.original.image)?void 0:n.icon,name:s.$helper.file.name(s.original.filename),removable:!1}},"k-upload-item",s.file,!1))],1)])}),[],!1,null,null,null,null).exports;const ne=ut({mixins:[Et,Ft],props:{empty:{type:Object,default:()=>({icon:"users",text:window.panel.$t("dialog.users.empty")})},item:{type:Function,default:t=>({...t,key:t.email,info:t.info!==t.text?t.info:null})}}},(function(){var t=this;return(0,t._self._c)("k-models-dialog",t._b({on:{cancel:function(e){return t.$emit("cancel")},submit:function(e){return t.$emit("submit",e)}}},"k-models-dialog",t.$props,!1))}),[],!1,null,null,null,null).exports,se={install(t){t.use(Dt),t.component("k-dialog",Tt),t.component("k-changes-dialog",Lt),t.component("k-email-dialog",Bt),t.component("k-error-dialog",qt),t.component("k-fiber-dialog",Pt),t.component("k-files-dialog",Rt),t.component("k-form-dialog",Ut),t.component("k-license-dialog",Vt),t.component("k-link-dialog",Kt),t.component("k-language-dialog",Ht),t.component("k-models-dialog",Yt),t.component("k-page-create-dialog",Wt),t.component("k-page-move-dialog",Jt),t.component("k-pages-dialog",Gt),t.component("k-remove-dialog",Zt),t.component("k-search-dialog",Qt),t.component("k-text-dialog",Xt),t.component("k-totp-dialog",te),t.component("k-upload-dialog",ee),t.component("k-upload-replace-dialog",ie),t.component("k-users-dialog",ne)}};const oe=ut({},(function(){return(0,this._self._c)("div",{staticClass:"k-drawer-body scroll-y-auto"},[this._t("default")],2)}),[],!1,null,null,null,null).exports,le={props:{empty:{type:String,default:()=>window.panel.$t("drawer.fields.empty")},fields:Object,novalidate:{type:Boolean,default:!0},value:Object}};const ae=ut({mixins:[le],emits:["input","submit"],computed:{hasFields(){return this.$helper.object.length(this.fields)>0}}},(function(){var t=this,e=t._self._c;return t.hasFields?e("k-fieldset",{staticClass:"k-drawer-fields",attrs:{novalidate:t.novalidate,fields:t.fields,value:t.value},on:{input:function(e){return t.$emit("input",e)},submit:function(e){return t.$emit("submit",e)}}}):e("k-box",{attrs:{theme:"info"}},[t._v(t._s(t.empty))])}),[],!1,null,null,null,null).exports,re={props:{breadcrumb:{default:()=>[],type:Array},tab:{type:String},tabs:{default:()=>({}),type:Object}}};const ue=ut({mixins:[re],emits:["crumb","tab"]},(function(){var t=this,e=t._self._c;return e("header",{staticClass:"k-drawer-header"},[e("nav",{staticClass:"k-breadcrumb k-drawer-breadcrumb"},[e("ol",t._l(t.breadcrumb,(function(i,n){return e("li",{key:i.id},[e("k-button",{staticClass:"k-breadcrumb-link",attrs:{icon:i.props.icon,text:i.props.title,current:n===t.breadcrumb.length-1,variant:"dimmed"},on:{click:function(e){return t.$emit("crumb",i.id)}}})],1)})),0)]),e("k-drawer-tabs",{attrs:{tab:t.tab,tabs:t.tabs},on:{open:function(e){return t.$emit("tab",e)}}}),e("nav",{staticClass:"k-drawer-options"},[t._t("default"),e("k-button",{staticClass:"k-drawer-option",attrs:{icon:"check",type:"submit"}})],2)],1)}),[],!1,null,null,null,null).exports;const ce=ut({},(function(){var t=this,e=t._self._c;return"drawer"===t.$panel.notification.context?e("k-notification",{staticClass:"k-drawer-notification"}):t._e()}),[],!1,null,null,null,null).exports;const de=ut({mixins:[{props:{tab:{type:String},tabs:{default:()=>({}),type:[Array,Object]}}}],emits:["open"],computed:{hasTabs(){return this.$helper.object.length(this.tabs)>1}}},(function(){var t=this,e=t._self._c;return t.hasTabs?e("nav",{staticClass:"k-drawer-tabs"},t._l(t.tabs,(function(i){return e("k-button",{key:i.name,staticClass:"k-drawer-tab",attrs:{current:t.tab===i.name,text:i.label},on:{click:function(e){return t.$emit("open",i.name)}}})})),1):t._e()}),[],!1,null,null,null,null).exports,pe={props:{empty:{type:String,default:()=>window.panel.$t("drawer.text.empty")},text:{type:String}}};const he=ut({mixins:[pe]},(function(){var t=this,e=t._self._c;return t.text?e("k-text",{attrs:{html:t.text}}):e("k-box",{attrs:{theme:"info"}},[t._v(t._s(t.empty))])}),[],!1,null,null,null,null).exports,me={install(t){t.component("k-drawer-body",oe),t.component("k-drawer-fields",ae),t.component("k-drawer-header",ue),t.component("k-drawer-notification",ce),t.component("k-drawer-tabs",de),t.component("k-drawer-text",he)}},fe={mixins:[re],props:{disabled:{default:!1,type:Boolean},icon:String,id:String,options:{type:Array},title:String,visible:{default:!1,type:Boolean}}};const ge=ut({mixins:[fe],emits:["cancel","crumb","submit","tab"]},(function(){var t=this,e=t._self._c;return t.visible?e("portal",{attrs:{to:"drawer"}},[e("form",{staticClass:"k-drawer",class:t.$vnode.data.staticClass,attrs:{"aria-disabled":t.disabled,method:"dialog"},on:{submit:function(e){return e.preventDefault(),t.$emit("submit")}}},[e("k-drawer-notification"),e("k-drawer-header",{attrs:{breadcrumb:t.breadcrumb,tab:t.tab,tabs:t.tabs},on:{crumb:function(e){return t.$emit("crumb",e)},tab:function(e){return t.$emit("tab",e)}}},[t._t("options",(function(){return[t._l(t.options,(function(i,n){return[i.dropdown?[e("k-button",t._b({key:"btn-"+n,staticClass:"k-drawer-option",on:{click:function(e){t.$refs["dropdown-"+n][0].toggle()}}},"k-button",i,!1)),e("k-dropdown-content",{key:"dropdown-"+n,ref:"dropdown-"+n,refInFor:!0,attrs:{options:i.dropdown,"align-x":"end",theme:"light"}})]:e("k-button",t._b({key:n,staticClass:"k-drawer-option"},"k-button",i,!1))]}))]}))],2),e("k-drawer-body",[t._t("default")],2)],1)]):t._e()}),[],!1,null,null,null,null).exports,ke={props:{hidden:{type:Boolean},next:{type:Object},prev:{type:Object}}};const be=ut({mixins:[fe,le,ke],emits:["cancel","crumb","input","next","prev","remove","show","submit","tab"]},(function(){var t=this,e=t._self._c;return e("k-form-drawer",t._b({ref:"drawer",staticClass:"k-block-drawer",on:{cancel:function(e){return t.$emit("cancel",e)},crumb:function(e){return t.$emit("crumb",e)},input:function(e){return t.$emit("input",e)},submit:function(e){return t.$emit("submit",e)},tab:function(e){return t.$emit("tab",e)}},scopedSlots:t._u([{key:"options",fn:function(){return[t.hidden?e("k-button",{staticClass:"k-drawer-option",attrs:{icon:"hidden"},on:{click:function(e){return t.$emit("show")}}}):t._e(),e("k-button",{staticClass:"k-drawer-option",attrs:{disabled:!t.prev,icon:"angle-left"},on:{click:function(e){return t.$emit("prev")}}}),e("k-button",{staticClass:"k-drawer-option",attrs:{disabled:!t.next,icon:"angle-right"},on:{click:function(e){return t.$emit("next")}}}),e("k-button",{staticClass:"k-drawer-option",attrs:{icon:"trash"},on:{click:function(e){return t.$emit("remove")}}})]},proxy:!0}])},"k-form-drawer",t.$props,!1))}),[],!1,null,null,null,null).exports;const ve=ut({methods:{isCurrent(t){return this.$panel.drawer.id===t}}},(function(){var t=this,e=t._self._c;return e("div",t._l(t.$panel.drawer.history.milestones,(function(i){return e(i.component,t._g(t._b({key:i.id,tag:"component",attrs:{breadcrumb:t.$panel.drawer.breadcrumb,disabled:!1===t.isCurrent(i.id),visible:!0}},"component",t.isCurrent(i.id)?t.$panel.drawer.props:i.props,!1),t.isCurrent(i.id)?t.$panel.drawer.listeners():i.on))})),1)}),[],!1,null,null,null,null).exports;const ye=ut({mixins:[fe,le],emits:["cancel","crumb","input","submit","tab"]},(function(){var t=this,e=t._self._c;return e("k-drawer",t._b({ref:"drawer",staticClass:"k-form-drawer",on:{cancel:function(e){return t.$emit("cancel")},crumb:function(e){return t.$emit("crumb",e)},submit:function(e){return t.$emit("submit",t.value)},tab:function(e){return t.$emit("tab",e)}}},"k-drawer",t.$props,!1),[t._t("options",null,{slot:"options"}),e("k-drawer-fields",{attrs:{fields:t.fields,value:t.value},on:{input:function(e){return t.$emit("input",e)},submit:function(e){return t.$emit("submit",e)}}})],2)}),[],!1,null,null,null,null).exports;const $e=ut({mixins:[fe,le,{props:{next:{type:Object},prev:{type:Object}}}],emits:["cancel","crumb","input","next","prev","remove","submit","tab"]},(function(){var t=this,e=t._self._c;return e("k-form-drawer",t._b({ref:"drawer",staticClass:"k-structure-drawer",on:{cancel:function(e){return t.$emit("cancel",e)},crumb:function(e){return t.$emit("crumb",e)},input:function(e){return t.$emit("input",e)},submit:function(e){return t.$emit("submit",e)},tab:function(e){return t.$emit("tab",e)}},scopedSlots:t._u([{key:"options",fn:function(){return[e("k-button",{staticClass:"k-drawer-option",attrs:{disabled:!t.prev,icon:"angle-left"},on:{click:function(e){return t.$emit("prev")}}}),e("k-button",{staticClass:"k-drawer-option",attrs:{disabled:!t.next,icon:"angle-right"},on:{click:function(e){return t.$emit("next")}}}),e("k-button",{staticClass:"k-drawer-option",attrs:{icon:"trash"},on:{click:function(e){return t.$emit("remove")}}})]},proxy:!0}])},"k-form-drawer",t.$props,!1))}),[],!1,null,null,null,null).exports;const we=ut({mixins:[fe,pe],emits:["cancel","crumb","input","submit","tab"]},(function(){var t=this,e=t._self._c;return e("k-drawer",t._b({ref:"drawer",staticClass:"k-text-drawer",on:{cancel:function(e){return t.$emit("cancel")},crumb:function(e){return t.$emit("crumb",e)},submit:function(e){return t.$emit("submit",t.value)},tab:function(e){return t.$emit("tab",e)}}},"k-drawer",t.$props,!1),[t._t("options",null,{slot:"options"}),e("k-dialog-text",{attrs:{text:t.text}})],2)}),[],!1,null,null,null,null).exports,xe={install(t){t.use(me),t.component("k-drawer",ge),t.component("k-block-drawer",be),t.component("k-fiber-drawer",ve),t.component("k-form-drawer",ye),t.component("k-structure-drawer",$e),t.component("k-text-drawer",we)}};const _e=ut({mounted(){window.panel.deprecated(" will be removed in a future version. Since Kirby 4.0, you don't need it anymore as wrapper element. Use `` as standalone instead.")}},(function(){return(0,this._self._c)("span",{staticClass:"k-dropdown",on:{click:function(t){t.stopPropagation()}}},[this._t("default")],2)}),[],!1,null,null,null,null).exports;let Ce=null;const Se=ut({props:{align:{type:String},alignX:{type:String,default:"start"},alignY:{type:String,default:"bottom"},disabled:{type:Boolean,default:!1},navigate:{default:!0,type:Boolean},options:[Array,Function,String],theme:{type:String,default:"dark"}},emits:["action","close","open"],data(){return{axis:{x:this.alignX,y:this.alignY},position:{x:0,y:0},isOpen:!1,items:[],opener:null}},mounted(){this.align&&window.panel.deprecated(": `align` prop will be removed in a future version. Use the `alignX` prop instead.")},methods:{close(){var t;null==(t=this.$refs.dropdown)||t.close()},async fetchOptions(t){return this.options?"string"==typeof this.options?this.$dropdown(this.options)(t):"function"==typeof this.options?this.options(t):Array.isArray(this.options)?t(this.options):void 0:t(this.items)},focus(t=0){this.$refs.navigate.focus(t)},onClick(){this.close()},onClose(){this.resetPosition(),this.isOpen=Ce=!1,this.$emit("close"),window.removeEventListener("resize",this.setPosition)},async onOpen(){this.isOpen=!0;const t=window.scrollY;Ce=this,await this.$nextTick(),this.$el&&this.opener&&(window.addEventListener("resize",this.setPosition),await this.setPosition(),window.scrollTo(0,t),this.$emit("open"))},onOptionClick(t){return this.close(),"function"==typeof t.click?t.click.call(this):"string"==typeof t.click?this.$emit("action",t.click):void(t.click&&(t.click.name&&this.$emit(t.click.name,t.click.payload),t.click.global&&this.$events.emit(t.click.global,t.click.payload)))},open(t){var e,i;if(!0===this.disabled)return!1;Ce&&Ce!==this&&Ce.close(),this.opener=t??(null==(e=window.event)?void 0:e.target.closest("button"))??(null==(i=window.event)?void 0:i.target),this.fetchOptions((t=>{this.items=t,this.onOpen()}))},async setPosition(){this.axis={x:this.alignX??this.align,y:this.alignY},"right"===this.axis.x?this.axis.x="end":"left"===this.axis.x&&(this.axis.x="start"),"rtl"===this.$panel.direction&&("start"===this.axis.x?this.axis.x="end":"end"===this.axis.x&&(this.axis.x="start")),this.opener.$el&&(this.opener=this.opener.$el);const t=this.opener.getBoundingClientRect();this.position.x=t.left+window.scrollX+t.width,this.position.y=t.top+window.scrollY+t.height,!0!==this.$el.open&&this.$el.showModal(),await this.$nextTick();const e=this.$el.getBoundingClientRect(),i=10;"end"===this.axis.x?t.left-e.widthwindow.innerWidth-i&&e.width+ie.top&&(this.axis.y="bottom"):t.top+e.height>window.innerHeight-i&&e.height+i!0===t.default));t.push(this.item(e)),t.push("-");const i=this.languages.filter((t=>!1===t.default));for(const n of i)t.push(this.item(n));return t}},methods:{change(t){this.$reload({query:{language:t.code}})},item(t){return{click:()=>this.change(t),current:t.code===this.language.code,text:t.name}}}},(function(){var t=this,e=t._self._c;return t.languages.length>1?e("div",{staticClass:"k-languages-dropdown"},[e("k-button",{attrs:{dropdown:!0,text:t.code,icon:"translate",responsive:"text",size:"sm",variant:"filled"},on:{click:function(e){return t.$refs.languages.toggle()}}}),e("k-dropdown-content",{ref:"languages",attrs:{options:t.options}})],1):t._e()}),[],!1,null,null,null,null).exports;const Ae=ut({props:{align:{type:String,default:"right"},disabled:{type:Boolean},icon:{type:String,default:"dots"},options:{type:[Array,Function,String],default:()=>[]},text:{type:[Boolean,String],default:!0},theme:{type:String,default:"dark"},size:String,variant:String},emits:["action","option"],computed:{hasSingleOption(){return Array.isArray(this.options)&&1===this.options.length}},methods:{onAction(t,e,i){"function"==typeof t?t.call(this):(this.$emit("action",t,e,i),this.$emit("option",t,e,i))},toggle(t=this.$el){this.$refs.options.toggle(t)}}},(function(){var t=this,e=t._self._c;return t.hasSingleOption?e("k-button",{staticClass:"k-options-dropdown-toggle",attrs:{disabled:t.disabled,icon:t.options[0].icon??t.icon,size:t.options[0].size??t.size,title:t.options[0].title??t.options[0].tooltip??t.options[0].text,variant:t.options[0].variant??t.variant},on:{click:function(e){return t.onAction(t.options[0].option??t.options[0].click,t.options[0],0)}}},[!0===t.text?[t._v(" "+t._s(t.options[0].text)+" ")]:!1!==t.text?[t._v(" "+t._s(t.text)+" ")]:t._e()],2):t.options.length?e("div",{staticClass:"k-options-dropdown"},[e("k-button",{staticClass:"k-options-dropdown-toggle",attrs:{disabled:t.disabled,dropdown:!0,icon:t.icon,size:t.size,text:!0!==t.text&&!1!==t.text?t.text:null,title:t.$t("options"),variant:t.variant},on:{click:function(e){return t.$refs.options.toggle()}}}),e("k-dropdown-content",{ref:"options",staticClass:"k-options-dropdown-content",attrs:{"align-x":t.align,options:t.options},on:{action:t.onAction}})],1):t._e()}),[],!1,null,null,null,null).exports,je={mixins:[V,W,X,nt,at]},Ie={mixins:[je],inheritAttrs:!1,emits:["input"],methods:{focus(){this.$el.focus()}}},De={mixins:[V,W,st,at],props:{ignore:{default:()=>[],type:Array},max:Number,min:Number,search:{default:!0,type:[Object,Boolean]}}},Ee={mixins:[je,De],props:{create:{type:[Boolean,Object],default:!1},multiple:{type:Boolean,default:!0},value:{type:[Array,String],default:()=>[]}},emits:["create","escape","input"]};const Te=ut({mixins:[Ie,Ee],data(){return{display:this.search.display??!0,query:""}},computed:{choices(){let t=this.filteredOptions;return!0!==this.display&&(t=t.slice(0,this.display)),t.map((t=>({...t,disabled:t.disabled||this.isFull&&!1===this.value.includes(t.value),text:this.highlight(t.text)})))},filteredOptions(){if(!(this.query.length<(this.search.min??0)))return this.$helper.array.search(this.options,this.query,{field:"text"})},isFull(){return this.max&&this.value.length>=this.max},placeholder(){return this.search.placeholder?this.search.placeholder:this.options.length>0?this.$t("filter")+"…":this.$t("enter")+"…"},showCreate(){var t;if(!1===this.create)return!1;if(this.isFull)return!1;if(0===this.query.trim().length)return!1;if(!0===this.ignore.includes(this.query))return!1;if(!0===(null==(t=this.create.ignore)?void 0:t.includes(this.query)))return!1;return 0===this.options.filter((t=>t.text===this.query||t.value===this.query)).length},showEmpty(){return!1===this.create&&0===this.filteredOptions.length}},watch:{value:{handler(){this.$emit("invalid",this.$v.$invalid,this.$v)},immediate:!0}},methods:{add(){this.showCreate&&this.$emit("create",this.query)},enter(t){var e;null==(e=t.target)||e.click()},escape(){0===this.query.length?this.$emit("escape"):this.query=""},focus(){var t;this.$refs.search?this.$refs.search.focus():null==(t=this.$refs.options)||t.focus()},highlight(t){if(t=this.$helper.string.stripHTML(t),this.query.length>0){const e=new RegExp(`(${RegExp.escape(this.query)})`,"ig");return t.replace(e,"$1")}return t},input(t){this.$emit("input",t)}},validations(){return{value:{required:!this.required||t.required,minLength:!this.min||t.minLength(this.min),maxLength:!this.max||t.maxLength(this.max)}}}},(function(){var t=this,e=t._self._c;return e("k-navigate",{staticClass:"k-picklist-input",attrs:{element:"nav",axis:"y",select:"input[type=search], label, .k-picklist-input-body button"},on:{prev:function(e){return t.$emit("escape")}}},[t.search?e("header",{staticClass:"k-picklist-input-header"},[e("div",{staticClass:"k-picklist-input-search"},[e("k-search-input",{ref:"search",attrs:{autofocus:t.autofocus,disabled:t.disabled,placeholder:t.placeholder,value:t.query},on:{input:function(e){t.query=e}},nativeOn:{keydown:[function(e){return!e.type.indexOf("key")&&t._k(e.keyCode,"escape",void 0,e.key,void 0)?null:(e.preventDefault(),t.escape.apply(null,arguments))},function(e){return!e.type.indexOf("key")&&t._k(e.keyCode,"enter",13,e.key,"Enter")?null:(e.preventDefault(),t.add.apply(null,arguments))}]}}),t.showCreate?e("k-button",{staticClass:"k-picklist-input-create",attrs:{icon:"add",size:"xs"},on:{click:t.add}}):t._e()],1)]):t._e(),t.filteredOptions.length?[e("div",{staticClass:"k-picklist-input-body"},[e(t.multiple?"k-checkboxes-input":"k-radio-input",{ref:"options",tag:"component",staticClass:"k-picklist-input-options",attrs:{disabled:t.disabled,options:t.choices,value:t.value},on:{input:t.input},nativeOn:{keydown:function(e){return!e.type.indexOf("key")&&t._k(e.keyCode,"enter",13,e.key,"Enter")?null:(e.preventDefault(),t.enter.apply(null,arguments))}}}),!0!==t.display&&t.filteredOptions.length>t.display?e("k-button",{staticClass:"k-picklist-input-more",attrs:{icon:"angle-down"},on:{click:function(e){t.display=!0}}},[t._v(" "+t._s(t.$t("options.all",{count:t.filteredOptions.length}))+" ")]):t._e()],1)]:t.showEmpty?[e("div",{staticClass:"k-picklist-input-body"},[e("p",{staticClass:"k-picklist-input-empty"},[t._v(" "+t._s(t.$t("options.none"))+" ")])])]:t._e()],2)}),[],!1,null,null,null,null).exports;const Le=ut({mixins:[Ee],emits:["create","input"],methods:{close(){this.$refs.dropdown.close()},add(t){this.$emit("create",t)},input(t){this.$emit("input",t)},open(t){this.$refs.dropdown.open(t)},toggle(){this.$refs.dropdown.toggle()}}},(function(){var t=this,e=t._self._c;return e("k-dropdown-content",{ref:"dropdown",staticClass:"k-picklist-dropdown",attrs:{"align-x":"start",disabled:t.disabled,navigate:!1},nativeOn:{click:function(t){t.stopPropagation()}}},[e("k-picklist-input",t._b({on:{create:t.add,input:t.input,escape:function(e){return t.$refs.dropdown.close()}},nativeOn:{click:function(t){t.stopPropagation()}}},"k-picklist-input",t.$props,!1))],1)}),[],!1,null,null,null,null).exports,Be={install(t){t.component("k-dropdown",_e),t.component("k-dropdown-content",Se),t.component("k-dropdown-item",Oe),t.component("k-languages-dropdown",Me),t.component("k-options-dropdown",Ae),t.component("k-picklist-dropdown",Le)}};const qe=ut({props:{html:{type:Boolean,default:!1},limit:{type:Number,default:10},skip:{type:Array,default:()=>[]},options:Array,query:String},emits:["leave","search","select"],data:()=>({matches:[],selected:{text:null}}),mounted(){window.panel.deprecated(" will be removed in a future version.")},methods:{close(){this.$refs.dropdown.close()},onSelect(t){this.$emit("select",t),this.$refs.dropdown.close()},search(t){const e=this.options.filter((t=>-1!==this.skip.indexOf(t.value)));this.matches=this.$helper.array.search(e,t,{field:"text",limit:this.limit}),this.$emit("search",t,this.matches),this.$refs.dropdown.open()}}},(function(){var t=this,e=t._self._c;return e("div",{staticClass:"k-autocomplete"},[t._t("default"),e("k-dropdown-content",{ref:"dropdown",attrs:{autofocus:!0},on:{leave:function(e){return t.$emit("leave")}}},t._l(t.matches,(function(i,n){return e("k-dropdown-item",t._b({key:n,nativeOn:{mousedown:function(e){return t.onSelect(i)},keydown:[function(e){return!e.type.indexOf("key")&&t._k(e.keyCode,"tab",9,e.key,"Tab")?null:(e.preventDefault(),t.onSelect(i))},function(e){return!e.type.indexOf("key")&&t._k(e.keyCode,"enter",13,e.key,"Enter")?null:(e.preventDefault(),t.onSelect(i))},function(e){return!e.type.indexOf("key")&&t._k(e.keyCode,"left",37,e.key,["Left","ArrowLeft"])||"button"in e&&0!==e.button?null:(e.preventDefault(),t.close.apply(null,arguments))},function(e){return!e.type.indexOf("key")&&t._k(e.keyCode,"backspace",void 0,e.key,void 0)?null:(e.preventDefault(),t.close.apply(null,arguments))},function(e){return!e.type.indexOf("key")&&t._k(e.keyCode,"delete",[8,46],e.key,["Backspace","Delete","Del"])?null:(e.preventDefault(),t.close.apply(null,arguments))}]}},"k-dropdown-item",i,!1),[e("span",{domProps:{innerHTML:t._s(t.html?i.text:t.$esc(i.text))}})])})),1),t._v(" "+t._s(t.query)+" ")],2)}),[],!1,null,null,null,null).exports;const Pe=ut({props:{count:Number,min:Number,max:Number,required:{type:Boolean,default:!1}},computed:{valid(){return!1===this.required&&0===this.count||(!0!==this.required||0!==this.count)&&(!(this.min&&this.countthis.max))}}},(function(){var t=this,e=t._self._c;return e("span",{staticClass:"k-counter",attrs:{"data-invalid":!t.valid}},[e("span",[t._v(t._s(t.count))]),t.min||t.max?e("span",{staticClass:"k-counter-rules"},[t.min&&t.max?[t._v(t._s(t.min)+"–"+t._s(t.max))]:t.min?[t._v("≥ "+t._s(t.min))]:t.max?[t._v("≤ "+t._s(t.max))]:t._e()],2):t._e()])}),[],!1,null,null,null,null).exports;const Ne=ut({props:{disabled:Boolean,config:Object,fields:{type:[Array,Object],default:()=>[]},novalidate:{type:Boolean,default:!1},value:{type:Object,default:()=>({})}},emits:["focus","input","submit"],data:()=>({errors:{}}),methods:{focus(t){var e,i;null==(i=null==(e=this.$refs.fields)?void 0:e.focus)||i.call(e,t)},onFocus(t,e,i){this.$emit("focus",t,e,i)},onInput(t,e,i){this.$emit("input",t,e,i)},onInvalid(t){this.$emit("invalid",t)},onSubmit(){this.$emit("submit",this.value)},submit(){this.$refs.submitter.click()}}},(function(){var t=this,e=t._self._c;return e("form",{ref:"form",staticClass:"k-form",attrs:{method:"POST",autocomplete:"off",novalidate:""},on:{submit:function(e){return e.preventDefault(),t.onSubmit.apply(null,arguments)}}},[t._t("header"),t._t("default",(function(){return[e("k-fieldset",{ref:"fields",attrs:{disabled:t.disabled,fields:t.fields,novalidate:t.novalidate,value:t.value},on:{focus:t.onFocus,input:t.onInput,invalid:t.onInvalid,submit:t.onSubmit}})]})),t._t("footer"),e("input",{ref:"submitter",staticClass:"k-form-submitter",attrs:{type:"submit"}})],2)}),[],!1,null,null,null,null).exports;const ze=ut({props:{lock:[Boolean,Object]},data:()=>({isLoading:null,isLocking:null}),computed:{api(){return[this.$panel.view.path+"/lock",null,null,!0]},buttons(){return"unlock"===this.mode?[{icon:"check",text:this.$t("lock.isUnlocked"),click:()=>this.resolve()},{icon:"download",text:this.$t("download"),click:()=>this.download()}]:"lock"===this.mode?[{icon:this.lock.data.unlockable?"unlock":"loader",text:this.$t("lock.isLocked",{email:this.$esc(this.lock.data.email)}),title:this.$t("lock.unlock"),disabled:!this.lock.data.unlockable,click:()=>this.unlock()}]:"changes"===this.mode?[{icon:"undo",text:this.$t("revert"),click:()=>this.revert()},{icon:"check",text:this.$t("save"),click:()=>this.save()}]:[]},disabled(){return"unlock"!==this.mode&&("lock"===this.mode?!this.lock.data.unlockable:"changes"===this.mode&&this.isDisabled)},hasChanges(){return this.$store.getters["content/hasChanges"]()},isDisabled(){return!1===this.$store.state.content.status.enabled},isLocked(){return"lock"===this.lockState},isUnlocked(){return"unlock"===this.lockState},mode(){return null!==this.lockState?this.lockState:!0===this.hasChanges?"changes":null},lockState(){return this.supportsLocking&&this.lock?this.lock.state:null},supportsLocking(){return!1!==this.lock},theme(){return"lock"===this.mode?"negative":"unlock"===this.mode?"info":"changes"===this.mode?"notice":null}},watch:{hasChanges:{handler(t,e){!0===this.supportsLocking&&!1===this.isLocked&&!1===this.isUnlocked&&(!0===t?(this.locking(),this.isLocking=setInterval(this.locking,3e4)):e&&(clearInterval(this.isLocking),this.locking(!1)))},immediate:!0},isLocked(t){!1===t&&this.$events.emit("model.reload")}},mounted(){this.supportsLocking&&(this.isLoading=setInterval(this.check,1e4)),this.$events.on("view.save",this.save)},destroyed(){clearInterval(this.isLoading),clearInterval(this.isLocking),this.$events.off("view.save",this.save)},methods:{async check(){if(!1===this.$panel.isOffline){const{lock:t}=await this.$api.get(...this.api);Vue.set(this.$panel.view.props,"lock",t)}},download(){let t="";const e=this.$store.getters["content/changes"]();for(const n in e){const i=e[n];t+=n+": \n\n","object"==typeof i&&Object.keys(i).length||Array.isArray(i)&&i.length?t+=JSON.stringify(i,null,2):t+=i,t+="\n\n----\n\n"}let i=document.createElement("a");i.setAttribute("href","data:text/plain;charset=utf-8,"+encodeURIComponent(t)),i.setAttribute("download",this.$panel.view.path+".txt"),i.style.display="none",document.body.appendChild(i),i.click(),document.body.removeChild(i)},async locking(t=!0){if(!0!==this.$panel.isOffline)if(!0===t)try{await this.$api.patch(...this.api)}catch{clearInterval(this.isLocking),this.$store.dispatch("content/revert")}else clearInterval(this.isLocking),await this.$api.delete(...this.api)},async resolve(){await this.unlock(!1),this.$store.dispatch("content/revert")},revert(){this.$panel.dialog.open({component:"k-remove-dialog",props:{submitButton:{icon:"undo",text:this.$t("revert")},text:this.$t("revert.confirm")},on:{submit:()=>{this.$store.dispatch("content/revert"),this.$panel.dialog.close()}}})},async save(t){var e;null==(e=null==t?void 0:t.preventDefault)||e.call(t),await this.$store.dispatch("content/save"),this.$events.emit("model.update"),this.$panel.notification.success()},async unlock(t=!0){const e=[this.$panel.view.path+"/unlock",null,null,!0];!0!==t?(await this.$api.delete(...e),this.$reload({silent:!0})):this.$panel.dialog.open({component:"k-remove-dialog",props:{submitButton:{icon:"unlock",text:this.$t("lock.unlock")},text:this.$t("lock.unlock.submit",{email:this.$esc(this.lock.data.email)})},on:{submit:async()=>{await this.$api.patch(...e),this.$panel.dialog.close(),this.$reload({silent:!0})}}})}}},(function(){var t=this,e=t._self._c;return t.buttons.length>0?e("k-button-group",{staticClass:"k-form-buttons",attrs:{layout:"collapsed"}},t._l(t.buttons,(function(i){return e("k-button",t._b({key:i.icon,attrs:{size:"sm",variant:"filled",disabled:t.isDisabled,responsive:!0,theme:t.theme}},"k-button",i,!1))})),1):t._e()}),[],!1,null,null,null,null).exports,Fe={mixins:[W,G,X,Q,nt,at],props:{counter:[Boolean,Object],endpoints:Object,input:[String,Number],translate:Boolean,type:String}};const Ye=ut({mixins:[Fe],inheritAttrs:!1,emits:["blur","focus"]},(function(){var t=this,e=t._self._c;return e("div",{class:"k-field k-field-name-"+t.name,attrs:{"data-disabled":t.disabled,"data-translate":t.translate},on:{focusin:function(e){return t.$emit("focus",e)},focusout:function(e){return t.$emit("blur",e)}}},[t._t("header",(function(){return[e("header",{staticClass:"k-field-header"},[t._t("label",(function(){return[e("k-label",{attrs:{input:t.input,required:t.required,title:t.label,type:"field"}},[t._v(" "+t._s(t.label)+" ")])]})),t._t("options"),t._t("counter",(function(){return[t.counter?e("k-counter",t._b({staticClass:"k-field-counter",attrs:{required:t.required}},"k-counter",t.counter,!1)):t._e()]}))],2)]})),t._t("default"),t._t("footer",(function(){return[t.help||t.$slots.help?e("footer",{staticClass:"k-field-footer"},[t._t("help",(function(){return[t.help?e("k-text",{staticClass:"k-help k-field-help",attrs:{html:t.help}}):t._e()]}))],2):t._e()]}))],2)}),[],!1,null,null,null,null).exports;const Re=ut({props:{config:Object,disabled:Boolean,fields:{type:[Array,Object],default:()=>({})},novalidate:{type:Boolean,default:!1},value:{type:Object,default:()=>({})}},emits:["focus","input","invalid","submit"],data:()=>({errors:{}}),methods:{focus(t){if(t)return void(this.hasField(t)&&"function"==typeof this.$refs[t][0].focus&&this.$refs[t][0].focus());const e=Object.keys(this.$refs)[0];this.focus(e)},hasFieldType(t){return this.$helper.isComponent(`k-${t}-field`)},hasField(t){var e;return null==(e=this.$refs[t])?void 0:e[0]},onInvalid(t,e,i,n){this.errors[n]=e,this.$emit("invalid",this.errors)},onInput(t,e,i){const n=this.value;this.$set(n,i,t),this.$emit("input",n,e,i)},hasErrors(){return this.$helper.object.length(this.errors)>0}}},(function(){var t=this,e=t._self._c;return e("div",{staticClass:"k-fieldset"},[e("k-grid",{attrs:{variant:"fields"}},[t._l(t.fields,(function(i,n){return[t.$helper.field.isVisible(i,t.value)?e("k-column",{key:i.signature,attrs:{width:i.width}},[t.hasFieldType(i.type)?e("k-"+i.type+"-field",t._b({ref:n,refInFor:!0,tag:"component",attrs:{disabled:t.disabled||i.disabled,"form-data":t.value,name:n,novalidate:t.novalidate,value:t.value[n]},on:{input:function(e){return t.onInput(e,i,n)},focus:function(e){return t.$emit("focus",e,i,n)},invalid:(e,s)=>t.onInvalid(e,s,i,n),submit:function(e){return t.$emit("submit",e,i,n)}}},"component",i,!1)):e("k-box",{attrs:{theme:"negative"}},[e("k-text",{attrs:{size:"small"}},[t._v(" "+t._s(t.$t("error.field.type.missing",{name:n,type:i.type}))+" ")])],1)],1):t._e()]}))],2)],1)}),[],!1,null,null,null,null).exports,Ue={mixins:[U,K,W,Z],inheritAttrs:!1,props:{autofocus:Boolean,type:String,icon:[String,Boolean],novalidate:{type:Boolean,default:!1},value:{type:[String,Boolean,Number,Object,Array],default:null}}};const He=ut({mixins:[Ue],data(){return{isInvalid:this.invalid,listeners:{...this.$listeners,invalid:(t,e)=>{this.isInvalid=t,this.$emit("invalid",t,e)}}}},computed:{inputProps(){return{...this.$props,...this.$attrs}}},watch:{invalid(){this.isInvalid=this.invalid}},methods:{blur(t){(null==t?void 0:t.relatedTarget)&&!1===this.$el.contains(t.relatedTarget)&&this.trigger(null,"blur")},focus(t){this.trigger(t,"focus")},select(t){this.trigger(t,"select")},trigger(t,e){var i,n,s;if("INPUT"===(null==(i=null==t?void 0:t.target)?void 0:i.tagName)&&"function"==typeof(null==(n=null==t?void 0:t.target)?void 0:n[e]))return void t.target[e]();if("function"==typeof(null==(s=this.$refs.input)?void 0:s[e]))return void this.$refs.input[e]();const o=this.$el.querySelector("input, select, textarea");"function"==typeof(null==o?void 0:o[e])&&o[e]()}}},(function(){var t=this,e=t._self._c;return e("div",{staticClass:"k-input",attrs:{"data-disabled":t.disabled,"data-invalid":!t.novalidate&&t.isInvalid,"data-type":t.type}},[t.$slots.before||t.before?e("span",{staticClass:"k-input-description k-input-before",on:{click:t.focus}},[t._t("before",(function(){return[t._v(t._s(t.before))]}))],2):t._e(),e("span",{staticClass:"k-input-element",on:{click:function(e){return e.stopPropagation(),t.focus.apply(null,arguments)}}},[t._t("default",(function(){return[e("k-"+t.type+"-input",t._g(t._b({ref:"input",tag:"component",attrs:{value:t.value}},"component",t.inputProps,!1),t.listeners))]}))],2),t.$slots.after||t.after?e("span",{staticClass:"k-input-description k-input-after",on:{click:t.focus}},[t._t("after",(function(){return[t._v(t._s(t.after))]}))],2):t._e(),t.$slots.icon||t.icon?e("span",{staticClass:"k-input-icon",on:{click:t.focus}},[t._t("icon",(function(){return[e("k-icon",{attrs:{type:t.icon}})]}))],2):t._e()])}),[],!1,null,null,null,null).exports;const Ve=ut({props:{accept:{type:String,default:"*"},attributes:{type:Object},max:{type:Number},method:{type:String,default:"POST"},multiple:{type:Boolean,default:!0},url:{type:String}},emits:["success"],methods:{open(t){window.panel.deprecated(" will be removed in a future version. Use `$panel.upload.open()` instead."),this.$panel.upload.pick(this.params(t))},params(t){return{...this.$props,...t??{},on:{complete:(t,e)=>{this.$emit("success",t,e)}}}},select(t){this.$panel.upload.select(t.target.files)},drop(t,e){window.panel.deprecated(" will be removed in a future version. Use `$panel.upload.select()` instead."),this.$panel.upload.open(t,this.params(e))},upload(t,e){window.panel.deprecated(" will be removed in a future version. Use `$panel.upload.select()` instead."),this.$panel.upload.select(t,this.params(e)),this.$panel.upload.start()}},render:()=>""},null,null,!1,null,null,null,null).exports,Ke={props:{content:{default:()=>({}),type:[Array,Object]},fieldset:{default:()=>({}),type:Object}}};const We=ut({mixins:[Ke],inheritAttrs:!1,computed:{icon(){return this.fieldset.icon??"box"},label(){if(!this.fieldset.label||0===this.fieldset.label.length)return!1;if(this.fieldset.label===this.name)return!1;let t=this.$helper.string.template(this.fieldset.label,this.content);return"…"!==t&&(t=this.$helper.string.stripHTML(t),this.$helper.string.unescapeHTML(t))},name(){return this.fieldset.name??this.fieldset.label}}},(function(){var t=this,e=t._self._c;return e("div",{staticClass:"k-block-title"},[e("k-icon",{staticClass:"k-block-icon",attrs:{type:t.icon}}),t.name?e("span",{staticClass:"k-block-name"},[t._v(" "+t._s(t.name)+" ")]):t._e(),t.label?e("span",{staticClass:"k-block-label"},[t._v(" "+t._s(t.label)+" ")]):t._e()],1)}),[],!1,null,null,null,null).exports,Je={mixins:[Ke,W],props:{endpoints:{default:()=>({}),type:[Array,Object]},id:String}};const Ge=ut({mixins:[Je],inheritAttrs:!1,methods:{field(t,e=null){let i=null;for(const n of Object.values(this.fieldset.tabs??{}))n.fields[t]&&(i=n.fields[t]);return i??e},open(){this.$emit("open")},update(t){this.$emit("update",{...this.content,...t})}}},(function(){var t=this;return(0,t._self._c)("k-block-title",{attrs:{content:t.content,fieldset:t.fieldset},nativeOn:{dblclick:function(e){return t.$emit("open")}}})}),[],!1,null,null,null,null).exports,Xe={props:{isBatched:Boolean,isFull:Boolean,isHidden:Boolean,isMergable:Boolean}};const Ze=ut({mixins:[Xe],props:{isEditable:Boolean,isSplitable:Boolean},emits:["chooseToAppend","chooseToConvert","chooseToPrepend","copy","duplicate","hide","merge","open","paste","remove","removeSelected","show","split","sortDown","sortUp"],computed:{buttons(){return this.isBatched?[{icon:"template",title:this.$t("copy"),click:()=>this.$emit("copy")},{when:this.isMergable,icon:"merge",title:this.$t("merge"),click:()=>this.$emit("merge")},{icon:"trash",title:this.$t("remove"),click:()=>this.$emit("removeSelected")}]:[{when:this.isEditable,icon:"edit",title:this.$t("edit"),click:()=>this.$emit("open")},{icon:"add",title:this.$t("insert.after"),disabled:this.isFull,click:()=>this.$emit("chooseToAppend")},{icon:"trash",title:this.$t("delete"),click:()=>this.$emit("remove")},{icon:"sort",title:this.$t("sort.drag"),class:"k-sort-handle",key:t=>this.sort(t)},{icon:"dots",title:this.$t("more"),dropdown:[{icon:"angle-up",label:this.$t("insert.before"),disabled:this.isFull,click:()=>this.$emit("chooseToPrepend")},{icon:"angle-down",label:this.$t("insert.after"),disabled:this.isFull,click:()=>this.$emit("chooseToAppend")},"-",{when:this.isEditable,icon:"edit",label:this.$t("edit"),click:()=>this.$emit("open")},{icon:"refresh",label:this.$t("field.blocks.changeType"),click:()=>this.$emit("chooseToConvert")},{when:this.isSplitable,icon:"split",label:this.$t("split"),click:()=>this.$emit("split")},"-",{icon:"template",label:this.$t("copy"),click:()=>this.$emit("copy")},{icon:"download",label:this.$t("paste.after"),disabled:this.isFull,click:()=>this.$emit("paste")},"-",{icon:this.isHidden?"preview":"hidden",label:this.isHidden?this.$t("show"):this.$t("hide"),click:()=>this.$emit(this.isHidden?"show":"hide")},{icon:"copy",label:this.$t("duplicate"),click:()=>this.$emit("duplicate")},"-",{icon:"trash",label:this.$t("delete"),click:()=>this.$emit("remove")}]}]}},methods:{open(){this.$refs.options.open()},sort(t){switch(t.preventDefault(),t.key){case"ArrowUp":this.$emit("sortUp");break;case"ArrowDown":this.$emit("sortDown")}}}},(function(){return(0,this._self._c)("k-toolbar",{staticClass:"k-block-options",attrs:{buttons:this.buttons},nativeOn:{mousedown:function(t){t.preventDefault()}}})}),[],!1,null,null,null,null).exports;const Qe=ut({mixins:[Je,Xe],inheritAttrs:!1,props:{attrs:{default:()=>({}),type:[Array,Object]},isLastSelected:Boolean,isSelected:Boolean,name:String,next:Object,prev:Object,type:String},emits:["append","chooseToAppend","chooseToConvert","chooseToPrepend","close","copy","duplicate","focus","hide","merge","open","paste","prepend","remove","selectDown","selectUp","show","sortDown","sortUp","split","submit","update"],computed:{className(){let t=["k-block-type-"+this.type];return this.fieldset.preview&&this.fieldset.preview!==this.type&&t.push("k-block-type-"+this.fieldset.preview),!1===this.wysiwyg&&t.push("k-block-type-default"),t},containerType(){const t=this.fieldset.preview;return!1!==t&&(t&&this.$helper.isComponent("k-block-type-"+t)?t:!!this.$helper.isComponent("k-block-type-"+this.type)&&this.type)},customComponent(){return this.wysiwyg?this.wysiwygComponent:"k-block-type-default"},isDisabled(){return!0===this.disabled||!0===this.fieldset.disabled},isEditable(){return!1!==this.fieldset.editable},listeners(){return{append:t=>this.$emit("append",t),chooseToAppend:t=>this.$emit("chooseToAppend",t),chooseToConvert:t=>this.$emit("chooseToConvert",t),chooseToPrepend:t=>this.$emit("chooseToPrepend",t),close:()=>this.$emit("close"),copy:()=>this.$emit("copy"),duplicate:()=>this.$emit("duplicate"),focus:()=>this.$emit("focus"),hide:()=>this.$emit("hide"),merge:()=>this.$emit("merge"),open:t=>this.open(t),paste:()=>this.$emit("paste"),prepend:t=>this.$emit("prepend",t),remove:()=>this.remove(),removeSelected:()=>this.$emit("removeSelected"),show:()=>this.$emit("show"),sortDown:()=>this.$emit("sortDown"),sortUp:()=>this.$emit("sortUp"),split:t=>this.$emit("split",t),update:t=>this.$emit("update",t)}},tabs(){const t=this.fieldset.tabs??{};for(const[e,i]of Object.entries(t))for(const[n]of Object.entries(i.fields??{}))t[e].fields[n].section=this.name,t[e].fields[n].endpoints={field:this.endpoints.field+"/fieldsets/"+this.type+"/fields/"+n,section:this.endpoints.section,model:this.endpoints.model};return t},wysiwyg(){return!1!==this.wysiwygComponent},wysiwygComponent(){return!!this.containerType&&"k-block-type-"+this.containerType}},methods:{backspace(t){if(t.target.matches("[contenteditable], input, textarea"))return!1;t.preventDefault(),this.remove()},close(){this.$panel.drawer.close(this.id)},focus(){var t,e;"function"==typeof(null==(t=this.$refs.editor)?void 0:t.focus)?this.$refs.editor.focus():null==(e=this.$refs.container)||e.focus()},goTo(t){var e;t&&(null==(e=t.$refs.container)||e.focus(),t.open(null,!0))},isSplitable(){var t;return!0!==this.isFull&&(!!this.$refs.editor&&((this.$refs.editor.isSplitable??!0)&&"function"==typeof(null==(t=this.$refs.editor)?void 0:t.split)))},onClose(){this.$emit("close"),this.focus()},onFocus(t){this.disabled||this.$emit("focus",t)},onFocusIn(t){var e,i;this.disabled||(null==(i=null==(e=this.$refs.options)?void 0:e.$el)?void 0:i.contains(t.target))||this.$emit("focus",t)},onInput(t){this.$emit("update",t)},open(t,e=!1){!this.isEditable||this.isBatched||this.isDisabled||(this.$panel.drawer.open({component:"k-block-drawer",id:this.id,tab:t,on:{close:this.onClose,input:this.onInput,next:()=>this.goTo(this.next),prev:()=>this.goTo(this.prev),remove:this.remove,show:this.show,submit:this.submit},props:{hidden:this.isHidden,icon:this.fieldset.icon??"box",next:this.next,prev:this.prev,tabs:this.tabs,title:this.fieldset.name,value:this.content},replace:e}),this.$emit("open"))},remove(){if(this.isBatched)return this.$emit("removeSelected");this.$panel.dialog.open({component:"k-remove-dialog",props:{text:this.$t("field.blocks.delete.confirm")},on:{submit:()=>{this.$panel.dialog.close(),this.close(),this.$emit("remove",this.id)}}})},show(){this.$emit("show")},submit(){this.close(),this.$emit("submit")}}},(function(){var t=this,e=t._self._c;return e("div",{ref:"container",staticClass:"k-block-container",class:["k-block-container-fieldset-"+t.type,t.containerType?"k-block-container-type-"+t.containerType:""],attrs:{"data-batched":t.isBatched,"data-disabled":t.isDisabled,"data-hidden":t.isHidden,"data-id":t.id,"data-last-selected":t.isLastSelected,"data-selected":t.isSelected,"data-translate":t.fieldset.translate,tabindex:t.isDisabled?null:0},on:{keydown:[function(e){return!e.type.indexOf("key")&&t._k(e.keyCode,"j",void 0,e.key,void 0)?null:e.ctrlKey?(e.preventDefault(),e.stopPropagation(),t.$emit("merge")):null},function(e){return!e.type.indexOf("key")&&t._k(e.keyCode,"down",40,e.key,["Down","ArrowDown"])?null:e.ctrlKey&&e.altKey?(e.preventDefault(),e.stopPropagation(),t.$emit("selectDown")):null},function(e){return!e.type.indexOf("key")&&t._k(e.keyCode,"up",38,e.key,["Up","ArrowUp"])?null:e.ctrlKey&&e.altKey?(e.preventDefault(),e.stopPropagation(),t.$emit("selectUp")):null},function(e){return!e.type.indexOf("key")&&t._k(e.keyCode,"down",40,e.key,["Down","ArrowDown"])?null:e.ctrlKey&&e.shiftKey?(e.preventDefault(),e.stopPropagation(),t.$emit("sortDown")):null},function(e){return!e.type.indexOf("key")&&t._k(e.keyCode,"up",38,e.key,["Up","ArrowUp"])?null:e.ctrlKey&&e.shiftKey?(e.preventDefault(),e.stopPropagation(),t.$emit("sortUp")):null},function(e){return!e.type.indexOf("key")&&t._k(e.keyCode,"backspace",void 0,e.key,void 0)?null:e.ctrlKey?(e.stopPropagation(),t.backspace.apply(null,arguments)):null}],focus:function(e){return e.stopPropagation(),t.onFocus.apply(null,arguments)},focusin:function(e){return e.stopPropagation(),t.onFocusIn.apply(null,arguments)}}},[e("div",{staticClass:"k-block",class:t.className,attrs:{"data-disabled":t.isDisabled}},[e(t.customComponent,t._g(t._b({ref:"editor",tag:"component",attrs:{tabs:t.tabs}},"component",t.$props,!1),t.listeners))],1),t.isDisabled?t._e():e("k-block-options",t._g(t._b({ref:"options"},"k-block-options",{isBatched:t.isBatched,isEditable:t.isEditable,isFull:t.isFull,isHidden:t.isHidden,isMergable:t.isMergable,isSplitable:t.isSplitable()},!1),{...t.listeners,split:()=>t.$refs.editor.split(),open:()=>{"function"==typeof t.$refs.editor.open?t.$refs.editor.open():t.open()}}))],1)}),[],!1,null,null,null,null).exports,ti={mixins:[V,W,X],props:{empty:String,endpoints:Object,fieldsets:Object,fieldsetGroups:Object,group:String,max:{type:Number,default:null},value:{type:Array,default:()=>[]}},emits:["input"]};const ei=ut({mixins:[ti],inheritAttrs:!1,data(){return{blocks:this.value??[],isEditing:!1,isMultiSelectKey:!1,selected:[]}},computed:{draggableOptions(){return{id:this.id,handle:".k-sort-handle",list:this.blocks,move:this.move,delay:10,data:{fieldsets:this.fieldsets,isFull:this.isFull},options:{group:this.group}}},hasFieldsets(){return this.$helper.object.length(this.fieldsets)>0},isEmpty(){return 0===this.blocks.length},isFull(){return null!==this.max&&this.blocks.length>=this.max},isMergable(){if(this.selected.length<2)return!1;const t=this.selected.map((t=>this.find(t)));return!(new Set(t.map((t=>t.type))).size>1)&&"function"==typeof this.ref(t[0]).$refs.editor.merge}},watch:{value(){this.blocks=this.value}},mounted(){!0===this.$props.autofocus&&setTimeout(this.focus,100),this.$events.on("blur",this.onBlur),this.$events.on("click",this.onClickGlobal),this.$events.on("copy",this.onCopy),this.$events.on("keydown",this.onKey),this.$events.on("keyup",this.onKey),this.$events.on("paste",this.onPaste)},destroyed(){this.$events.off("blur",this.onBlur),this.$events.off("click",this.onClickGlobal),this.$events.off("copy",this.onCopy),this.$events.off("keydown",this.onKey),this.$events.off("keyup",this.onKey),this.$events.off("paste",this.onPaste)},methods:{async add(t="text",e){const i=await this.$api.get(this.endpoints.field+"/fieldsets/"+t);this.blocks.splice(e,0,i),this.save(),await this.$nextTick(),this.focusOrOpen(i)},choose(t){if(1===this.$helper.object.length(this.fieldsets))return this.add(Object.values(this.fieldsets)[0].type,t);this.$panel.dialog.open({component:"k-block-selector",props:{fieldsetGroups:this.fieldsetGroups,fieldsets:this.fieldsets},on:{submit:e=>{this.add(e,t),this.$panel.dialog.close()},paste:e=>{this.paste(e,t)}}})},chooseToConvert(t){this.$panel.dialog.open({component:"k-block-selector",props:{disabledFieldsets:[t.type],fieldsetGroups:this.fieldsetGroups,fieldsets:this.fieldsets,headline:this.$t("field.blocks.changeType")},on:{submit:e=>{this.convert(e,t),this.$panel.dialog.close()},paste:this.paste}})},copy(t){if(0===this.blocks.length)return!1;if(0===this.selected.length)return!1;let e=[];for(const i of this.blocks)this.selected.includes(i.id)&&e.push(i);if(0===e.length)return!1;this.$helper.clipboard.write(e,t),this.selected=e.map((t=>t.id)),this.$panel.notification.success({message:this.$t("copy.success",{count:e.length}),icon:"template"})},copyAll(){this.selectAll(),this.copy(),this.deselectAll()},async convert(t,e){var i;const n=this.findIndex(e.id);if(-1===n)return!1;const s=t=>{let e={};for(const i of Object.values((null==t?void 0:t.tabs)??{}))e={...e,...i.fields};return e},o=this.blocks[n],l=await this.$api.get(this.endpoints.field+"/fieldsets/"+t),a=this.fieldsets[o.type],r=this.fieldsets[t];if(!r)return!1;let u=l.content;const c=s(r),d=s(a);for(const[p,h]of Object.entries(c)){const t=d[p];(null==t?void 0:t.type)===h.type&&(null==(i=null==o?void 0:o.content)?void 0:i[p])&&(u[p]=o.content[p])}this.blocks[n]={...l,id:o.id,content:u},this.save()},deselect(t){const e=this.selected.findIndex((e=>e===t.id));-1!==e&&this.selected.splice(e,1)},deselectAll(){this.selected=[]},async duplicate(t,e){const i={...structuredClone(t),id:this.$helper.uuid()};this.blocks.splice(e+1,0,i),this.save()},fieldset(t){return this.fieldsets[t.type]??{icon:"box",name:t.type,tabs:{content:{fields:{}}},type:t.type}},find(t){return this.blocks.find((e=>e.id===t))},findIndex(t){return this.blocks.findIndex((e=>e.id===t))},focus(t){const e=this.ref(t);this.selected=[(null==t?void 0:t.id)??this.blocks[0]],null==e||e.focus(),null==e||e.$el.scrollIntoView({block:"nearest"})},focusOrOpen(t){this.fieldsets[t.type].wysiwyg?this.focus(t):this.open(t)},hide(t){Vue.set(t,"isHidden",!0),this.save()},isInputEvent(){const t=document.querySelector(":focus");return null==t?void 0:t.matches("input, textarea, [contenteditable], .k-writer")},isLastSelected(t){const[e]=this.selected.slice(-1);return e&&t.id===e},isOnlyInstance:()=>1===document.querySelectorAll(".k-blocks").length,isSelected(t){return this.selected.includes(t.id)},async merge(){if(this.isMergable){const t=this.selected.map((t=>this.find(t)));this.ref(t[0]).$refs.editor.merge(t);for(const e of t.slice(1))this.remove(e);await this.$nextTick(),this.focus(t[0])}},move(t){if(t.from!==t.to){const e=t.draggedContext.element,i=t.relatedContext.component.componentData||t.relatedContext.component.$parent.componentData;if(!1===Object.keys(i.fieldsets).includes(e.type))return!1;if(!0===i.isFull)return!1}return!0},onBlur(){0===this.selected.length&&(this.isMultiSelectKey=!1)},onClickBlock(t,e){e&&this.isMultiSelectKey&&this.onKey(e),this.isMultiSelectKey&&(e.preventDefault(),e.stopPropagation(),this.isSelected(t)?this.deselect(t):this.select(t))},onClickGlobal(t){var e;if("function"==typeof t.target.closest&&(t.target.closest(".k-dialog")||t.target.closest(".k-drawer")))return;const i=document.querySelector(".k-overlay:last-of-type");!1!==this.$el.contains(t.target)||!1!==(null==i?void 0:i.contains(t.target))?i&&!1===(null==(e=this.$el.closest(".k-layout-column"))?void 0:e.contains(t.target))&&this.deselectAll():this.deselectAll()},onCopy(t){return!1!==this.$el.contains(t.target)&&!0!==this.isEditing&&!0!==this.$panel.dialog.isOpen&&!0!==this.isInputEvent(t)&&this.copy(t)},onFocus(t){!1===this.isMultiSelectKey&&(this.selected=[t.id])},async onKey(t){if(this.isMultiSelectKey=t.metaKey||t.ctrlKey||t.altKey,"Escape"===t.code&&this.selected.length>1){const t=this.find(this.selected[0]);await this.$nextTick(),this.focus(t)}},onPaste(t){return!0!==this.isInputEvent(t)&&(!0!==this.isEditing&&!0!==this.$panel.dialog.isOpen&&((0!==this.selected.length||!1!==this.$el.contains(t.target))&&this.paste(t)))},open(t){var e;null==(e=this.$refs["block-"+t.id])||e[0].open()},async paste(t,e){const i=this.$helper.clipboard.read(t);let n=await this.$api.post(this.endpoints.field+"/paste",{html:i});if(void 0===e){let t=this.selected[this.selected.length-1];-1===(e=this.findIndex(t))&&(e=this.blocks.length),e++}if(this.max){const t=this.max-this.blocks.length;n=n.slice(0,t)}this.blocks.splice(e,0,...n),this.save(),this.$panel.notification.success({message:this.$t("paste.success",{count:n.length}),icon:"download"})},pasteboard(){this.$panel.dialog.open({component:"k-block-pasteboard",on:{paste:this.paste}})},prevNext(t){var e;if(this.blocks[t])return null==(e=this.$refs["block-"+this.blocks[t].id])?void 0:e[0]},ref(t){var e,i;return null==(i=this.$refs["block-"+((null==t?void 0:t.id)??(null==(e=this.blocks[0])?void 0:e.id))])?void 0:i[0]},remove(t){const e=this.findIndex(t.id);-1!==e&&(this.deselect(t),this.$delete(this.blocks,e),this.save())},removeAll(){this.$panel.dialog.open({component:"k-remove-dialog",props:{text:this.$t("field.blocks.delete.confirm.all"),submitButton:this.$t("delete.all")},on:{submit:()=>{this.selected=[],this.blocks=[],this.save(),this.$panel.dialog.close()}}})},removeSelected(){this.$panel.dialog.open({component:"k-remove-dialog",props:{text:this.$t("field.blocks.delete.confirm.selected")},on:{submit:()=>{for(const t of this.selected){const e=this.findIndex(t);-1!==e&&this.$delete(this.blocks,e)}this.deselectAll(),this.save(),this.$panel.dialog.close()}}})},save(){this.$emit("input",this.blocks)},select(t){!1===this.isSelected(t)&&this.selected.push(t.id)},selectDown(){const t=this.selected[this.selected.length-1],e=this.findIndex(t)+1;e=0&&this.select(this.blocks[e])},selectAll(){this.selected=Object.values(this.blocks).map((t=>t.id))},show(t){Vue.set(t,"isHidden",!1),this.save()},async sort(t,e,i){if(i<0)return;let n=structuredClone(this.blocks);n.splice(e,1),n.splice(i,0,t),this.blocks=n,this.save(),await this.$nextTick(),this.focus(t)},async split(t,e,i){const n=structuredClone(t);n.content={...n.content,...i[0]};const s=await this.$api.get(this.endpoints.field+"/fieldsets/"+t.type);s.content={...s.content,...n.content,...i[1]},this.blocks.splice(e,1,n,s),this.save(),await this.$nextTick(),this.focus(s)},update(t,e){const i=this.findIndex(t.id);if(-1!==i)for(const n in e)Vue.set(this.blocks[i].content,n,e[n]);this.save()}}},(function(){var t=this,e=t._self._c;return e("div",{staticClass:"k-blocks",attrs:{"data-disabled":t.disabled,"data-empty":0===t.blocks.length}},[t.hasFieldsets?[e("k-draggable",t._b({staticClass:"k-blocks-list",attrs:{"data-multi-select-key":t.isMultiSelectKey},on:{sort:t.save},scopedSlots:t._u([0===t.blocks.length?{key:"footer",fn:function(){return[e("k-empty",{staticClass:"k-blocks-empty",attrs:{icon:"box"},on:{click:function(e){return t.choose(t.blocks.length)}}},[t._v(" "+t._s(t.empty??t.$t("field.blocks.empty"))+" ")])]},proxy:!0}:null],null,!0)},"k-draggable",t.draggableOptions,!1),t._l(t.blocks,(function(i,n){return e("k-block",t._b({key:i.id,ref:"block-"+i.id,refInFor:!0,on:{append:function(e){return t.add(e,n+1)},chooseToAppend:function(e){return t.choose(n+1)},chooseToConvert:function(e){return t.chooseToConvert(i)},chooseToPrepend:function(e){return t.choose(n)},close:function(e){t.isEditing=!1},copy:function(e){return t.copy()},duplicate:function(e){return t.duplicate(i,n)},focus:function(e){return t.onFocus(i)},hide:function(e){return t.hide(i)},merge:function(e){return t.merge()},open:function(e){t.isEditing=!0},paste:function(e){return t.pasteboard()},prepend:function(e){return t.add(e,n)},remove:function(e){return t.remove(i)},removeSelected:t.removeSelected,show:function(e){return t.show(i)},selectDown:t.selectDown,selectUp:t.selectUp,sortDown:function(e){return t.sort(i,n,n+1)},sortUp:function(e){return t.sort(i,n,n-1)},split:function(e){return t.split(i,n,e)},update:function(e){return t.update(i,e)}},nativeOn:{click:function(e){return t.onClickBlock(i,e)}}},"k-block",{...i,disabled:t.disabled,endpoints:t.endpoints,fieldset:t.fieldset(i),isBatched:t.isSelected(i)&&t.selected.length>1,isFull:t.isFull,isHidden:!0===i.isHidden,isLastSelected:t.isLastSelected(i),isMergable:t.isMergable,isSelected:t.isSelected(i),next:t.prevNext(n+1),prev:t.prevNext(n-1)},!1))})),1)]:e("k-empty",{attrs:{icon:"box"}},[t._v(" "+t._s(t.$t("field.blocks.fieldsets.empty"))+" ")])],2)}),[],!1,null,null,null,null).exports;const ii=ut({inheritAttrs:!1,emits:["close","paste","submit"],computed:{shortcut(){return this.$helper.keyboard.metaKey()+"+v"}},methods:{paste(t){this.$emit("close"),this.$emit("paste",t)}}},(function(){var t=this,e=t._self._c;return e("k-dialog",{ref:"dialog",staticClass:"k-block-importer",attrs:{"cancel-button":!1,"submit-button":!1,visible:!0,size:"large"},on:{cancel:function(e){return t.$emit("cancel")},submit:function(e){return t.$emit("submit")}}},[e("label",{attrs:{for:"pasteboard"},domProps:{innerHTML:t._s(t.$t("field.blocks.fieldsets.paste",{shortcut:t.shortcut}))}}),e("textarea",{attrs:{id:"pasteboard"},on:{paste:function(e){return e.preventDefault(),t.paste.apply(null,arguments)}}})])}),[],!1,null,null,null,null).exports;const ni=ut({inheritAttrs:!1,props:{disabledFieldsets:{default:()=>[],type:Array},fieldsets:{type:Object},fieldsetGroups:{type:Object},headline:{type:String},size:{type:String,default:"medium"},value:{default:null,type:String}},emits:["cancel","input","paste","submit"],data:()=>({selected:null}),computed:{groups(){const t={};let e=0;const i=this.fieldsetGroups??{blocks:{label:this.$t("field.blocks.fieldsets.label"),sets:Object.keys(this.fieldsets)}};for(const n in i){const s=i[n];s.open=!1!==s.open,s.fieldsets=s.sets.filter((t=>this.fieldsets[t])).map((t=>(e++,{...this.fieldsets[t],index:e}))),0!==s.fieldsets.length&&(t[n]=s)}return t},shortcut(){return this.$helper.keyboard.metaKey()+"+v"}},mounted(){this.$events.on("paste",this.paste)},destroyed(){this.$events.off("paste",this.paste)},methods:{paste(t){this.$emit("paste",t),this.close()}}},(function(){var t=this,e=t._self._c;return e("k-dialog",{staticClass:"k-block-selector",attrs:{"cancel-button":!1,size:t.size,"submit-button":!1,visible:!0},on:{cancel:function(e){return t.$emit("cancel")},submit:function(e){return t.$emit("submit",t.value)}}},[t.headline?e("k-headline",[t._v(" "+t._s(t.headline)+" ")]):t._e(),t._l(t.groups,(function(i,n){return e("details",{key:n,attrs:{open:i.open}},[e("summary",[t._v(t._s(i.label))]),e("k-navigate",{staticClass:"k-block-types"},t._l(i.fieldsets,(function(i){return e("k-button",{key:i.name,attrs:{disabled:t.disabledFieldsets.includes(i.type),icon:i.icon??"box",text:i.name,size:"lg"},on:{click:function(e){return t.$emit("submit",i.type)}},nativeOn:{focus:function(e){return t.$emit("input",i.type)}}})})),1)],1)})),e("p",{staticClass:"k-clipboard-hint",domProps:{innerHTML:t._s(t.$t("field.blocks.fieldsets.paste",{shortcut:t.shortcut}))}})],2)}),[],!1,null,null,null,null).exports;const si=ut({inheritAttrs:!1,props:{caption:String,captionMarks:{default:!0,type:[Boolean,Array]},disabled:Boolean,isEmpty:Boolean,emptyIcon:String,emptyText:String},emits:["open","update"]},(function(){var t=this,e=t._self._c;return e("figure",{staticClass:"k-block-figure"},[t.isEmpty?e("k-button",{staticClass:"k-block-figure-empty",attrs:{disabled:t.disabled,icon:t.emptyIcon,text:t.emptyText},on:{click:function(e){return t.$emit("open")}}}):e("span",{staticClass:"k-block-figure-container",attrs:{"data-disabled":t.disabled},on:{dblclick:function(e){return t.$emit("open")}}},[t._t("default")],2),t.caption?e("figcaption",[e("k-writer",{attrs:{disabled:t.disabled,inline:!0,marks:t.captionMarks,value:t.caption},on:{input:function(e){return t.$emit("update",{caption:e})}}})],1):t._e()],1)}),[],!1,null,null,null,null).exports;const oi=ut({extends:Ge,computed:{placeholder(){return this.field("code",{}).placeholder},languages(){return this.field("language",{options:[]}).options}},methods:{focus(){this.$refs.code.focus()}}},(function(){var t=this,e=t._self._c;return e("div",{staticClass:"k-block-type-code-editor"},[e("k-input",{ref:"code",attrs:{buttons:!1,disabled:t.disabled,placeholder:t.placeholder,spellcheck:!1,value:t.content.code,font:"monospace",type:"textarea"},on:{input:function(e){return t.update({code:e})}}}),t.languages.length?e("div",{staticClass:"k-block-type-code-editor-language"},[e("k-input",{ref:"language",attrs:{disabled:t.disabled,empty:!1,options:t.languages,value:t.content.language,icon:"code",type:"select"},on:{input:function(e){return t.update({language:e})}}})],1):t._e()],1)}),[],!1,null,null,null,null).exports;const li=ut({extends:Ge,props:{endpoints:Object,tabs:Object},data(){return{collapsed:this.state(),tab:Object.keys(this.tabs)[0]}},computed:{fields(){var t;return null==(t=this.tabs[this.tab])?void 0:t.fields},values(){return Object.assign({},this.content)}},methods:{open(){this.$emit("open",this.tab)},state(t){const e=`kirby.fieldsBlock.${this.endpoints.field}.${this.id}`;if(void 0===t)return JSON.parse(sessionStorage.getItem(e));sessionStorage.setItem(e,t)},toggle(){this.collapsed=!this.collapsed,this.state(this.collapsed)}}},(function(){var t=this,e=t._self._c;return e("div",{attrs:{"data-collapsed":t.collapsed},on:{dblclick:function(e){!t.fieldset.wysiwyg&&t.$emit("open")}}},[e("header",{staticClass:"k-block-type-fields-header"},[e("k-block-title",{attrs:{content:t.values,fieldset:t.fieldset},nativeOn:{click:function(e){return t.toggle.apply(null,arguments)}}}),t.collapsed?t._e():e("k-drawer-tabs",{attrs:{tab:t.tab,tabs:t.fieldset.tabs},on:{open:function(e){t.tab=e}}})],1),t.collapsed?t._e():e("k-form",{ref:"form",staticClass:"k-block-type-fields-form",attrs:{autofocus:!0,disabled:t.disabled||!t.fieldset.wysiwyg,fields:t.fields,value:t.values},on:{input:function(e){return t.$emit("update",e)}}})],1)}),[],!1,null,null,null,null).exports;const ai=ut({extends:Ge,computed:{captionMarks(){return this.field("caption",{marks:!0}).marks},crop(){return this.content.crop},ratio(){return this.content.ratio}}},(function(){var t,e=this,i=e._self._c;return i("figure",[i("ul",{on:{dblclick:e.open}},[(null==(t=e.content.images)?void 0:t.length)?e._l(e.content.images,(function(t){return i("li",{key:t.id},[i("k-image-frame",{attrs:{ratio:e.ratio,cover:e.crop,src:t.url,srcset:t.image.srcset,alt:t.alt}})],1)})):e._l(3,(function(t){return i("li",{key:t,staticClass:"k-block-type-gallery-placeholder"},[i("k-image-frame",{attrs:{ratio:e.ratio}})],1)}))],2),e.content.caption?i("figcaption",[i("k-writer",{attrs:{disabled:e.disabled,inline:!0,marks:e.captionMarks,value:e.content.caption},on:{input:function(t){return e.$emit("update",{caption:t})}}})],1):e._e()])}),[],!1,null,null,null,null).exports;const ri=ut({extends:Ge,inheritAttrs:!1,emits:["append","open","split","update"],computed:{isSplitable(){return this.content.text.length>0&&!1===this.$refs.input.isCursorAtStart&&!1===this.$refs.input.isCursorAtEnd},keys(){return{Enter:()=>!0===this.$refs.input.isCursorAtEnd?this.$emit("append","text"):this.split(),"Mod-Enter":this.split}},levels(){return this.field("level",{options:[]}).options},textField(){return this.field("text",{marks:!0})}},methods:{focus(){this.$refs.input.focus()},merge(t){this.update({text:t.map((t=>t.content.text)).join(" ")})},split(){var t,e;const i=null==(e=(t=this.$refs.input).getSplitContent)?void 0:e.call(t);i&&this.$emit("split",[{text:i[0]},{level:"h"+Math.min(parseInt(this.content.level.slice(1))+1,6),text:i[1]}])}}},(function(){var t=this,e=t._self._c;return e("div",{staticClass:"k-block-type-heading-input",attrs:{"data-level":t.content.level}},[e("k-writer",t._b({ref:"input",attrs:{disabled:t.disabled,inline:!0,keys:t.keys,value:t.content.text},on:{input:function(e){return t.update({text:e})}}},"k-writer",t.textField,!1)),t.levels.length>1?e("k-input",{ref:"level",staticClass:"k-block-type-heading-level",attrs:{disabled:t.disabled,empty:!1,options:t.levels,value:t.content.level,type:"select"},on:{input:function(e){return t.update({level:e})}}}):t._e()],1)}),[],!1,null,null,null,null).exports;const ui=ut({extends:Ge,computed:{captionMarks(){return this.field("caption",{marks:!0}).marks},crop(){return this.content.crop??!1},src(){var t,e;return"web"===this.content.location?this.content.src:!!(null==(e=null==(t=this.content.image)?void 0:t[0])?void 0:e.url)&&this.content.image[0].url},ratio(){return this.content.ratio??!1}}},(function(){var t=this,e=t._self._c;return e("k-block-figure",{attrs:{caption:t.content.caption,"caption-marks":t.captionMarks,"empty-text":t.$t("field.blocks.image.placeholder")+" …",disabled:t.disabled,"is-empty":!t.src,"empty-icon":"image"},on:{open:t.open,update:t.update}},[t.src?[t.ratio?e("k-image-frame",{attrs:{ratio:t.ratio,cover:t.crop,alt:t.content.alt,src:t.src}}):e("img",{staticClass:"k-block-type-image-auto",attrs:{alt:t.content.alt,src:t.src}})]:t._e()],2)}),[],!1,null,null,null,null).exports;const ci=ut({},(function(){return this._self._c,this._m(0)}),[function(){var t=this._self._c;return t("div",[t("hr")])}],!1,null,null,null,null).exports;const di=ut({extends:Ge,emits:["open","split","update"],computed:{isSplitable(){return this.content.text.length>0&&!1===this.input().isCursorAtStart&&!1===this.input().isCursorAtEnd},keys(){return{"Mod-Enter":this.split}},marks(){return this.field("text",{}).marks}},methods:{focus(){this.$refs.input.focus()},input(){return this.$refs.input.$refs.input.$refs.input},merge(t){this.update({text:t.map((t=>t.content.text)).join("").replaceAll("

    ","")})},split(){var t,e;const i=null==(e=(t=this.input()).getSplitContent)?void 0:e.call(t);i&&this.$emit("split",[{text:i[0].replace(/(
  • <\/p><\/li><\/ul>)$/,"

")},{text:i[1].replace(/^(
  • <\/p><\/li>)/,"

      ")}])}}},(function(){var t=this;return(0,t._self._c)("k-input",{ref:"input",staticClass:"k-block-type-list-input",attrs:{disabled:t.disabled,keys:t.keys,marks:t.marks,value:t.content.text,type:"list"},on:{input:function(e){return t.update({text:e})}}})}),[],!1,null,null,null,null).exports;const pi=ut({extends:Ge,computed:{placeholder(){return this.field("text",{}).placeholder}},methods:{focus(){this.$refs.input.focus()}}},(function(){var t=this;return(0,t._self._c)("k-input",{ref:"input",staticClass:"k-block-type-markdown-input",attrs:{buttons:!1,disabled:t.disabled,placeholder:t.placeholder,spellcheck:!1,value:t.content.text,font:"monospace",type:"textarea"},on:{input:function(e){return t.update({text:e})}}})}),[],!1,null,null,null,null).exports;const hi=ut({extends:Ge,computed:{citationField(){return this.field("citation",{})},textField(){return this.field("text",{})}},methods:{focus(){this.$refs.text.focus()}}},(function(){var t=this,e=t._self._c;return e("div",{staticClass:"k-block-type-quote-editor"},[e("k-writer",{ref:"text",staticClass:"k-block-type-quote-text",attrs:{disabled:t.disabled,inline:t.textField.inline??!1,marks:t.textField.marks,placeholder:t.textField.placeholder,value:t.content.text},on:{input:function(e){return t.update({text:e})}}}),e("k-writer",{ref:"citation",staticClass:"k-block-type-quote-citation",attrs:{disabled:t.disabled,inline:t.citationField.inline??!0,marks:t.citationField.marks,placeholder:t.citationField.placeholder,value:t.content.citation},on:{input:function(e){return t.update({citation:e})}}})],1)}),[],!1,null,null,null,null).exports;const mi=ut({extends:Ge,inheritAttrs:!1,computed:{columns(){return this.table.columns??this.fields},fields(){return this.table.fields??{}},rows(){return this.content.rows??[]},table(){let t=null;for(const e of Object.values(this.fieldset.tabs??{}))e.fields.rows&&(t=e.fields.rows);return t??{}}}},(function(){var t=this;return(0,t._self._c)("k-table",{staticClass:"k-block-type-table-preview",attrs:{columns:t.columns,empty:t.$t("field.structure.empty"),rows:t.rows},nativeOn:{dblclick:function(e){return t.open.apply(null,arguments)}}})}),[],!1,null,null,null,null).exports;const fi=ut({extends:Ge,emits:["open","split","update"],computed:{component(){const t="k-"+this.textField.type+"-input";return this.$helper.isComponent(t)?t:"k-writer-input"},isSplitable(){return this.content.text.length>0&&!1===this.input().isCursorAtStart&&!1===this.input().isCursorAtEnd},keys(){const t={"Mod-Enter":this.split};return!0===this.textField.inline&&(t.Enter=this.split),t},textField(){return this.field("text",{})}},methods:{focus(){this.$refs.input.focus()},input(){return this.$refs.input.$refs.input},merge(t){this.update({text:t.map((t=>t.content.text)).join(this.textField.inline?" ":"")})},split(){var t,e;const i=null==(e=(t=this.input()).getSplitContent)?void 0:e.call(t);i&&("writer"===this.textField.type&&(i[0]=i[0].replace(/(

      <\/p>)$/,""),i[1]=i[1].replace(/^(

      <\/p>)/,"")),this.$emit("split",i.map((t=>({text:t})))))}}},(function(){var t=this;return(0,t._self._c)(t.component,t._b({ref:"input",tag:"component",staticClass:"k-block-type-text-input",attrs:{disabled:t.disabled,keys:t.keys,value:t.content.text},on:{input:function(e){return t.update({text:e})}}},"component",t.textField,!1))}),[],!1,null,null,null,null).exports;const gi=ut({extends:Ge,computed:{captionMarks(){return this.field("caption",{marks:!0}).marks},location(){return this.content.location},poster(){var t,e;return null==(e=null==(t=this.content.poster)?void 0:t[0])?void 0:e.url},video(){var t,e;return"kirby"===this.content.location?null==(e=null==(t=this.content.video)?void 0:t[0])?void 0:e.url:this.$helper.embed.video(this.content.url??"",!0)}}},(function(){var t=this,e=t._self._c;return e("k-block-figure",{staticClass:"k-block-type-video-figure",attrs:{caption:t.content.caption,"caption-marks":t.captionMarks,disabled:t.disabled,"empty-text":t.$t("field.blocks.video.placeholder")+" …","is-empty":!t.video,"empty-icon":"video"},on:{open:t.open,update:t.update}},[e("k-frame",{attrs:{ratio:"16/9"}},[t.video?["kirby"==t.location?e("video",{attrs:{src:t.video,poster:t.poster,controls:""}}):e("iframe",{attrs:{src:t.video,referrerpolicy:"strict-origin-when-cross-origin"}})]:t._e()],2)],1)}),[],!1,null,null,null,null).exports,ki={install(t){t.component("k-block",Qe),t.component("k-blocks",ei),t.component("k-block-options",Ze),t.component("k-block-pasteboard",ii),t.component("k-block-selector",ni),t.component("k-block-figure",si),t.component("k-block-title",We),t.component("k-block-type-code",oi),t.component("k-block-type-default",Ge),t.component("k-block-type-fields",li),t.component("k-block-type-gallery",ai),t.component("k-block-type-heading",ri),t.component("k-block-type-image",ui),t.component("k-block-type-line",ci),t.component("k-block-type-list",di),t.component("k-block-type-markdown",pi),t.component("k-block-type-quote",hi),t.component("k-block-type-table",mi),t.component("k-block-type-text",fi),t.component("k-block-type-video",gi)}};const bi=ut({mixins:[Fe,ti],inheritAttrs:!1,data:()=>({opened:[]}),computed:{hasFieldsets(){return this.$helper.object.length(this.fieldsets)>0},isEmpty(){return 0===this.value.length},isFull(){return this.max&&this.value.length>=this.max},options(){return[{click:()=>this.$refs.blocks.copyAll(),disabled:this.isEmpty,icon:"template",text:this.$t("copy.all")},{click:()=>this.$refs.blocks.pasteboard(),disabled:this.isFull,icon:"download",text:this.$t("paste")},"-",{click:()=>this.$refs.blocks.removeAll(),disabled:this.isEmpty,icon:"trash",text:this.$t("delete.all")}]}},methods:{focus(){this.$refs.blocks.focus()}}},(function(){var t=this,e=t._self._c;return e("k-field",t._b({staticClass:"k-blocks-field",scopedSlots:t._u([!t.disabled&&t.hasFieldsets?{key:"options",fn:function(){return[e("k-button-group",{attrs:{layout:"collapsed"}},[e("k-button",{attrs:{autofocus:t.autofocus,disabled:t.isFull,responsive:!0,text:t.$t("add"),icon:"add",variant:"filled",size:"xs"},on:{click:function(e){return t.$refs.blocks.choose(t.value.length)}}}),e("k-button",{attrs:{icon:"dots",variant:"filled",size:"xs"},on:{click:function(e){return t.$refs.options.toggle()}}}),e("k-dropdown-content",{ref:"options",attrs:{options:t.options,"align-x":"end"}})],1)]},proxy:!0}:null],null,!0)},"k-field",t.$props,!1),[e("k-blocks",t._g(t._b({ref:"blocks",on:{close:function(e){t.opened=e},open:function(e){t.opened=e}}},"k-blocks",t.$props,!1),t.$listeners)),t.disabled||t.isEmpty||t.isFull||!t.hasFieldsets?t._e():e("footer",[e("k-button",{attrs:{title:t.$t("add"),icon:"add",size:"xs",variant:"filled"},on:{click:function(e){return t.$refs.blocks.choose(t.value.length)}}})],1)],1)}),[],!1,null,null,null,null).exports,vi={mixins:[je,st],props:{columns:{default:1,type:Number},max:Number,min:Number,theme:String,value:{type:Array,default:()=>[]}}};const yi=ut({mixins:[Ie,vi],data:()=>({selected:[]}),computed:{choices(){return this.options.map(((t,e)=>({autofocus:this.autofocus&&0===e,checked:this.selected.includes(t.value),disabled:this.disabled||t.disabled,id:`${this.id}-${e}`,info:t.info,label:t.text,name:this.name??this.id,type:"checkbox",value:t.value})))}},watch:{value:{handler(t){this.selected=Array.isArray(t)?t:[],this.validate()},immediate:!0}},methods:{focus(){var t;null==(t=this.$el.querySelector("input"))||t.focus()},input(t,e){if(!0===e)this.selected.push(t);else{const e=this.selected.indexOf(t);-1!==e&&this.selected.splice(e,1)}this.$emit("input",this.selected)},select(){this.focus()},validate(){this.$emit("invalid",this.$v.$invalid,this.$v)}},validations(){return{selected:{required:!this.required||t.required,min:!this.min||t.minLength(this.min),max:!this.max||t.maxLength(this.max)}}}},(function(){var t=this,e=t._self._c;return e("ul",{staticClass:"k-checkboxes-input k-grid",style:{"--columns":t.columns},attrs:{"data-variant":"choices"}},t._l(t.choices,(function(i,n){return e("li",{key:n},[e("k-choice-input",t._b({on:{input:function(e){return t.input(i.value,e)}}},"k-choice-input",i,!1))],1)})),0)}),[],!1,null,null,null,null).exports,$i={props:{counter:{type:Boolean,default:!0}},computed:{counterOptions(){const t=this.counterValue??this.value;return!(!1===this.counter||this.disabled||!t)&&{count:Array.isArray(t)?t.length:String(t).length,min:this.$props.min??this.$props.minlength,max:this.$props.max??this.$props.maxlength}},counterValue:()=>null}};const wi=ut({mixins:[Fe,Ue,vi,$i],inheritAttrs:!1,methods:{focus(){this.$refs.input.focus()}}},(function(){var t,e=this,i=e._self._c;return i("k-field",e._b({staticClass:"k-checkboxes-field",attrs:{input:e.id+"-0",counter:e.counterOptions}},"k-field",e.$props,!1),[(null==(t=e.options)?void 0:t.length)?i("k-checkboxes-input",e._g(e._b({ref:"input"},"k-checkboxes-input",e.$props,!1),e.$listeners)):i("k-empty",{attrs:{text:e.$t("options.none"),icon:"checklist"}})],1)}),[],!1,null,null,null,null).exports,xi={mixins:[je,H,J,et,it,ot,lt,rt],props:{ariaLabel:String,type:{default:"text",type:String},value:{type:String}}};const _i=ut({mixins:[Ie,xi]},(function(){var t=this;return(0,t._self._c)("input",t._b({directives:[{name:"direction",rawName:"v-direction"}],staticClass:"k-string-input",attrs:{"aria-label":t.ariaLabel,"data-font":t.font},on:{input:function(e){return t.$emit("input",e.target.value)}}},"input",{autocomplete:t.autocomplete,autofocus:t.autofocus,disabled:t.disabled,id:t.id,maxlength:t.maxlength,minlength:t.minlength,name:t.name,pattern:t.pattern,placeholder:t.placeholder,required:t.required,spellcheck:t.spellcheck,type:t.type,value:t.value},!1))}),[],!1,null,null,null,null).exports,Ci={mixins:[xi],props:{autocomplete:null,font:null,maxlength:null,minlength:null,pattern:null,spellcheck:null,alpha:{type:Boolean,default:!0},format:{type:String,default:"hex",validator:t=>["hex","rgb","hsl"].includes(t)}}};const Si=ut({mixins:[_i,Ci],watch:{value(){this.validate()}},mounted(){this.validate()},methods:{convert(t){if(!t)return t;try{return this.$library.colors.toString(t,this.format,this.alpha)}catch{const e=document.createElement("div");return e.style.color=t,document.body.append(e),t=window.getComputedStyle(e).color,e.remove(),this.$library.colors.toString(t,this.format,this.alpha)}},convertAndEmit(t){this.emit(this.convert(t))},emit(t){this.$emit("input",t)},onBlur(){this.convertAndEmit(this.value)},onPaste(t){t instanceof ClipboardEvent&&(t=this.$helper.clipboard.read(t,!0)),this.convertAndEmit(t)},async onSave(){var t;this.convertAndEmit(this.value),await this.$nextTick(),null==(t=this.$el.form)||t.requestSubmit()},validate(){let t="";null===this.$library.colors.parse(this.value)&&(t=this.$t("error.validation.color",{format:this.format})),this.$el.setCustomValidity(t)}}},(function(){var t=this;return(0,t._self._c)("k-string-input",t._b({staticClass:"k-colorname-input",attrs:{spellcheck:!1,autocomplete:"off",type:"text"},on:{input:function(e){return t.$emit("input",e)}},nativeOn:{blur:function(e){return t.onBlur.apply(null,arguments)},paste:function(e){return t.onPaste.apply(null,arguments)},keydown:[function(e){return!e.type.indexOf("key")&&t._k(e.keyCode,"s",void 0,e.key,void 0)?null:e.metaKey?(e.stopPropagation(),e.preventDefault(),t.onSave.apply(null,arguments)):null},function(e){return!e.type.indexOf("key")&&t._k(e.keyCode,"enter",13,e.key,"Enter")?null:t.onSave.apply(null,arguments)}]}},"k-string-input",t.$props,!1))}),[],!1,null,null,null,null).exports;const Oi=ut({mixins:[Fe,Ue,Ci],inheritAttrs:!1,props:{icon:{type:String,default:"pipette"},mode:{type:String,default:"picker",validator:t=>["picker","input","options"].includes(t)},options:{type:Array,default:()=>[]}},computed:{convertedOptions(){return this.options.map((t=>({...t,value:this.convert(t.value)})))},currentOption(){return this.convertedOptions.find((t=>t.value===this.value))}},methods:{convert(t){return this.$library.colors.toString(t,this.format,this.alpha)}}},(function(){var t,e=this,i=e._self._c;return i("k-field",e._b({staticClass:"k-color-field",attrs:{input:e.id}},"k-field",e.$props,!1),["options"===e.mode?i("k-coloroptions-input",e._b({staticClass:"k-color-field-options",attrs:{options:e.convertedOptions},on:{input:function(t){return e.$emit("input",t)}}},"k-coloroptions-input",e.$props,!1)):i("k-input",e._b({attrs:{type:"color"},scopedSlots:e._u([{key:"before",fn:function(){return["picker"===e.mode?[i("button",{staticClass:"k-color-field-picker-toggle",attrs:{disabled:e.disabled,type:"button"},on:{click:function(t){return e.$refs.picker.toggle()}}},[i("k-color-frame",{attrs:{color:e.value}})],1),i("k-dropdown-content",{ref:"picker",staticClass:"k-color-field-picker"},[i("k-colorpicker-input",e._b({ref:"color",attrs:{options:e.convertedOptions},on:{input:function(t){return e.$emit("input",t)}},nativeOn:{click:function(t){t.stopPropagation()}}},"k-colorpicker-input",e.$props,!1))],1)]:i("k-color-frame",{attrs:{color:e.value}})]},proxy:!0},{key:"default",fn:function(){return[i("k-colorname-input",e._b({on:{input:function(t){return e.$emit("input",t)}}},"k-colorname-input",e.$props,!1))]},proxy:!0},(null==(t=e.currentOption)?void 0:t.text)?{key:"after",fn:function(){return[i("span",{domProps:{innerHTML:e._s(e.currentOption.text)}})]},proxy:!0}:null,"picker"===e.mode?{key:"icon",fn:function(){return[i("k-button",{staticClass:"k-input-icon-button",attrs:{icon:e.icon},on:{click:function(t){return t.stopPropagation(),e.$refs.picker.toggle()}}})]},proxy:!0}:null],null,!0)},"k-input",e.$props,!1))],1)}),[],!1,null,null,null,null).exports,Mi={props:{max:String,min:String,value:String}},Ai={mixins:[je,Mi],props:{display:{type:String,default:"DD.MM.YYYY"},step:{type:Object,default:()=>({size:1,unit:"day"})},type:{type:String,default:"date"}}};const ji=ut({mixins:[Ie,Ai],emits:["input","focus","submit"],data:()=>({dt:null,formatted:null}),computed:{inputType:()=>"date",pattern(){return this.$library.dayjs.pattern(this.display)},rounding(){return{...this.$options.props.step.default(),...this.step}}},watch:{value:{handler(t,e){if(t!==e){const e=this.toDatetime(t);this.commit(e)}},immediate:!0}},mounted(){this.$events.on("keydown.cmd.s",this.onBlur)},destroyed(){this.$events.off("keydown.cmd.s",this.onBlur)},methods:{async alter(t){let e=this.parse()??this.round(this.$library.dayjs()),i=this.rounding.unit,n=this.rounding.size;const s=this.selection();null!==s&&("meridiem"===s.unit?(t="pm"===e.format("a")?"subtract":"add",i="hour",n=12):(i=s.unit,i!==this.rounding.unit&&(n=1))),e=e[t](n,i).round(this.rounding.unit,this.rounding.size),this.commit(e),this.emit(e),await this.$nextTick(),this.select(s)},commit(t){this.dt=t,this.formatted=this.pattern.format(t),this.validate(),this.$emit("invalid",this.$v.$invalid,this.$v)},emit(t){this.$emit("input",this.toISO(t))},onArrowDown(){this.alter("subtract")},onArrowUp(){this.alter("add")},onBlur(){const t=this.parse();this.commit(t),this.emit(t)},async onEnter(){this.onBlur(),await this.$nextTick(),this.$emit("submit")},onInput(t){const e=this.parse(),i=this.pattern.format(e);if(!t||i==t)return this.commit(e),this.emit(e)},async onTab(t){if(""==this.$el.value)return;this.onBlur(),await this.$nextTick();const e=this.selection();if(this.$el&&e.start===this.$el.selectionStart&&e.end===this.$el.selectionEnd-1)if(t.shiftKey){if(0===e.index)return;this.selectPrev(e.index)}else{if(e.index===this.pattern.parts.length-1)return;this.selectNext(e.index)}else{if(this.$el&&this.$el.selectionStart==e.end+1&&e.index==this.pattern.parts.length-1)return;if(this.$el&&this.$el.selectionEnd-1>e.end){const t=this.pattern.at(this.$el.selectionEnd,this.$el.selectionEnd);this.select(this.pattern.parts[t.index])}else this.select(this.pattern.parts[e.index])}t.preventDefault()},parse(){const t=this.$library.dayjs.interpret(this.$el.value,this.inputType);return this.round(t)},round(t){return null==t?void 0:t.round(this.rounding.unit,this.rounding.size)},select(t){var e;t??(t=this.selection()),null==(e=this.$el)||e.setSelectionRange(t.start,t.end+1)},selectFirst(){this.select(this.pattern.parts[0])},selectLast(){this.select(this.pattern.parts[this.pattern.parts.length-1])},selectNext(t){this.select(this.pattern.parts[t+1])},selectPrev(t){this.select(this.pattern.parts[t-1])},selection(){return this.pattern.at(this.$el.selectionStart,this.$el.selectionEnd)},toDatetime(t){return this.round(this.$library.dayjs.iso(t,this.inputType))},toISO(t){return null==t?void 0:t.toISO(this.inputType)},validate(){var t,e,i;const n=[];this.required&&!this.dt&&n.push(this.$t("error.validation.required")),this.min&&!1===(null==(t=this.dt)?void 0:t.validate(this.min,"min",this.rounding.unit))&&n.push(this.$t("error.validation.date.after",{date:this.min})),this.max&&!1===(null==(e=this.dt)?void 0:e.validate(this.max,"max",this.rounding.unit))&&n.push(this.$t("error.validation.date.before",{date:this.max})),null==(i=this.$el)||i.setCustomValidity(n.join(", "))}},validations(){return{value:{min:!this.dt||!this.min||(()=>this.dt.validate(this.min,"min",this.rounding.unit)),max:!this.dt||!this.max||(()=>this.dt.validate(this.max,"max",this.rounding.unit)),required:!this.required||(()=>!!this.dt)}}}},(function(){var t=this;return(0,t._self._c)("input",{directives:[{name:"direction",rawName:"v-direction"}],class:`k-text-input k-${t.type}-input`,attrs:{id:t.id,autofocus:t.autofocus,disabled:t.disabled,placeholder:t.display,required:t.required,autocomplete:"off",spellcheck:"false",type:"text"},domProps:{value:t.formatted},on:{blur:t.onBlur,focus:function(e){return t.$emit("focus")},input:function(e){return t.onInput(e.target.value)},keydown:[function(e){return!e.type.indexOf("key")&&t._k(e.keyCode,"down",40,e.key,["Down","ArrowDown"])?null:(e.stopPropagation(),e.preventDefault(),t.onArrowDown.apply(null,arguments))},function(e){return!e.type.indexOf("key")&&t._k(e.keyCode,"up",38,e.key,["Up","ArrowUp"])?null:(e.stopPropagation(),e.preventDefault(),t.onArrowUp.apply(null,arguments))},function(e){return!e.type.indexOf("key")&&t._k(e.keyCode,"enter",13,e.key,"Enter")?null:(e.stopPropagation(),e.preventDefault(),t.onEnter.apply(null,arguments))},function(e){return!e.type.indexOf("key")&&t._k(e.keyCode,"tab",9,e.key,"Tab")?null:t.onTab.apply(null,arguments)}]}})}),[],!1,null,null,null,null).exports;const Ii=ut({mixins:[Fe,Ue,Ai],inheritAttrs:!1,props:{calendar:{type:Boolean,default:!0},icon:{type:String,default:"calendar"},time:{type:[Boolean,Object],default:()=>({})},times:{type:Boolean,default:!0}},emits:["input","submit"],data(){return{isInvalid:!1,iso:this.toIso(this.value)}},computed:{isEmpty(){return this.time?!this.iso.date||!this.iso.time:!this.iso.date}},watch:{value(t,e){t!==e&&(this.iso=this.toIso(t))}},methods:{focus(){this.$refs.dateInput.focus()},now(){const t=this.$library.dayjs();return{date:t.toISO("date"),time:this.time?t.toISO("time"):"00:00:00"}},onInput(){if(this.isEmpty)return this.$emit("input","");const t=this.$library.dayjs.iso(this.iso.date+" "+this.iso.time);(t||null!==this.iso.date&&null!==this.iso.time)&&this.$emit("input",(null==t?void 0:t.toISO())??"")},onDateInput(t){t&&!this.iso.time&&(this.iso.time=this.now().time),this.iso.date=t,this.onInput()},onDateInvalid(t){this.isInvalid=t},onTimeInput(t){t&&!this.iso.date&&(this.iso.date=this.now().date),this.iso.time=t,this.onInput()},onTimesInput(t){var e;null==(e=this.$refs.times)||e.close(),this.onTimeInput(t+":00")},toIso(t){const e=this.$library.dayjs.iso(t);return{date:(null==e?void 0:e.toISO("date"))??null,time:(null==e?void 0:e.toISO("time"))??null}}}},(function(){var t=this,e=t._self._c;return e("k-field",t._b({staticClass:"k-date-field",attrs:{input:t.id}},"k-field",t.$props,!1),[e("div",{ref:"body",staticClass:"k-date-field-body",attrs:{"data-has-time":Boolean(t.time),"data-invalid":!t.novalidate&&t.isInvalid}},[e("k-input",t._b({ref:"dateInput",attrs:{type:"date"},on:{invalid:t.onDateInvalid,input:t.onDateInput,submit:function(e){return t.$emit("submit")}},scopedSlots:t._u([t.calendar?{key:"icon",fn:function(){return[e("k-button",{staticClass:"k-input-icon-button",attrs:{disabled:t.disabled,icon:t.icon,title:t.$t("date.select")},on:{click:function(e){return t.$refs.calendar.toggle()}}}),e("k-dropdown-content",{ref:"calendar",attrs:{"align-x":"end"}},[e("k-calendar",{attrs:{value:t.iso.date,min:t.min,max:t.max},on:{input:t.onDateInput}})],1)]},proxy:!0}:null],null,!0)},"k-input",t.$props,!1)),t.time?e("k-input",{ref:"timeInput",attrs:{disabled:t.disabled,display:t.time.display,required:t.required,step:t.time.step,value:t.iso.time,icon:t.time.icon,type:"time"},on:{input:t.onTimeInput,submit:function(e){return t.$emit("submit")}},scopedSlots:t._u([t.times?{key:"icon",fn:function(){return[e("k-button",{staticClass:"k-input-icon-button",attrs:{disabled:t.disabled,icon:t.time.icon??"clock",title:t.$t("time.select")},on:{click:function(e){return t.$refs.times.toggle()}}}),e("k-dropdown-content",{ref:"times",attrs:{"align-x":"end"}},[e("k-timeoptions-input",{attrs:{display:t.time.display,value:t.value},on:{input:t.onTimesInput}})],1)]},proxy:!0}:null],null,!0)}):t._e()],1)])}),[],!1,null,null,null,null).exports,Di={mixins:[je,J,et,it,ot,lt,rt],props:{autocomplete:{type:[Boolean,String],default:"off"},preselect:Boolean,type:{type:String,default:"text"},value:String}};const Ei=ut({mixins:[Ie,Di],data(){return{listeners:{...this.$listeners,input:t=>this.onInput(t.target.value)}}},watch:{value(){this.onInvalid()}},mounted(){this.onInvalid(),this.$props.autofocus&&this.focus(),this.$props.preselect&&this.select()},methods:{onInput(t){this.$emit("input",t)},onInvalid(){this.$emit("invalid",this.$v.$invalid,this.$v)},select(){this.$refs.input.select()}},validations(){return{value:{required:!this.required||t.required,minLength:!this.minlength||t.minLength(this.minlength),maxLength:!this.maxlength||t.maxLength(this.maxlength),email:"email"!==this.type||t.email,url:"url"!==this.type||t.url,pattern:!this.pattern||(t=>!this.required&&!t||!this.$refs.input.validity.patternMismatch)}}}},(function(){var t=this;return(0,t._self._c)("input",t._g(t._b({directives:[{name:"direction",rawName:"v-direction"}],ref:"input",staticClass:"k-text-input",attrs:{"data-font":t.font}},"input",{autocomplete:t.autocomplete,autofocus:t.autofocus,disabled:t.disabled,id:t.id,minlength:t.minlength,name:t.name,pattern:t.pattern,placeholder:t.placeholder,required:t.required,spellcheck:t.spellcheck,type:t.type,value:t.value},!1),t.listeners))}),[],!1,null,null,null,null).exports,Ti={mixins:[Di],props:{autocomplete:{type:String,default:"email"},placeholder:{type:String,default:()=>window.panel.$t("email.placeholder")},type:{type:String,default:"email"}}};const Li=ut({extends:Ei,mixins:[Ti]},null,null,!1,null,null,null,null).exports;const Bi=ut({mixins:[Fe,Ue,Ti],inheritAttrs:!1,props:{link:{type:Boolean,default:!0},icon:{type:String,default:"email"}},computed:{mailto(){var t;return(null==(t=this.value)?void 0:t.length)>0?"mailto:"+this.value:null}},methods:{focus(){this.$refs.input.focus()}}},(function(){var t=this,e=t._self._c;return e("k-field",t._b({staticClass:"k-email-field",attrs:{input:t.id}},"k-field",t.$props,!1),[e("k-input",t._g(t._b({ref:"input",attrs:{type:"email"},scopedSlots:t._u([{key:"icon",fn:function(){return[t.link?e("k-button",{staticClass:"k-input-icon-button",attrs:{icon:t.icon,link:t.mailto,title:t.$t("open"),tabindex:"-1",target:"_blank"}}):t._e()]},proxy:!0}])},"k-input",t.$props,!1),t.$listeners))],1)}),[],!1,null,null,null,null).exports;const qi=ut({type:"model",mixins:[Fe,V,tt],inheritAttrs:!1,props:{empty:String,info:String,link:Boolean,max:Number,multiple:Boolean,parent:String,search:Boolean,size:String,text:String,value:{type:Array,default:()=>[]}},emits:["change","input"],data(){return{selected:this.value}},computed:{buttons(){return[{autofocus:this.autofocus,text:this.$t("select"),icon:"checklist",responsive:!0,click:()=>this.open()}]},collection(){return{empty:this.emptyProps,items:this.selected,layout:this.layout,link:this.link,size:this.size,sortable:!this.disabled&&this.selected.length>1,theme:this.disabled?"disabled":null}},hasDropzone:()=>!1,isInvalid(){return this.required&&0===this.selected.length||this.min&&this.selected.lengththis.max},more(){return!this.max||this.max>this.selected.length}},watch:{value(t){this.selected=t}},methods:{drop(){},focus(){},onInput(){this.$emit("input",this.selected)},open(){if(this.disabled)return!1;this.$panel.dialog.open({component:`k-${this.$options.type}-dialog`,props:{endpoint:this.endpoints.field,hasSearch:this.search,max:this.max,multiple:this.multiple,value:this.selected.map((t=>t.id))},on:{submit:t=>{this.select(t),this.$panel.dialog.close()}}})},remove(t){this.selected.splice(t,1),this.onInput()},removeById(t){this.selected=this.selected.filter((e=>e.id!==t)),this.onInput()},select(t){if(0===t.length)return this.selected=[],void this.onInput();this.selected=this.selected.filter((e=>t.find((t=>t.id===e.id))));for(const e of t)this.selected.find((t=>e.id===t.id))||this.selected.push(e);this.onInput()}}},(function(){var t=this,e=t._self._c;return e("k-field",t._b({class:`k-models-field k-${t.$options.type}-field`,scopedSlots:t._u([t.disabled?null:{key:"options",fn:function(){return[e("k-button-group",{ref:"buttons",staticClass:"k-field-options",attrs:{buttons:t.buttons,layout:"collapsed",size:"xs",variant:"filled"}})]},proxy:!0}],null,!0)},"k-field",t.$props,!1),[e("k-dropzone",{attrs:{disabled:!t.hasDropzone},on:{drop:t.drop}},[e("k-collection",t._b({on:{empty:t.open,sort:t.onInput,sortChange:function(e){return t.$emit("change",e)}},scopedSlots:t._u([t.disabled?null:{key:"options",fn:function({index:i}){return[e("k-button",{attrs:{title:t.$t("remove"),icon:"remove"},on:{click:function(e){return t.remove(i)}}})]}}],null,!0)},"k-collection",t.collection,!1))],1)],1)}),[],!1,null,null,null,null).exports;const Pi=ut({extends:qi,type:"files",props:{uploads:[Boolean,Object,Array]},computed:{buttons(){const t=qi.computed.buttons.call(this);return this.hasDropzone&&t.unshift({autofocus:this.autofocus,text:this.$t("upload"),responsive:!0,icon:"upload",click:()=>this.$panel.upload.pick(this.uploadOptions)}),t},emptyProps(){return{icon:"image",text:this.empty??this.$t("field.files.empty")}},hasDropzone(){return!this.disabled&&this.more&&this.uploads},uploadOptions(){return{accept:this.uploads.accept,max:this.max,multiple:this.multiple,url:this.$panel.urls.api+"/"+this.endpoints.field+"/upload",on:{done:t=>{!1===this.multiple&&(this.selected=[]);for(const e of t)void 0===this.selected.find((t=>t.id===e.id))&&this.selected.push(e);this.onInput(),this.$events.emit("model.update")}}}}},mounted(){this.$events.on("file.delete",this.removeById)},destroyed(){this.$events.off("file.delete",this.removeById)},methods:{drop(t){return!1!==this.uploads&&this.$panel.upload.open(t,this.uploadOptions)}}},null,null,!1,null,null,null,null).exports;const Ni=ut({},(function(){return(0,this._self._c)("div",{staticClass:"k-field k-gap-field"})}),[],!1,null,null,null,null).exports;const zi=ut({mixins:[G,Q],inheritAttrs:!1},(function(){var t=this,e=t._self._c;return e("div",{staticClass:"k-headline-field"},[e("k-headline",{staticClass:"h2"},[t._v(" "+t._s(t.label)+" ")]),t.help?e("footer",{staticClass:"k-field-footer"},[e("k-text",{staticClass:"k-help k-field-help",attrs:{html:t.help}})],1):t._e()],1)}),[],!1,null,null,null,null).exports;const Fi=ut({mixins:[G,Q],props:{icon:String,text:String,theme:{type:String,default:"info"}}},(function(){var t=this,e=t._self._c;return e("div",{staticClass:"k-field k-info-field"},[t.label?e("k-headline",[t._v(t._s(t.label))]):t._e(),e("k-box",{attrs:{icon:t.icon,theme:t.theme}},[e("k-text",{attrs:{html:t.text}})],1),t.help?e("footer",{staticClass:"k-field-footer"},[e("k-text",{staticClass:"k-help k-field-help",attrs:{html:t.help}})],1):t._e()],1)}),[],!1,null,null,null,null).exports,Yi={props:{endpoints:Object,fieldsetGroups:Object,fieldsets:Object,id:String,isSelected:Boolean}};const Ri=ut({mixins:[Yi],props:{blocks:Array,width:{type:String,default:"1/1"}},emits:["input"]},(function(){var t=this,e=t._self._c;return e("div",{staticClass:"k-column k-layout-column",style:{"--width":t.width},attrs:{id:t.id,tabindex:"0"},on:{dblclick:function(e){return t.$refs.blocks.choose(t.blocks.length)}}},[e("k-blocks",t._b({ref:"blocks",on:{input:function(e){return t.$emit("input",e)}},nativeOn:{dblclick:function(t){t.stopPropagation()}}},"k-blocks",{endpoints:t.endpoints,fieldsets:t.fieldsets,fieldsetGroups:t.fieldsetGroups,group:"layout",value:t.blocks},!1))],1)}),[],!1,null,null,null,null).exports,Ui={mixins:[Yi,W],props:{columns:Array,layouts:{type:Array,default:()=>[["1/1"]]},settings:Object}};const Hi=ut({mixins:[Ui],props:{attrs:[Array,Object]},emits:["append","change","copy","duplicate","prepend","remove","select","updateAttrs","updateColumn"],computed:{options(){return[{click:()=>this.$emit("prepend"),icon:"angle-up",text:this.$t("insert.before")},{click:()=>this.$emit("append"),icon:"angle-down",text:this.$t("insert.after")},"-",{click:()=>this.openSettings(),icon:"settings",text:this.$t("settings"),when:!1===this.$helper.object.isEmpty(this.settings)},{click:()=>this.$emit("duplicate"),icon:"copy",text:this.$t("duplicate")},{click:()=>this.$emit("change"),disabled:1===this.layouts.length,icon:"dashboard",text:this.$t("field.layout.change")},"-",{click:()=>this.$emit("copy"),icon:"template",text:this.$t("copy")},{click:()=>this.$emit("paste"),icon:"download",text:this.$t("paste.after")},"-",{click:()=>this.remove(),icon:"trash",text:this.$t("field.layout.delete")}]},tabs(){let t=this.settings.tabs;for(const[e,i]of Object.entries(t))for(const n in i.fields)t[e].fields[n].endpoints={field:this.endpoints.field+"/fields/"+n,section:this.endpoints.section,model:this.endpoints.model};return t}},methods:{openSettings(){this.$panel.drawer.open({component:"k-form-drawer",props:{icon:"settings",tabs:this.tabs,title:this.$t("settings"),value:this.attrs},on:{input:t=>this.$emit("updateAttrs",t)}})},remove(){this.$panel.dialog.open({component:"k-remove-dialog",props:{text:this.$t("field.layout.delete.confirm")},on:{submit:()=>{this.$emit("remove"),this.$panel.dialog.close()}}})}}},(function(){var t=this,e=t._self._c;return e("section",{staticClass:"k-layout",attrs:{"data-selected":t.isSelected,tabindex:"0"},on:{click:function(e){return t.$emit("select")}}},[e("k-grid",{staticClass:"k-layout-columns"},t._l(t.columns,(function(i,n){return e("k-layout-column",t._b({key:i.id,on:{input:function(e){return t.$emit("updateColumn",{column:i,columnIndex:n,blocks:e})}}},"k-layout-column",{...i,endpoints:t.endpoints,fieldsetGroups:t.fieldsetGroups,fieldsets:t.fieldsets},!1))})),1),t.disabled?t._e():e("nav",{staticClass:"k-layout-toolbar"},[t.settings?e("k-button",{staticClass:"k-layout-toolbar-button",attrs:{title:t.$t("settings"),icon:"settings"},on:{click:t.openSettings}}):t._e(),e("k-button",{staticClass:"k-layout-toolbar-button",attrs:{icon:"angle-down"},on:{click:function(e){return t.$refs.options.toggle()}}}),e("k-dropdown-content",{ref:"options",attrs:{options:t.options,"align-x":"end"}}),e("k-sort-handle")],1)],1)}),[],!1,null,null,null,null).exports,Vi={mixins:[Ui,X],props:{empty:String,max:Number,selector:Object,value:{type:Array,default:()=>[]}}};const Ki=ut({mixins:[Vi],emits:["input"],data(){return{current:null,nextIndex:null,rows:this.value,selected:null}},computed:{draggableOptions(){return{id:this.id,handle:!0,list:this.rows}},hasFieldsets(){return this.$helper.object.length(this.fieldsets)>0}},watch:{value(){this.rows=this.value}},methods:{copy(t,e){if(0===this.rows.length)return!1;const i=void 0!==e?this.rows[e]:this.rows;this.$helper.clipboard.write(JSON.stringify(i),t),this.$panel.notification.success({message:this.$t("copy.success",{count:i.length??1}),icon:"template"})},change(t,e){const i=e.columns.map((t=>t.width)),n=this.layouts.findIndex((t=>t.toString()===i.toString()));this.$panel.dialog.open({component:"k-layout-selector",props:{label:this.$t("field.layout.change"),layouts:this.layouts,selector:this.selector,value:this.layouts[n]},on:{submit:i=>{this.onChange(i,n,{rowIndex:t,layoutIndex:n,layout:e}),this.$panel.dialog.close()}}})},duplicate(t,e){const i=structuredClone(e),n=this.updateIds(i);this.rows.splice(t+1,0,...n),this.save()},async onAdd(t){let e=await this.$api.post(this.endpoints.field+"/layout",{columns:t});this.rows.splice(this.nextIndex,0,e),this.save()},async onChange(t,e,i){if(e===this.layouts[i.layoutIndex])return;const n=i.layout,s=await this.$api.post(this.endpoints.field+"/layout",{attrs:n.attrs,columns:t}),o=n.columns.filter((t=>{var e;return(null==(e=null==t?void 0:t.blocks)?void 0:e.length)>0})),l=[];if(0===o.length)l.push(s);else{const t=Math.ceil(o.length/s.columns.length)*s.columns.length;for(let e=0;e{var n;return t.blocks=(null==(n=o[i+e])?void 0:n.blocks)??[],t})),t.columns.filter((t=>{var e;return null==(e=null==t?void 0:t.blocks)?void 0:e.length})).length&&l.push(t)}}this.rows.splice(i.rowIndex,1,...l),this.save()},async paste(t,e=this.rows.length){let i=await this.$api.post(this.endpoints.field+"/layout/paste",{json:this.$helper.clipboard.read(t)});i.length&&(this.rows.splice(e,0,...i),this.save()),this.$panel.notification.success({message:this.$t("paste.success",{count:i.length}),icon:"download"})},pasteboard(t){this.$panel.dialog.open({component:"k-block-pasteboard",on:{paste:e=>this.paste(e,t)}})},remove(t){const e=this.rows.findIndex((e=>e.id===t.id));-1!==e&&this.$delete(this.rows,e),this.save()},removeAll(){this.$panel.dialog.open({component:"k-remove-dialog",props:{text:this.$t("field.layout.delete.confirm.all")},on:{submit:()=>{this.rows=[],this.save(),this.$panel.dialog.close()}}})},save(){this.$emit("input",this.rows)},select(t){if(this.nextIndex=t,1===this.layouts.length)return this.onAdd(this.layouts[0]);this.$panel.dialog.open({component:"k-layout-selector",props:{layouts:this.layouts,selector:this.selector,value:null},on:{submit:t=>{this.onAdd(t),this.$panel.dialog.close()}}})},updateAttrs(t,e){this.rows[t].attrs=e,this.save()},updateColumn(t){this.rows[t.index].columns[t.columnIndex].blocks=t.blocks,this.save()},updateIds(t){return!1===Array.isArray(t)&&(t=[t]),t.map((t=>(t.id=this.$helper.uuid(),t.columns=t.columns.map((t=>(t.id=this.$helper.uuid(),t.blocks=t.blocks.map((t=>(t.id=this.$helper.uuid(),t))),t))),t)))}}},(function(){var t=this,e=t._self._c;return e("div",[t.hasFieldsets&&t.rows.length?[e("k-draggable",t._b({staticClass:"k-layouts",on:{sort:t.save}},"k-draggable",t.draggableOptions,!1),t._l(t.rows,(function(i,n){return e("k-layout",t._b({key:i.id,on:{append:function(e){return t.select(n+1)},change:function(e){return t.change(n,i)},copy:function(e){return t.copy(e,n)},duplicate:function(e){return t.duplicate(n,i)},paste:function(e){return t.pasteboard(n+1)},prepend:function(e){return t.select(n)},remove:function(e){return t.remove(i)},select:function(e){t.selected=i.id},updateAttrs:function(e){return t.updateAttrs(n,e)},updateColumn:function(e){return t.updateColumn({layout:i,index:n,...e})}}},"k-layout",{...i,disabled:t.disabled,endpoints:t.endpoints,fieldsetGroups:t.fieldsetGroups,fieldsets:t.fieldsets,isSelected:t.selected===i.id,layouts:t.layouts,settings:t.settings},!1))})),1)]:!1===t.hasFieldsets?e("k-empty",{staticClass:"k-layout-empty",attrs:{icon:"dashboard"}},[t._v(" "+t._s(t.$t("field.blocks.fieldsets.empty"))+" ")]):e("k-empty",{staticClass:"k-layout-empty",attrs:{icon:"dashboard"},on:{click:function(e){return t.select(0)}}},[t._v(" "+t._s(t.empty??t.$t("field.layout.empty"))+" ")])],2)}),[],!1,null,null,null,null).exports;const Wi=ut({mixins:[Fe,Vi,V],inheritAttrs:!1,computed:{hasFieldsets(){return this.$helper.object.length(this.fieldsets)>0},isEmpty(){return 0===this.value.length},options(){return[{click:()=>this.$refs.layouts.copy(),disabled:this.isEmpty,icon:"template",text:this.$t("copy.all")},{click:()=>this.$refs.layouts.pasteboard(),icon:"download",text:this.$t("paste")},"-",{click:()=>this.$refs.layouts.removeAll(),disabled:this.isEmpty,icon:"trash",text:this.$t("delete.all")}]}}},(function(){var t=this,e=t._self._c;return e("k-field",t._b({staticClass:"k-layout-field",scopedSlots:t._u([!t.disabled&&t.hasFieldsets?{key:"options",fn:function(){return[e("k-button-group",{attrs:{layout:"collapsed"}},[e("k-button",{attrs:{autofocus:t.autofocus,text:t.$t("add"),icon:"add",variant:"filled",size:"xs"},on:{click:function(e){return t.$refs.layouts.select(0)}}}),e("k-button",{attrs:{icon:"dots",variant:"filled",size:"xs"},on:{click:function(e){return t.$refs.options.toggle()}}}),e("k-dropdown-content",{ref:"options",attrs:{options:t.options,"align-x":"end"}})],1)]},proxy:!0}:null],null,!0)},"k-field",t.$props,!1),[e("k-layouts",t._b({ref:"layouts",on:{input:function(e){return t.$emit("input",e)}}},"k-layouts",t.$props,!1)),!t.disabled&&t.hasFieldsets?e("footer",[e("k-button",{attrs:{title:t.$t("add"),icon:"add",size:"xs",variant:"filled"},on:{click:function(e){return t.$refs.layouts.select(t.value.length)}}})],1):t._e()],1)}),[],!1,null,null,null,null).exports;const Ji=ut({},(function(){return(0,this._self._c)("hr",{staticClass:"k-line-field"})}),[],!1,null,null,null,null).exports;const Gi=ut({mixins:[{mixins:[Fe,Ue,je,st],props:{value:{default:"",type:String}}}],inheritAttrs:!1,data:()=>({linkType:null,linkValue:null,expanded:!1,isInvalid:!1}),computed:{activeTypes(){return this.$helper.link.types(this.options)},activeTypesOptions(){const t=[];for(const e in this.activeTypes)t.push({click:()=>this.switchType(e),current:e===this.currentType.id,icon:this.activeTypes[e].icon,label:this.activeTypes[e].label});return t},currentType(){return this.activeTypes[this.linkType]??Object.values(this.activeTypes)[0]}},watch:{value:{async handler(t,e){if(t===e||t===this.linkValue)return;const i=this.$helper.link.detect(t,this.activeTypes);i&&(this.linkType=i.type,this.linkValue=i.link)},immediate:!0}},mounted(){this.$events.on("click",this.onOutsideClick)},destroyed(){this.$events.off("click",this.onOutsideClick)},methods:{clear(){this.linkValue="",this.$emit("input","")},focus(){var t;null==(t=this.$refs.input)||t.focus()},onInput(t){const e=(null==t?void 0:t.trim())??"";if(this.linkType??(this.linkType=this.currentType.id),this.linkValue=e,!e.length)return this.clear();this.$emit("input",this.currentType.value(e))},onInvalid(t){this.isInvalid=!!t},onOutsideClick(t){!1===this.$el.contains(t.target)&&(this.expanded=!1)},removeModel(){this.clear(),this.expanded=!1},selectModel(t){t.uuid?this.onInput(t.uuid):(this.switchType("url"),this.onInput(t.url))},async switchType(t){t!==this.currentType.id&&(this.isInvalid=!1,this.linkType=t,this.clear(),"page"===this.currentType.id||"file"===this.currentType.id?this.expanded=!0:this.expanded=!1,await this.$nextTick(),this.focus())},toggle(){this.expanded=!this.expanded}}},(function(){var t=this,e=t._self._c;return e("k-field",t._b({staticClass:"k-link-field",attrs:{input:t.id}},"k-field",t.$props,!1),[e("k-input",t._b({attrs:{invalid:t.isInvalid,icon:!1}},"k-input",t.$props,!1),[e("div",{staticClass:"k-link-input-header"},[e("k-button",{staticClass:"k-link-input-toggle",attrs:{disabled:t.disabled,dropdown:!t.disabled&&t.activeTypesOptions.length>1,icon:t.currentType.icon,variant:"filled"},on:{click:function(e){t.activeTypesOptions.length>1?t.$refs.types.toggle():t.toggle()}}},[t._v(" "+t._s(t.currentType.label)+" ")]),e("k-dropdown-content",{ref:"types",attrs:{options:t.activeTypesOptions}}),"page"===t.currentType.id||"file"===t.currentType.id?e("div",{staticClass:"k-link-input-model",on:{click:t.toggle}},[e("k-link-field-preview",{attrs:{removable:!0,type:t.currentType.id,value:t.value},on:{remove:t.removeModel},scopedSlots:t._u([{key:"placeholder",fn:function(){return[e("k-button",{staticClass:"k-link-input-model-placeholder"},[t._v(" "+t._s(t.currentType.placeholder)+" ")])]},proxy:!0}],null,!1,3171606015)}),e("k-button",{staticClass:"k-link-input-model-toggle",attrs:{icon:"bars"}})],1):e("k-"+t.currentType.input+"-input",{ref:"input",tag:"component",attrs:{id:t.id,disabled:t.disabled,pattern:t.currentType.pattern??null,placeholder:t.currentType.placeholder,value:t.linkValue},on:{invalid:t.onInvalid,input:t.onInput}})],1),"page"===t.currentType.id?e("div",{directives:[{name:"show",rawName:"v-show",value:t.expanded,expression:"expanded"}],staticClass:"k-link-input-body",attrs:{"data-type":"page"}},[e("div",{staticClass:"k-page-browser"},[e("k-page-tree",{attrs:{current:t.$helper.link.getPageUUID(t.value),root:!1},on:{select:function(e){return t.selectModel(e)}}})],1)]):"file"===t.currentType.id?e("div",{directives:[{name:"show",rawName:"v-show",value:t.expanded,expression:"expanded"}],staticClass:"k-link-input-body",attrs:{"data-type":"file"}},[e("k-file-browser",{attrs:{selected:t.$helper.link.getFileUUID(t.value)},on:{select:function(e){return t.selectModel(e)}}})],1):t._e()])],1)}),[],!1,null,null,null,null).exports;const Xi=t=>({$from:e})=>((t,e)=>{for(let i=t.depth;i>0;i--){const n=t.node(i);if(e(n))return{pos:i>0?t.before(i):0,start:t.start(i),depth:i,node:n}}})(e,t),Zi=t=>e=>{if((t=>t instanceof o)(e)){const{node:i,$from:n}=e;if(((t,e)=>Array.isArray(t)&&t.indexOf(e.type)>-1||e.type===t)(t,i))return{node:i,pos:n.pos,depth:n.depth}}},Qi=(t,e,i={})=>{const n=Zi(e)(t.selection)||Xi((t=>t.type===e))(t.selection);return 0!==yt(i)&&n?n.node.hasMarkup(e,{...n.node.attrs,...i}):!!n};function tn(t=null,e=null){if(!t||!e)return!1;const i=t.parent.childAfter(t.parentOffset);if(!i.node)return!1;const n=i.node.marks.find((t=>t.type===e));if(!n)return!1;let s=t.index(),o=t.start()+i.offset,l=s+1,a=o+i.node.nodeSize;for(;s>0&&n.isInSet(t.parent.child(s-1).marks);)s-=1,o-=t.parent.child(s).nodeSize;for(;l{s=[...s,...t.marks]}));const o=s.find((t=>t.type.name===e.name));return o?o.attrs:{}},getNodeAttrs:function(t,e){const{from:i,to:n}=t.selection;let s=[];t.doc.nodesBetween(i,n,(t=>{s=[...s,t]}));const o=s.reverse().find((t=>t.type.name===e.name));return o?o.attrs:{}},insertNode:function(t,e,i,n){return(s,o)=>{o(s.tr.replaceSelectionWith(t.create(e,i,n)).scrollIntoView())}},markInputRule:function(t,i,n){return new e(t,((t,e,s,o)=>{const l=n instanceof Function?n(e):n,{tr:a}=t,r=e.length-1;let u=o,c=s;if(e[r]){const n=s+e[0].indexOf(e[r-1]),l=n+e[r-1].length-1,d=n+e[r-1].lastIndexOf(e[r]),p=d+e[r].length,h=function(t,e,i){let n=[];return i.doc.nodesBetween(t,e,((t,e)=>{n=[...n,...t.marks.map((i=>({start:e,end:e+t.nodeSize,mark:i})))]})),n}(s,o,t).filter((t=>{const{excluded:e}=t.mark.type;return e.find((t=>t.name===i.name))})).filter((t=>t.end>n));if(h.length)return!1;pn&&a.delete(n,d),c=n,u=c+e[r].length}return a.addMark(c,u,i.create(l)),a.removeStoredMark(i),a}))},markIsActive:function(t,e){const{from:i,$from:n,to:s,empty:o}=t.selection;return o?!!e.isInSet(t.storedMarks||n.marks()):!!t.doc.rangeHasMark(i,s,e)},markPasteRule:function(t,e,o){const l=(i,n)=>{const a=[];return i.forEach((i=>{var s;if(i.isText){const{text:l,marks:r}=i;let u,c=0;const d=!!r.filter((t=>"link"===t.type.name))[0];for(;!d&&null!==(u=t.exec(l));)if((null==(s=null==n?void 0:n.type)?void 0:s.allowsMarkType(e))&&u[1]){const t=u.index,n=t+u[0].length,s=t+u[0].indexOf(u[1]),l=s+u[1].length,r=o instanceof Function?o(u):o;t>0&&a.push(i.cut(c,t)),a.push(i.cut(s,l).mark(e.create(r).addToSet(i.marks))),c=n}cnew n(l(t.content),t.openStart,t.openEnd)}})},minMax:function(t=0,e=0,i=0){return Math.min(Math.max(parseInt(t,10),e),i)},nodeIsActive:Qi,nodeInputRule:function(t,i,n){return new e(t,((t,e,s,o)=>{const l=n instanceof Function?n(e):n,{tr:a}=t;return e[0]&&a.replaceWith(s,o,i.create(l)),a}))},pasteRule:function(t,e,o){const l=i=>{const n=[];return i.forEach((i=>{if(i.isText){const{text:s}=i;let l,a=0;do{if(l=t.exec(s),l){const t=l.index,s=t+l[0].length,r=o instanceof Function?o(l[0]):o;t>0&&n.push(i.cut(a,t)),n.push(i.cut(t,s).mark(e.create(r).addToSet(i.marks))),a=s}}while(l);anew n(l(t.content),t.openStart,t.openEnd)}})},removeMark:function(t){return(e,i)=>{const{tr:n,selection:s}=e;let{from:o,to:l}=s;const{$from:a,empty:r}=s;if(r){const e=tn(a,t);o=e.from,l=e.to}return n.removeMark(o,l,t),i(n)}},toggleBlockType:function(t,e,i={}){return(n,s,o)=>Qi(n,t,i)?l(e)(n,s,o):l(t,i)(n,s,o)},toggleList:function(t,e){return(i,n,s)=>{const{schema:o,selection:l}=i,{$from:u,$to:c}=l,d=u.blockRange(c);if(!d)return!1;const p=Xi((t=>en(t,o)))(l);if(d.depth>=1&&p&&d.depth-p.depth<=1){if(p.node.type===t)return a(e)(i,n,s);if(en(p.node,o)&&t.validContent(p.node.content)){const{tr:e}=i;return e.setNodeMarkup(p.pos,t),n&&n(e),!1}}return r(t)(i,n,s)}},toggleWrap:function(t,e={}){return(i,n,s)=>Qi(i,t,e)?u(i,n):c(t,e)(i,n,s)},updateMark:function(t,e){return(i,n)=>{const{tr:s,selection:o,doc:l}=i,{ranges:a,empty:r}=o;if(r){const{from:i,to:n}=tn(o.$from,t);l.rangeHasMark(i,n,t)&&s.removeMark(i,n,t),s.addMark(i,n,t.create(e))}else a.forEach((i=>{const{$to:n,$from:o}=i;l.rangeHasMark(o.pos,n.pos,t)&&s.removeMark(o.pos,n.pos,t),s.addMark(o.pos,n.pos,t.create(e))}));return n(s)}}};class sn{emit(t,...e){this._callbacks=this._callbacks??{};const i=this._callbacks[t]??[];for(const n of i)n.apply(this,e);return this}off(t,e){if(arguments.length){const i=this._callbacks?this._callbacks[t]:null;i&&(e?this._callbacks[t]=i.filter((t=>t!==e)):delete this._callbacks[t])}else this._callbacks={};return this}on(t,e){return this._callbacks=this._callbacks??{},this._callbacks[t]=this._callbacks[t]??[],this._callbacks[t].push(e),this}}class on{constructor(t=[],e){for(const i of t)i.bindEditor(e),i.init();this.extensions=t}commands({schema:t,view:e}){return this.extensions.filter((t=>t.commands)).reduce(((i,n)=>{const{name:s,type:o}=n,l={},a=n.commands({schema:t,utils:nn,...["node","mark"].includes(o)?{type:t[`${o}s`][s]}:{}}),r=(t,i)=>{l[t]=t=>{if("function"!=typeof i||!e.editable)return!1;e.focus();const n=i(t);return"function"==typeof n?n(e.state,e.dispatch,e):n}};if("object"==typeof a)for(const[t,e]of Object.entries(a))r(t,e);else r(s,a);return{...i,...l}}),{})}buttons(t="mark"){const e={};for(const i of this.extensions)if(i.type===t&&i.button)if(Array.isArray(i.button))for(const t of i.button)e[t.id??t.name]=t;else e[i.name]=i.button;return e}getAllowedExtensions(t){return t instanceof Array||!t?t instanceof Array?this.extensions.filter((e=>!t.includes(e.name))):this.extensions:[]}getFromExtensions(t,e,i=this.extensions){return i.filter((t=>["extension"].includes(t.type))).filter((e=>e[t])).map((i=>i[t]({...e,utils:nn})))}getFromNodesAndMarks(t,e,i=this.extensions){return i.filter((t=>["node","mark"].includes(t.type))).filter((e=>e[t])).map((i=>i[t]({...e,type:e.schema[`${i.type}s`][i.name],utils:nn})))}inputRules({schema:t,excludedExtensions:e}){const i=this.getAllowedExtensions(e);return[...this.getFromExtensions("inputRules",{schema:t},i),...this.getFromNodesAndMarks("inputRules",{schema:t},i)].reduce(((t,e)=>[...t,...e]),[])}keymaps({schema:t}){return[...this.getFromExtensions("keys",{schema:t}),...this.getFromNodesAndMarks("keys",{schema:t})].map((t=>v(t)))}get marks(){return this.extensions.filter((t=>"mark"===t.type)).reduce(((t,{name:e,schema:i})=>({...t,[e]:i})),{})}get markViews(){return this.extensions.filter((t=>["mark"].includes(t.type))).filter((t=>t.view)).reduce(((t,{name:e,view:i})=>({...t,[e]:i})),{})}get nodes(){return this.extensions.filter((t=>"node"===t.type)).reduce(((t,{name:e,schema:i})=>({...t,[e]:i})),{})}get nodeViews(){return this.extensions.filter((t=>["node"].includes(t.type))).filter((t=>t.view)).reduce(((t,{name:e,view:i})=>({...t,[e]:i})),{})}get options(){const{view:t}=this;return this.extensions.reduce(((e,i)=>({...e,[i.name]:new Proxy(i.options,{set(e,i,n){const s=e[i]!==n;return Object.assign(e,{[i]:n}),s&&t.updateState(t.state),!0}})})),{})}pasteRules({schema:t,excludedExtensions:e}){const i=this.getAllowedExtensions(e);return[...this.getFromExtensions("pasteRules",{schema:t},i),...this.getFromNodesAndMarks("pasteRules",{schema:t},i)].reduce(((t,e)=>[...t,...e]),[])}plugins({schema:t}){return[...this.getFromExtensions("plugins",{schema:t}),...this.getFromNodesAndMarks("plugins",{schema:t})].reduce(((t,e)=>[...t,...e]),[]).map((t=>t instanceof i?t:new i(t)))}}class ln{constructor(t={}){this.options={...this.defaults,...t}}init(){return null}bindEditor(t=null){this.editor=t}get name(){return null}get type(){return"extension"}get defaults(){return{}}plugins(){return[]}inputRules(){return[]}pasteRules(){return[]}keys(){return{}}}class an extends ln{constructor(t={}){super(t)}get type(){return"node"}get schema(){return{}}commands(){return{}}}class rn extends an{get defaults(){return{inline:!1}}get name(){return"doc"}get schema(){return{content:this.options.inline?"inline*":"block+"}}}class un extends an{get button(){return{id:this.name,icon:"paragraph",label:window.panel.$t("toolbar.button.paragraph"),name:this.name,separator:!0}}commands({utils:t,schema:e,type:i}){return{paragraph:()=>this.editor.activeNodes.includes("bulletList")?t.toggleList(e.nodes.bulletList,e.nodes.listItem):this.editor.activeNodes.includes("orderedList")?t.toggleList(e.nodes.orderedList,e.nodes.listItem):this.editor.activeNodes.includes("quote")?t.toggleWrap(e.nodes.quote):t.setBlockType(i)}}get schema(){return{content:"inline*",group:"block",draggable:!1,parseDOM:[{tag:"p"}],toDOM:()=>["p",0]}}get name(){return"paragraph"}}let cn=class extends an{get name(){return"text"}get schema(){return{group:"inline"}}};class dn extends sn{constructor(t={}){super(),this.defaults={autofocus:!1,content:"",disableInputRules:!1,disablePasteRules:!1,editable:!0,element:null,extensions:[],emptyDocument:{type:"doc",content:[]},events:{},inline:!1,parseOptions:{},topNode:"doc",useBuiltInExtensions:!0},this.init(t)}blur(){this.view.dom.blur()}get builtInExtensions(){return!0!==this.options.useBuiltInExtensions?[]:[new rn({inline:this.options.inline}),new cn,new un]}buttons(t){return this.extensions.buttons(t)}clearContent(t=!1){this.setContent(this.options.emptyDocument,t)}command(t,...e){var i,n;null==(n=(i=this.commands)[t])||n.call(i,...e)}createCommands(){return this.extensions.commands({schema:this.schema,view:this.view})}createDocument(t,e=this.options.parseOptions){if(null===t)return this.schema.nodeFromJSON(this.options.emptyDocument);if("object"==typeof t)try{return this.schema.nodeFromJSON(t)}catch(i){return window.console.warn("Invalid content.","Passed value:",t,"Error:",i),this.schema.nodeFromJSON(this.options.emptyDocument)}if("string"==typeof t){const i=`

      ${t}
      `,n=(new window.DOMParser).parseFromString(i,"text/html").body.firstElementChild;return y.fromSchema(this.schema).parse(n,e)}return!1}createEvents(){const t=this.options.events??{};for(const[e,i]of Object.entries(t))this.on(e,i);return t}createExtensions(){return new on([...this.builtInExtensions,...this.options.extensions],this)}createFocusEvents(){const t=(t,e,i=!0)=>{this.focused=i,this.emit(i?"focus":"blur",{event:e,state:t.state,view:t});const n=this.state.tr.setMeta("focused",i);this.view.dispatch(n)};return new i({props:{attributes:{tabindex:0},handleDOMEvents:{focus:(e,i)=>t(e,i,!0),blur:(e,i)=>t(e,i,!1)}}})}createInputRules(){return this.extensions.inputRules({schema:this.schema,excludedExtensions:this.options.disableInputRules})}createKeymaps(){return this.extensions.keymaps({schema:this.schema})}createMarks(){return this.extensions.marks}createMarkViews(){return this.extensions.markViews}createNodes(){return this.extensions.nodes}createNodeViews(){return this.extensions.nodeViews}createPasteRules(){return this.extensions.pasteRules({schema:this.schema,excludedExtensions:this.options.disablePasteRules})}createPlugins(){return this.extensions.plugins({schema:this.schema})}createSchema(){return new $({topNode:this.options.topNode,nodes:this.nodes,marks:this.marks})}createState(){return w.create({schema:this.schema,doc:this.createDocument(this.options.content),plugins:[...this.plugins,x({rules:this.inputRules}),...this.pasteRules,...this.keymaps,v({Backspace:O}),v(M),this.createFocusEvents()]})}createView(){return new _(this.element,{dispatchTransaction:this.dispatchTransaction.bind(this),attributes:{class:"k-text"},editable:()=>this.options.editable,handlePaste:(t,e)=>{if("function"==typeof this.events.paste){const t=e.clipboardData.getData("text/html"),i=e.clipboardData.getData("text/plain");if(!0===this.events.paste(e,t,i))return!0}},handleDrop:(...t)=>{this.emit("drop",...t)},markViews:this.createMarkViews(),nodeViews:this.createNodeViews(),state:this.createState()})}destroy(){this.view&&this.view.destroy()}dispatchTransaction(t){const e=this.state,i=this.state.apply(t);this.view.updateState(i),this.setActiveNodesAndMarks();const n={editor:this,getHTML:this.getHTML.bind(this),getJSON:this.getJSON.bind(this),state:this.state,transaction:t};this.emit("transaction",n),!t.docChanged&&t.getMeta("preventUpdate")||this.emit("update",n);const{from:s,to:o}=this.state.selection,l=!e||!e.selection.eq(i.selection);this.emit(i.selection.empty?"deselect":"select",{...n,from:s,hasChanged:l,to:o})}focus(t=null){if(this.view.focused&&null===t||!1===t)return;const{from:e,to:i}=this.selectionAtPosition(t);this.setSelection(e,i),setTimeout((()=>this.view.focus()),10)}getHTML(t=this.state.doc.content){const e=document.createElement("div"),i=C.fromSchema(this.schema).serializeFragment(t);return e.appendChild(i),this.options.inline&&e.querySelector("p")?e.querySelector("p").innerHTML:e.innerHTML}getHTMLStartToSelection(){const t=this.state.doc.slice(0,this.selection.head).content;return this.getHTML(t)}getHTMLSelectionToEnd(){const t=this.state.doc.slice(this.selection.head).content;return this.getHTML(t)}getHTMLStartToSelectionToEnd(){return[this.getHTMLStartToSelection(),this.getHTMLSelectionToEnd()]}getJSON(){return this.state.doc.toJSON()}getMarkAttrs(t=null){return this.activeMarkAttrs[t]}getSchemaJSON(){return JSON.parse(JSON.stringify({nodes:this.nodes,marks:this.marks}))}init(t={}){this.options={...this.defaults,...t},this.element=this.options.element,this.focused=!1,this.events=this.createEvents(),this.extensions=this.createExtensions(),this.nodes=this.createNodes(),this.marks=this.createMarks(),this.schema=this.createSchema(),this.keymaps=this.createKeymaps(),this.inputRules=this.createInputRules(),this.pasteRules=this.createPasteRules(),this.plugins=this.createPlugins(),this.view=this.createView(),this.commands=this.createCommands(),this.setActiveNodesAndMarks(),!1!==this.options.autofocus&&this.focus(this.options.autofocus),this.emit("init",{view:this.view,state:this.state}),this.extensions.view=this.view,this.setContent(this.options.content,!0)}insertText(t,e=!1){const{tr:i}=this.state,n=i.insertText(t);if(this.view.dispatch(n),e){const e=i.selection.from,n=e-t.length;this.setSelection(n,e)}}isEditable(){return this.options.editable}isEmpty(){if(this.state)return 0===this.state.doc.textContent.length}get isActive(){return Object.entries({...this.activeMarks,...this.activeNodes}).reduce(((t,[e,i])=>({...t,[e]:(t={})=>i(t)})),{})}removeMark(t){if(this.schema.marks[t])return nn.removeMark(this.schema.marks[t])(this.state,this.view.dispatch)}get selection(){return this.state.selection}get selectionAtEnd(){return S.atEnd(this.state.doc)}get selectionIsAtEnd(){return this.selection.head===this.selectionAtEnd.head}get selectionAtStart(){return S.atStart(this.state.doc)}get selectionIsAtStart(){return this.selection.head===this.selectionAtStart.head}selectionAtPosition(t=null){return null===t?this.selection:"start"===t||!0===t?this.selectionAtStart:"end"===t?this.selectionAtEnd:{from:t,to:t}}setActiveNodesAndMarks(){this.activeMarks=Object.values(this.schema.marks).filter((t=>nn.markIsActive(this.state,t))).map((t=>t.name)),this.activeMarkAttrs=Object.entries(this.schema.marks).reduce(((t,[e,i])=>({...t,[e]:nn.getMarkAttrs(this.state,i)})),{}),this.activeNodes=Object.values(this.schema.nodes).filter((t=>nn.nodeIsActive(this.state,t))).map((t=>t.name)),this.activeNodeAttrs=Object.entries(this.schema.nodes).reduce(((t,[e,i])=>({...t,[e]:nn.getNodeAttrs(this.state,i)})),{})}setContent(t={},e=!1,i){const{doc:n,tr:s}=this.state,o=this.createDocument(t,i),l=s.replaceWith(0,n.content.size,o).setMeta("preventUpdate",!e);this.view.dispatch(l)}setSelection(t=0,e=0){const{doc:i,tr:n}=this.state,s=nn.minMax(t,0,i.content.size),o=nn.minMax(e,0,i.content.size),l=S.create(i,s,o),a=n.setSelection(l);this.view.dispatch(a)}get state(){var t;return null==(t=this.view)?void 0:t.state}toggleMark(t){if(this.schema.marks[t])return nn.toggleMark(this.schema.marks[t])(this.state,this.view.dispatch)}updateMark(t,e){if(this.schema.marks[t])return nn.updateMark(this.schema.marks[t],e)(this.state,this.view.dispatch)}}class pn extends ln{command(){return()=>{}}remove(){this.editor.removeMark(this.name)}get schema(){return{}}get type(){return"mark"}toggle(){return this.editor.toggleMark(this.name)}update(t){this.editor.updateMark(this.name,t)}}class hn extends pn{get button(){return{icon:"bold",label:window.panel.$t("toolbar.button.bold")}}commands(){return()=>this.toggle()}inputRules({type:t,utils:e}){return[e.markInputRule(/(?:\*\*|__)([^*_]+)(?:\*\*|__)$/,t)]}keys(){return{"Mod-b":()=>this.toggle()}}get name(){return"bold"}pasteRules({type:t,utils:e}){return[e.markPasteRule(/(?:\*\*|__)([^*_]+)(?:\*\*|__)/g,t)]}get schema(){return{parseDOM:[{tag:"strong"},{tag:"b",getAttrs:t=>"normal"!==t.style.fontWeight&&null},{style:"font-weight",getAttrs:t=>/^(bold(er)?|[5-9]\d{2,})$/.test(t)&&null}],toDOM:()=>["strong",0]}}}class mn extends pn{get button(){return{icon:"clear",label:window.panel.$t("toolbar.button.clear")}}commands(){return()=>this.clear()}clear(){const{state:t}=this.editor,{from:e,to:i}=t.tr.selection;for(const n of this.editor.activeMarks){const s=t.schema.marks[n],o=this.editor.state.tr.removeMark(e,i,s);this.editor.view.dispatch(o)}}get name(){return"clear"}}let fn=class extends pn{get button(){return{icon:"code",label:window.panel.$t("toolbar.button.code")}}commands(){return()=>this.toggle()}inputRules({type:t,utils:e}){return[e.markInputRule(/(?:`)([^`]+)(?:`)$/,t)]}keys(){return{"Mod-`":()=>this.toggle()}}get name(){return"code"}pasteRules({type:t,utils:e}){return[e.markPasteRule(/(?:`)([^`]+)(?:`)/g,t)]}get schema(){return{excludes:"_",parseDOM:[{tag:"code"}],toDOM:()=>["code",0]}}};class gn extends pn{get button(){return{icon:"email",label:window.panel.$t("toolbar.button.email")}}commands(){return{email:t=>{if(t.altKey||t.metaKey)return this.remove();this.editor.emit("email",this.editor)},insertEmail:(t={})=>{const{selection:e}=this.editor.state;if(e.empty&&this.editor.insertText(t.href,!0),t.href)return this.update(t)},removeEmail:()=>this.remove(),toggleEmail:(t={})=>{var e;(null==(e=t.href)?void 0:e.length)>0?this.editor.command("insertEmail",t):this.editor.command("removeEmail")}}}get defaults(){return{target:null}}get name(){return"email"}pasteRules({type:t,utils:e}){return[e.pasteRule(/^[\w-.]+@([\w-]+\.)+[\w-]{2,4}$/gi,t,(t=>({href:t})))]}plugins(){return[{props:{handleClick:(t,e,i)=>{const n=this.editor.getMarkAttrs("email");n.href&&!0===i.altKey&&i.target instanceof HTMLAnchorElement&&(i.stopPropagation(),window.open(n.href))}}}]}get schema(){return{attrs:{href:{default:null},title:{default:null}},inclusive:!1,parseDOM:[{tag:"a[href^='mailto:']",getAttrs:t=>({href:t.getAttribute("href").replace("mailto:",""),title:t.getAttribute("title")})}],toDOM:t=>["a",{...t.attrs,href:"mailto:"+t.attrs.href},0]}}}class kn extends pn{get button(){return{icon:"italic",label:window.panel.$t("toolbar.button.italic")}}commands(){return()=>this.toggle()}inputRules({type:t,utils:e}){return[e.markInputRule(/(?:^|\s)((?:\*)((?:[^*]+))(?:\*))$/,t),e.markInputRule(/(?:^|\s)((?:_)((?:[^_]+))(?:_))$/,t)]}keys(){return{"Mod-i":()=>this.toggle()}}get name(){return"italic"}pasteRules({type:t,utils:e}){return[e.markPasteRule(/_([^_]+)_/g,t),e.markPasteRule(/\*([^*]+)\*/g,t)]}get schema(){return{parseDOM:[{tag:"i"},{tag:"em"},{style:"font-style=italic"}],toDOM:()=>["em",0]}}}let bn=class extends pn{get button(){return{icon:"url",label:window.panel.$t("toolbar.button.link")}}commands(){return{link:t=>{if(t.altKey||t.metaKey)return this.remove();this.editor.emit("link",this.editor)},insertLink:(t={})=>{const{selection:e}=this.editor.state;if(e.empty&&!1===this.editor.activeMarks.includes("link")&&this.editor.insertText(t.href,!0),t.href)return this.update(t)},removeLink:()=>this.remove(),toggleLink:(t={})=>{var e;(null==(e=t.href)?void 0:e.length)>0?this.editor.command("insertLink",t):this.editor.command("removeLink")}}}get defaults(){return{target:null}}get name(){return"link"}pasteRules({type:t,utils:e}){return[e.pasteRule(/https?:\/\/(www\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z]{2,}\b([-a-zA-Z0-9@:%_+.~#?&//=,]*)/gi,t,(t=>({href:t})))]}plugins(){return[{props:{handleClick:(t,e,i)=>{const n=this.editor.getMarkAttrs("link");n.href&&!0===i.altKey&&i.target instanceof HTMLAnchorElement&&(i.stopPropagation(),window.open(n.href,n.target))}}}]}get schema(){return{attrs:{href:{default:null},target:{default:null},title:{default:null}},inclusive:!1,parseDOM:[{tag:"a[href]:not([href^='mailto:'])",getAttrs:t=>({href:t.getAttribute("href"),target:t.getAttribute("target"),title:t.getAttribute("title")})}],toDOM:t=>["a",{...t.attrs},0]}}};class vn extends pn{get button(){return{icon:"strikethrough",label:window.panel.$t("toolbar.button.strike")}}commands(){return()=>this.toggle()}inputRules({type:t,utils:e}){return[e.markInputRule(/~([^~]+)~$/,t)]}keys(){return{"Mod-d":()=>this.toggle()}}get name(){return"strike"}pasteRules({type:t,utils:e}){return[e.markPasteRule(/~([^~]+)~/g,t)]}get schema(){return{parseDOM:[{tag:"s"},{tag:"del"},{tag:"strike"},{style:"text-decoration",getAttrs:t=>"line-through"===t}],toDOM:()=>["s",0]}}}let yn=class extends pn{get button(){return{icon:"superscript",label:window.panel.$t("toolbar.button.sup")}}commands(){return()=>this.toggle()}get name(){return"sup"}get schema(){return{parseDOM:[{tag:"sup"}],toDOM:()=>["sup",0]}}};class $n extends pn{get button(){return{icon:"subscript",label:window.panel.$t("toolbar.button.sub")}}commands(){return()=>this.toggle()}get name(){return"sub"}get schema(){return{parseDOM:[{tag:"sub"}],toDOM:()=>["sub",0]}}}class wn extends pn{get button(){return{icon:"underline",label:window.panel.$t("toolbar.button.underline")}}commands(){return()=>this.toggle()}keys(){return{"Mod-u":()=>this.toggle()}}get name(){return"underline"}get schema(){return{parseDOM:[{tag:"u"},{style:"text-decoration",getAttrs:t=>"underline"===t}],toDOM:()=>["u",0]}}}class xn extends an{get button(){return{id:this.name,icon:"list-bullet",label:window.panel.$t("toolbar.button.ul"),name:this.name,when:["listItem","bulletList","orderedList","paragraph"]}}commands({type:t,schema:e,utils:i}){return()=>i.toggleList(t,e.nodes.listItem)}inputRules({type:t,utils:e}){return[e.wrappingInputRule(/^\s*([-+*])\s$/,t)]}keys({type:t,schema:e,utils:i}){return{"Shift-Ctrl-8":i.toggleList(t,e.nodes.listItem)}}get name(){return"bulletList"}get schema(){return{content:"listItem+",group:"block",parseDOM:[{tag:"ul"}],toDOM:()=>["ul",0]}}}class _n extends an{commands({utils:t,type:e}){return()=>this.createHardBreak(t,e)}createHardBreak(t,e){return t.chainCommands(t.exitCode,t.insertNode(e))}get defaults(){return{enter:!1,text:!1}}keys({utils:t,type:e}){const i=this.createHardBreak(t,e);let n={"Mod-Enter":i,"Shift-Enter":i};return this.options.enter&&(n.Enter=i),n}get name(){return"hardBreak"}get schema(){return{inline:!0,group:"inline",selectable:!1,parseDOM:[{tag:"br"}],toDOM:()=>["br"]}}}class Cn extends an{get button(){const t=this.options.levels.map((t=>({id:`h${t}`,command:`h${t}`,icon:`h${t}`,label:window.panel.$t("toolbar.button.heading."+t),attrs:{level:t},name:this.name,when:["heading","paragraph"]})));return t[t.length-1].separator=!0,t}commands({type:t,schema:e,utils:i}){let n={toggleHeading:n=>i.toggleBlockType(t,e.nodes.paragraph,n)};for(const s of this.options.levels)n[`h${s}`]=()=>i.toggleBlockType(t,e.nodes.paragraph,{level:s});return n}get defaults(){return{levels:[1,2,3,4,5,6]}}inputRules({type:t,utils:e}){return this.options.levels.map((i=>e.textblockTypeInputRule(new RegExp(`^(#{1,${i}})\\s$`),t,(()=>({level:i})))))}keys({type:t,utils:e}){return this.options.levels.reduce(((i,n)=>({...i,[`Shift-Ctrl-${n}`]:e.setBlockType(t,{level:n})})),{})}get name(){return"heading"}get schema(){return{attrs:{level:{default:1}},content:"inline*",group:"block",defining:!0,draggable:!1,parseDOM:this.options.levels.map((t=>({tag:`h${t}`,attrs:{level:t}}))),toDOM:t=>[`h${t.attrs.level}`,0]}}}class Sn extends an{commands({type:t,utils:e}){return()=>e.insertNode(t)}inputRules({type:t,utils:e}){const i=e.nodeInputRule(/^(?:---|___\s|\*\*\*\s)$/,t),n=i.handler;return i.handler=(t,e,i,s)=>n(t,e,i,s).replaceWith(i-1,i,""),[i]}get name(){return"horizontalRule"}get schema(){return{group:"block",parseDOM:[{tag:"hr"}],toDOM:()=>["hr"]}}}class On extends an{keys({type:t,utils:e}){return{Enter:e.splitListItem(t),"Shift-Tab":e.liftListItem(t),Tab:e.sinkListItem(t)}}get name(){return"listItem"}get schema(){return{content:"paragraph block*",defining:!0,draggable:!1,parseDOM:[{tag:"li"}],toDOM:()=>["li",0]}}}class Mn extends an{get button(){return{id:this.name,icon:"list-numbers",label:window.panel.$t("toolbar.button.ol"),name:this.name,when:["listItem","bulletList","orderedList","paragraph"],separator:!0}}commands({type:t,schema:e,utils:i}){return()=>i.toggleList(t,e.nodes.listItem)}inputRules({type:t,utils:e}){return[e.wrappingInputRule(/^(\d+)\.\s$/,t,(t=>({order:+t[1]})),((t,e)=>e.childCount+e.attrs.order===+t[1]))]}keys({type:t,schema:e,utils:i}){return{"Shift-Ctrl-9":i.toggleList(t,e.nodes.listItem)}}get name(){return"orderedList"}get schema(){return{attrs:{order:{default:1}},content:"listItem+",group:"block",parseDOM:[{tag:"ol",getAttrs:t=>({order:t.hasAttribute("start")?+t.getAttribute("start"):1})}],toDOM:t=>1===t.attrs.order?["ol",0]:["ol",{start:t.attrs.order},0]}}}class An extends an{get button(){return{id:this.name,icon:"quote",label:window.panel.$t("field.blocks.quote.name"),name:this.name}}commands({type:t,utils:e}){return()=>e.toggleWrap(t)}inputRules({type:t,utils:e}){return[e.wrappingInputRule(/^\s*>\s$/,t)]}keys({utils:t}){return{"Shift-Tab":(e,i)=>t.lift(e,i)}}get name(){return"quote"}get schema(){return{content:"block+",group:"block",defining:!0,draggable:!1,parseDOM:[{tag:"blockquote"}],toDOM:()=>["blockquote",0]}}}let jn=class extends ln{commands(){return{undo:()=>A,redo:()=>j,undoDepth:()=>I,redoDepth:()=>D}}get defaults(){return{depth:"",newGroupDelay:""}}keys(){return{"Mod-z":A,"Mod-y":j,"Shift-Mod-z":j,"Mod-я":A,"Shift-Mod-я":j}}get name(){return"history"}plugins(){return[E({depth:this.options.depth,newGroupDelay:this.options.newGroupDelay})]}};class In extends ln{commands(){return{insertHtml:t=>(e,i)=>{let n=document.createElement("div");n.innerHTML=t.trim();const s=y.fromSchema(e.schema).parse(n);i(e.tr.replaceSelectionWith(s).scrollIntoView())}}}}class Dn extends ln{keys(){const t={};for(const e in this.options)t[e]=()=>(this.options[e](),!0);return t}}let En=class extends ln{constructor(t){super(),this.writer=t}get component(){return this.writer.$refs.toolbar}init(){this.editor.on("deselect",(({event:t})=>{var e;return null==(e=this.component)?void 0:e.close(t)})),this.editor.on("select",(({hasChanged:t})=>{var e;!1!==t&&(null==(e=this.component)||e.open())}))}get type(){return"toolbar"}};const Tn={mixins:[V,W,lt,rt],props:{breaks:Boolean,code:Boolean,emptyDocument:{type:Object,default:()=>({type:"doc",content:[]})},extensions:Array,headings:{default:()=>[1,2,3,4,5,6],type:[Array,Boolean]},inline:Boolean,keys:Object,marks:{type:[Array,Boolean],default:!0},nodes:{type:[Array,Boolean],default:()=>["heading","bulletList","orderedList"]},paste:{type:Function,default:()=>()=>!1},toolbar:{type:Object,default:()=>({inline:!0})},value:{type:String,default:""}}};const Ln=ut({mixins:[Tn],emits:["input"],data(){return{editor:null,json:{},html:this.value,isEmpty:!0}},computed:{isCursorAtEnd(){return this.editor.selectionIsAtEnd},isCursorAtStart(){return this.editor.selectionIsAtStart},toolbarOptions(){return{marks:Array.isArray(this.marks)?this.marks:void 0,...this.toolbar,editor:this.editor}}},watch:{value(t,e){t!==e&&t!==this.html&&(this.html=t,this.editor.setContent(this.html))}},mounted(){this.editor=new dn({autofocus:this.autofocus,content:this.value,editable:!this.disabled,element:this.$el,emptyDocument:this.emptyDocument,parseOptions:{preserveWhitespace:!0},events:{link:t=>{this.$panel.dialog.open({component:"k-link-dialog",props:{value:t.getMarkAttrs("link")},on:{cancel:()=>t.focus(),submit:e=>{this.$panel.dialog.close(),t.command("toggleLink",e)}}})},email:t=>{this.$panel.dialog.open({component:"k-email-dialog",props:{value:this.editor.getMarkAttrs("email")},on:{cancel:()=>t.focus(),submit:e=>{this.$panel.dialog.close(),t.command("toggleEmail",e)}}})},paste:this.paste,update:t=>{if(!this.editor)return;const e=JSON.stringify(this.editor.getJSON());e!==JSON.stringify(this.json)&&(this.json=e,this.isEmpty=t.editor.isEmpty(),this.html=t.editor.getHTML(),this.isEmpty&&(0===t.editor.activeNodes.length||t.editor.activeNodes.includes("paragraph"))&&(this.html=""),this.$emit("input",this.html))}},extensions:[...this.createMarks(),...this.createNodes(),new Dn(this.keys),new jn,new In,new En(this),...this.extensions||[]],inline:this.inline}),this.isEmpty=this.editor.isEmpty(),this.json=this.editor.getJSON(),this.$panel.events.on("click",this.onBlur),this.$panel.events.on("focus",this.onBlur)},beforeDestroy(){this.editor.destroy(),this.$panel.events.off("click",this.onBlur),this.$panel.events.off("focus",this.onBlur)},methods:{command(t,...e){this.editor.command(t,...e)},createMarks(){return this.filterExtensions({clear:new mn,code:new fn,underline:new wn,strike:new vn,link:new bn,email:new gn,bold:new hn,italic:new kn,sup:new yn,sub:new $n,...this.createMarksFromPanelPlugins()},this.marks)},createMarksFromPanelPlugins(){const t=window.panel.plugins.writerMarks??{},e={};for(const i in t)e[i]=Object.create(pn.prototype,Object.getOwnPropertyDescriptors({name:i,...t[i]}));return e},createNodes(){const t=new _n({text:!0,enter:this.inline});return this.filterExtensions({bulletList:new xn,orderedList:new Mn,heading:new Cn({levels:this.headings}),horizontalRule:new Sn,listItem:new On,quote:new An,...this.createNodesFromPanelPlugins()},this.nodes,((e,i)=>((e.includes("bulletList")||e.includes("orderedList"))&&i.push(new On),!0===this.inline&&(i=i.filter((t=>!0===t.schema.inline))),i.push(t),i)))},createNodesFromPanelPlugins(){const t=window.panel.plugins.writerNodes??{},e={};for(const i in t)e[i]=Object.create(an.prototype,Object.getOwnPropertyDescriptors({name:i,...t[i]}));return e},getHTML(){return this.editor.getHTML()},filterExtensions(t,e,i){!1===e?e=[]:!0!==e&&!1!==Array.isArray(e)||(e=Object.keys(t));let n=[];for(const s in t)e.includes(s)&&n.push(t[s]);return"function"==typeof i&&(n=i(e,n)),n},focus(){this.editor.focus()},getSplitContent(){return this.editor.getHTMLStartToSelectionToEnd()},onBlur(t){var e;!1===this.$el.contains(t.target)&&(null==(e=this.$refs.toolbar)||e.close())},onCommand(t,...e){this.editor.command(t,...e)}}},(function(){var t=this,e=t._self._c;return e("div",{directives:[{name:"direction",rawName:"v-direction"}],ref:"editor",staticClass:"k-writer",attrs:{"data-disabled":t.disabled,"data-empty":t.isEmpty,"data-placeholder":t.placeholder,"data-toolbar-inline":Boolean(t.toolbar.inline??!0),spellcheck:t.spellcheck}},[t.editor&&!t.disabled?e("k-writer-toolbar",t._b({ref:"toolbar",on:{command:t.onCommand}},"k-writer-toolbar",t.toolbarOptions,!1)):t._e()],1)}),[],!1,null,null,null,null).exports,Bn={mixins:[je,Tn,et,it]};const qn=ut({mixins:[Ie,Bn],computed:{counterValue(){const t=this.$helper.string.stripHTML(this.value??"");return this.$helper.string.unescapeHTML(t)}},watch:{value(){this.onInvalid()}},mounted(){this.onInvalid(),this.$props.autofocus&&this.focus()},methods:{focus(){this.$refs.input.focus()},onInvalid(){this.$emit("invalid",this.$v.$invalid,this.$v)}},validations(){return{counterValue:{required:!this.required||t.required,minLength:!this.minlength||t.minLength(this.minlength),maxLength:!this.maxlength||t.maxLength(this.maxlength)}}}},(function(){var t=this;return(0,t._self._c)("k-writer",t._b({ref:"input",staticClass:"k-writer-input",on:{input:function(e){return t.$emit("input",e)}}},"k-writer",t.$props,!1))}),[],!1,null,null,null,null).exports;class Pn extends rn{get schema(){return{content:this.options.nodes.join("|")}}}const Nn={mixins:[Bn],inheritAttrs:!1,props:{nodes:{type:Array,default:()=>["bulletList","orderedList"]}}};const zn=ut({mixins:[Ie,Nn],data(){return{list:this.value,html:this.value}},computed:{listExtensions(){return[new Pn({inline:!0,nodes:this.nodes})]}},watch:{value(t){t!==this.html&&(this.list=t,this.html=t)}},methods:{focus(){this.$refs.input.focus()},onInput(t){let e=(new DOMParser).parseFromString(t,"text/html").querySelector("ul, ol");e&&0!==e.textContent.trim().length?(this.list=t,this.html=t.replace(/(

      |<\/p>)/gi,""),this.$emit("input",this.html)):this.$emit("input",this.list="")}}},(function(){var t=this;return(0,t._self._c)("k-writer",t._b({ref:"input",staticClass:"k-list-input",attrs:{extensions:t.listExtensions,value:t.list},on:{input:t.onInput}},"k-writer",t.$props,!1))}),[],!1,null,null,null,null).exports;const Fn=ut({mixins:[Fe,Ue,Nn],inheritAttrs:!1,methods:{focus(){this.$refs.input.focus()}}},(function(){var t=this,e=t._self._c;return e("k-field",t._b({staticClass:"k-list-field",attrs:{input:t.id,counter:!1}},"k-field",t.$props,!1),[e("k-input",t._b({ref:"input",attrs:{type:"list"},on:{input:function(e){return t.$emit("input",e)}}},"k-input",t.$props,!1))],1)}),[],!1,null,null,null,null).exports,Yn={mixins:[W,X,st],inheritAttrs:!1,props:{layout:String,sort:{default:!1,type:Boolean},value:{default:()=>[],type:Array}}};const Rn=ut({mixins:[Yn],props:{draggable:{default:!0,type:Boolean}},emits:["edit","input"],data:()=>({tags:[]}),computed:{dragOptions(){return{delay:1,disabled:!this.isDraggable,draggable:".k-tag",handle:".k-tag-text"}},isDraggable(){return!0!==this.sort&&!1!==this.draggable&&0!==this.tags.length&&!0!==this.disabled}},watch:{value:{handler(){let t=structuredClone(this.value);if(!0===this.sort){const e=[];for(const i of this.options){const n=t.indexOf(i.value);-1!==n&&(e.push(i),t.splice(n,1))}e.push(...t),t=e}this.tags=t.map(this.tag).filter((t=>t))},immediate:!0}},methods:{edit(t,e,i){!1===this.disabled&&this.$emit("edit",t,e,i)},focus(t="last"){this.$refs.navigate.move(t)},index(t){return this.tags.findIndex((e=>e.value===t.value))},input(){this.$emit("input",this.tags.map((t=>t.value)))},navigate(t){this.focus(t)},remove(t){this.tags.length<=1?this.navigate("last"):this.navigate("prev"),this.tags.splice(t,1),this.input()},option(t){return this.options.find((e=>e.value===t.value))},select(){this.focus()},tag(t){"object"!=typeof t&&(t={value:t});const e=this.option(t);return e||{text:this.$helper.string.escapeHTML(t.text??t.value),value:t.value}}}},(function(){var t=this,e=t._self._c;return e("k-navigate",{ref:"navigate",attrs:{axis:"list"===t.layout?"y":"x",select:":where(.k-tag, .k-tags-navigatable):not(:disabled)"}},[e("k-draggable",{staticClass:"k-tags",attrs:{list:t.tags,options:t.dragOptions,"data-layout":t.layout},on:{end:t.input},scopedSlots:t._u([{key:"footer",fn:function(){return[t._t("default")]},proxy:!0}],null,!0)},t._l(t.tags,(function(i,n){return e("k-tag",{key:n,attrs:{disabled:t.disabled,image:i.image,removable:!t.disabled,name:"tag"},on:{remove:function(e){return t.remove(n,i)}},nativeOn:{click:function(t){t.stopPropagation()},keypress:function(e){return!e.type.indexOf("key")&&t._k(e.keyCode,"enter",13,e.key,"Enter")?null:t.edit(n,i,e)},dblclick:function(e){return t.edit(n,i,e)}}},[e("span",{domProps:{innerHTML:t._s(i.text)}})])})),1)],1)}),[],!1,null,null,null,null).exports,Un={mixins:[nt,at,Yn,De],props:{value:{default:()=>[],type:Array}},watch:{value:{handler(){this.$emit("invalid",this.$v.$invalid,this.$v)},immediate:!0}},validations(){return{value:{required:!this.required||t.required,minLength:!this.min||t.minLength(this.min),maxLength:!this.max||t.maxLength(this.max)}}},methods:{open(){this.$refs.dropdown.open(this.$el)}}};const Hn=ut({mixins:[Ie,Un]},(function(){var t=this,e=t._self._c;return e("div",{staticClass:"k-multiselect-input"},[e("k-tags",t._b({ref:"tags",on:{input:function(e){return t.$emit("input",e)}},nativeOn:{click:function(e){return e.stopPropagation(),t.open.apply(null,arguments)}}},"k-tags",t.$props,!1),[!t.max||t.value.length({editing:null}),computed:{creatableOptions(){return this.options.filter((t=>!1===this.value.includes(t.value)))},picklist(){return{disabled:this.disabled,create:this.showCreate,ignore:this.ignore,min:this.min,max:this.max,search:this.showSearch}},replacableOptions(){return this.options.filter((t=>{var e;return!1===this.value.includes(t.value)||t.value===(null==(e=this.editing)?void 0:e.tag.value)}))},showCreate(){return"options"!==this.accept&&(!this.editing||{submit:this.$t("replace.with")})},showSearch(){return!1!==this.search&&(this.editing?{placeholder:this.$t("replace.with"),...this.search}:"options"===this.accept?{placeholder:this.$t("filter"),...this.search}:this.search)}},methods:{create(t){const e=t.split(this.separator).map((t=>t.trim())),i=structuredClone(this.value);for(let n of e)n=this.$refs.tags.tag(n,this.separator),!0===this.isAllowed(n)&&i.push(n.value);this.$emit("input",i),this.$refs.create.close()},async edit(t,e){this.editing={index:t,tag:e},this.$refs.replace.open()},focus(){this.$refs.create.open()},isAllowed(t){return"object"==typeof t&&0!==t.value.trim().length&&(!("options"===this.accept&&!this.$refs.tags.option(t))&&!0!==this.value.includes(t.value))},pick(t){this.$emit("input",t),this.$refs.create.close()},replace(t){const{index:e}=this.editing,i=this.$refs.tags.tag(t);if(this.$refs.replace.close(),this.editing=null,!1===this.isAllowed(i))return!1;const n=structuredClone(this.value);n.splice(e,1,i.value),this.$emit("input",n),this.$refs.tags.navigate(e)},toggle(t){return!(t.metaKey||t.altKey||t.ctrlKey)&&("ArrowDown"===t.key?(this.$refs.create.open(),void t.preventDefault()):void(String.fromCharCode(t.keyCode).match(/(\w)/g)&&this.$refs.create.open()))}}},(function(){var t,e=this,i=e._self._c;return i("div",{staticClass:"k-tags-input"},[i("k-tags",e._b({ref:"tags",on:{edit:e.edit,input:function(t){return e.$emit("input",t)}},nativeOn:{click:function(t){var i,n;t.stopPropagation(),null==(n=null==(i=e.$refs.toggle)?void 0:i.$el)||n.click()}}},"k-tags",e.$props,!1),[!e.max||e.value.lengththis.onInput(t.target.value),blur:this.onBlur}}},watch:{value(t){this.number=t},number:{immediate:!0,handler(){this.onInvalid()}}},mounted(){this.$props.autofocus&&this.focus(),this.$props.preselect&&this.select()},methods:{decimals(){const t=Number(this.step??0);return Math.floor(t)===t?0:-1!==t.toString().indexOf("e")?parseInt(t.toFixed(16).split(".")[1].split("").reverse().join("")).toString().length:t.toString().split(".")[1].length??0},format(t){if(isNaN(t)||""===t)return"";const e=this.decimals();return t=e?parseFloat(t).toFixed(e):Number.isInteger(this.step)?parseInt(t):parseFloat(t)},clean(){this.number=this.format(this.number)},emit(t){t=parseFloat(t),isNaN(t)&&(t=""),t!==this.value&&this.$emit("input",t)},onInvalid(){this.$emit("invalid",this.$v.$invalid,this.$v)},onInput(t){this.number=t,this.emit(t)},onBlur(){this.clean(),this.emit(this.number)},select(){this.$refs.input.select()}},validations(){return{value:{required:!this.required||t.required,min:!this.min||t.minValue(this.min),max:!this.max||t.maxValue(this.max)}}}},(function(){var t=this;return(0,t._self._c)("input",t._g(t._b({ref:"input",staticClass:"k-number-input",attrs:{step:t.stepNumber,type:"number"},domProps:{value:t.number},on:{keydown:[function(e){return!e.type.indexOf("key")&&t._k(e.keyCode,"s",void 0,e.key,void 0)?null:e.ctrlKey?t.clean.apply(null,arguments):null},function(e){return!e.type.indexOf("key")&&t._k(e.keyCode,"s",void 0,e.key,void 0)?null:e.metaKey?t.clean.apply(null,arguments):null}]}},"input",{autofocus:t.autofocus,disabled:t.disabled,id:t.id,max:t.max,min:t.min,name:t.name,placeholder:t.placeholder,required:t.required},!1),t.listeners))}),[],!1,null,null,null,null).exports;const Zn=ut({mixins:[Fe,Ue,Gn],inheritAttrs:!1,methods:{focus(){this.$refs.input.focus()}}},(function(){var t=this,e=t._self._c;return e("k-field",t._b({staticClass:"k-number-field",attrs:{input:t.id}},"k-field",t.$props,!1),[e("k-input",t._g(t._b({ref:"input",attrs:{type:"number"}},"k-input",t.$props,!1),t.$listeners))],1)}),[],!1,null,null,null,null).exports;const Qn=ut({mixins:[Fe,Ue],props:{empty:String,fields:[Object,Array],value:[String,Object]},data:()=>({object:{}}),computed:{hasFields(){return this.$helper.object.length(this.fields)>0},isEmpty(){return null===this.object||0===this.$helper.object.length(this.object)},isInvalid(){return!0===this.required&&this.isEmpty}},watch:{value:{handler(t){this.object=this.valueToObject(t)},immediate:!0}},methods:{add(){this.object=this.$helper.field.form(this.fields),this.save(),this.open()},cell(t,e){this.$set(this.object,t,e),this.save()},form(t){const e=this.$helper.field.subfields(this,this.fields);if(t)for(const i in e)e[i].autofocus=i===t;return e},remove(){this.object={},this.save()},open(t){if(this.disabled)return!1;this.$panel.drawer.open({component:"k-form-drawer",props:{breadcrumb:[],icon:"box",tab:"object",tabs:{object:{fields:this.form(t)}},title:this.label,value:this.object},on:{input:t=>{for(const e in t)this.$set(this.object,e,t[e]);this.save()}}})},save(){this.$emit("input",this.object)},valueToObject:t=>"object"!=typeof t?{}:t}},(function(){var t=this,e=t._self._c;return e("k-field",t._b({staticClass:"k-object-field",scopedSlots:t._u([!t.disabled&&t.hasFields?{key:"options",fn:function(){return[t.isEmpty?e("k-button",{attrs:{icon:"add",size:"xs",variant:"filled"},on:{click:t.add}}):e("k-button",{attrs:{icon:"remove",size:"xs",variant:"filled"},on:{click:t.remove}})]},proxy:!0}:null],null,!0)},"k-field",t.$props,!1),[t.hasFields?[t.isEmpty?e("k-empty",{attrs:{"data-invalid":t.isInvalid,icon:"box"},on:{click:t.add}},[t._v(" "+t._s(t.empty??t.$t("field.object.empty"))+" ")]):e("table",{staticClass:"k-table k-object-field-table",attrs:{"aria-disabled":t.disabled,"data-invalid":t.isInvalid}},[e("tbody",[t._l(t.fields,(function(i){return[i.saveable&&t.$helper.field.isVisible(i,t.value)?e("tr",{key:i.name,on:{click:function(e){return t.open(i.name)}}},[e("th",{attrs:{"data-has-button":"","data-mobile":"true"}},[e("button",{attrs:{type:"button"}},[t._v(t._s(i.label))])]),e("k-table-cell",{attrs:{column:i,field:i,mobile:!0,value:t.object[i.name]},on:{input:function(e){return t.cell(i.name,e)}}})],1):t._e()]}))],2)])]:[e("k-empty",{attrs:{icon:"box"}},[t._v(t._s(t.$t("fields.empty")))])]],2)}),[],!1,null,null,null,null).exports;const ts=ut({extends:qi,type:"pages",computed:{emptyProps(){return{icon:"page",text:this.empty??this.$t("field.pages.empty")}}}},null,null,!1,null,null,null,null).exports,es={mixins:[Di],props:{autocomplete:{type:String,default:"new-password"},type:{type:String,default:"password"}}};const is=ut({extends:Ei,mixins:[es]},null,null,!1,null,null,null,null).exports;const ns=ut({mixins:[Fe,Ue,es,$i],inheritAttrs:!1,props:{minlength:{type:Number,default:8},icon:{type:String,default:"key"}},methods:{focus(){this.$refs.input.focus()}}},(function(){var t=this,e=t._self._c;return e("k-field",t._b({staticClass:"k-password-field",attrs:{input:t.id,counter:t.counterOptions},scopedSlots:t._u([{key:"options",fn:function(){return[t._t("options")]},proxy:!0}],null,!0)},"k-field",t.$props,!1),[e("k-input",t._g(t._b({ref:"input",attrs:{type:"password"}},"k-input",t.$props,!1),t.$listeners))],1)}),[],!1,null,null,null,null).exports,ss={mixins:[je,st],props:{columns:Number,reset:{default:!0,type:Boolean},theme:String,value:[String,Number,Boolean]}};const os=ut({mixins:[Ie,ss],computed:{choices(){return this.options.map(((t,e)=>({autofocus:this.autofocus&&0===e,checked:this.value===t.value,disabled:this.disabled||t.disabled,id:`${this.id}-${e}`,info:t.info,label:t.text,name:this.name??this.id,type:"radio",value:t.value})))}},watch:{value:{handler(){this.validate()},immediate:!0}},methods:{focus(){var t;null==(t=this.$el.querySelector("input"))||t.focus()},select(){this.focus()},toggle(t){t===this.value&&this.reset&&!this.required&&this.$emit("input","")},validate(){this.$emit("invalid",this.$v.$invalid,this.$v)}},validations(){return{value:{required:!this.required||t.required}}}},(function(){var t=this,e=t._self._c;return e("ul",{staticClass:"k-radio-input k-grid",style:{"--columns":t.columns},attrs:{"data-variant":"choices"}},t._l(t.choices,(function(i,n){return e("li",{key:n},[e("k-choice-input",t._b({on:{input:function(e){return t.$emit("input",i.value)}},nativeOn:{click:function(e){return e.stopPropagation(),t.toggle(i.value)}}},"k-choice-input",i,!1))],1)})),0)}),[],!1,null,null,null,null).exports;const ls=ut({mixins:[Fe,Ue,ss],inheritAttrs:!1,methods:{focus(){this.$refs.input.focus()}}},(function(){var t,e=this,i=e._self._c;return i("k-field",e._b({staticClass:"k-radio-field",attrs:{input:e.id+"-0"}},"k-field",e.$props,!1),[(null==(t=e.options)?void 0:t.length)?i("k-radio-input",e._g(e._b({ref:"input"},"k-radio-input",e.$props,!1),e.$listeners)):i("k-empty",{attrs:{text:e.$t("options.none"),icon:"checklist"}})],1)}),[],!1,null,null,null,null).exports,as={mixins:[je],props:{default:[Number,String],max:{type:Number,default:100},min:{type:Number,default:0},step:{type:[Number,String],default:1},tooltip:{type:[Boolean,Object],default:()=>({before:null,after:null})},value:[Number,String]}};const rs=ut({mixins:[Ie,as],computed:{baseline(){return this.min<0?0:this.min},isEmpty(){return""===this.value||void 0===this.value||null===this.value},label(){return this.required||this.value||0===this.value?this.format(this.position):"–"},position(){return this.value||0===this.value?this.value:this.default??this.baseline}},watch:{position(){this.onInvalid()},value(){this.validate()}},mounted(){this.onInvalid(),this.validate(),this.$props.autofocus&&this.focus()},methods:{focus(){var t;null==(t=this.$el.querySelector("input"))||t.focus()},format(t){const e=document.lang?document.lang.replace("_","-"):"en",i=this.step.toString().split("."),n=i.length>1?i[1].length:0;return new Intl.NumberFormat(e,{minimumFractionDigits:n}).format(t)},onInvalid(){this.$emit("invalid",this.$v.$invalid,this.$v)},onInput(t){this.$emit("input",t)},validate(){var t;const e=[];this.required&&!0===this.isEmpty&&e.push(this.$t("error.validation.required")),!1===this.isEmpty&&this.min&&this.valuethis.max&&e.push(this.$t("error.validation.max",{max:this.max})),null==(t=this.$refs.range)||t.setCustomValidity(e.join(", "))}},validations(){return{position:{required:!this.required||t.required,min:!this.min||t.minValue(this.min),max:!this.max||t.maxValue(this.max)}}}},(function(){var t=this,e=t._self._c;return e("div",{staticClass:"k-range-input",attrs:{"data-disabled":t.disabled}},[e("input",t._b({ref:"range",attrs:{type:"range"},domProps:{value:t.position},on:{input:function(e){return t.$emit("input",e.target.valueAsNumber)}}},"input",{autofocus:t.autofocus,disabled:t.disabled,id:t.id,max:t.max,min:t.min,name:t.name,required:t.required,step:t.step},!1)),t.tooltip?e("output",{staticClass:"k-range-input-tooltip",attrs:{for:t.id}},[t.tooltip.before?e("span",{staticClass:"k-range-input-tooltip-before"},[t._v(t._s(t.tooltip.before))]):t._e(),e("span",{staticClass:"k-range-input-tooltip-text"},[t._v(t._s(t.label))]),t.tooltip.after?e("span",{staticClass:"k-range-input-tooltip-after"},[t._v(t._s(t.tooltip.after))]):t._e()]):t._e()])}),[],!1,null,null,null,null).exports;const us=ut({mixins:[Ue,Fe,as],inheritAttrs:!1,methods:{focus(){this.$refs.input.focus()}}},(function(){var t=this,e=t._self._c;return e("k-field",t._b({staticClass:"k-range-field",attrs:{input:t.id}},"k-field",t.$props,!1),[e("k-input",t._g(t._b({ref:"input",attrs:{type:"range"}},"k-input",t.$props,!1),t.$listeners))],1)}),[],!1,null,null,null,null).exports,cs={mixins:[je,st,lt],props:{ariaLabel:String,default:String,empty:{type:[Boolean,String],default:!0},value:{type:[String,Number,Boolean],default:""}}};const ds=ut({mixins:[Ie,cs],emits:["click","input"],data(){return{selected:this.value,listeners:{...this.$listeners,click:t=>this.onClick(t),change:t=>this.onInput(t.target.value),input:()=>{}}}},computed:{emptyOption(){return this.placeholder??"—"},hasEmptyOption(){return!1!==this.empty&&!(this.required&&this.default)},isEmpty(){return null===this.selected||void 0===this.selected||""===this.selected},label(){const t=this.text(this.selected);return""===this.selected||null===this.selected||null===t?this.emptyOption:t}},watch:{value(t){this.selected=t,this.onInvalid()}},mounted(){this.onInvalid(),this.$props.autofocus&&this.focus()},methods:{focus(){this.$refs.input.focus()},onClick(t){t.stopPropagation(),this.$emit("click",t)},onInvalid(){this.$emit("invalid",this.$v.$invalid,this.$v)},onInput(t){this.selected=t,this.$emit("input",this.selected)},select(){this.focus()},text(t){let e=null;for(const i of this.options)i.value==t&&(e=i.text);return e}},validations(){return{selected:{required:!this.required||t.required}}}},(function(){var t=this,e=t._self._c;return e("span",{staticClass:"k-select-input",attrs:{"data-disabled":t.disabled,"data-empty":t.isEmpty}},[e("select",t._g({ref:"input",staticClass:"k-select-input-native",attrs:{id:t.id,autofocus:t.autofocus,"aria-label":t.ariaLabel,disabled:t.disabled,name:t.name,required:t.required},domProps:{value:t.selected}},t.listeners),[t.hasEmptyOption?e("option",{attrs:{disabled:t.required,value:""}},[t._v(" "+t._s(t.emptyOption)+" ")]):t._e(),t._l(t.options,(function(i){return e("option",{key:i.value,attrs:{disabled:i.disabled},domProps:{value:i.value}},[t._v(" "+t._s(i.text)+" ")])}))],2),t._v(" "+t._s(t.label)+" ")])}),[],!1,null,null,null,null).exports;const ps=ut({mixins:[Fe,Ue,cs],inheritAttrs:!1,props:{icon:{type:String,default:"angle-down"}},methods:{focus(){this.$refs.input.focus()}}},(function(){var t=this,e=t._self._c;return e("k-field",t._b({staticClass:"k-select-field",attrs:{input:t.id}},"k-field",t.$props,!1),[e("k-input",t._g(t._b({ref:"input",attrs:{type:"select"}},"k-input",t.$props,!1),t.$listeners))],1)}),[],!1,null,null,null,null).exports,hs={mixins:[Di],props:{allow:{type:String,default:""},formData:{type:Object,default:()=>({})},sync:{type:String}}};const ms=ut({extends:Ei,mixins:[hs],data(){return{slug:this.sluggify(this.value),slugs:this.$panel.language.rules??this.$panel.system.slugs,syncValue:null}},watch:{formData:{handler(t){return!this.disabled&&(!(!this.sync||void 0===t[this.sync])&&(t[this.sync]!=this.syncValue&&(this.syncValue=t[this.sync],void this.onInput(this.sluggify(this.syncValue)))))},deep:!0,immediate:!0},value(t){(t=this.sluggify(t))!==this.slug&&(this.slug=t,this.$emit("input",this.slug))}},methods:{sluggify(t){return this.$helper.slug(t,[this.slugs,this.$panel.system.ascii],this.allow)},onInput(t){this.slug=this.sluggify(t),this.$emit("input",this.slug)}}},(function(){var t=this;return(0,t._self._c)("input",t._g(t._b({directives:[{name:"direction",rawName:"v-direction"}],ref:"input",staticClass:"k-text-input",attrs:{autocomplete:"off",spellcheck:"false",type:"text"},domProps:{value:t.slug}},"input",{autofocus:t.autofocus,disabled:t.disabled,id:t.id,minlength:t.minlength,name:t.name,pattern:t.pattern,placeholder:t.placeholder,required:t.required},!1),t.listeners))}),[],!1,null,null,null,null).exports;const fs=ut({mixins:[Fe,Ue,hs],inheritAttrs:!1,props:{icon:{type:String,default:"url"},path:{type:String},wizard:{type:[Boolean,Object],default:!1}},data(){return{slug:this.value}},computed:{preview(){return void 0!==this.help?this.help:void 0!==this.path?this.path+this.value:null}},watch:{value(){this.slug=this.value}},methods:{focus(){this.$refs.input.focus()},onWizard(){var t;let e=null==(t=this.wizard)?void 0:t.field;if(e){const t=this.formData[e.toLowerCase()];t&&(this.slug=t)}}}},(function(){var t=this,e=t._self._c;return e("k-field",t._b({staticClass:"k-slug-field",attrs:{input:t.id,help:t.preview},scopedSlots:t._u([t.wizard&&t.wizard.text?{key:"options",fn:function(){return[e("k-button",{attrs:{text:t.wizard.text,icon:"sparkling",size:"xs",variant:"filled"},on:{click:t.onWizard}})]},proxy:!0}:null],null,!0)},"k-field",t.$props,!1),[e("k-input",t._g(t._b({ref:"input",attrs:{value:t.slug,type:"slug"}},"k-input",t.$props,!1),t.$listeners))],1)}),[],!1,null,null,null,null).exports;const gs=ut({mixins:[Fe],inheritAttrs:!1,props:{autofocus:Boolean,columns:Object,duplicate:{type:Boolean,default:!0},empty:String,fields:[Array,Object],limit:Number,max:Number,min:Number,prepend:{type:Boolean,default:!1},sortable:{type:Boolean,default:!0},sortBy:String,value:{type:Array,default:()=>[]}},data:()=>({items:[],page:1}),computed:{dragOptions(){return{disabled:!this.isSortable,fallbackClass:"k-sortable-row-fallback"}},index(){return this.limit?(this.page-1)*this.limit+1:1},more(){return!0!==this.disabled&&!(this.max&&this.items.length>=this.max)},hasFields(){return this.$helper.object.length(this.fields)>0},isInvalid(){return!0!==this.disabled&&(!!(this.min&&this.items.lengththis.max))},isSortable(){return!this.sortBy&&(!this.limit&&(!0!==this.disabled&&(!(this.items.length<=1)&&!1!==this.sortable)))},pagination(){let t=0;return this.limit&&(t=(this.page-1)*this.limit),{page:this.page,offset:t,limit:this.limit,total:this.items.length,align:"center",details:!0}},options(){if(this.disabled)return[];let t=[],e=this.duplicate&&this.more;return t.push({icon:"edit",text:this.$t("edit"),click:"edit"}),t.push({disabled:!e,icon:"copy",text:this.$t("duplicate"),click:"duplicate"}),t.push("-"),t.push({icon:"trash",text:e?this.$t("delete"):null,click:"remove"}),t},paginatedItems(){return this.limit?this.items.slice(this.pagination.offset,this.pagination.offset+this.limit):this.items}},watch:{value:{handler(t){t!==this.items&&(this.items=this.toItems(t))},immediate:!0}},methods:{add(t=null){if(!1===this.more)return!1;(t=t??this.$helper.field.form(this.fields))._id=t._id??this.$helper.uuid(),!0===this.prepend?this.items.unshift(t):this.items.push(t),this.save(),this.open(t)},close(){this.$panel.drawer.close(this.id)},focus(){var t,e;null==(e=null==(t=this.$refs.add)?void 0:t.focus)||e.call(t)},form(t){const e=this.$helper.field.subfields(this,this.fields);if(t)for(const i in e)e[i].autofocus=i===t;return e},findIndex(t){return this.items.findIndex((e=>e._id===t._id))},navigate(t,e){const i=this.findIndex(t);!0!==this.disabled&&-1!==i&&this.open(this.items[i+e],null,!0)},open(t,e,i=!1){const n=this.findIndex(t);if(!0===this.disabled||-1===n)return!1;this.$panel.drawer.open({component:"k-structure-drawer",id:this.id,props:{icon:this.icon??"list-bullet",next:this.items[n+1],prev:this.items[n-1],tabs:{content:{fields:this.form(e)}},title:this.label,value:t},replace:i,on:{input:e=>{const i=this.findIndex(t);this.$panel.drawer.props.next=this.items[i+1],this.$panel.drawer.props.prev=this.items[i-1],this.$set(this.items,i,e),this.save()},next:()=>{this.navigate(t,1)},prev:()=>{this.navigate(t,-1)},remove:()=>{this.remove(t)}}})},option(t,e){switch(t){case"remove":this.remove(e);break;case"duplicate":this.add({...structuredClone(e),_id:this.$helper.uuid()});break;case"edit":this.open(e)}},paginate({page:t}){this.page=t},remove(t){const e=this.findIndex(t);this.disabled||-1===e||this.$panel.dialog.open({component:"k-remove-dialog",props:{text:this.$t("field.structure.delete.confirm")},on:{submit:()=>{this.items.splice(e,1),this.save(),this.$panel.dialog.close(),this.close(),0===this.paginatedItems.length&&this.page>1&&this.page--}}})},removeAll(){this.$panel.dialog.open({component:"k-remove-dialog",props:{text:this.$t("field.structure.delete.confirm.all")},on:{submit:()=>{this.page=1,this.items=[],this.save(),this.$panel.dialog.close()}}})},save(t=this.items){this.$emit("input",t)},sort(t){return this.sortBy?this.$helper.array.sortBy(t,this.sortBy):t},toItems(t){return!1===Array.isArray(t)?[]:(t=t.map((t=>({_id:t._id??this.$helper.uuid(),...t}))),this.sort(t))}}},(function(){var t=this,e=t._self._c;return e("k-field",t._b({staticClass:"k-structure-field",nativeOn:{click:function(t){t.stopPropagation()}},scopedSlots:t._u([t.hasFields&&!t.disabled?{key:"options",fn:function(){return[e("k-button-group",{attrs:{layout:"collapsed"}},[e("k-button",{attrs:{autofocus:t.autofocus,disabled:!t.more,responsive:!0,text:t.$t("add"),icon:"add",variant:"filled",size:"xs"},on:{click:function(e){return t.add()}}}),e("k-button",{attrs:{icon:"dots",size:"xs",variant:"filled"},on:{click:function(e){return t.$refs.options.toggle()}}}),e("k-dropdown-content",{ref:"options",attrs:{options:[{click:()=>t.add(),disabled:!t.more,icon:"add",text:t.$t("add")},{click:()=>t.removeAll(),disabled:0===t.items.length||t.disabled,icon:"trash",text:t.$t("delete.all")}],"align-x":"end"}})],1)]},proxy:!0}:null],null,!0)},"k-field",t.$props,!1),[t.hasFields?[0===t.items.length?e("k-empty",{attrs:{"data-invalid":t.isInvalid,icon:"list-bullet"},on:{click:function(e){return t.add()}}},[t._v(" "+t._s(t.empty??t.$t("field.structure.empty"))+" ")]):[e("k-table",{attrs:{columns:t.columns,disabled:t.disabled,fields:t.fields,empty:t.$t("field.structure.empty"),index:t.index,options:t.options,pagination:!!t.limit&&t.pagination,rows:t.paginatedItems,sortable:t.isSortable,"data-invalid":t.isInvalid},on:{cell:function(e){return t.open(e.row,e.columnIndex)},input:t.save,option:t.option,paginate:t.paginate}}),t.more?e("footer",[e("k-button",{attrs:{title:t.$t("add"),icon:"add",size:"xs",variant:"filled"},on:{click:function(e){return t.add()}}})],1):t._e()]]:[e("k-empty",{attrs:{icon:"list-bullet"}},[t._v(t._s(t.$t("fields.empty")))])]],2)}),[],!1,null,null,null,null).exports,ks={mixins:[Di],props:{autocomplete:{default:"tel"},placeholder:{default:()=>window.panel.$t("tel.placeholder")},type:{default:"tel"}}};const bs=ut({extends:Ei,mixins:[ks]},null,null,!1,null,null,null,null).exports;const vs=ut({mixins:[Fe,Ue,ks],inheritAttrs:!1,props:{icon:{type:String,default:"phone"}},methods:{focus(){this.$refs.input.focus()}}},(function(){var t=this,e=t._self._c;return e("k-field",t._b({staticClass:"k-tel-field",attrs:{input:t.id}},"k-field",t.$props,!1),[e("k-input",t._g(t._b({ref:"input",attrs:{type:"tel"}},"k-input",t.$props,!1),t.$listeners))],1)}),[],!1,null,null,null,null).exports;const ys=ut({mixins:[Fe,Ue,Di,$i],inheritAttrs:!1,computed:{inputType(){return this.$helper.isComponent(`k-${this.type}-input`)?this.type:"text"}},methods:{focus(){this.$refs.input.focus()},select(){this.$refs.input.select()}}},(function(){var t=this,e=t._self._c;return e("k-field",t._b({staticClass:"k-text-field",attrs:{input:t.id,counter:t.counterOptions},scopedSlots:t._u([{key:"options",fn:function(){return[t._t("options")]},proxy:!0}],null,!0)},"k-field",t.$props,!1),[e("k-input",t._g(t._b({ref:"input",attrs:{type:t.inputType}},"k-input",t.$props,!1),t.$listeners))],1)}),[],!1,null,null,null,null).exports,$s={props:{buttons:{type:[Array,Boolean],default:!0},uploads:[Boolean,Object,Array]}};const ws=ut({mixins:[$s],emits:["command"],computed:{commands(){return{headlines:{label:this.$t("toolbar.button.headings"),icon:"title",dropdown:[{label:this.$t("toolbar.button.heading.1"),icon:"h1",click:()=>this.command("prepend","#")},{label:this.$t("toolbar.button.heading.2"),icon:"h2",click:()=>this.command("prepend","##")},{label:this.$t("toolbar.button.heading.3"),icon:"h3",click:()=>this.command("prepend","###")}]},bold:{label:this.$t("toolbar.button.bold"),icon:"bold",click:()=>this.command("toggle","**"),shortcut:"b"},italic:{label:this.$t("toolbar.button.italic"),icon:"italic",click:()=>this.command("toggle","*"),shortcut:"i"},link:{label:this.$t("toolbar.button.link"),icon:"url",click:()=>this.command("dialog","link"),shortcut:"k"},email:{label:this.$t("toolbar.button.email"),icon:"email",click:()=>this.command("dialog","email"),shortcut:"e"},file:{label:this.$t("toolbar.button.file"),icon:"attachment",click:()=>this.command("file"),dropdown:this.uploads?[{label:this.$t("toolbar.button.file.select"),icon:"check",click:()=>this.command("file")},{label:this.$t("toolbar.button.file.upload"),icon:"upload",click:()=>this.command("upload")}]:void 0},code:{label:this.$t("toolbar.button.code"),icon:"code",click:()=>this.command("toggle","`")},ul:{label:this.$t("toolbar.button.ul"),icon:"list-bullet",click:()=>this.command("insert",((t,e)=>e.split("\n").map((t=>"- "+t)).join("\n")))},ol:{label:this.$t("toolbar.button.ol"),icon:"list-numbers",click:()=>this.command("insert",((t,e)=>e.split("\n").map(((t,e)=>e+1+". "+t)).join("\n")))}}},default:()=>["headlines","|","bold","italic","code","|","link","email","file","|","ul","ol"],layout(){if(!1===this.buttons)return[];const t=[],e=Array.isArray(this.buttons)?this.buttons:this.default,i={...this.commands,...window.panel.plugins.textareaButtons??{}};for(const n of e)if("|"===n)t.push("|");else if(i[n]){const e={...i[n],click:()=>{var t;null==(t=i[n].click)||t.call(this)}};t.push(e)}return t}},methods:{close(){this.$refs.toolbar.close()},command(t,...e){this.$emit("command",t,...e)},shortcut(t,e){var i;const n=this.layout.find((e=>e.shortcut===t));n&&(e.preventDefault(),null==(i=n.click)||i.call(n))}}},(function(){return(0,this._self._c)("k-toolbar",{ref:"toolbar",staticClass:"k-textarea-toolbar",attrs:{buttons:this.layout}})}),[],!1,null,null,null,null).exports,xs={mixins:[$s,je,J,et,it,lt,rt],props:{endpoints:Object,preselect:Boolean,size:String,theme:String,value:String}};const _s=ut({mixins:[Ie,xs],emits:["focus","input","submit"],data:()=>({over:!1}),computed:{uploadOptions(){const t=this.restoreSelectionCallback();return{url:this.$panel.urls.api+"/"+this.endpoints.field+"/upload",multiple:!1,on:{cancel:t,done:e=>{t((()=>this.insertUpload(e)))}}}}},watch:{async value(){this.onInvalid(),await this.$nextTick(),this.$library.autosize.update(this.$refs.input)}},async mounted(){await this.$nextTick(),this.$library.autosize(this.$refs.input),this.onInvalid(),this.$props.autofocus&&this.focus(),this.$props.preselect&&this.select()},methods:{dialog(t){const e=this.restoreSelectionCallback();this.$panel.dialog.open({component:"k-toolbar-"+t+"-dialog",props:{value:this.parseSelection()},on:{cancel:e,submit:t=>{this.$panel.dialog.close(),e((()=>this.insert(t)))}}})},file(){const t=this.restoreSelectionCallback();this.$panel.dialog.open({component:"k-files-dialog",props:{endpoint:this.endpoints.field+"/files",multiple:!1},on:{cancel:t,submit:e=>{t((()=>this.insertFile(e))),this.$panel.dialog.close()}}})},focus(){this.$refs.input.focus()},insert(t){const e=this.$refs.input,i=e.value;"function"==typeof t&&(t=t(this.$refs.input,this.selection())),setTimeout((()=>{if(e.focus(),document.execCommand("insertText",!1,t),e.value===i){const i=e.selectionStart,n=e.selectionEnd,s=i===n?"end":"select";e.setRangeText(t,i,n,s)}this.$emit("input",e.value)}))},insertFile(t){(null==t?void 0:t.length)>0&&this.insert(t.map((t=>t.dragText)).join("\n\n"))},insertUpload(t){this.insertFile(t),this.$events.emit("model.update")},onCommand(t,...e){if("function"!=typeof this[t])return console.warn(t+" is not a valid command");this[t](...e)},onDrop(t){if(this.uploads&&this.$helper.isUploadEvent(t))return this.$panel.upload.open(t.dataTransfer.files,this.uploadOptions);"text"===this.$panel.drag.type&&(this.focus(),this.insert(this.$panel.drag.data))},onFocus(t){this.$emit("focus",t)},onInput(t){this.$emit("input",t.target.value)},onInvalid(){this.$emit("invalid",this.$v.$invalid,this.$v)},onOut(){this.$refs.input.blur(),this.over=!1},onOver(t){if(this.uploads&&this.$helper.isUploadEvent(t))return t.dataTransfer.dropEffect="copy",this.focus(),void(this.over=!0);"text"===this.$panel.drag.type&&(t.dataTransfer.dropEffect="copy",this.focus(),this.over=!0)},onShortcut(t){var e;!1!==this.buttons&&"Meta"!==t.key&&"Control"!==t.key&&(null==(e=this.$refs.toolbar)||e.shortcut(t.key,t))},onSubmit(t){return this.$emit("submit",t)},parseSelection(){const t=this.selection();if(0===(null==t?void 0:t.length))return{href:null,title:null};let e;e=this.$panel.config.kirbytext?/^\(link:\s*(?.*?)(?:\s*text:\s*(?.*?))?\)$/is:/^(\[(?.*?)\]\((?.*?)\))|(<(?.*?)>)$/is;const i=e.exec(t);return null!==i?{href:i.groups.url??i.groups.link,title:i.groups.text??null}:{href:null,title:t}},prepend(t){this.insert(t+" "+this.selection())},restoreSelectionCallback(){const t=this.$refs.input.selectionStart,e=this.$refs.input.selectionEnd;return i=>{setTimeout((()=>{this.$refs.input.setSelectionRange(t,e),i&&i()}))}},select(){this.$refs.select()},selection(){return this.$refs.input.value.substring(this.$refs.input.selectionStart,this.$refs.input.selectionEnd)},toggle(t,e){e=e??t;const i=this.selection();return i.startsWith(t)&&i.endsWith(e)?this.insert(i.slice(t.length).slice(0,i.length-t.length-e.length)):this.wrap(t,e)},upload(){this.$panel.upload.pick(this.uploadOptions)},wrap(t,e){this.insert(t+this.selection()+(e??t))}},validations(){return{value:{required:!this.required||t.required,minLength:!this.minlength||t.minLength(this.minlength),maxLength:!this.maxlength||t.maxLength(this.maxlength)}}}},(function(){var t=this,e=t._self._c;return e("div",{staticClass:"k-textarea-input",attrs:{"data-over":t.over,"data-size":t.size}},[e("div",{staticClass:"k-textarea-input-wrapper"},[t.buttons&&!t.disabled?e("k-textarea-toolbar",{ref:"toolbar",attrs:{buttons:t.buttons,disabled:t.disabled,uploads:t.uploads},on:{command:t.onCommand},nativeOn:{mousedown:function(t){t.preventDefault()}}}):t._e(),e("textarea",t._b({directives:[{name:"direction",rawName:"v-direction"}],ref:"input",staticClass:"k-textarea-input-native",attrs:{"data-font":t.font},on:{click:function(e){var i;null==(i=t.$refs.toolbar)||i.close()},focus:t.onFocus,input:t.onInput,keydown:[function(e){return!e.type.indexOf("key")&&t._k(e.keyCode,"enter",13,e.key,"Enter")?null:e.metaKey?t.onSubmit.apply(null,arguments):null},function(e){return!e.type.indexOf("key")&&t._k(e.keyCode,"enter",13,e.key,"Enter")?null:e.ctrlKey?t.onSubmit.apply(null,arguments):null},function(e){return e.metaKey?e.ctrlKey||e.shiftKey||e.altKey?null:t.onShortcut.apply(null,arguments):null},function(e){return e.ctrlKey?e.shiftKey||e.altKey||e.metaKey?null:t.onShortcut.apply(null,arguments):null}],dragover:t.onOver,dragleave:t.onOut,drop:t.onDrop}},"textarea",{autofocus:t.autofocus,disabled:t.disabled,id:t.id,minlength:t.minlength,name:t.name,placeholder:t.placeholder,required:t.required,spellcheck:t.spellcheck,value:t.value},!1))],1)])}),[],!1,null,null,null,null).exports;const Cs=ut({mixins:[Fe,Ue,xs,$i],inheritAttrs:!1,methods:{focus(){this.$refs.input.focus()}}},(function(){var t=this,e=t._self._c;return e("k-field",t._b({staticClass:"k-textarea-field",attrs:{input:t.id,counter:t.counterOptions}},"k-field",t.$props,!1),[e("k-input",t._g(t._b({ref:"input",attrs:{type:"textarea"}},"k-input",t.$props,!1),t.$listeners))],1)}),[],!1,null,null,null,null).exports,Ss={props:{max:String,min:String,value:String}},Os={mixins:[Ss],props:{display:{type:String,default:"HH:mm"},step:{type:Object,default:()=>({size:5,unit:"minute"})},type:{type:String,default:"time"}}};const Ms=ut({mixins:[ji,Os],computed:{inputType:()=>"time"}},null,null,!1,null,null,null,null).exports;const As=ut({mixins:[Fe,Ue,Os],inheritAttrs:!1,props:{icon:{type:String,default:"clock"},times:{type:Boolean,default:!0}},methods:{focus(){this.$refs.input.focus()},select(t){var e;this.$emit("input",t),null==(e=this.$refs.times)||e.close()}}},(function(){var t=this,e=t._self._c;return e("k-field",t._b({staticClass:"k-time-field",attrs:{input:t.id}},"k-field",t.$props,!1),[e("k-input",t._b({ref:"input",attrs:{type:"time"},on:{input:function(e){return t.$emit("input",e??"")}},scopedSlots:t._u([t.times?{key:"icon",fn:function(){return[e("k-button",{staticClass:"k-input-icon-button",attrs:{disabled:t.disabled,icon:t.icon??"clock",title:t.$t("time.select")},on:{click:function(e){return t.$refs.times.toggle()}}}),e("k-dropdown-content",{ref:"times",attrs:{"align-x":"end"}},[e("k-timeoptions-input",{attrs:{display:t.display,value:t.value},on:{input:t.select}})],1)]},proxy:!0}:null],null,!0)},"k-input",t.$props,!1))],1)}),[],!1,null,null,null,null).exports,js={props:{autofocus:Boolean,disabled:Boolean,id:[Number,String],text:{type:[Array,String]},required:Boolean,value:Boolean}};const Is=ut({mixins:[Ie,js],computed:{label(){const t=this.text??[this.$t("off"),this.$t("on")];return Array.isArray(t)?this.value?t[1]:t[0]:t}},watch:{value(){this.onInvalid()}},mounted(){this.onInvalid(),this.$props.autofocus&&this.focus()},methods:{onEnter(t){"Enter"===t.key&&this.$refs.input.click()},onInput(t){this.$emit("input",t)},onInvalid(){this.$emit("invalid",this.$v.$invalid,this.$v)},select(){this.$refs.input.focus()}},validations(){return{value:{required:!this.required||t.required}}}},(function(){var t=this;return(0,t._self._c)("k-choice-input",{ref:"input",staticClass:"k-toggle-input",attrs:{id:t.id,checked:t.value,disabled:t.disabled,label:t.label,type:"checkbox",variant:"toggle"},on:{input:function(e){return t.$emit("input",e)}}})}),[],!1,null,null,null,null).exports;const Ds=ut({mixins:[Fe,Ue,js],inheritAttrs:!1,methods:{focus(){this.$refs.input.focus()}}},(function(){var t=this,e=t._self._c;return e("k-field",t._b({staticClass:"k-toggle-field",attrs:{input:t.id}},"k-field",t.$props,!1),[e("k-input",t._g(t._b({ref:"input",attrs:{type:"toggle"}},"k-input",t.$props,!1),t.$listeners))],1)}),[],!1,null,null,null,null).exports,Es={mixins:[je],props:{columns:Number,grow:Boolean,labels:Boolean,options:Array,reset:Boolean,value:[String,Number,Boolean]}};const Ts=ut({mixins:[Ie,Es],watch:{value(){this.onInvalid()}},mounted(){this.onInvalid(),this.$props.autofocus&&this.focus()},methods:{focus(){var t;null==(t=this.$el.querySelector("input[checked]")||this.$el.querySelector("input"))||t.focus()},onClick(t){t===this.value&&this.reset&&!this.required&&this.$emit("input","")},onInput(t){this.$emit("input",t)},onInvalid(){this.$emit("invalid",this.$v.$invalid,this.$v)},select(){this.focus()}},validations(){return{value:{required:!this.required||t.required}}}},(function(){var t=this,e=t._self._c;return e("ul",{staticClass:"k-toggles-input",style:{"--options":t.columns??t.options.length},attrs:{"data-invalid":t.$v.$invalid,"data-labels":t.labels}},t._l(t.options,(function(i,n){return e("li",{key:n,attrs:{"data-disabled":t.disabled}},[e("input",{staticClass:"input-hidden",attrs:{id:t.id+"-"+n,"aria-label":i.text,disabled:t.disabled,name:t.id,type:"radio"},domProps:{value:i.value,checked:t.value===i.value},on:{click:function(e){return t.onClick(i.value)},change:function(e){return t.onInput(i.value)}}}),e("label",{attrs:{for:t.id+"-"+n,title:i.text}},[i.icon?e("k-icon",{attrs:{type:i.icon}}):t._e(),t.labels||!i.icon?e("span",{staticClass:"k-toggles-text",domProps:{innerHTML:t._s(i.text)}}):t._e()],1)])})),0)}),[],!1,null,null,null,null).exports;const Ls=ut({mixins:[Fe,Ue,Es],inheritAttrs:!1,methods:{focus(){this.$refs.input.focus()},onInput(t){this.$emit("input",t)}}},(function(){var t,e=this,i=e._self._c;return i("k-field",e._b({staticClass:"k-toggles-field",attrs:{input:e.id}},"k-field",e.$props,!1),[(null==(t=e.options)?void 0:t.length)?i("k-input",e._g(e._b({ref:"input",class:{grow:e.grow},attrs:{type:"toggles"}},"k-input",e.$props,!1),e.$listeners)):i("k-empty",{attrs:{text:e.$t("options.none"),icon:"checklist"}})],1)}),[],!1,null,null,null,null).exports,Bs={mixins:[Di],props:{autocomplete:{type:String,default:"url"},placeholder:{type:String,default:()=>window.panel.$t("url.placeholder")},type:{type:String,default:"url"}}};const qs=ut({extends:Ei,mixins:[Bs]},null,null,!1,null,null,null,null).exports;const Ps=ut({mixins:[Fe,Ue,Bs],inheritAttrs:!1,props:{link:{type:Boolean,default:!0},icon:{type:String,default:"url"}},computed:{isValidUrl(){return""!==this.value&&!0===this.$helper.url.isUrl(this.value,!0)}},methods:{focus(){this.$refs.input.focus()}}},(function(){var t=this,e=t._self._c;return e("k-field",t._b({staticClass:"k-url-field",attrs:{input:t.id}},"k-field",t.$props,!1),[e("k-input",t._g(t._b({ref:"input",attrs:{type:"url"},scopedSlots:t._u([{key:"icon",fn:function(){return[t.link&&t.isValidUrl?e("k-button",{staticClass:"k-input-icon-button",attrs:{icon:t.icon,link:t.value,title:t.$t("open"),tabindex:"-1",target:"_blank"}}):t._e()]},proxy:!0}])},"k-input",t.$props,!1),t.$listeners))],1)}),[],!1,null,null,null,null).exports;const Ns=ut({extends:qi,type:"users",computed:{emptyProps(){return{icon:"users",text:this.empty??this.$t("field.users.empty")}}}},null,null,!1,null,null,null,null).exports;const zs=ut({mixins:[Fe,Ue,Bn,$i],inheritAttrs:!1,computed:{counterValue(){const t=this.$helper.string.stripHTML(this.value??"");return this.$helper.string.unescapeHTML(t)}},methods:{focus(){this.$refs.input.focus()}}},(function(){var t=this,e=t._self._c;return e("k-field",t._b({staticClass:"k-writer-field",attrs:{input:t.id,counter:t.counterOptions}},"k-field",t.$props,!1),[e("k-input",t._b({ref:"input",attrs:{after:t.after,before:t.before,icon:t.icon,type:"writer"},on:{input:function(e){return t.$emit("input",e)}}},"k-input",t.$props,!1))],1)}),[],!1,null,null,null,null).exports,Fs={install(t){t.component("k-blocks-field",bi),t.component("k-checkboxes-field",wi),t.component("k-color-field",Oi),t.component("k-date-field",Ii),t.component("k-email-field",Bi),t.component("k-files-field",Pi),t.component("k-gap-field",Ni),t.component("k-headline-field",zi),t.component("k-info-field",Fi),t.component("k-layout-field",Wi),t.component("k-line-field",Ji),t.component("k-link-field",Gi),t.component("k-list-field",Fn),t.component("k-multiselect-field",Jn),t.component("k-number-field",Zn),t.component("k-object-field",Qn),t.component("k-pages-field",ts),t.component("k-password-field",ns),t.component("k-radio-field",ls),t.component("k-range-field",us),t.component("k-select-field",ps),t.component("k-slug-field",fs),t.component("k-structure-field",gs),t.component("k-tags-field",Wn),t.component("k-text-field",ys),t.component("k-textarea-field",Cs),t.component("k-tel-field",vs),t.component("k-time-field",As),t.component("k-toggle-field",Ds),t.component("k-toggles-field",Ls),t.component("k-url-field",Ps),t.component("k-users-field",Ns),t.component("k-writer-field",zs)}},Ys={mixins:[as],props:{max:null,min:null,step:{default:.01,type:Number},tooltip:{default:!1,type:[Boolean,Object]}}};const Rs=ut({mixins:[rs,Ys]},(function(){var t=this;return(0,t._self._c)("k-range-input",t._b({staticClass:"k-alpha-input",attrs:{min:0,max:1},on:{input:function(e){return t.$emit("input",e)}}},"k-range-input",t.$props,!1))}),[],!1,null,null,null,null).exports;const Us=ut({mixins:[je,Mi],data(){const t=this.$library.dayjs();return{maxdate:null,mindate:null,month:t.month(),selected:null,today:t,year:t.year()}},computed:{numberOfDays(){return this.toDate().daysInMonth()},firstWeekday(){const t=this.toDate().day();return t>0?t:7},weekdays(){return["mon","tue","wed","thu","fri","sat","sun"].map((t=>this.$t("days."+t)))},weeks(){const t=this.firstWeekday-1;return Math.ceil((this.numberOfDays+t)/7)},monthnames(){return["january","february","march","april","may","june","july","august","september","october","november","december"].map((t=>this.$t("months."+t)))},months(){var t=[];return this.monthnames.forEach(((e,i)=>{t.push({value:i,text:e})})),t},years(){const t=this.year-20,e=this.year+20;return this.toOptions(t,e)}},watch:{max:{handler(t,e){t!==e&&(this.maxdate=this.$library.dayjs.interpret(t,"date"))},immediate:!0},min:{handler(t,e){t!==e&&(this.mindate=this.$library.dayjs.interpret(t,"date"))},immediate:!0},value:{handler(t,e){t!==e&&(this.selected=this.$library.dayjs.interpret(t,"date"),this.show(this.selected))},immediate:!0}},methods:{days(t){let e=[];const i=7*(t-1)+1,n=i+7;for(let s=i;sthis.numberOfDays;e.push(i?"":t)}return e},isDisabled(t){const e=this.toDate(t);return this.disabled||e.isBefore(this.mindate,"day")||e.isAfter(this.maxdate,"day")},isSelected(t){return this.toDate(t).isSame(this.selected,"day")},isToday(t){return this.toDate(t).isSame(this.today,"day")},onNext(){const t=this.toDate().add(1,"month");this.show(t)},onPrev(){const t=this.toDate().subtract(1,"month");this.show(t)},select(t){this.$emit("input",(null==t?void 0:t.toISO("date"))??null)},show(t){this.month=(t??this.today).month(),this.year=(t??this.today).year()},toDate(t=1,e){return this.$library.dayjs(`${this.year}-${(e??this.month)+1}-${t}`)},toOptions(t,e){for(var i=[],n=t;n<=e;n++)i.push({value:n,text:this.$helper.pad(n)});return i}}},(function(){var t=this,e=t._self._c;return e("fieldset",{staticClass:"k-calendar-input",on:{click:function(t){t.stopPropagation()}}},[e("legend",{staticClass:"sr-only"},[t._v(t._s(t.$t("date.select")))]),e("nav",[e("k-button",{attrs:{title:t.$t("prev"),icon:"angle-left"},on:{click:t.onPrev}}),e("span",{staticClass:"k-calendar-selects"},[e("k-select-input",{attrs:{"aria-label":t.$t("month"),autofocus:t.autofocus,options:t.months,empty:!1,required:!0,value:t.month},on:{input:function(e){t.month=Number(e)}}}),e("k-select-input",{attrs:{"aria-label":t.$t("year"),options:t.years,empty:!1,required:!0,value:t.year},on:{input:function(e){t.year=Number(e)}}})],1),e("k-button",{attrs:{title:t.$t("next"),icon:"angle-right"},on:{click:t.onNext}})],1),e("table",{key:t.year+"-"+t.month,staticClass:"k-calendar-table"},[e("thead",[e("tr",t._l(t.weekdays,(function(i){return e("th",{key:"weekday_"+i},[t._v(" "+t._s(i)+" ")])})),0)]),e("tbody",t._l(t.weeks,(function(i){return e("tr",{key:"week_"+i},t._l(t.days(i),(function(i,n){return e("td",{key:"day_"+n,staticClass:"k-calendar-day",attrs:{"aria-current":!!t.isToday(i)&&"date","aria-selected":!!t.isSelected(i)&&"date"}},[i?e("k-button",{attrs:{disabled:t.isDisabled(i),text:i},on:{click:function(e){t.select(t.toDate(i))}}}):t._e()],1)})),0)})),0),e("tfoot",[e("tr",[e("td",{staticClass:"k-calendar-today",attrs:{colspan:"7"}},[e("k-button",{attrs:{disabled:t.disabled,text:t.$t("today")},on:{click:function(e){t.show(t.today),t.select(t.today)}}})],1)])])]),e("input",{staticClass:"input-hidden",attrs:{id:t.id,disabled:t.disabled,min:t.min,max:t.max,name:t.name,required:t.required,tabindex:"-1",type:"date"},domProps:{value:t.value}})])}),[],!1,null,null,null,null).exports;const Hs=ut({mixins:[Ie,{mixins:[je],props:{checked:{type:Boolean},info:{type:String},label:{type:String},type:{default:"checkbox",type:String},value:{type:[Boolean,Number,String]},variant:{type:String}}}]},(function(){var t=this,e=t._self._c;return e("label",{staticClass:"k-choice-input",attrs:{"aria-disabled":t.disabled}},[e("input",t._b({class:{"sr-only":"invisible"===t.variant},attrs:{"data-variant":t.variant},on:{input:function(e){return t.$emit("input",e.target.checked)}}},"input",{autofocus:t.autofocus,id:t.id,checked:t.checked,disabled:t.disabled,name:t.name,required:t.required,type:t.type,value:t.value},!1)),t.label||t.info?e("span",{staticClass:"k-choice-input-label"},[e("span",{staticClass:"k-choice-input-label-text",domProps:{innerHTML:t._s(t.label)}}),t.info?e("span",{staticClass:"k-choice-input-label-info",domProps:{innerHTML:t._s(t.info)}}):t._e()]):t._e()])}),[],!1,null,null,null,null).exports;const Vs=ut({extends:Hs},null,null,!1,null,null,null,null).exports;const Ks=ut({mixins:[os,{mixins:[ss],props:{format:{type:String,default:"hex",validator:t=>["hex","rgb","hsl"].includes(t)},value:{type:String}}}],computed:{choices(){return this.options.map((t=>({...t,title:t.text??t.value,value:this.colorToString(t.value)})))}},methods:{colorToString(t){try{return this.$library.colors.toString(t,this.format)}catch{return t}}}},(function(){var t=this,e=t._self._c;return t.choices.length?e("fieldset",{staticClass:"k-coloroptions-input",attrs:{disabled:t.disabled}},[e("legend",{staticClass:"sr-only"},[t._v(t._s(t.$t("options")))]),e("ul",t._l(t.choices,(function(i,n){return e("li",{key:n},[e("label",{attrs:{title:i.title}},[e("input",{staticClass:"input-hidden",attrs:{autofocus:t.autofocus&&0===n,disabled:t.disabled,name:t.name??t.id,required:t.required,type:"radio"},domProps:{checked:i.value===t.value,value:i.value},on:{click:function(e){return t.toggle(i.value)},input:function(e){return t.$emit("input",i.value)}}}),e("k-color-frame",{attrs:{color:i.value}})],1)])})),0)]):t._e()}),[],!1,null,null,null,null).exports;const Ws=ut({mixins:[Ie,{mixins:[je,st],props:{alpha:{default:!0,type:Boolean},format:{default:"hex",type:String,validator:t=>["hex","rgb","hsl"].includes(t)},value:{type:[Object,String]}}}],data:()=>({color:{h:0,s:0,v:1,a:1},formatted:null}),computed:{coords(){return this.value?{x:100*this.color.s,y:100*(1-this.color.v)}:null},hsl(){try{const t=this.$library.colors.convert(this.color,"hsl");return{h:t.h,s:(100*t.s).toFixed()+"%",l:(100*t.l).toFixed()+"%",a:t.a}}catch{return{h:0,s:"0%",l:"0%",a:1}}}},watch:{value:{handler(t,e){if(t===e||t===this.formatted)return;const i=this.$library.colors.parseAs(t??"","hsv");i?(this.formatted=this.$library.colors.toString(i,this.format),this.color=i):(this.formatted=null,this.color={h:0,s:0,v:1,a:1})},immediate:!0}},methods:{between:(t,e,i)=>Math.min(Math.max(t,e),i),emit(){return this.formatted=this.$library.colors.toString(this.color,this.format),this.$emit("input",this.formatted)},focus(){this.$refs.coords.focus()},setAlpha(t){this.color.a=this.alpha?this.between(Number(t),0,1):1,this.emit()},setCoords(t){if(!t)return this.$emit("input","");const e=Math.round(t.x),i=Math.round(t.y);this.color.s=this.between(e/100,0,1),this.color.v=this.between(1-i/100,0,1),this.emit()},setHue(t){this.color.h=this.between(Number(t),0,360),this.emit()}}},(function(){var t=this,e=t._self._c;return e("fieldset",{staticClass:"k-colorpicker-input",style:{"--h":t.hsl.h,"--s":t.hsl.s,"--l":t.hsl.l,"--a":t.hsl.a}},[e("legend",{staticClass:"sr-only"},[t._v(t._s(t.$t("color")))]),e("k-coords-input",{ref:"coords",attrs:{autofocus:t.autofocus,disabled:t.disabled,required:t.required,value:t.coords},on:{input:function(e){return t.setCoords(e)}}}),e("label",{attrs:{"aria-label":t.$t("hue")}},[e("k-hue-input",{attrs:{disabled:t.disabled,required:t.required,value:t.color.h},on:{input:function(e){return t.setHue(e)}}})],1),t.alpha?e("label",{attrs:{"aria-label":t.$t("alpha")}},[e("k-alpha-input",{attrs:{disabled:t.disabled,required:t.required,value:t.color.a},on:{input:function(e){return t.setAlpha(e)}}})],1):t._e(),e("k-coloroptions-input",{attrs:{disabled:t.disabled,format:t.format,options:t.options,required:t.required,value:t.value},on:{input:function(e){return t.$emit("input",e)}}}),e("input",{staticClass:"input-hidden",attrs:{name:t.name,required:t.required,tabindex:"-1",type:"text"},domProps:{value:t.formatted}})],1)}),[],!1,null,null,null,null).exports;const Js=ut({mixins:[Ie,{mixins:[je],props:{reset:{default:!0,type:Boolean},value:{default:()=>({x:0,y:0}),type:Object}}}],data:()=>({x:0,y:0}),watch:{value:{handler(t){const e=this.parse(t);this.x=(null==e?void 0:e.x)??0,this.y=(null==e?void 0:e.y)??0},immediate:!0}},methods:{focus(){var t;null==(t=this.$el.querySelector("button"))||t.focus()},getCoords:(t,e)=>({x:Math.min(Math.max(t.clientX-e.left,0),e.width),y:Math.min(Math.max(t.clientY-e.top,0),e.height)}),onDelete(){this.reset&&!this.required&&this.$emit("input",null)},onDrag(t){if(0!==t.button)return;const e=t=>this.onMove(t),i=()=>{window.removeEventListener("mousemove",e),window.removeEventListener("mouseup",i)};window.addEventListener("mousemove",e),window.addEventListener("mouseup",i)},onEnter(){var t;null==(t=this.$el.form)||t.requestSubmit()},onInput(t,e){if(t.preventDefault(),t.stopPropagation(),this.disabled)return!1;this.x=Math.min(Math.max(parseFloat(e.x??this.x??0),0),100),this.y=Math.min(Math.max(parseFloat(e.y??this.y??0),0),100),this.$emit("input",{x:this.x,y:this.y})},onKeys(t){const e=t.shiftKey?10:1,i={ArrowUp:{y:this.y-e},ArrowDown:{y:this.y+e},ArrowLeft:{x:this.x-e},ArrowRight:{x:this.x+e}};i[t.key]&&this.onInput(t,i[t.key])},async onMove(t){const e=this.$el.getBoundingClientRect(),i=this.getCoords(t,e),n=i.x/e.width*100,s=i.y/e.height*100;this.onInput(t,{x:n,y:s}),await this.$nextTick(),this.focus()},parse(t){if("object"==typeof t)return t;const e={"top left":{x:0,y:0},"top center":{x:50,y:0},"top right":{x:100,y:0},"center left":{x:0,y:50},center:{x:50,y:50},"center center":{x:50,y:50},"center right":{x:100,y:50},"bottom left":{x:0,y:100},"bottom center":{x:50,y:100},"bottom right":{x:100,y:100}};if(e[t])return e[t];const i=t.split(",").map((t=>t.trim()));return{x:i[0],y:i[1]??0}}}},(function(){var t=this,e=t._self._c;return e("div",{staticClass:"k-coords-input",attrs:{"aria-disabled":t.disabled,"data-empty":!t.value},on:{mousedown:t.onDrag,click:t.onMove,keydown:t.onKeys}},[t._t("default"),e("button",{staticClass:"k-coords-input-thumb",style:{left:`${t.x}%`,top:`${t.y}%`},attrs:{id:t.id,autofocus:t.autofocus,disabled:t.disabled},on:{keydown:[function(e){return!e.type.indexOf("key")&&t._k(e.keyCode,"enter",13,e.key,"Enter")?null:(e.preventDefault(),t.onEnter.apply(null,arguments))},function(e){return!e.type.indexOf("key")&&t._k(e.keyCode,"delete",[8,46],e.key,["Backspace","Delete","Del"])?null:t.onDelete.apply(null,arguments)}]}}),e("input",{staticClass:"input-hidden",attrs:{name:t.name,required:t.required,tabindex:"-1",type:"text"},domProps:{value:t.value?[t.value.x,t.value.y]:null}})],2)}),[],!1,null,null,null,null).exports,Gs={mixins:[as],props:{max:null,min:null,step:{default:1,type:Number},tooltip:{default:!1,type:[Boolean,Object]}}};const Xs=ut({mixins:[rs,Gs]},(function(){var t=this;return(0,t._self._c)("k-range-input",t._b({staticClass:"k-hue-input",attrs:{min:0,max:360},on:{input:function(e){return t.$emit("input",e)}}},"k-range-input",t.$props,!1))}),[],!1,null,null,null,null).exports;const Zs=ut({mixins:[_i,{mixins:[xi],props:{autocomplete:null,pattern:null,spellcheck:null,placeholder:{default:()=>window.panel.$t("search")+" …",type:String}}}]},(function(){var t=this;return(0,t._self._c)("k-string-input",t._b({staticClass:"k-search-input",attrs:{spellcheck:!1,autocomplete:"off",type:"search"},on:{input:function(e){return t.$emit("input",e)}}},"k-string-input",t.$props,!1))}),[],!1,null,null,null,null).exports;const Qs=ut({mixins:[Ie,{mixins:[je,Ss]}],props:{display:{type:String,default:"HH:mm"},value:String},computed:{day(){return this.formatTimes([6,7,8,9,10,11,"-",12,13,14,15,16,17])},night(){return this.formatTimes([18,19,20,21,22,23,"-",0,1,2,3,4,5])}},methods:{focus(){this.$el.querySelector("button").focus()},formatTimes(t){return t.map((t=>{if("-"===t)return t;const e=this.$library.dayjs(t+":00","H:mm");return{display:e.format(this.display),select:e.toISO("time")}}))},select(t){this.$emit("input",t)}}},(function(){var t=this,e=t._self._c;return e("div",{staticClass:"k-timeoptions-input"},[e("div",[e("h3",[e("k-icon",{attrs:{type:"sun"}}),t._v(" "),e("span",{staticClass:"sr-only"},[t._v(t._s(t.$t("day")))])],1),e("ul",t._l(t.day,(function(i,n){return e("li",{key:i.select},["-"===i?e("hr"):e("k-button",{attrs:{autofocus:t.autofocus&&0===n,disabled:t.disabled,selected:i.select===t.value&&"time"},on:{click:function(e){return t.select(i.select)}}},[t._v(" "+t._s(i.display)+" ")])],1)})),0)]),e("div",[e("h3",[e("k-icon",{attrs:{type:"moon"}}),t._v(" "),e("span",{staticClass:"sr-only"},[t._v(t._s(t.$t("night")))])],1),e("ul",t._l(t.night,(function(i){return e("li",{key:i.select},["-"===i?e("hr"):e("k-button",{attrs:{disabled:t.disabled,selected:i.select===t.value&&"time"},on:{click:function(e){return t.select(i.select)}}},[t._v(" "+t._s(i.display)+" ")])],1)})),0)]),e("input",{staticClass:"input-hidden",attrs:{id:t.id,disabled:t.disabled,min:t.min,max:t.max,name:t.name,required:t.required,tabindex:"-1",type:"time"},domProps:{value:t.value}})])}),[],!1,null,null,null,null).exports,to={install(t){t.component("k-alpha-input",Rs),t.component("k-calendar-input",Us),t.component("k-checkbox-input",Vs),t.component("k-checkboxes-input",yi),t.component("k-choice-input",Hs),t.component("k-colorname-input",Si),t.component("k-coloroptions-input",Ks),t.component("k-colorpicker-input",Ws),t.component("k-coords-input",Js),t.component("k-date-input",ji),t.component("k-email-input",Li),t.component("k-hue-input",Xs),t.component("k-list-input",zn),t.component("k-multiselect-input",Hn),t.component("k-number-input",Xn),t.component("k-password-input",is),t.component("k-picklist-input",Te),t.component("k-radio-input",os),t.component("k-range-input",rs),t.component("k-search-input",Zs),t.component("k-select-input",ds),t.component("k-slug-input",ms),t.component("k-string-input",_i),t.component("k-tags-input",Kn),t.component("k-tel-input",bs),t.component("k-text-input",Ei),t.component("k-textarea-input",_s),t.component("k-time-input",Ms),t.component("k-timeoptions-input",Qs),t.component("k-toggle-input",Is),t.component("k-toggles-input",Ts),t.component("k-url-input",qs),t.component("k-writer-input",qn),t.component("k-calendar",Us),t.component("k-times",Qs)}};const eo=ut({mixins:[Et],inheritAttrs:!1,props:{cancelButton:{default:!1},label:{default(){return this.$t("field.layout.select")},type:String},layouts:{type:Array},selector:Object,submitButton:{default:!1},value:{type:Array}},emits:["cancel","input","submit"]},(function(){var t,e,i=this,n=i._self._c;return n("k-dialog",i._b({staticClass:"k-layout-selector",attrs:{size:(null==(t=i.selector)?void 0:t.size)??"medium"},on:{cancel:function(t){return i.$emit("cancel")},submit:function(t){return i.$emit("submit",i.value)}}},"k-dialog",i.$props,!1),[n("h3",{staticClass:"k-label"},[i._v(i._s(i.label))]),n("k-navigate",{staticClass:"k-layout-selector-options",style:{"--columns":Number((null==(e=i.selector)?void 0:e.columns)??3)},attrs:{axis:"x"}},i._l(i.layouts,(function(t,e){return n("button",{key:e,staticClass:"k-layout-selector-option",attrs:{"aria-current":i.value===t,"aria-label":t.join(","),value:t},on:{click:function(e){return i.$emit("input",t)}}},[n("k-grid",{attrs:{"aria-hidden":""}},i._l(t,(function(t,e){return n("k-column",{key:e,attrs:{width:t}})})),1)],1)})),0)],1)}),[],!1,null,null,null,null).exports,io={install(t){t.component("k-layout",Hi),t.component("k-layout-column",Ri),t.component("k-layouts",Ki),t.component("k-layout-selector",eo)}},no={inheritAttrs:!1,props:{column:{default:()=>({}),type:Object},field:{default:()=>({}),type:Object},value:{}}},so={props:{html:{type:Boolean}}};const oo=ut({mixins:[so],inheritAttrs:!1,props:{bubbles:[Array,String]},computed:{items(){let t=this.bubbles;return"string"==typeof t&&(t=t.split(",")),t.map((t=>"string"===t?{text:t}:t))}}},(function(){var t=this,e=t._self._c;return e("ul",{staticClass:"k-bubbles"},t._l(t.items,(function(i,n){return e("li",{key:n},[e("k-bubble",t._b({attrs:{html:t.html}},"k-bubble",i,!1))],1)})),0)}),[],!1,null,null,null,null).exports;const lo=ut({mixins:[no,so],props:{value:{default:()=>[],type:[Array,String]}},computed:{bubbles(){let t=this.value;const e=this.column.options??this.field.options??[];return"string"==typeof t&&(t=t.split(",")),(t??[]).map((t=>{"string"==typeof t&&(t={value:t,text:t});for(const i of e)i.value===t.value&&(t.text=i.text);return t}))}}},(function(){var t=this,e=t._self._c;return e("div",{staticClass:"k-bubbles-field-preview",class:t.$options.class},[e("k-bubbles",{attrs:{bubbles:t.bubbles,html:t.html}})],1)}),[],!1,null,null,null,null).exports;const ao=ut({extends:lo,inheritAttrs:!1,class:"k-array-field-preview",computed:{bubbles(){return[{text:1===this.value.length?`1 ${this.$t("entry")}`:`${this.value.length} ${this.$t("entries")}`}]}}},null,null,!1,null,null,null,null).exports;const ro=ut({mixins:[no],props:{value:String},computed:{text(){var t;if(!this.value)return;const e=this.$library.colors.toString(this.value,this.field.format,this.field.alpha),i=null==(t=this.field.options)?void 0:t.find((t=>this.$library.colors.toString(t.value,this.field.format,this.field.alpha)===e));return i?i.text:null}}},(function(){var t=this,e=t._self._c;return e("div",{staticClass:"k-color-field-preview"},[e("k-color-frame",{attrs:{color:t.value}}),t.text?[t._v(" "+t._s(t.text)+" ")]:t._e()],2)}),[],!1,null,null,null,null).exports;const uo=ut({mixins:[no],inheritAttrs:!1,computed:{text(){return this.value}}},(function(){var t=this;return(0,t._self._c)("p",{staticClass:"k-text-field-preview",class:t.$options.class},[t._v(" "+t._s(t.column.before)+" "),t._t("default",(function(){return[t._v(t._s(t.text))]})),t._v(" "+t._s(t.column.after)+" ")],2)}),[],!1,null,null,null,null).exports;const co=ut({extends:uo,props:{value:String},class:"k-date-field-preview",computed:{display(){return this.column.display??this.field.display},format(){var t;let e=this.display??"YYYY-MM-DD";return(null==(t=this.time)?void 0:t.display)&&(e+=" "+this.time.display),e},parsed(){return this.$library.dayjs(this.value)},text(){var t;return!1===this.parsed.isValid()?this.value:null==(t=this.parsed)?void 0:t.format(this.format)},time(){return this.column.time??this.field.time}}},null,null,!1,null,null,null,null).exports;const po=ut({mixins:[no],props:{value:[String,Object]},computed:{link(){return"object"==typeof this.value?this.value.href:this.value},text(){return"object"==typeof this.value?this.value.text:this.link}}},(function(){var t=this,e=t._self._c;return e("p",{staticClass:"k-url-field-preview",class:t.$options.class,attrs:{"data-link":t.link}},[t._v(" "+t._s(t.column.before)+" "),e("k-link",{attrs:{to:t.link},nativeOn:{click:function(t){t.stopPropagation()}}},[e("span",[t._v(t._s(t.text))])]),t._v(" "+t._s(t.column.after)+" ")],1)}),[],!1,null,null,null,null).exports;const ho=ut({extends:po,class:"k-email-field-preview"},null,null,!1,null,null,null,null).exports;const mo=ut({extends:lo,class:"k-files-field-preview",props:{html:{type:Boolean,default:!0}},computed:{bubbles(){return this.value.map((t=>({text:t.filename,link:t.link,image:t.image})))}}},null,null,!1,null,null,null,null).exports;const fo=ut({mixins:[no],props:{value:Object},computed:{status(){var t;return{...this.$helper.page.status(null==(t=this.value)?void 0:t.status),...this.value}}}},(function(){var t=this,e=t._self._c;return t.value?e("k-button",t._b({staticClass:"k-flag-field-preview",attrs:{size:"md"}},"k-button",t.status,!1)):t._e()}),[],!1,null,null,null,null).exports;const go=ut({mixins:[no],props:{value:String},computed:{html(){return this.value}}},(function(){var t=this,e=t._self._c;return e("div",{staticClass:"k-html-field-preview",class:t.$options.class},[t._v(" "+t._s(t.column.before)+" "),e("k-text",{attrs:{html:t.html}}),t._v(" "+t._s(t.column.after)+" ")],1)}),[],!1,null,null,null,null).exports;const ko=ut({mixins:[no],props:{value:[Object]}},(function(){var t=this,e=t._self._c;return t.value?e("k-item-image",{staticClass:"k-image-field-preview",attrs:{image:t.value}}):t._e()}),[],!1,null,null,null,null).exports;const bo=ut({mixins:[no],inheritAttrs:!1,props:{removable:Boolean,type:String},emits:["remove"],data:()=>({model:null}),computed:{currentType(){return this.type??this.detected.type},detected(){return this.$helper.link.detect(this.value)},isLink(){return["url","email","tel"].includes(this.currentType)}},watch:{detected:{async handler(t,e){t!==e&&(this.model=await this.$helper.link.preview(this.detected))},immediate:!0},type(){this.model=null}}},(function(){var t=this,e=t._self._c;return e("div",{staticClass:"k-link-field-preview"},["page"===t.currentType||"file"===t.currentType?[t.model?[e("k-tag",{attrs:{image:{...t.model.image,cover:!0},removable:t.removable,text:t.model.label},on:{remove:function(e){return t.$emit("remove",e)}}})]:t._t("placeholder")]:t.isLink?[e("p",{staticClass:"k-text"},[e("a",{attrs:{href:t.value,target:"_blank"}},[t._v(t._s(t.detected.link))])])]:[t._v(" "+t._s(t.detected.link)+" ")]],2)}),[],!1,null,null,null,null).exports;const vo=ut({extends:lo,class:"k-object-field-preview",props:{value:[Array,Object]},computed:{bubbles(){return this.value?[{text:"{ ... }"}]:[]}}},null,null,!1,null,null,null,null).exports;const yo=ut({extends:lo,inheritAttrs:!1,class:"k-pages-field-preview",props:{html:{type:Boolean,default:!0}}},null,null,!1,null,null,null,null).exports;const $o=ut({extends:co,class:"k-time-field-preview",computed:{format(){return this.display??"HH:mm"},parsed(){return this.$library.dayjs.iso(this.value,"time")},text(){var t;return null==(t=this.parsed)?void 0:t.format(this.format)}}},null,null,!1,null,null,null,null).exports;const wo=ut({mixins:[no],props:{value:Boolean},emits:["input"],computed:{isEditable(){return!0!==this.field.disabled},text(){return!1!==this.column.text?this.field.text:null}}},(function(){var t=this,e=t._self._c;return e("div",{staticClass:"k-toggle-field-preview"},[e("k-toggle-input",{attrs:{disabled:!t.isEditable,text:t.text,value:t.value},on:{input:function(e){return t.$emit("input",e)}},nativeOn:{click:function(e){t.isEditable&&e.stopPropagation()}}})],1)}),[],!1,null,null,null,null).exports;const xo=ut({extends:lo,class:"k-users-field-preview",computed:{bubble(){return this.value.map((t=>({text:t.username,link:t.link,image:t.image})))}}},null,null,!1,null,null,null,null).exports,_o={install(t){t.component("k-array-field-preview",ao),t.component("k-bubbles-field-preview",lo),t.component("k-color-field-preview",ro),t.component("k-date-field-preview",co),t.component("k-email-field-preview",ho),t.component("k-files-field-preview",mo),t.component("k-flag-field-preview",fo),t.component("k-html-field-preview",go),t.component("k-image-field-preview",ko),t.component("k-link-field-preview",bo),t.component("k-object-field-preview",vo),t.component("k-pages-field-preview",yo),t.component("k-text-field-preview",uo),t.component("k-toggle-field-preview",wo),t.component("k-time-field-preview",$o),t.component("k-url-field-preview",po),t.component("k-users-field-preview",xo),t.component("k-list-field-preview",go),t.component("k-writer-field-preview",go),t.component("k-checkboxes-field-preview",lo),t.component("k-multiselect-field-preview",lo),t.component("k-radio-field-preview",lo),t.component("k-select-field-preview",lo),t.component("k-tags-field-preview",lo),t.component("k-toggles-field-preview",lo)}};const Co=ut({mixins:[{props:{buttons:{type:Array,default:()=>[]},theme:{type:String,default:"light"}}}],methods:{close(){for(const t in this.$refs){const e=this.$refs[t][0];"function"==typeof(null==e?void 0:e.close)&&e.close()}}}},(function(){var t=this,e=t._self._c;return e("nav",{staticClass:"k-toolbar",attrs:{"data-theme":t.theme}},[t._l(t.buttons,(function(i,n){var s;return["|"===i?e("hr",{key:n}):i.when??1?e("k-button",{key:n,class:["k-toolbar-button",i.class],attrs:{current:i.current,disabled:i.disabled,icon:i.icon,title:i.label,tabindex:"0"},on:{click:function(e){var s,o;(null==(s=i.dropdown)?void 0:s.length)?t.$refs[n+"-dropdown"][0].toggle():null==(o=i.click)||o.call(i,e)}},nativeOn:{keydown:function(t){var e;null==(e=i.key)||e.call(i,t)}}}):t._e(),(i.when??1)&&(null==(s=i.dropdown)?void 0:s.length)?e("k-dropdown-content",{key:n+"-dropdown",ref:n+"-dropdown",refInFor:!0,attrs:{options:i.dropdown,theme:"dark"===t.theme?"light":"dark"}}):t._e()]}))],2)}),[],!1,null,null,null,null).exports;const So=ut({extends:Bt,props:{fields:{default:()=>{const t=Bt.props.fields.default();return t.title.label=window.panel.$t("link.text"),t}}},methods:{submit(){const t=this.values.href??"",e=this.values.title??"";return this.$panel.config.kirbytext?(null==e?void 0:e.length)>0?this.$emit("submit",`(email: ${t} text: ${e})`):this.$emit("submit",`(email: ${t})`):(null==e?void 0:e.length)>0?this.$emit("submit",`[${e}](mailto:${t})`):this.$emit("submit",`<${t}>`)}}},null,null,!1,null,null,null,null).exports;const Oo=ut({extends:Kt,props:{fields:{default:()=>({href:{label:window.panel.$t("link"),type:"link",placeholder:window.panel.$t("url.placeholder"),icon:"url"},title:{label:window.panel.$t("link.text"),type:"text",icon:"title"}})}},methods:{submit(){const t=this.values.href??"",e=this.values.title??"";return this.$panel.config.kirbytext?(null==e?void 0:e.length)>0?this.$emit("submit",`(link: ${t} text: ${e})`):this.$emit("submit",`(link: ${t})`):(null==e?void 0:e.length)>0?this.$emit("submit",`[${e}](${t})`):this.$emit("submit",`<${t}>`)}}},null,null,!1,null,null,null,null).exports,Mo={install(t){t.component("k-toolbar",Co),t.component("k-textarea-toolbar",ws),t.component("k-toolbar-email-dialog",So),t.component("k-toolbar-link-dialog",Oo)}};const Ao=ut({props:{editor:{required:!0,type:Object},inline:{default:!0,type:Boolean},marks:{default:()=>["bold","italic","underline","strike","code","|","link","email","|","clear"],type:[Array,Boolean]},nodes:{default:!0,type:[Array,Boolean]}},emits:["command"],data:()=>({isOpen:!1,position:{x:0,y:0}}),computed:{activeNode(){return Object.values(this.nodeButtons).find((t=>this.isNodeActive(t)))??!1},buttons(){var t,e,i;const n=[];if(this.hasNodes){const s=[];let o=0;for(const n in this.nodeButtons){const l=this.nodeButtons[n];s.push({current:(null==(t=this.activeNode)?void 0:t.id)===l.id,disabled:!1===(null==(i=null==(e=this.activeNode)?void 0:e.when)?void 0:i.includes(l.name)),icon:l.icon,label:l.label,click:()=>this.command(l.command??n)}),!0===l.separator&&o!==Object.keys(this.nodeButtons).length-1&&s.push("-"),o++}n.push({current:Boolean(this.activeNode),icon:this.activeNode.icon??"title",dropdown:s})}if(this.hasNodes&&this.hasMarks&&n.push("|"),this.hasMarks)for(const s in this.markButtons){const t=this.markButtons[s];"|"!==t?n.push({current:this.editor.activeMarks.includes(s),icon:t.icon,label:t.label,click:e=>this.command(t.command??s,e)}):n.push("|")}return n},hasMarks(){return this.$helper.object.length(this.markButtons)>0},hasNodes(){return this.$helper.object.length(this.nodeButtons)>1},markButtons(){const t=this.editor.buttons("mark");if(!1===this.marks||0===this.$helper.object.length(t))return{};if(!0===this.marks)return t;const e={};for(const[i,n]of this.marks.entries())"|"===n?e["divider"+i]="|":t[n]&&(e[n]=t[n]);return e},nodeButtons(){const t=this.editor.buttons("node");if(!1===this.nodes||0===this.$helper.object.length(t))return{};if("block+"!==this.editor.nodes.doc.content&&t.paragraph&&delete t.paragraph,!0===this.nodes)return t;const e={};for(const i of this.nodes)t[i]&&(e[i]=t[i]);return e},positions(){return!1===this.inline?null:{top:this.position.y+"px",left:this.position.x+"px"}}},methods:{close(t){t&&!1!==this.$el.contains(t.relatedTarget)||(this.isOpen=!1)},command(t,...e){this.$emit("command",t,...e)},isNodeActive(t){if(!1===this.editor.activeNodes.includes(t.name))return!1;if("paragraph"===t.name)return!1===this.editor.activeNodes.includes("listItem")&&!1===this.editor.activeNodes.includes("quote");if(t.attrs){if(void 0===Object.values(this.editor.activeNodeAttrs).find((e=>JSON.stringify(e)===JSON.stringify(t.attrs))))return!1}return!0},open(){this.isOpen=!0,this.inline&&this.$nextTick(this.setPosition)},setPosition(){const t=this.$el.getBoundingClientRect(),e=this.editor.element.getBoundingClientRect(),i=document.querySelector(".k-panel-menu").getBoundingClientRect(),{from:n,to:s}=this.editor.selection,o=this.editor.view.coordsAtPos(n),l=this.editor.view.coordsAtPos(s,!0),a=new DOMRect(o.left,o.top,l.right-o.left,l.bottom-o.top);let r=a.x-e.x+a.width/2-t.width/2,u=a.y-e.y-t.height-5;if(t.widthe.width&&(r=e.width-t.width);else{const n=e.x+r,s=n+t.width,o=i.width+20,l=20;nwindow.innerWidth-l&&(r-=s-(window.innerWidth-l))}this.position={x:r,y:u}}}},(function(){var t=this,e=t._self._c;return t.isOpen||!t.inline?e("k-toolbar",{ref:"toolbar",staticClass:"k-writer-toolbar",style:t.positions,attrs:{buttons:t.buttons,"data-inline":t.inline,theme:t.inline?"dark":"light"}}):t._e()}),[],!1,null,null,null,null).exports,jo={install(t){t.component("k-writer-toolbar",Ao),t.component("k-writer",Ln)}},Io={install(t){t.component("k-counter",Pe),t.component("k-autocomplete",qe),t.component("k-form",Ne),t.component("k-form-buttons",ze),t.component("k-field",Ye),t.component("k-fieldset",Re),t.component("k-input",He),t.component("k-upload",Ve),t.use(ki),t.use(to),t.use(Fs),t.use(io),t.use(_o),t.use(Mo),t.use(jo)}},Do=()=>Y((()=>import("./IndexView.min.js")),__vite__mapDeps([0,1]),import.meta.url),Eo=()=>Y((()=>import("./DocsView.min.js")),__vite__mapDeps([2,3,1]),import.meta.url),To=()=>Y((()=>import("./PlaygroundView.min.js")),__vite__mapDeps([4,3,1]),import.meta.url),Lo={install(t){t.component("k-lab-index-view",Do),t.component("k-lab-docs-view",Eo),t.component("k-lab-playground-view",To)}};const Bo=ut({props:{cover:Boolean,ratio:String},computed:{ratioPadding(){return this.$helper.ratio(this.ratio)}},mounted(){window.panel.deprecated(" will be removed in a future version. Use the instead.")}},(function(){var t=this;return(0,t._self._c)("span",{staticClass:"k-aspect-ratio",style:{"padding-bottom":t.ratioPadding},attrs:{"data-cover":t.cover}},[t._t("default")],2)}),[],!1,null,null,null,null).exports;const qo=ut({props:{align:{type:String,default:"start"}},mounted(){(this.$slots.left||this.$slots.center||this.$slots.right)&&window.panel.deprecated(": left/centre/right slots will be removed in a future version. Use with default slot only instead.")}},(function(){var t=this,e=t._self._c;return e("div",{staticClass:"k-bar",attrs:{"data-align":t.align}},[t.$slots.left||t.$slots.center||t.$slots.right?[t.$slots.left?e("div",{staticClass:"k-bar-slot",attrs:{"data-position":"left"}},[t._t("left")],2):t._e(),t.$slots.center?e("div",{staticClass:"k-bar-slot",attrs:{"data-position":"center"}},[t._t("center")],2):t._e(),t.$slots.right?e("div",{staticClass:"k-bar-slot",attrs:{"data-position":"right"}},[t._t("right")],2):t._e()]:t._t("default")],2)}),[],!1,null,null,null,null).exports;const Po=ut({props:{align:{type:String,default:"start"},button:Boolean,height:String,icon:String,theme:{type:String},text:String,html:{type:Boolean}},computed:{element(){return this.button?"button":"div"},type(){return this.button?"button":null}}},(function(){var t=this,e=t._self._c;return e(t.element,{tag:"component",staticClass:"k-box",style:t.height?{"--box-height":t.height}:null,attrs:{"data-align":t.align,"data-theme":t.theme,type:t.type}},[t.icon?e("k-icon",{attrs:{type:t.icon}}):t._e(),t._t("default",(function(){return[t.html?e("k-text",{attrs:{html:t.text}}):e("k-text",[t._v(" "+t._s(t.text)+" ")])]}),null,{html:t.html,text:t.text})],2)}),[],!1,null,null,null,null).exports;const No=ut({inheritAttrs:!1,props:{back:String,color:String,element:{type:String,default:"li"},html:{type:Boolean},image:Object,link:String,text:String},mounted(){this.back&&window.panel.deprecated(": `back` prop will be removed in a future version. Use the `--bubble-back` CSS property instead."),this.color&&window.panel.deprecated(": `color` prop will be removed in a future version. Use the `--bubble-text` CSS property instead.")}},(function(){var t=this,e=t._self._c;return e(t.link?"k-link":"p",{tag:"component",staticClass:"k-bubble",style:{color:t.$helper.color(t.color),background:t.$helper.color(t.back)},attrs:{to:t.link,"data-has-text":Boolean(t.text)},nativeOn:{click:function(t){t.stopPropagation()}}},[t._t("image",(function(){var i;return[(null==(i=t.image)?void 0:i.src)?e("k-image-frame",t._b({},"k-image-frame",t.image,!1)):t.image?e("k-icon-frame",t._b({},"k-icon-frame",t.image,!1)):e("span")]})),t.text?[t.html?e("span",{staticClass:"k-bubble-text",domProps:{innerHTML:t._s(t.text)}}):e("span",{staticClass:"k-bubble-text"},[t._v(t._s(t.text))])]:t._e()],2)}),[],!1,null,null,null,null).exports;const zo=ut({props:{width:{type:String,default:"1/1"},sticky:Boolean}},(function(){var t=this,e=t._self._c;return e("div",{staticClass:"k-column",style:{"--width":t.width},attrs:{"data-sticky":t.sticky}},[t.sticky?e("div",[t._t("default")],2):t._t("default")],2)}),[],!1,null,null,null,null).exports,Fo={props:{element:{type:String,default:"div"},fit:String,ratio:String,cover:Boolean,back:String,theme:String}};const Yo=ut({mixins:[Fo],inheritAttrs:!1,computed:{background(){return this.$helper.color(this.back)}}},(function(){var t=this;return(0,t._self._c)(t.element,{tag:"component",staticClass:"k-frame",style:{"--fit":t.fit??(t.cover?"cover":"contain"),"--ratio":t.ratio,"--back":t.background},attrs:{"data-theme":t.theme}},[t._t("default")],2)}),[],!1,null,null,null,null).exports;const Ro=ut({mixins:[{mixins:[Fo],props:{color:String}}],inheritAttrs:!1},(function(){var t=this;return(0,t._self._c)("k-frame",t._b({staticClass:"k-color-frame",style:{color:t.color}},"k-frame",t.$props,!1),[t._t("default")],2)}),[],!1,null,null,null,null).exports;const Uo=ut({props:{disabled:{type:Boolean}},emits:["drop"],data:()=>({files:[],dragging:!1,over:!1}),methods:{cancel(){this.reset()},reset(){this.dragging=!1,this.over=!1},onDrop(t){return!0===this.disabled||!1===this.$helper.isUploadEvent(t)?this.reset():(this.$events.emit("dropzone.drop"),this.files=t.dataTransfer.files,this.$emit("drop",this.files),void this.reset())},onEnter(t){!1===this.disabled&&this.$helper.isUploadEvent(t)&&(this.dragging=!0)},onLeave(){this.reset()},onOver(t){!1===this.disabled&&this.$helper.isUploadEvent(t)&&(t.dataTransfer.dropEffect="copy",this.over=!0)}}},(function(){var t=this;return(0,t._self._c)("div",{staticClass:"k-dropzone",attrs:{"data-dragging":t.dragging,"data-over":t.over},on:{dragenter:t.onEnter,dragleave:t.onLeave,dragover:t.onOver,drop:t.onDrop}},[t._t("default")],2)}),[],!1,null,null,null,null).exports;const Ho=ut({props:{gutter:String,variant:String},mounted(){this.gutter&&window.panel.deprecated(': the `gutter` prop will be removed in a future version. Use `style="gap: "` or `variant` prop instead.')}},(function(){var t=this;return(0,t._self._c)("div",{staticClass:"k-grid",attrs:{"data-gutter":t.gutter,"data-variant":t.variant}},[t._t("default")],2)}),[],!1,null,null,null,null).exports;const Vo=ut({props:{editable:{type:Boolean},tabs:Array},emits:["edit"],mounted(){this.tabs&&window.panel.deprecated(": `tabs` prop isn't supported anymore and has no effect. Use `` as standalone component instead."),(this.$slots.left||this.$slots.right)&&window.panel.deprecated(": left/right slots will be removed in a future version. Use `buttons` slot instead.")}},(function(){var t=this,e=t._self._c;return e("header",{staticClass:"k-header",attrs:{"data-has-buttons":Boolean(t.$slots.buttons||t.$slots.left||t.$slots.right)}},[e("h1",{staticClass:"k-header-title"},[t.editable?e("button",{staticClass:"k-header-title-button",attrs:{type:"button"},on:{click:function(e){return t.$emit("edit")}}},[e("span",{staticClass:"k-header-title-text"},[t._t("default")],2),e("span",{staticClass:"k-header-title-icon"},[e("k-icon",{attrs:{type:"edit"}})],1)]):e("span",{staticClass:"k-header-title-text"},[t._t("default")],2)]),t.$slots.buttons||t.$slots.left||t.$slots.right?e("div",{staticClass:"k-header-buttons"},[t._t("buttons"),t._t("left"),t._t("right")],2):t._e()])}),[],!1,null,null,null,null).exports,Ko={props:{alt:String,color:String,type:String}};const Wo=ut({mixins:[Ko],computed:{isEmoji(){return this.$helper.string.hasEmoji(this.type)}}},(function(){var t=this,e=t._self._c;return t.isEmoji?e("span",{attrs:{"data-type":"emoji"}},[t._v(t._s(t.type))]):e("svg",{staticClass:"k-icon",style:{color:t.$helper.color(t.color)},attrs:{"aria-label":t.alt,role:t.alt?"img":null,"aria-hidden":!t.alt,"data-type":t.type}},[e("use",{attrs:{"xlink:href":"#icon-"+t.type}})])}),[],!1,null,null,null,null).exports;const Jo=ut({mixins:[{mixins:[Fo,Ko],props:{type:null,icon:String}}],inheritAttrs:!1},(function(){var t=this,e=t._self._c;return e("k-frame",t._b({staticClass:"k-icon-frame",attrs:{element:"figure"}},"k-frame",t.$props,!1),[e("k-icon",t._b({},"k-icon",{color:t.color,type:t.icon,alt:t.alt},!1))],1)}),[],!1,null,null,null,null).exports;const Go=ut({mixins:[{mixins:[Fo],props:{alt:String,sizes:String,src:String,srcset:String}}],inheritAttrs:!1},(function(){var t=this,e=t._self._c;return e("k-frame",t._g(t._b({staticClass:"k-image-frame k-image",attrs:{element:"figure"}},"k-frame",t.$props,!1),t.$listeners),[t.src?e("img",{key:t.src,attrs:{alt:t.alt??"",src:t.src,srcset:t.srcset,sizes:t.sizes},on:{dragstart:function(t){t.preventDefault()}}}):t._e()])}),[],!1,null,null,null,null).exports;const Xo=ut({mixins:[{props:{autofocus:{default:!0,type:Boolean},nested:{default:!1,type:Boolean},type:{default:"overlay",type:String},visible:{default:!1,type:Boolean}}}],inheritAttrs:!0,emits:["cancel","close","open"],watch:{visible(t,e){t!==e&&this.toggle()}},mounted(){this.toggle()},methods:{cancel(){this.$emit("cancel"),this.close()},close(){if(!1!==this.$refs.overlay.open)return this.nested?this.onClose():void this.$refs.overlay.close()},focus(){this.$helper.focus(this.$refs.overlay)},onCancel(t){this.nested&&(t.preventDefault(),this.cancel())},onClick(t){t.target.matches(".k-portal")&&this.cancel()},onClose(){this.$emit("close")},open(){!0!==this.$refs.overlay.open&&this.$refs.overlay.showModal(),setTimeout((()=>{!0===this.autofocus&&this.focus(),this.$emit("open")}))},toggle(){!0===this.visible?this.open():this.close()}}},(function(){var t=this;return(0,t._self._c)("dialog",{ref:"overlay",staticClass:"k-overlay",attrs:{"data-type":t.type},on:{cancel:t.onCancel,mousedown:t.onClick,touchdown:t.onClick,close:t.onClose}},[t._t("default")],2)}),[],!1,null,null,null,null).exports;const Zo=ut({props:{label:String,value:String,icon:String,info:String,theme:String,link:String,click:Function,dialog:{type:[String,Object]}},computed:{component(){return null!==this.target?"k-link":"div"},target(){return this.link?this.link:this.click?this.click:this.dialog?()=>this.$dialog(this.dialog):null}}},(function(){var t=this,e=t._self._c;return e(t.component,{tag:"component",staticClass:"k-stat",attrs:{"data-theme":t.theme,to:t.target}},[t.label?e("dt",{staticClass:"k-stat-label"},[t.icon?e("k-icon",{attrs:{type:t.icon}}):t._e(),t._v(" "+t._s(t.label)+" ")],1):t._e(),t.value?e("dd",{staticClass:"k-stat-value"},[t._v(t._s(t.value))]):t._e(),t.info?e("dd",{staticClass:"k-stat-info"},[t._v(t._s(t.info))]):t._e()])}),[],!1,null,null,null,null).exports;const Qo=ut({props:{reports:{type:Array,default:()=>[]},size:{type:String,default:"large"}},methods:{component(t){return null!==this.target(t)?"k-link":"div"},target(t){return t.link?t.link:t.click?t.click:t.dialog?()=>this.$dialog(t.dialog):null}}},(function(){var t=this,e=t._self._c;return e("dl",{staticClass:"k-stats",attrs:{"data-size":t.size}},t._l(t.reports,(function(i,n){return e("k-stat",t._b({key:n},"k-stat",i,!1))})),1)}),[],!1,null,null,null,null).exports;const tl=ut({inheritAttrs:!1,props:{columns:{type:Object,default:()=>({})},disabled:Boolean,fields:{type:Object,default:()=>({})},empty:String,index:{type:[Number,Boolean],default:1},rows:Array,options:{default:()=>[],type:[Array,Function]},pagination:[Object,Boolean],sortable:Boolean},emits:["cell","change","header","input","option","paginate","sort"],data(){return{values:this.rows}},computed:{colspan(){let t=this.columnsCount;return this.hasIndexColumn&&t++,this.hasOptions&&t++,t},columnsCount(){return this.$helper.object.length(this.columns)},dragOptions(){return{disabled:!this.sortable,fallbackClass:"k-table-row-fallback",ghostClass:"k-table-row-ghost"}},hasIndexColumn(){return this.sortable||!1!==this.index},hasOptions(){var t;return this.$scopedSlots.options||(null==(t=this.options)?void 0:t.length)>0||Object.values(this.values).filter((t=>null==t?void 0:t.options)).length>0}},watch:{rows(){this.values=this.rows}},methods:{isColumnEmpty(t){return 0===this.rows.filter((e=>!1===this.$helper.object.isEmpty(e[t]))).length},label(t,e){return t.label??this.$helper.string.ucfirst(e)},onChange(t){this.$emit("change",t)},onCell(t){this.$emit("cell",t)},onCellUpdate({columnIndex:t,rowIndex:e,value:i}){this.values[e][t]=i,this.$emit("input",this.values)},onHeader(t){this.$emit("header",t)},onOption(t,e,i){this.$emit("option",t,e,i)},onSort(){this.$emit("input",this.values),this.$emit("sort",this.values)},width(t){return"string"!=typeof t?"auto":!1===t.includes("/")?t:this.$helper.ratio(t,"auto",!1)}}},(function(){var t=this,e=t._self._c;return e("div",{staticClass:"k-table",attrs:{"aria-disabled":t.disabled}},[e("table",{attrs:{"data-disabled":t.disabled,"data-indexed":t.hasIndexColumn}},[e("thead",[e("tr",[t.hasIndexColumn?e("th",{staticClass:"k-table-index-column",attrs:{"data-mobile":"true"}},[t._v(" # ")]):t._e(),t._l(t.columns,(function(i,n){return e("th",{key:n+"-header",staticClass:"k-table-column",style:{width:t.width(i.width)},attrs:{"data-align":i.align,"data-column-id":n,"data-mobile":i.mobile},on:{click:function(e){return t.onHeader({column:i,columnIndex:n})}}},[t._t("header",(function(){return[t._v(" "+t._s(t.label(i,n))+" ")]}),null,{column:i,columnIndex:n,label:t.label(i,n)})],2)})),t.hasOptions?e("th",{staticClass:"k-table-options-column",attrs:{"data-mobile":"true"}}):t._e()],2)]),e("k-draggable",{attrs:{list:t.values,options:t.dragOptions,handle:!0,element:"tbody"},on:{change:t.onChange,end:t.onSort}},[0===t.rows.length?e("tr",[e("td",{staticClass:"k-table-empty",attrs:{colspan:t.colspan}},[t._v(" "+t._s(t.empty)+" ")])]):t._l(t.values,(function(i,n){return e("tr",{key:n},[t.hasIndexColumn?e("td",{staticClass:"k-table-index-column",attrs:{"data-sortable":t.sortable&&!1!==i.sortable,"data-mobile":"true"}},[t._t("index",(function(){return[e("div",{staticClass:"k-table-index",domProps:{textContent:t._s(t.index+n)}})]}),null,{row:i,rowIndex:n}),t.sortable&&!1!==i.sortable?e("k-sort-handle",{staticClass:"k-table-sort-handle"}):t._e()],2):t._e(),t._l(t.columns,(function(s,o){return e("k-table-cell",{key:n+"-"+o,staticClass:"k-table-column",style:{width:t.width(s.width)},attrs:{id:o,column:s,field:t.fields[o],row:i,mobile:s.mobile,value:i[o]},on:{input:function(e){return t.onCellUpdate({columnIndex:o,rowIndex:n,value:e})}},nativeOn:{click:function(e){return t.onCell({row:i,rowIndex:n,column:s,columnIndex:o})}}})})),t.hasOptions?e("td",{staticClass:"k-table-options-column",attrs:{"data-mobile":"true"}},[t._t("options",(function(){return[e("k-options-dropdown",{attrs:{options:i.options??t.options,text:(i.options??t.options).length>1},on:{option:function(e){return t.onOption(e,i,n)}}})]}),null,{row:i,rowIndex:n})],2):t._e()],2)}))],2)],1),t.pagination?e("k-pagination",t._b({staticClass:"k-table-pagination",on:{paginate:function(e){return t.$emit("paginate",e)}}},"k-pagination",t.pagination,!1)):t._e()],1)}),[],!1,null,null,null,null).exports;const el=ut({inheritAttrs:!1,props:{column:Object,field:Object,id:String,mobile:{type:Boolean,default:!1},row:Object,value:{default:""}},emits:["input"],computed:{component(){return this.$helper.isComponent(`k-${this.type}-field-preview`)?`k-${this.type}-field-preview`:this.$helper.isComponent(`k-table-${this.type}-cell`)?`k-table-${this.type}-cell`:Array.isArray(this.value)?"k-array-field-preview":"object"==typeof this.value?"k-object-field-preview":"k-text-field-preview"},type(){var t;return this.column.type??(null==(t=this.field)?void 0:t.type)}}},(function(){var t=this,e=t._self._c;return e("td",{staticClass:"k-table-cell",attrs:{"data-align":t.column.align,"data-column-id":t.id,"data-mobile":t.mobile}},[!1===t.$helper.object.isEmpty(t.value)?e(t.component,{tag:"component",attrs:{column:t.column,field:t.field,row:t.row,value:t.value},on:{input:function(e){return t.$emit("input",e)}}}):t._e()],1)}),[],!1,null,null,null,null).exports;const il=ut({props:{tab:String,tabs:{type:Array,default:()=>[]},theme:{type:String,default:"passive"}},data(){return{observer:null,visible:this.tabs,invisible:[]}},computed:{buttons(){return this.visible.map(this.button)},current(){const t=this.tabs.find((t=>t.name===this.tab))??this.tabs[0];return null==t?void 0:t.name},dropdown(){return this.invisible.map(this.button)}},watch:{tabs:{async handler(){var t;null==(t=this.observer)||t.disconnect(),await this.$nextTick(),this.$el instanceof Element&&(this.observer=new ResizeObserver(this.resize),this.observer.observe(this.$el))},immediate:!0}},destroyed(){var t;null==(t=this.observer)||t.disconnect()},methods:{button(t){return{...t,current:t.name===this.current,title:t.label,text:t.label??t.text??t.name}},async resize(){const t=this.$el.offsetWidth;this.visible=this.tabs,this.invisible=[],await this.$nextTick();const e=[...this.$refs.visible].map((t=>t.$el.offsetWidth));let i=32;for(let n=0;nt)return this.visible=this.tabs.slice(0,n),void(this.invisible=this.tabs.slice(n))}}},(function(){var t=this,e=t._self._c;return t.tabs.length>1?e("nav",{staticClass:"k-tabs"},[t._l(t.buttons,(function(i){return e("div",{key:i.name,staticClass:"k-tabs-tab"},[e("k-button",t._b({ref:"visible",refInFor:!0,staticClass:"k-tab-button",attrs:{variant:"dimmed"}},"k-button",i,!1),[t._v(" "+t._s(i.text)+" ")]),i.badge?e("span",{staticClass:"k-tabs-badge",attrs:{"data-theme":t.theme}},[t._v(" "+t._s(i.badge)+" ")]):t._e()],1)})),t.invisible.length?[e("k-button",{staticClass:"k-tab-button k-tabs-dropdown-button",attrs:{current:!!t.invisible.find((e=>t.tab===e.name)),title:t.$t("more"),icon:"dots",variant:"dimmed"},on:{click:function(e){return e.stopPropagation(),t.$refs.more.toggle()}}}),e("k-dropdown-content",{ref:"more",staticClass:"k-tabs-dropdown",attrs:{options:t.dropdown,"align-x":"end"}})]:t._e()],2):t._e()}),[],!1,null,null,null,null).exports;const nl=ut({props:{align:String},mounted(){window.panel.deprecated(" will be removed in a future version.")}},(function(){var t=this;return(0,t._self._c)("div",{staticClass:"k-view",attrs:{"data-align":t.align}},[t._t("default")],2)}),[],!1,null,null,null,null).exports,sl={install(t){t.component("k-aspect-ratio",Bo),t.component("k-bar",qo),t.component("k-box",Po),t.component("k-bubble",No),t.component("k-bubbles",oo),t.component("k-color-frame",Ro),t.component("k-column",zo),t.component("k-dropzone",Uo),t.component("k-frame",Yo),t.component("k-grid",Ho),t.component("k-header",Vo),t.component("k-icon-frame",Jo),t.component("k-image-frame",Go),t.component("k-image",Go),t.component("k-overlay",Xo),t.component("k-stat",Zo),t.component("k-stats",Qo),t.component("k-table",tl),t.component("k-table-cell",el),t.component("k-tabs",il),t.component("k-view",nl)}};const ol=ut({components:{draggable:()=>Y((()=>import("./vuedraggable.min.js")),[],import.meta.url)},props:{data:Object,element:{type:String,default:"div"},handle:[String,Boolean],list:[Array,Object],move:Function,options:Object},emits:["change","end","sort","start"],computed:{dragOptions(){let t=this.handle;return!0===t&&(t=".k-sort-handle"),{fallbackClass:"k-sortable-fallback",fallbackOnBody:!0,forceFallback:!0,ghostClass:"k-sortable-ghost",handle:t,scroll:document.querySelector(".k-panel-main"),...this.options}}},methods:{onStart(t){this.$panel.drag.start("data",{}),this.$emit("start",t)},onEnd(t){this.$panel.drag.stop(),this.$emit("end",t)}}},(function(){var t=this;return(0,t._self._c)("draggable",t._b({staticClass:"k-draggable",attrs:{"component-data":t.data,tag:t.element,list:t.list,move:t.move},on:{change:function(e){return t.$emit("change",e)},end:t.onEnd,sort:function(e){return t.$emit("sort",e)},start:t.onStart},scopedSlots:t._u([{key:"footer",fn:function(){return[t._t("footer")]},proxy:!0}],null,!0)},"draggable",t.dragOptions,!1),[t._t("default")],2)}),[],!1,null,null,null,null).exports;const ll=ut({data:()=>({error:null}),errorCaptured(t){return this.$panel.debug&&window.console.warn(t),this.error=t,!1},render(){return this.error?this.$slots.error?this.$slots.error[0]:this.$scopedSlots.error?this.$scopedSlots.error({error:this.error}):Vue.h("k-box",{attrs:{theme:"negative"}},this.error.message??this.error):this.$slots.default[0]}},null,null,!1,null,null,null,null).exports;const al=ut({props:{html:String},mounted(){try{let t=this.$refs.iframe.contentWindow.document;t.open(),t.write(this.html),t.close()}catch(t){console.error(t)}}},(function(){var t=this,e=t._self._c;return e("k-overlay",{staticClass:"k-fatal",attrs:{visible:!0}},[e("div",{staticClass:"k-fatal-box"},[e("div",{staticClass:"k-notification",attrs:{"data-theme":"negative"}},[e("p",[t._v("The JSON response could not be parsed")]),e("k-button",{attrs:{icon:"cancel"},on:{click:function(e){return e.stopPropagation(),t.$panel.notification.close()}}})],1),e("iframe",{ref:"iframe",staticClass:"k-fatal-iframe"})])])}),[],!1,null,null,null,null).exports;const rl=ut({icons:window.panel.plugins.icons,methods:{viewbox(t,e){const i=document.createElementNS("http://www.w3.org/2000/svg","svg");i.innerHTML=e,document.body.appendChild(i);const n=i.getBBox(),s=(n.width+2*n.x+(n.height+2*n.y))/2,o=Math.abs(s-16),l=Math.abs(s-24);return document.body.removeChild(i),o element with the corresponding viewBox attribute.`),"0 0 16 16"):"0 0 24 24"}}},(function(){var t=this,e=t._self._c;return e("svg",{staticClass:"k-icons",attrs:{"aria-hidden":"true",xmlns:"http://www.w3.org/2000/svg",overflow:"hidden"}},[e("defs",t._l(t.$options.icons,(function(i,n){return e("symbol",{key:n,attrs:{id:"icon-"+n,viewBox:t.viewbox(n,i)},domProps:{innerHTML:t._s(i)}})})),0)])}),[],!1,null,null,null,null).exports;const ul=ut({mounted(){window.panel.deprecated(' will be removed in a future version. Use instead.')}},(function(){var t=this._self._c;return t("span",{staticClass:"k-loader"},[t("k-icon",{staticClass:"k-loader-icon",attrs:{type:"loader"}})],1)}),[],!1,null,null,null,null).exports;const cl=ut({},(function(){var t=this,e=t._self._c;return t.$panel.notification.isOpen?e("div",{staticClass:"k-notification",attrs:{"data-theme":t.$panel.notification.theme}},[e("p",[t._v(t._s(t.$panel.notification.message))]),e("k-button",{attrs:{icon:"cancel"},on:{click:function(e){return t.$panel.notification.close()}}})],1):t._e()}),[],!1,null,null,null,null).exports;const dl=ut({},(function(){var t=this,e=t._self._c;return t.$panel.isOffline?e("div",{staticClass:"k-offline-warning"},[e("p",[e("k-icon",{attrs:{type:"bolt"}}),t._v(" "+t._s(t.$t("error.offline")))],1)]):t._e()}),[],!1,null,null,null,null).exports,pl=(t,e=!1)=>{if(t>=0&&t<=100)return!0;if(e)throw new Error("value has to be between 0 and 100");return!1};const hl=ut({props:{value:{type:Number,default:0,validator:pl}},data(){return{state:this.value}},watch:{value(t){this.state=t}},methods:{set(t){window.panel.deprecated(": `set` method will be removed in a future version. Use the `value` prop instead."),pl(t,!0),this.state=t}}},(function(){var t=this;return(0,t._self._c)("progress",{staticClass:"k-progress",attrs:{max:"100"},domProps:{value:t.state}},[t._v(t._s(t.state)+"%")])}),[],!1,null,null,null,null).exports;const ml=ut({},(function(){return(0,this._self._c)("k-button",{staticClass:"k-sort-handle k-sort-button",attrs:{title:this.$t("sort.drag"),icon:"sort","aria-hidden":"true"}})}),[],!1,null,null,null,null).exports,fl={install(t){t.component("k-draggable",ol),t.component("k-error-boundary",ll),t.component("k-fatal",al),t.component("k-icon",Wo),t.component("k-icons",rl),t.component("k-loader",ul),t.component("k-notification",cl),t.component("k-offline-warning",dl),t.component("k-progress",hl),t.component("k-sort-handle",ml)}};const gl=ut({props:{crumbs:{type:Array,default:()=>[]},label:{type:String,default:"Breadcrumb"},view:Object},computed:{dropdown(){return this.segments.map((t=>({...t,text:t.label,icon:"angle-right"})))},segments(){const t=[];return this.view&&t.push({link:this.view.link,label:this.view.label??this.view.breadcrumbLabel,icon:this.view.icon,loading:this.$panel.isLoading}),[...t,...this.crumbs]}},mounted(){this.view&&window.panel.deprecated(": `view` prop will be removed in a future version. Use `crumbs` instead.")}},(function(){var t=this,e=t._self._c;return e("nav",{staticClass:"k-breadcrumb",attrs:{"aria-label":t.label}},[t.segments.length>1?e("div",{staticClass:"k-breadcrumb-dropdown"},[e("k-button",{attrs:{icon:"home"},on:{click:function(e){return t.$refs.dropdown.toggle()}}}),e("k-dropdown-content",{ref:"dropdown",attrs:{options:t.dropdown}})],1):t._e(),e("ol",t._l(t.segments,(function(i,n){return e("li",{key:n},[e("k-button",{staticClass:"k-breadcrumb-link",attrs:{icon:i.loading?"loader":i.icon,link:i.link,disabled:!i.link,text:i.text??i.label,title:i.text??i.label,current:n===t.segments.length-1&&"page",variant:"dimmed",size:"sm"}})],1)})),0)])}),[],!1,null,null,null,null).exports;const kl=ut({props:{items:{type:Array},name:{default:"items",type:String},selected:{type:String},type:{default:"radio",type:String}},emits:["select"]},(function(){var t=this,e=t._self._c;return e("nav",{staticClass:"k-browser"},[e("div",{staticClass:"k-browser-items"},t._l(t.items,(function(i){return e("label",{key:i.value,staticClass:"k-browser-item",attrs:{"aria-selected":t.selected===i.value}},[e("input",{attrs:{name:t.name,type:t.type},domProps:{checked:t.selected===i.value},on:{change:function(e){return t.$emit("select",i)}}}),i.image?e("k-item-image",{staticClass:"k-browser-item-image",attrs:{image:{...i.image,cover:!0,back:"black"}}}):t._e(),e("span",{staticClass:"k-browser-item-info"},[t._v(" "+t._s(i.label)+" ")])],1)})),0)])}),[],!1,null,null,null,null).exports,bl={props:{disabled:Boolean,download:Boolean,rel:String,tabindex:[String,Number],target:String,title:String}};const vl=ut({mixins:[bl],props:{to:[String,Function]},emits:["click"],computed:{href(){return"function"==typeof this.to?"":"/"!==this.to[0]||this.target?!0===this.to.includes("@")&&!1===this.to.includes("/")&&!1===this.to.startsWith("mailto:")?"mailto:"+this.to:this.to:this.$url(this.to)},relAttr(){return"_blank"===this.target?"noreferrer noopener":this.rel}},methods:{isRoutable(t){if(t.metaKey||t.altKey||t.ctrlKey||t.shiftKey)return!1;if(t.defaultPrevented)return!1;if(void 0!==t.button&&0!==t.button)return!1;if(this.target)return!1;if("string"==typeof this.href){if(this.href.includes("://")||this.href.startsWith("//"))return!1;if(this.href.includes("mailto:"))return!1}return!0},onClick(t){if(!0===this.disabled)return t.preventDefault(),!1;"function"==typeof this.to&&(t.preventDefault(),this.to()),this.isRoutable(t)&&(t.preventDefault(),this.$go(this.to)),this.$emit("click",t)}}},(function(){var t=this,e=t._self._c;return t.to&&!t.disabled?e("a",{ref:"link",staticClass:"k-link",attrs:{download:t.download,href:t.href,rel:t.relAttr,tabindex:t.tabindex,target:t.target,title:t.title},on:{click:t.onClick}},[t._t("default")],2):e("span",{staticClass:"k-link",attrs:{title:t.title,"aria-disabled":""}},[t._t("default")],2)}),[],!1,null,null,null,null).exports;const yl=ut({mixins:[{mixins:[bl],props:{autofocus:Boolean,click:{type:Function,default:()=>{}},current:[String,Boolean],dialog:String,drawer:String,dropdown:Boolean,element:String,icon:String,id:[String,Number],link:String,responsive:[Boolean,String],role:String,selected:[String,Boolean],size:String,text:[String,Number],theme:String,tooltip:String,type:{type:String,default:"button"},variant:String}}],inheritAttrs:!1,emits:["click"],computed:{attrs(){const t={"aria-current":this.current,"aria-disabled":this.disabled,"aria-selected":this.selected,"data-responsive":this.responsive,"data-size":this.size,"data-theme":this.theme,"data-variant":this.variant,id:this.id,tabindex:this.tabindex,title:this.title??this.tooltip};return"k-link"===this.component?(t.disabled=this.disabled,t.download=this.download,t.to=this.link,t.rel=this.rel,t.target=this.target):"button"===this.component&&(t.autofocus=this.autofocus,t.role=this.role,t.type=this.type),this.dropdown&&(t["aria-haspopup"]="menu",t["data-dropdown"]=this.dropdown),t},component(){return this.element?this.element:this.link?"k-link":"button"}},mounted(){this.tooltip&&window.panel.deprecated(": the `tooltip` prop will be removed in a future version. Use the `title` prop instead.")},methods:{focus(){var t,e;null==(e=(t=this.$el).focus)||e.call(t)},onClick(t){var e;return this.disabled?(t.preventDefault(),!1):this.dialog?this.$dialog(this.dialog):this.drawer?this.$drawer(this.drawer):(null==(e=this.click)||e.call(this,t),void this.$emit("click",t))}}},(function(){var t=this,e=t._self._c;return e(t.component,t._b({tag:"component",staticClass:"k-button",attrs:{"data-has-icon":Boolean(t.icon),"data-has-text":Boolean(t.text||t.$slots.default)},on:{click:t.onClick}},"component",t.attrs,!1),[t.icon?e("span",{staticClass:"k-button-icon"},[e("k-icon",{attrs:{type:t.icon}})],1):t._e(),t.text||t.$slots.default?e("span",{staticClass:"k-button-text"},[t._t("default",(function(){return[t._v(" "+t._s(t.text)+" ")]}))],2):t._e(),t.dropdown&&(t.text||t.$slots.default)?e("span",{staticClass:"k-button-arrow"},[e("k-icon",{attrs:{type:"angle-down"}})],1):t._e()])}),[],!1,null,null,null,null).exports;const $l=ut({props:{buttons:Array,layout:String,variant:String,theme:String,size:String,responsive:Boolean}},(function(){var t=this,e=t._self._c;return e("div",{staticClass:"k-button-group",attrs:{"data-layout":t.layout}},[t.$slots.default?t._t("default"):t._l(t.buttons,(function(i,n){return e("k-button",t._b({key:n},"k-button",{variant:t.variant,theme:t.theme,size:t.size,responsive:t.responsive,...i},!1))}))],2)}),[],!1,null,null,null,null).exports;const wl=ut({props:{limit:{default:50,type:Number},selected:{type:String}},emits:["select"],data:()=>({files:[],page:null,pagination:null,view:"tree"}),methods:{paginate(t){this.selectPage(this.page,t.page)},selectFile(t){this.$emit("select",t)},async selectPage(t,e=1){this.page=t;const i="/"===t.id?"/site/files":"/pages/"+this.$api.pages.id(t.id)+"/files",{data:n,pagination:s}=await this.$api.get(i,{select:"filename,id,panelImage,url,uuid",limit:this.limit,page:e});this.pagination=s,this.files=n.map((t=>({label:t.filename,image:t.panelImage,id:t.id,url:t.url,uuid:t.uuid,value:t.uuid??t.url}))),this.view="files"},async togglePage(){await this.$nextTick(),this.$refs.tree.scrollIntoView({behaviour:"smooth",block:"nearest",inline:"nearest"})}}},(function(){var t,e,i=this,n=i._self._c;return n("div",{staticClass:"k-file-browser",attrs:{"data-view":i.view}},[n("div",{staticClass:"k-file-browser-layout"},[n("aside",{ref:"tree",staticClass:"k-file-browser-tree"},[n("k-page-tree",{attrs:{current:null==(t=i.page)?void 0:t.value},on:{select:i.selectPage,toggleBranch:i.togglePage}})],1),n("div",{ref:"items",staticClass:"k-file-browser-items"},[n("k-button",{staticClass:"k-file-browser-back-button",attrs:{icon:"angle-left",text:null==(e=i.page)?void 0:e.label},on:{click:function(t){i.view="tree"}}}),i.files.length?n("k-browser",{attrs:{items:i.files,selected:i.selected},on:{select:i.selectFile}}):i._e()],1),n("div",{staticClass:"k-file-browser-pagination",on:{click:function(t){t.stopPropagation()}}},[i.pagination?n("k-pagination",i._b({attrs:{details:!0},on:{paginate:i.paginate}},"k-pagination",i.pagination,!1)):i._e()],1)])])}),[],!1,null,null,null,null).exports;const xl=ut({props:{tab:String,tabs:{type:Array,default:()=>[]}},computed:{withBadges(){const t=Object.keys(this.$store.getters["content/changes"]());return this.tabs.map((e=>{const i=[];for(const t in e.columns)for(const n in e.columns[t].sections)if("fields"===e.columns[t].sections[n].type)for(const s in e.columns[t].sections[n].fields)i.push(s);return e.badge=i.filter((e=>t.includes(e.toLowerCase()))).length,e}))}}},(function(){var t=this;return(0,t._self._c)("k-tabs",{staticClass:"k-model-tabs",attrs:{tab:t.tab,tabs:t.withBadges,theme:"notice"}})}),[],!1,null,null,null,null).exports;const _l=ut({props:{axis:String,disabled:Boolean,element:{type:String,default:"div"},select:{type:String,default:":where(button, a):not(:disabled)"}},emits:["next","prev"],computed:{keys(){switch(this.axis){case"x":return{ArrowLeft:this.prev,ArrowRight:this.next};case"y":return{ArrowUp:this.prev,ArrowDown:this.next};default:return{ArrowLeft:this.prev,ArrowRight:this.next,ArrowUp:this.prev,ArrowDown:this.next}}}},mounted(){this.$el.addEventListener("keydown",this.keydown)},destroyed(){this.$el.removeEventListener("keydown",this.keydown)},methods:{focus(t=0,e){this.move(t,e)},keydown(t){var e;if(this.disabled)return!1;null==(e=this.keys[t.key])||e.apply(this,[t])},move(t=0,e){var i;const n=[...this.$el.querySelectorAll(this.select)];let s=n.findIndex((t=>t===document.activeElement||t.contains(document.activeElement)));switch(-1===s&&(s=0),t){case"first":t=0;break;case"next":t=s+1;break;case"last":t=n.length-1;break;case"prev":t=s-1}t<0?this.$emit("prev"):t>=n.length?this.$emit("next"):null==(i=n[t])||i.focus(),null==e||e.preventDefault()},next(t){this.move("next",t)},prev(t){this.move("prev",t)}}},(function(){var t=this;return(0,t._self._c)(t.element,{tag:"component",staticClass:"k-navigate"},[t._t("default")],2)}),[],!1,null,null,null,null).exports;const Cl=ut({name:"k-tree",inheritAttrs:!1,props:{element:{type:String,default:"k-tree"},current:{type:String},items:{type:[Array,Object]},level:{default:0,type:Number}},emits:["close","open","select","toggle"],data(){return{state:this.items}},methods:{arrow:t=>!0===t.loading?"loader":t.open?"angle-down":"angle-right",close(t){this.$set(t,"open",!1),this.$emit("close",t)},open(t){this.$set(t,"open",!0),this.$emit("open",t)},select(t){this.$emit("select",t)},toggle(t){this.$emit("toggle",t),!0===t.open?this.close(t):this.open(t)}}},(function(){var t=this,e=t._self._c;return e("ul",{staticClass:"k-tree",class:t.$options.name,style:{"--tree-level":t.level}},t._l(t.state,(function(i,n){return e("li",{key:n,attrs:{"aria-expanded":i.open,"aria-current":i.value===t.current}},[e("p",{staticClass:"k-tree-branch",attrs:{"data-has-subtree":i.hasChildren&&i.open}},[e("button",{staticClass:"k-tree-toggle",attrs:{disabled:!i.hasChildren,type:"button"},on:{click:function(e){return t.toggle(i)}}},[e("k-icon",{attrs:{type:t.arrow(i)}})],1),e("button",{staticClass:"k-tree-folder",attrs:{disabled:i.disabled,type:"button"},on:{click:function(e){return t.select(i)},dblclick:function(e){return t.toggle(i)}}},[e("k-icon-frame",{attrs:{icon:i.icon??"folder"}}),e("span",{staticClass:"k-tree-folder-label"},[t._v(t._s(i.label))])],1)]),i.hasChildren&&i.open?[e(t.$options.name,t._b({tag:"component",attrs:{items:i.children,level:t.level+1},on:{close:function(e){return t.$emit("close",e)},open:function(e){return t.$emit("open",e)},select:function(e){return t.$emit("select",e)},toggle:function(e){return t.$emit("toggle",e)}}},"component",t.$props,!1))]:t._e()],2)})),0)}),[],!1,null,null,null,null).exports;const Sl=ut({name:"k-page-tree",extends:Cl,inheritAttrs:!1,props:{root:{default:!0,type:Boolean},current:{type:String},move:{type:String}},data:()=>({state:[]}),async mounted(){if(this.items)this.state=this.items;else{const t=await this.load(null);await this.open(t[0]),this.state=this.root?t:t[0].children}},methods:{async load(t){return await this.$panel.get("site/tree",{query:{move:this.move??null,parent:t}})},async open(t){if(!1===t.hasChildren)return!1;this.$set(t,"loading",!0),"string"==typeof t.children&&(t.children=await this.load(t.children)),this.$set(t,"open",!0),this.$set(t,"loading",!1)}}},null,null,!1,null,null,null,null).exports;const Ol=ut({props:{details:Boolean,limit:{type:Number,default:10},page:{type:Number,default:1},total:{type:Number,default:0},validate:{type:Function,default:()=>Promise.resolve()}},emits:["paginate"],computed:{detailsText(){return 1===this.limit?this.start:this.start+"-"+this.end},end(){return Math.min(this.start-1+this.limit,this.total)},offset(){return this.start-1},pages(){return Math.ceil(this.total/this.limit)},start(){return(this.page-1)*this.limit+1}},methods:{async goTo(t){var e;try{await this.validate(t),null==(e=this.$refs.dropdown)||e.close();const i=((t=Math.max(1,Math.min(t,this.pages)))-1)*this.limit+1;this.$emit("paginate",{page:t,start:i,end:Math.min(i-1+this.limit,this.total),limit:this.limit,offset:i-1,total:this.total})}catch{}},prev(){this.goTo(this.page-1)},next(){this.goTo(this.page+1)}}},(function(){var t=this,e=t._self._c;return t.pages>1?e("k-button-group",{staticClass:"k-pagination",attrs:{layout:"collapsed"},nativeOn:{keydown:[function(e){return!e.type.indexOf("key")&&t._k(e.keyCode,"left",37,e.key,["Left","ArrowLeft"])||"button"in e&&0!==e.button?null:t.prev.apply(null,arguments)},function(e){return!e.type.indexOf("key")&&t._k(e.keyCode,"right",39,e.key,["Right","ArrowRight"])||"button"in e&&2!==e.button?null:t.next.apply(null,arguments)}]}},[e("k-button",{staticClass:"k-pagination-button",attrs:{disabled:t.start<=1,title:t.$t("prev"),icon:"angle-left",size:"xs",variant:"filled"},on:{click:t.prev}}),t.details?[e("k-button",{staticClass:"k-pagination-details",attrs:{disabled:t.total<=t.limit,text:t.total>1?`${t.detailsText} / ${t.total}`:t.total,size:"xs",variant:"filled"},on:{click:function(e){return t.$refs.dropdown.toggle()}}}),e("k-dropdown-content",{ref:"dropdown",staticClass:"k-pagination-selector",attrs:{"align-x":"end"},nativeOn:{keydown:[function(e){return!e.type.indexOf("key")&&t._k(e.keyCode,"left",37,e.key,["Left","ArrowLeft"])||"button"in e&&0!==e.button?null:void e.stopPropagation()},function(e){return!e.type.indexOf("key")&&t._k(e.keyCode,"right",39,e.key,["Right","ArrowRight"])||"button"in e&&2!==e.button?null:void e.stopPropagation()}]}},[e("form",{attrs:{method:"dialog"},on:{click:function(t){t.stopPropagation()},submit:function(e){return t.goTo(t.$refs.page.value)}}},[e("label",[t._v(" "+t._s(t.$t("pagination.page"))+": "),e("select",{ref:"page",attrs:{autofocus:!0}},t._l(t.pages,(function(i){return e("option",{key:i,domProps:{selected:t.page===i,value:i}},[t._v(" "+t._s(i)+" ")])})),0)]),e("k-button",{attrs:{type:"submit",icon:"check"}})],1)])]:t._e(),e("k-button",{staticClass:"k-pagination-button",attrs:{disabled:t.end>=t.total,title:t.$t("next"),icon:"angle-right",size:"xs",variant:"filled"},on:{click:t.next}})],2):t._e()}),[],!1,null,null,null,null).exports;const Ml=ut({props:{prev:{type:[Boolean,Object],default:!1},next:{type:[Boolean,Object],default:!1}},computed:{buttons(){return[{...this.button(this.prev),icon:"angle-left"},{...this.button(this.next),icon:"angle-right"}]},isFullyDisabled(){return 0===this.buttons.filter((t=>!t.disabled)).length}},methods:{button:t=>t||{disabled:!0,link:"#"}}},(function(){var t=this,e=t._self._c;return t.isFullyDisabled?t._e():e("k-button-group",{staticClass:"k-prev-next",attrs:{buttons:t.buttons,layout:"collapsed",size:"xs"}})}),[],!1,null,null,null,null).exports;const Al=ut({props:{disabled:Boolean,html:{type:Boolean},image:{type:Object},removable:Boolean,text:String},emits:["remove"],computed:{isRemovable(){return this.removable&&!this.disabled}},methods:{remove(){this.isRemovable&&this.$emit("remove")},focus(){this.$refs.button.focus()}}},(function(){var t=this,e=t._self._c;return e("button",{ref:"button",staticClass:"k-tag",attrs:{"aria-disabled":t.disabled,"data-has-image":Boolean(t.image),"data-has-toggle":t.isRemovable,type:"button"},on:{keydown:function(e){return!e.type.indexOf("key")&&t._k(e.keyCode,"delete",[8,46],e.key,["Backspace","Delete","Del"])?null:(e.preventDefault(),t.remove.apply(null,arguments))}}},[t._t("image",(function(){var i;return[(null==(i=t.image)?void 0:i.src)?e("k-image-frame",t._b({staticClass:"k-tag-image"},"k-image-frame",t.image,!1)):t.image?e("k-icon-frame",t._b({staticClass:"k-tag-image"},"k-icon-frame",t.image,!1)):t._e()]})),t.text?[t.html?e("span",{staticClass:"k-tag-text",domProps:{innerHTML:t._s(t.text)}}):e("span",{staticClass:"k-tag-text"},[t._v(t._s(t.text))])]:t.$slots.default?[e("span",{staticClass:"k-tag-text"},[t._t("default")],2)]:t._e(),t.isRemovable?e("k-icon-frame",{staticClass:"k-tag-toggle",attrs:{icon:"cancel-small"},nativeOn:{click:function(e){return e.stopPropagation(),t.remove.apply(null,arguments)}}}):t._e()],2)}),[],!1,null,null,null,null).exports;const jl=ut({inheritAttrs:!1,props:{icon:String,id:[String,Number],responsive:Boolean,theme:String,tooltip:String},mounted(){window.panel.deprecated(' will be removed in a future version. Use instead.')}},(function(){var t=this,e=t._self._c;return e("span",{staticClass:"k-button",attrs:{id:t.id,"data-disabled":!0,"data-responsive":t.responsive,"data-theme":t.theme,title:t.tooltip}},[t.icon?e("k-icon",{staticClass:"k-button-icon",attrs:{type:t.icon,alt:t.tooltip}}):t._e(),t.$slots.default?e("span",{staticClass:"k-button-text"},[t._t("default")],2):t._e()],1)}),[],!1,null,null,null,null).exports;const Il=ut({inheritAttrs:!1,props:{autofocus:Boolean,current:[String,Boolean],icon:String,id:[String,Number],link:String,rel:String,responsive:Boolean,role:String,target:String,tabindex:String,theme:String,tooltip:String},mounted(){window.panel.deprecated(' will be removed in a future version. Use instead.')},methods:{focus(){this.$el.focus()}}},(function(){var t=this,e=t._self._c;return e("k-link",{staticClass:"k-button",attrs:{id:t.id,"aria-current":t.current,autofocus:t.autofocus,"data-theme":t.theme,"data-responsive":t.responsive,rel:t.rel,role:t.role,tabindex:t.tabindex,target:t.target,title:t.tooltip,to:t.link}},[t.icon?e("k-icon",{staticClass:"k-button-icon",attrs:{type:t.icon,alt:t.tooltip}}):t._e(),t.$slots.default?e("span",{staticClass:"k-button-text"},[t._t("default")],2):t._e()],1)}),[],!1,null,null,null,null).exports;const Dl=ut({inheritAttrs:!1,props:{autofocus:Boolean,click:{type:Function,default:()=>{}},current:[String,Boolean],icon:String,id:[String,Number],responsive:Boolean,role:String,tabindex:String,theme:String,tooltip:String,type:{type:String,default:"button"}},mounted(){window.panel.deprecated(" will be removed in a future version. Use instead.")}},(function(){var t=this,e=t._self._c;return e("button",{staticClass:"k-button",attrs:{id:t.id,"aria-current":t.current,autofocus:t.autofocus,"data-theme":t.theme,"data-responsive":t.responsive,role:t.role,tabindex:t.tabindex,title:t.tooltip,type:t.type},on:{click:t.click}},[t.icon?e("k-icon",{staticClass:"k-button-icon",attrs:{type:t.icon,alt:t.tooltip}}):t._e(),t.$slots.default?e("span",{staticClass:"k-button-text"},[t._t("default")],2):t._e()],1)}),[],!1,null,null,null,null).exports,El={install(t){t.component("k-breadcrumb",gl),t.component("k-browser",kl),t.component("k-button",yl),t.component("k-button-group",$l),t.component("k-file-browser",wl),t.component("k-link",vl),t.component("k-model-tabs",xl),t.component("k-navigate",_l),t.component("k-page-tree",Sl),t.component("k-pagination",Ol),t.component("k-prev-next",Ml),t.component("k-tag",Al),t.component("k-tags",Rn),t.component("k-tree",Cl),t.component("k-button-disabled",jl),t.component("k-button-link",Il),t.component("k-button-native",Dl)}};const Tl=ut({props:{buttons:Array,headline:String,invalid:Boolean,label:String,link:String,required:Boolean}},(function(){var t=this,e=t._self._c;return e("section",{staticClass:"k-section",attrs:{"data-invalid":t.invalid}},[t.label||t.headline||t.buttons||t.$slots.options?e("header",{staticClass:"k-section-header"},[e("k-label",{attrs:{invalid:t.invalid,link:t.link,required:t.required,title:t.label??t.headline,type:"section"}},[t._v(" "+t._s(t.label??t.headline)+" ")]),t._t("options",(function(){return[t.buttons?e("k-button-group",{staticClass:"k-section-buttons",attrs:{buttons:t.buttons,size:"xs",variant:"filled"}}):t._e()]}))],2):t._e(),t._t("default")],2)}),[],!1,null,null,null,null).exports;const Ll=ut({props:{empty:String,blueprint:String,lock:[Boolean,Object],parent:String,tab:Object},emits:["submit"],computed:{content(){return this.$store.getters["content/values"]()}},methods:{exists(t){return this.$helper.isComponent(`k-${t}-section`)}}},(function(){var t=this,e=t._self._c;return 0===t.tab.columns.length?e("k-box",{attrs:{html:!0,text:t.empty,theme:"info"}}):e("k-grid",{staticClass:"k-sections",attrs:{variant:"columns"}},t._l(t.tab.columns,(function(i,n){return e("k-column",{key:t.parent+"-column-"+n,attrs:{width:i.width,sticky:i.sticky}},[t._l(i.sections,(function(s,o){return[t.$helper.field.isVisible(s,t.content)?[t.exists(s.type)?e("k-"+s.type+"-section",t._b({key:t.parent+"-column-"+n+"-section-"+o+"-"+t.blueprint,tag:"component",class:"k-section-name-"+s.name,attrs:{column:i.width,lock:t.lock,name:s.name,parent:t.parent,timestamp:t.$panel.view.timestamp},on:{submit:function(e){return t.$emit("submit",e)}}},"component",s,!1)):[e("k-box",{key:t.parent+"-column-"+n+"-section-"+o,attrs:{text:t.$t("error.section.type.invalid",{type:s.type}),icon:"alert",theme:"negative"}})]]:t._e()]}))],2)})),1)}),[],!1,null,null,null,null).exports,Bl={props:{blueprint:String,lock:[Boolean,Object],help:String,name:String,parent:String,timestamp:Number},methods:{load(){return this.$api.get(this.parent+"/sections/"+this.name)}}};const ql=ut({mixins:[Bl],inheritAttrs:!1,data:()=>({fields:{},isLoading:!0,issue:null}),computed:{values(){return this.$store.getters["content/values"]()}},watch:{timestamp(){this.fetch()}},mounted(){this.onInput=Nt(this.onInput,50),this.fetch()},methods:{async fetch(){try{const t=await this.load();this.fields=t.fields;for(const e in this.fields)this.fields[e].section=this.name,this.fields[e].endpoints={field:this.parent+"/fields/"+e,section:this.parent+"/sections/"+this.name,model:this.parent}}catch(t){this.issue=t}finally{this.isLoading=!1}},onInput(t,e,i){this.$store.dispatch("content/update",[i,t[i]])},onSubmit(t){this.$store.dispatch("content/update",[null,t]),this.$events.emit("keydown.cmd.s",t)}}},(function(){var t=this,e=t._self._c;return t.isLoading?t._e():e("k-section",{staticClass:"k-fields-section",attrs:{headline:t.issue?"Error":null}},[t.issue?e("k-box",{attrs:{text:t.issue.message,html:!1,icon:"alert",theme:"negative"}}):t._e(),e("k-form",{attrs:{fields:t.fields,validate:!0,value:t.values,disabled:t.lock&&"lock"===t.lock.state},on:{input:t.onInput,submit:t.onSubmit}})],1)}),[],!1,null,null,null,null).exports;const Pl=ut({inheritAttrs:!1,props:{blueprint:String,column:String,parent:String,name:String,timestamp:Number},data:()=>({data:[],error:null,isLoading:!1,isProcessing:!1,options:{columns:{},empty:null,headline:null,help:null,layout:"list",link:null,max:null,min:null,size:null,sortable:null},pagination:{page:null},searchterm:null,searching:!1}),computed:{addIcon:()=>"add",buttons(){let t=[];return this.canSearch&&t.push({icon:"filter",text:this.$t("filter"),click:this.onSearchToggle,responsive:!0}),this.canAdd&&t.push({icon:this.addIcon,text:this.$t("add"),click:this.onAdd,responsive:!0}),t},canAdd:()=>!0,canDrop:()=>!1,canSearch(){return this.options.search},collection(){return{columns:this.options.columns,empty:this.emptyPropsWithSearch,fields:this.options.fields,layout:this.options.layout,help:this.options.help,items:this.items,pagination:this.pagination,sortable:!this.isProcessing&&this.options.sortable,size:this.options.size}},emptyProps(){return{icon:"page",text:this.$t("pages.empty")}},emptyPropsWithSearch(){return{...this.emptyProps,text:this.searching?this.$t("search.results.none"):this.options.empty??this.emptyProps.text}},items(){return this.data},isInvalid(){var t;return!((null==(t=this.searchterm)?void 0:t.length)>0)&&(!!(this.options.min&&this.data.lengththis.options.max))},paginationId(){return"kirby$pagination$"+this.parent+"/"+this.name},type:()=>"models"},watch:{searchterm(){this.search()},timestamp(){this.reload()}},mounted(){this.search=Nt(this.search,200),this.load()},methods:{async load(t){this.isProcessing=!0,t||(this.isLoading=!0);const e=this.pagination.page??localStorage.getItem(this.paginationId)??1;try{const t=await this.$api.get(this.parent+"/sections/"+this.name,{page:e,searchterm:this.searchterm});this.options=t.options,this.pagination=t.pagination,this.data=t.data}catch(i){this.error=i.message}finally{this.isProcessing=!1,this.isLoading=!1}},onAction(){},onAdd(){},onChange(){},onDrop(){},onSort(){},onPaginate(t){localStorage.setItem(this.paginationId,t.page),this.pagination=t,this.reload()},onSearchToggle(){this.searching=!this.searching,this.searchterm=null},async reload(){await this.load(!0)},async search(){this.pagination.page=0,await this.reload()},update(){this.reload(),this.$events.emit("model.update")}}},(function(){var t=this,e=t._self._c;return!1===t.isLoading?e("k-section",{class:`k-models-section k-${t.type}-section`,attrs:{buttons:t.buttons,"data-processing":t.isProcessing,headline:t.options.headline??" ",invalid:t.isInvalid,link:t.options.link,required:Boolean(t.options.min)}},[t.error?e("k-box",{attrs:{icon:"alert",theme:"negative"}},[e("k-text",{attrs:{size:"small"}},[e("strong",[t._v(" "+t._s(t.$t("error.section.notLoaded",{name:t.name}))+": ")]),t._v(" "+t._s(t.error)+" ")])],1):[e("k-dropzone",{attrs:{disabled:!t.canDrop},on:{drop:t.onDrop}},[t.searching&&t.options.search?e("k-input",{staticClass:"k-models-section-search",attrs:{autofocus:!0,placeholder:t.$t("filter")+" …",value:t.searchterm,icon:"search",type:"text"},on:{input:function(e){t.searchterm=e},keydown:function(e){return!e.type.indexOf("key")&&t._k(e.keyCode,"esc",27,e.key,["Esc","Escape"])?null:t.onSearchToggle.apply(null,arguments)}}}):t._e(),e("k-collection",t._g(t._b({on:{action:t.onAction,change:t.onChange,sort:t.onSort,paginate:t.onPaginate}},"k-collection",t.collection,!1),t.canAdd?{empty:t.onAdd}:{}))],1)]],2):t._e()}),[],!1,null,null,null,null).exports;const Nl=ut({extends:Pl,computed:{addIcon:()=>"upload",canAdd(){return this.$panel.permissions.files.create&&!1!==this.options.upload},canDrop(){return!1!==this.canAdd},emptyProps(){return{icon:"image",text:this.$t("files.empty")}},items(){return this.data.map((t=>(t.sortable=this.options.sortable,t.column=this.column,t.options=this.$dropdown(t.link,{query:{view:"list",update:this.options.sortable,delete:this.data.length>this.options.min}}),t.data={"data-id":t.id,"data-template":t.template},t)))},type:()=>"files",uploadOptions(){return{...this.options.upload,url:this.$panel.urls.api+"/"+this.options.upload.api,on:{complete:()=>{this.$panel.notification.success({context:"view"})}}}}},mounted(){this.$events.on("model.update",this.reload),this.$events.on("file.sort",this.reload)},destroyed(){this.$events.off("model.update",this.reload),this.$events.off("file.sort",this.reload)},methods:{onAction(t,e){"replace"===t&&this.replace(e)},onAdd(){this.canAdd&&this.$panel.upload.pick(this.uploadOptions)},onDrop(t){this.canAdd&&this.$panel.upload.open(t,this.uploadOptions)},async onSort(t){if(!1===this.options.sortable)return!1;this.isProcessing=!0;try{await this.$api.patch(this.options.apiUrl+"/sort",{files:t.map((t=>t.id)),index:this.pagination.offset}),this.$panel.notification.success(),this.$events.emit("file.sort")}catch(e){this.$panel.error(e),this.reload()}finally{this.isProcessing=!1}},replace(t){this.$panel.upload.replace(t,this.uploadOptions)}}},null,null,!1,null,null,null,null).exports;const zl=ut({mixins:[Bl],inheritAttrs:!1,data:()=>({icon:null,label:null,text:null,theme:null}),async mounted(){const t=await this.load();this.icon=t.icon,this.label=t.label,this.text=t.text,this.theme=t.theme??"info"}},(function(){var t=this,e=t._self._c;return e("k-section",{staticClass:"k-info-section",attrs:{headline:t.label}},[e("k-box",{attrs:{html:!0,icon:t.icon,text:t.text,theme:t.theme}})],1)}),[],!1,null,null,null,null).exports;const Fl=ut({extends:Pl,computed:{canAdd(){return this.options.add&&this.$panel.permissions.pages.create},items(){return this.data.map((t=>{const e=!1===t.permissions.changeStatus,i=this.$helper.page.status(t.status,e);return i.click=()=>this.$dialog(t.link+"/changeStatus"),t.flag={status:t.status,disabled:e,click:()=>this.$dialog(t.link+"/changeStatus")},t.sortable=t.permissions.sort&&this.options.sortable,t.deletable=this.data.length>this.options.min,t.column=this.column,t.buttons=[i,...t.buttons??[]],t.options=this.$dropdown(t.link,{query:{view:"list",delete:t.deletable,sort:t.sortable}}),t.data={"data-id":t.id,"data-status":t.status,"data-template":t.template},t}))},type:()=>"pages"},mounted(){this.$events.on("page.changeStatus",this.reload),this.$events.on("page.sort",this.reload)},destroyed(){this.$events.off("page.changeStatus",this.reload),this.$events.off("page.sort",this.reload)},methods:{onAdd(){this.canAdd&&this.$dialog("pages/create",{query:{parent:this.options.link??this.parent,view:this.parent,section:this.name}})},async onChange(t){let e=null;if(t.added&&(e="added"),t.moved&&(e="moved"),e){this.isProcessing=!0;const n=t[e].element,s=t[e].newIndex+1+this.pagination.offset;try{await this.$api.pages.changeStatus(n.id,"listed",s),this.$panel.notification.success(),this.$events.emit("page.sort",n)}catch(i){this.$panel.error({message:i.message,details:i.details}),await this.reload()}finally{this.isProcessing=!1}}}}},null,null,!1,null,null,null,null).exports;const Yl=ut({mixins:[Bl],data:()=>({headline:null,isLoading:!0,reports:null,size:null}),async mounted(){const t=await this.load();this.isLoading=!1,this.headline=t.headline,this.reports=t.reports,this.size=t.size},methods:{}},(function(){var t=this,e=t._self._c;return!1===t.isLoading?e("k-section",{staticClass:"k-stats-section",attrs:{headline:t.headline}},[t.reports.length>0?e("k-stats",{attrs:{reports:t.reports,size:t.size}}):e("k-empty",{attrs:{icon:"chart"}},[t._v(" "+t._s(t.$t("stats.empty")))])],1):t._e()}),[],!1,null,null,null,null).exports,Rl={install(t){t.component("k-section",Tl),t.component("k-sections",Ll),t.component("k-fields-section",ql),t.component("k-files-section",Nl),t.component("k-info-section",zl),t.component("k-pages-section",Fl),t.component("k-stats-section",Yl)}};const Ul=ut({components:{"k-highlight":()=>Y((()=>import("./Highlight.min.js")),__vite__mapDeps([5,1]),import.meta.url)},props:{language:{type:String}}},(function(){var t=this,e=t._self._c;return e("k-highlight",[e("div",[e("pre",{staticClass:"k-code",attrs:{"data-language":t.language}},[e("code",{key:t.$slots.default[0].text+"-"+t.language,class:t.language?`language-${t.language}`:null},[t._t("default")],2)])])])}),[],!1,null,null,null,null).exports;const Hl=ut({props:{link:String,size:{type:String},tag:{type:String,default:"h2"},theme:{type:String}},emits:["click"],mounted(){this.size&&window.panel.deprecated(": the `size` prop will be removed in a future version. Use the `tag` prop instead."),this.theme&&window.panel.deprecated(": the `theme` prop will be removed in a future version.")}},(function(){var t=this,e=t._self._c;return e(t.tag,{tag:"component",staticClass:"k-headline",attrs:{"data-theme":t.theme,"data-size":t.size},on:{click:function(e){return t.$emit("click",e)}}},[t.link?e("k-link",{attrs:{to:t.link}},[t._t("default")],2):t._t("default")],2)}),[],!1,null,null,null,null).exports;const Vl=ut({props:{input:{type:[String,Number]},invalid:{type:Boolean},link:{type:String},required:{default:!1,type:Boolean},type:{default:"field",type:String}},computed:{element(){return"section"===this.type?"h2":"label"}}},(function(){var t=this,e=t._self._c;return e(t.element,{tag:"component",staticClass:"k-label",class:"k-"+t.type+"-label",attrs:{for:t.input,"data-invalid":t.invalid}},[t.link?e("k-link",{attrs:{to:t.link}},[e("span",{staticClass:"k-label-text"},[t._t("default")],2)]):e("span",{staticClass:"k-label-text"},[t._t("default")],2),t.required&&!t.invalid?e("abbr",{attrs:{title:t.$t(t.type+".required")}},[t._v("✶")]):t._e(),e("abbr",{staticClass:"k-label-invalid",attrs:{title:t.$t(t.type+".invalid")}},[t._v("×")])],1)}),[],!1,null,null,null,null).exports;const Kl=ut({props:{align:String,html:String,size:String,theme:String},computed:{attrs(){return{class:"k-text","data-align":this.align,"data-size":this.size,"data-theme":this.theme}}},mounted(){this.theme&&window.panel.deprecated(': the `theme` prop will be removed in a future version. For help text, add `.k-help "` CSS class instead.')}},(function(){var t=this,e=t._self._c;return t.html?e("div",t._b({domProps:{innerHTML:t._s(t.html)}},"div",t.attrs,!1)):e("div",t._b({},"div",t.attrs,!1),[t._t("default")],2)}),[],!1,null,null,null,null).exports,Wl={install(t){t.component("k-code",Ul),t.component("k-headline",Hl),t.component("k-label",Vl),t.component("k-text",Kl)}},Jl={props:{color:String,icon:String,type:String,url:String}};const Gl=ut({mixins:[Jl],computed:{fallbackColor(){var t,e,i;return(null==(t=this.type)?void 0:t.startsWith("image/"))?"orange-500":(null==(e=this.type)?void 0:e.startsWith("audio/"))?"aqua-500":(null==(i=this.type)?void 0:i.startsWith("video/"))?"yellow-500":"white"},fallbackIcon(){var t,e,i;return(null==(t=this.type)?void 0:t.startsWith("image/"))?"image":(null==(e=this.type)?void 0:e.startsWith("audio/"))?"audio":(null==(i=this.type)?void 0:i.startsWith("video/"))?"video":"file"},isPreviewable(){return["image/jpeg","image/jpg","image/gif","image/png","image/webp","image/avif","image/svg+xml"].includes(this.type)}}},(function(){var t=this,e=t._self._c;return e("a",{staticClass:"k-upload-item-preview",attrs:{href:t.url,target:"_blank"}},[t.isPreviewable?e("k-image",{attrs:{cover:!0,src:t.url,back:"pattern"}}):e("k-icon-frame",{attrs:{color:t.color??t.fallbackColor,icon:t.icon??t.fallbackIcon,back:"black",ratio:"1/1"}})],1)}),[],!1,null,null,null,null).exports;const Xl=ut({mixins:[Jl],props:{completed:Boolean,editable:{type:Boolean,default:!0},error:[String,Boolean],extension:String,id:String,name:String,niceSize:String,progress:Number,removable:{type:Boolean,default:!0}},emits:["remove","rename"]},(function(){var t=this,e=t._self._c;return e("li",{staticClass:"k-upload-item",attrs:{"data-completed":t.completed}},[e("k-upload-item-preview",{attrs:{color:t.color,icon:t.icon,type:t.type,url:t.url}}),e("k-input",{staticClass:"k-upload-item-input",attrs:{disabled:t.completed||!t.editable,after:"."+t.extension,novalidate:!0,required:!0,value:t.name,allow:"a-z0-9@._-",type:"slug"},on:{input:function(e){return t.$emit("rename",e)}}}),e("div",{staticClass:"k-upload-item-body"},[e("p",{staticClass:"k-upload-item-meta"},[t._v(" "+t._s(t.niceSize)+" "),t.progress?[t._v(" - "+t._s(t.progress)+"% ")]:t._e()],2),t.error?e("p",{staticClass:"k-upload-item-error"},[t._v(" "+t._s(t.error)+" ")]):t.progress?e("k-progress",{staticClass:"k-upload-item-progress",attrs:{value:t.progress}}):t._e()],1),e("div",{staticClass:"k-upload-item-toggle"},[t.completed||t.progress||!t.removable?!t.completed&&t.progress?e("k-button",{attrs:{disabled:!0,icon:"loader"}}):t.completed?e("k-button",{attrs:{icon:"check",theme:"positive"},on:{click:function(e){return t.$emit("remove")}}}):t._e():e("k-button",{attrs:{icon:"remove"},on:{click:function(e){return t.$emit("remove")}}})],1)],1)}),[],!1,null,null,null,null).exports;const Zl=ut({props:{items:Array},emits:["remove","rename"]},(function(){var t=this,e=t._self._c;return e("ul",{staticClass:"k-upload-items"},t._l(t.items,(function(i){return e("k-upload-item",t._b({key:i.id,on:{rename:function(e){return t.$emit("rename",i,e)},remove:function(e){return t.$emit("remove",i)}}},"k-upload-item",i,!1))})),1)}),[],!1,null,null,null,null).exports,Ql={install(t){t.component("k-upload-item",Xl),t.component("k-upload-item-preview",Gl),t.component("k-upload-items",Zl)}};const ta=ut({props:{status:{default:"missing",type:String}}},(function(){var t=this,e=t._self._c;return t.$panel.activation.isOpen?e("div",{staticClass:"k-activation"},[e("p",[e("strong",[t._v(t._s(t.$t(`license.status.${t.status}.bubble`)))]),"missing"===t.status?[e("a",{attrs:{href:"https://getkirby.com/buy",target:"_blank"}},[t._v(t._s(t.$t("license.buy")))]),t._v(" & "),e("button",{attrs:{type:"button"},on:{click:function(e){return t.$dialog("registration")}}},[t._v(" "+t._s(t.$t("license.activate"))+" ")])]:t._e()],2),e("k-button",{staticClass:"k-activation-toggle",attrs:{icon:"cancel-small"},on:{click:function(e){return t.$panel.activation.close()}}})],1):t._e()}),[],!1,null,null,null,null).exports;const ea=ut({computed:{notification(){return"view"!==this.$panel.notification.context||this.$panel.notification.isFatal?null:this.$panel.notification}}},(function(){var t=this,e=t._self._c;return e("k-panel",{staticClass:"k-panel-inside"},[e("k-panel-menu"),e("main",{staticClass:"k-panel-main"},[e("k-topbar",{attrs:{breadcrumb:t.$panel.view.breadcrumb,view:t.$panel.view}},[t._t("topbar")],2),t._t("default")],2),t.notification&&"error"!==t.notification.type?e("k-button",{staticClass:"k-panel-notification",attrs:{icon:t.notification.icon,text:t.notification.message,theme:t.notification.theme,variant:"filled"},on:{click:function(e){return t.notification.close()}}}):t._e()],1)}),[],!1,null,null,null,null).exports;const ia=ut({data:()=>({over:!1}),computed:{activationButton(){return"missing"===this.$panel.license?{click:()=>this.$dialog("registration"),text:this.$t("activate")}:"legacy"===this.$panel.license&&{click:()=>this.$dialog("license"),text:this.$t("renew")}},hasSearch(){return this.$helper.object.length(this.$panel.searches)>0},menus(){return this.$helper.array.split(this.$panel.menu.entries,"-")}}},(function(){var t=this,e=t._self._c;return e("nav",{staticClass:"k-panel-menu",attrs:{"aria-label":t.$t("menu"),"data-hover":t.$panel.menu.hover},on:{mouseenter:function(e){t.$panel.menu.hover=!0},mouseleave:function(e){t.$panel.menu.hover=!1}}},[e("div",{staticClass:"k-panel-menu-body"},[t.hasSearch?e("k-button",{staticClass:"k-panel-menu-search k-panel-menu-button",attrs:{text:t.$t("search"),icon:"search"},on:{click:function(e){return t.$panel.search()}}}):t._e(),t._l(t.menus,(function(i,n){return e("menu",{key:n,staticClass:"k-panel-menu-buttons",attrs:{"data-second-last":n===t.menus.length-2}},t._l(i,(function(i){return e("k-button",t._b({key:i.id,staticClass:"k-panel-menu-button",attrs:{title:i.title??i.text}},"k-button",i,!1))})),1)})),t.activationButton?e("menu",[e("k-button",t._b({staticClass:"k-activation-button k-panel-menu-button",attrs:{icon:"key",theme:"love",variant:"filled"}},"k-button",t.activationButton,!1)),e("k-activation",{attrs:{status:t.$panel.license}})],1):t._e()],2),e("k-button",{staticClass:"k-panel-menu-toggle",attrs:{icon:t.$panel.menu.isOpen?"angle-left":"angle-right",title:t.$panel.menu.isOpen?t.$t("collapse"):t.$t("expand"),size:"xs"},on:{click:function(e){return t.$panel.menu.toggle()}}})],1)}),[],!1,null,null,null,null).exports;const na=ut({},(function(){return(0,this._self._c)("k-panel",{staticClass:"k-panel-outside",attrs:{tabindex:"0"}},[this._t("default")],2)}),[],!1,null,null,null,null).exports;const sa=ut({},(function(){var t=this,e=t._self._c;return e("div",{staticClass:"k-panel",attrs:{"data-dragging":t.$panel.drag.isDragging,"data-loading":t.$panel.isLoading,"data-language":t.$panel.language.code,"data-language-default":t.$panel.language.isDefault,"data-menu":t.$panel.menu.isOpen?"true":"false","data-role":t.$panel.user.role,"data-translation":t.$panel.translation.code,"data-user":t.$panel.user.id,dir:t.$panel.direction}},[t._t("default"),t.$panel.dialog.isOpen&&!t.$panel.dialog.legacy?e("k-fiber-dialog"):t._e(),t.$panel.drawer.isOpen&&!t.$panel.drawer.legacy?e("k-fiber-drawer"):t._e(),t.$panel.notification.isFatal&&t.$panel.notification.isOpen?e("k-fatal",{attrs:{html:t.$panel.notification.message}}):t._e(),e("k-offline-warning"),e("k-icons"),e("k-overlay",{attrs:{nested:t.$panel.drawer.history.milestones.length>1,visible:t.$panel.drawer.isOpen,type:"drawer"},on:{close:function(e){return t.$panel.drawer.close()}}},[e("portal-target",{staticClass:"k-drawer-portal k-portal",attrs:{name:"drawer",multiple:""}})],1),e("k-overlay",{attrs:{visible:t.$panel.dialog.isOpen,type:"dialog"},on:{close:function(e){return t.$panel.dialog.close()}}},[e("portal-target",{staticClass:"k-dialog-portal k-portal",attrs:{name:"dialog",multiple:""}})],1),e("portal-target",{staticClass:"k-overlay-portal k-portal",attrs:{name:"overlay",multiple:""}})],2)}),[],!1,null,null,null,null).exports;const oa=ut({props:{breadcrumb:Array,view:Object},computed:{crumbs(){return[{link:this.view.link,label:this.view.label??this.view.breadcrumbLabel,icon:this.view.icon,loading:this.$panel.isLoading},...this.breadcrumb]}}},(function(){var t=this,e=t._self._c;return e("div",{staticClass:"k-topbar"},[e("k-button",{staticClass:"k-panel-menu-proxy",attrs:{icon:"bars"},on:{click:function(e){return t.$panel.menu.toggle()}}}),e("k-breadcrumb",{staticClass:"k-topbar-breadcrumb",attrs:{crumbs:t.crumbs}}),e("div",{staticClass:"k-topbar-spacer"}),e("div",{staticClass:"k-topbar-signals"},[t._t("default")],2)],1)}),[],!1,null,null,null,null).exports,la={install(t){t.component("k-activation",ta),t.component("k-panel",sa),t.component("k-panel-inside",ea),t.component("k-panel-menu",ia),t.component("k-panel-outside",na),t.component("k-topbar",oa),t.component("k-inside",ea),t.component("k-outside",na)}};const aa=ut({props:{error:String,layout:String}},(function(){var t=this,e=t._self._c;return e(`k-panel-${t.layout}`,{tag:"component",staticClass:"k-error-view"},["outside"===t.layout?[e("div",[e("k-box",{attrs:{icon:"alert",theme:"negative"}},[t._v(t._s(t.error))])],1)]:[e("k-header",[t._v(t._s(t.$t("error")))]),e("k-box",{attrs:{icon:"alert",theme:"negative"}},[t._v(t._s(t.error))])]],2)}),[],!1,null,null,null,null).exports;const ra=ut({mixins:[zt],props:{type:{default:"pages",type:String}},data:()=>({items:[],query:new URLSearchParams(window.location.search).get("query"),pagination:{}}),computed:{currentType(){return this.$panel.searches[this.type]??Object.values(this.$panel.searches)[0]},tabs(){const t=[];for(const e in this.$panel.searches){const i=this.$panel.searches[e];t.push({label:i.label,link:"/search/?type="+e+"&query="+this.query,name:e})}return t}},watch:{query:{handler(){this.search(1)},immediate:!0},type(){this.search()}},methods:{focus(){var t;null==(t=this.$refs.input)||t.focus()},onPaginate(t){this.search(t.page)},async search(t){this.$panel.isLoading=!0,t||(t=new URLSearchParams(window.location.search).get("page")??1);const e=this.$panel.url(window.location,{type:this.currentType.id,query:this.query,page:t});window.history.pushState("","",e.toString());try{if(null===this.query||this.query.length<2)throw Error("Empty query");const e=await this.$search(this.currentType.id,this.query,{page:t,limit:15});this.items=e.results,this.pagination=e.pagination}catch{this.items=[],this.pagination={}}finally{this.$panel.isLoading=!1}}}},(function(){var t=this,e=t._self._c;return e("k-panel-inside",{staticClass:"k-search-view"},[e("k-header",[t._v(" "+t._s(t.$t("search"))+" "),e("k-input",{ref:"input",staticClass:"k-search-view-input",attrs:{slot:"buttons","aria-label":t.$t("search"),autofocus:!0,placeholder:t.$t("search")+" …",spellcheck:!1,value:t.query,icon:"search",type:"text"},on:{input:function(e){t.query=e}},slot:"buttons"})],1),e("k-tabs",{attrs:{tab:t.currentType.id,tabs:t.tabs}}),e("div",{staticClass:"k-search-view-results"},[e("k-collection",{attrs:{items:t.items,empty:{icon:"search",text:t.$t("search.results.none")},pagination:t.pagination},on:{paginate:t.onPaginate}})],1)],1)}),[],!1,null,null,null,null).exports;const ua=ut({props:{blueprint:String,next:Object,prev:Object,permissions:{type:Object,default:()=>({})},lock:{type:[Boolean,Object]},model:{type:Object,default:()=>({})},tab:{type:Object,default:()=>({columns:[]})},tabs:{type:Array,default:()=>[]}},computed:{id(){return this.model.link},isLocked(){var t;return"lock"===(null==(t=this.lock)?void 0:t.state)},protectedFields:()=>[]},watch:{"$panel.view.timestamp":{handler(){this.$store.dispatch("content/create",{id:this.id,api:this.id,content:this.model.content,ignore:this.protectedFields})},immediate:!0}},mounted(){this.$events.on("model.reload",this.$reload),this.$events.on("keydown.left",this.toPrev),this.$events.on("keydown.right",this.toNext)},destroyed(){this.$events.off("model.reload",this.$reload),this.$events.off("keydown.left",this.toPrev),this.$events.off("keydown.right",this.toNext)},methods:{toPrev(t){this.prev&&"body"===t.target.localName&&this.$go(this.prev.link)},toNext(t){this.next&&"body"===t.target.localName&&this.$go(this.next.link)}}},null,null,!1,null,null,null,null).exports;const ca=ut({extends:ua,props:{preview:Object},computed:{focus(){const t=this.$store.getters["content/values"]().focus;if(!t)return;const[e,i]=t.replaceAll("%","").split(" ");return{x:parseFloat(e),y:parseFloat(i)}}},methods:{action(t){if("replace"===t)return this.$panel.upload.replace({...this.preview,...this.model})},setFocus(t){!0===this.$helper.object.isObject(t)&&(t=`${t.x}% ${t.y}%`),this.$store.dispatch("content/update",["focus",t])}}},(function(){var t=this,e=t._self._c;return e("k-panel-inside",{staticClass:"k-file-view",attrs:{"data-has-tabs":t.tabs.length>1,"data-id":t.model.id,"data-locked":t.isLocked,"data-template":t.blueprint},scopedSlots:t._u([{key:"topbar",fn:function(){return[e("k-prev-next",{attrs:{prev:t.prev,next:t.next}})]},proxy:!0}])},[e("k-header",{staticClass:"k-file-view-header",attrs:{editable:t.permissions.changeName&&!t.isLocked},on:{edit:function(e){return t.$dialog(t.id+"/changeName")}},scopedSlots:t._u([{key:"buttons",fn:function(){return[e("k-button-group",[e("k-button",{staticClass:"k-file-view-options",attrs:{link:t.preview.url,responsive:!0,title:t.$t("open"),icon:"open",size:"sm",target:"_blank",variant:"filled"}}),e("k-button",{staticClass:"k-file-view-options",attrs:{disabled:t.isLocked,dropdown:!0,title:t.$t("settings"),icon:"cog",size:"sm",variant:"filled"},on:{click:function(e){return t.$refs.settings.toggle()}}}),e("k-dropdown-content",{ref:"settings",attrs:{options:t.$dropdown(t.id),"align-x":"end"},on:{action:t.action}}),e("k-languages-dropdown")],1),e("k-form-buttons",{attrs:{lock:t.lock}})]},proxy:!0}])},[t._v(" "+t._s(t.model.filename)+" ")]),e("k-file-preview",t._b({attrs:{focus:t.focus},on:{focus:t.setFocus}},"k-file-preview",t.preview,!1)),e("k-model-tabs",{attrs:{tab:t.tab.name,tabs:t.tabs}}),e("k-sections",{attrs:{blueprint:t.blueprint,empty:t.$t("file.blueprint",{blueprint:t.$esc(t.blueprint)}),lock:t.lock,parent:t.id,tab:t.tab}})],1)}),[],!1,null,null,null,null).exports;const da=ut({props:{focus:Object},emits:["set"],methods:{set(){this.$emit("set",{x:50,y:50})},reset(){this.$emit("set",void 0)}}},(function(){var t=this;return(0,t._self._c)("k-button",{attrs:{icon:t.focus?"cancel-small":"preview",title:t.focus?t.$t("file.focus.reset"):void 0,size:"xs",variant:"filled"},on:{click:function(e){t.focus?t.reset():t.set()}}},[t.focus?[t._v(t._s(t.focus.x)+"% "+t._s(t.focus.y)+"%")]:[t._v(t._s(t.$t("file.focus.placeholder")))]],2)}),[],!1,null,null,null,null).exports;const pa=ut({props:{details:{default:()=>[],type:Array},focus:{type:Object},focusable:Boolean,image:{default:()=>({}),type:Object},url:String},emits:["focus"],computed:{options(){return[{icon:"open",text:this.$t("open"),link:this.url,target:"_blank"},{icon:"cancel",text:this.$t("file.focus.reset"),click:()=>this.$refs.focus.reset(),when:this.focusable&&this.focus},{icon:"preview",text:this.$t("file.focus.placeholder"),click:()=>this.$refs.focus.set(),when:this.focusable&&!this.focus}]}},methods:{setFocus(t){if(!t)return this.$emit("focus",null);this.$emit("focus",{x:t.x.toFixed(1),y:t.y.toFixed(1)})}}},(function(){var t=this,e=t._self._c;return e("div",{staticClass:"k-file-preview",attrs:{"data-has-focus":Boolean(t.focus)}},[e("div",{staticClass:"k-file-preview-thumb-column"},[e("div",{staticClass:"k-file-preview-thumb"},[t.image.src?[e("k-coords-input",{attrs:{disabled:!t.focusable,value:t.focus},on:{input:function(e){return t.setFocus(e)}}},[e("img",t._b({on:{dragstart:function(t){t.preventDefault()}}},"img",t.image,!1))]),e("k-button",{staticStyle:{color:"var(--color-gray-500)"},attrs:{icon:"dots",size:"xs"},on:{click:function(e){return t.$refs.dropdown.toggle()}}}),e("k-dropdown-content",{ref:"dropdown",attrs:{options:t.options,theme:"light"}})]:e("k-icon",{staticClass:"k-item-icon",attrs:{color:t.$helper.color(t.image.color),type:t.image.icon}})],2)]),e("div",{staticClass:"k-file-preview-details"},[e("dl",[t._l(t.details,(function(i){return e("div",{key:i.title},[e("dt",[t._v(t._s(i.title))]),e("dd",[i.link?e("k-link",{attrs:{to:i.link,tabindex:"-1",target:"_blank"}},[t._v(" /"+t._s(i.text)+" ")]):[t._v(" "+t._s(i.text)+" ")]],2)])})),t.image.src?e("div",{staticClass:"k-file-preview-focus-info"},[e("dt",[t._v(t._s(t.$t("file.focus.title")))]),e("dd",[t.focusable?e("k-file-focus-button",{ref:"focus",attrs:{focus:t.focus},on:{set:t.setFocus}}):t.focus?[t._v(" "+t._s(t.focus.x)+"% "+t._s(t.focus.y)+"% ")]:[t._v("–")]],2)]):t._e()],2)])])}),[],!1,null,null,null,null).exports,ha={install(t){t.component("k-file-view",ca),t.component("k-file-preview",pa),t.component("k-file-focus-button",da)}};const ma=ut({props:{isInstallable:Boolean,isInstalled:Boolean,isOk:Boolean,requirements:Object,translations:Array},data(){return{user:{name:"",email:"",language:this.$panel.translation.code,password:"",role:"admin"}}},computed:{fields(){return{email:{label:this.$t("email"),type:"email",link:!1,autofocus:!0,required:!0},password:{label:this.$t("password"),type:"password",placeholder:this.$t("password")+" …",required:!0},language:{label:this.$t("language"),type:"select",options:this.translations,icon:"translate",empty:!1,required:!0}}},isReady(){return this.isOk&&this.isInstallable},isComplete(){return this.isOk&&this.isInstalled}},methods:{async install(){try{await this.$api.system.install(this.user),await this.$reload({globals:["$system","$translation"]}),this.$panel.notification.success({message:this.$t("welcome")+"!",icon:"smile"})}catch(t){this.$panel.error(t)}}}},(function(){var t=this,e=t._self._c;return e("k-panel-outside",{staticClass:"k-installation-view"},[e("div",{staticClass:"k-dialog k-installation-dialog"},[e("k-dialog-body",[t.isComplete?e("k-text",[e("k-headline",[t._v(t._s(t.$t("installation.completed")))]),e("k-link",{attrs:{to:"/login"}},[t._v(" "+t._s(t.$t("login"))+" ")])],1):t.isReady?e("form",{on:{submit:function(e){return e.preventDefault(),t.install.apply(null,arguments)}}},[e("h1",{staticClass:"sr-only"},[t._v(" "+t._s(t.$t("installation"))+" ")]),e("k-fieldset",{attrs:{fields:t.fields,novalidate:!0,value:t.user},on:{input:function(e){t.user=e}}}),e("k-button",{attrs:{text:t.$t("install"),icon:"check",size:"lg",theme:"positive",type:"submit",variant:"filled"}})],1):e("div",[e("k-headline",[t._v(" "+t._s(t.$t("installation.issues.headline"))+" ")]),e("ul",{staticClass:"k-installation-issues"},[!1===t.isInstallable?e("li",[e("k-icon",{attrs:{type:"alert"}}),e("span",{domProps:{innerHTML:t._s(t.$t("installation.disabled"))}})],1):t._e(),!1===t.requirements.php?e("li",[e("k-icon",{attrs:{type:"alert"}}),e("span",{domProps:{innerHTML:t._s(t.$t("installation.issues.php"))}})],1):t._e(),!1===t.requirements.server?e("li",[e("k-icon",{attrs:{type:"alert"}}),e("span",{domProps:{innerHTML:t._s(t.$t("installation.issues.server"))}})],1):t._e(),!1===t.requirements.mbstring?e("li",[e("k-icon",{attrs:{type:"alert"}}),e("span",{domProps:{innerHTML:t._s(t.$t("installation.issues.mbstring"))}})],1):t._e(),!1===t.requirements.curl?e("li",[e("k-icon",{attrs:{type:"alert"}}),e("span",{domProps:{innerHTML:t._s(t.$t("installation.issues.curl"))}})],1):t._e(),!1===t.requirements.accounts?e("li",[e("k-icon",{attrs:{type:"alert"}}),e("span",{domProps:{innerHTML:t._s(t.$t("installation.issues.accounts"))}})],1):t._e(),!1===t.requirements.content?e("li",[e("k-icon",{attrs:{type:"alert"}}),e("span",{domProps:{innerHTML:t._s(t.$t("installation.issues.content"))}})],1):t._e(),!1===t.requirements.media?e("li",[e("k-icon",{attrs:{type:"alert"}}),e("span",{domProps:{innerHTML:t._s(t.$t("installation.issues.media"))}})],1):t._e(),!1===t.requirements.sessions?e("li",[e("k-icon",{attrs:{type:"alert"}}),e("span",{domProps:{innerHTML:t._s(t.$t("installation.issues.sessions"))}})],1):t._e()]),e("k-button",{attrs:{text:t.$t("retry"),icon:"refresh",size:"lg",theme:"positive",variant:"filled"},on:{click:t.$reload}})],1)],1)],1)])}),[],!1,null,null,null,null).exports,fa={install(t){t.component("k-installation-view",ma)}};const ga=ut({props:{languages:{type:Array,default:()=>[]},variables:{type:Boolean,default:!0}},computed:{languagesCollection(){return this.languages.map((t=>({...t,image:{back:"black",color:"gray",icon:"translate"},link:()=>{if(!1===this.variables)return null;this.$go(`languages/${t.id}`)},options:[{icon:"edit",text:this.$t("edit"),disabled:!1===this.variables,click:()=>this.$go(`languages/${t.id}`)},{icon:"cog",text:this.$t("settings"),disabled:!this.$panel.permissions.languages.update,click:()=>this.$dialog(`languages/${t.id}/update`)},{when:t.deletable,icon:"trash",text:this.$t("delete"),disabled:!this.$panel.permissions.languages.delete,click:()=>this.$dialog(`languages/${t.id}/delete`)}]})))},primaryLanguage(){return this.languagesCollection.filter((t=>t.default))},secondaryLanguages(){return this.languagesCollection.filter((t=>!1===t.default))}}},(function(){var t=this,e=t._self._c;return e("k-panel-inside",{staticClass:"k-languages-view"},[e("k-header",[t._v(" "+t._s(t.$t("view.languages"))+" "),e("k-button-group",{attrs:{slot:"buttons"},slot:"buttons"},[e("k-button",{attrs:{disabled:!t.$panel.permissions.languages.create,text:t.$t("language.create"),icon:"add",size:"sm",variant:"filled"},on:{click:function(e){return t.$dialog("languages/create")}}})],1)],1),t.languages.length>0?[e("k-section",{attrs:{headline:t.$t("languages.default")}},[e("k-collection",{attrs:{items:t.primaryLanguage}})],1),e("k-section",{attrs:{headline:t.$t("languages.secondary")}},[t.secondaryLanguages.length?e("k-collection",{attrs:{items:t.secondaryLanguages}}):e("k-empty",{attrs:{icon:"translate",disabled:!t.$panel.permissions.languages.create},on:{click:function(e){return t.$dialog("languages/create")}}},[t._v(" "+t._s(t.$t("languages.secondary.empty"))+" ")])],1)]:0===t.languages.length?[e("k-empty",{attrs:{icon:"translate",disabled:!t.$panel.permissions.languages.create},on:{click:function(e){return t.$dialog("languages/create")}}},[t._v(" "+t._s(t.$t("languages.empty"))+" ")])]:t._e()],2)}),[],!1,null,null,null,null).exports;const ka=ut({props:{code:String,deletable:Boolean,direction:String,id:String,info:Array,next:Object,name:String,prev:Object,translations:Array,url:String},computed:{canUpdate(){return this.$panel.permissions.languages.update}},methods:{createTranslation(){this.canUpdate&&this.$dialog(`languages/${this.id}/translations/create`)},option(t,e){this.canUpdate&&this.$dialog(`languages/${this.id}/translations/${window.btoa(encodeURIComponent(e.key))}/${t}`)},remove(){this.$dialog(`languages/${this.id}/delete`)},update(t){this.$dialog(`languages/${this.id}/update`,{on:{ready:()=>{this.$panel.dialog.focus(t)}}})},updateTranslation({row:t}){this.canUpdate&&this.$dialog(`languages/${this.id}/translations/${window.btoa(encodeURIComponent(t.key))}/update`)}}},(function(){var t=this,e=t._self._c;return e("k-panel-inside",{staticClass:"k-language-view",scopedSlots:t._u([{key:"topbar",fn:function(){return[e("k-prev-next",{attrs:{prev:t.prev,next:t.next}})]},proxy:!0}])},[e("k-header",{attrs:{editable:t.canUpdate},on:{edit:function(e){return t.update()}},scopedSlots:t._u([{key:"buttons",fn:function(){return[e("k-button-group",[e("k-button",{attrs:{link:t.url,title:t.$t("open"),icon:"open",size:"sm",target:"_blank",variant:"filled"}}),e("k-button",{attrs:{disabled:!t.canUpdate,title:t.$t("settings"),icon:"cog",size:"sm",variant:"filled"},on:{click:function(e){return t.update()}}}),t.deletable?e("k-button",{attrs:{disabled:!t.$panel.permissions.languages.delete,title:t.$t("delete"),icon:"trash",size:"sm",variant:"filled"},on:{click:function(e){return t.remove()}}}):t._e()],1)]},proxy:!0}])},[t._v(" "+t._s(t.name)+" ")]),e("k-section",{attrs:{headline:t.$t("language.settings")}},[e("k-stats",{attrs:{reports:t.info,size:"small"}})],1),e("k-section",{attrs:{buttons:[{click:t.createTranslation,disabled:!t.canUpdate,icon:"add",text:t.$t("add")}],headline:t.$t("language.variables")}},[t.translations.length?[e("k-table",{attrs:{columns:{key:{label:t.$t("language.variable.key"),mobile:!0,width:"1/4"},value:{label:t.$t("language.variable.value"),mobile:!0}},disabled:!t.canUpdate,rows:t.translations},on:{cell:t.updateTranslation,option:t.option}})]:[e("k-empty",{attrs:{disabled:!t.canUpdate,icon:"translate"},on:{click:t.createTranslation}},[t._v(" "+t._s(t.$t("language.variables.empty"))+" ")])]],2)],1)}),[],!1,null,null,null,null).exports,ba={install(t){t.component("k-languages-view",ga),t.component("k-language-view",ka)}};const va=ut({emits:["click"]},(function(){var t=this,e=t._self._c;return e("div",{staticClass:"k-notification k-login-alert",attrs:{"data-theme":"error"}},[e("p",[t._t("default")],2),e("k-button",{attrs:{icon:"cancel"},on:{click:function(e){return t.$emit("click")}}})],1)}),[],!1,null,null,null,null).exports,ya={props:{methods:{type:Array,default:()=>[]},pending:{type:Object,default:()=>({challenge:"email"})},value:String}};const $a=ut({mixins:[ya],emits:["error"],data(){return{code:this.value??"",isLoading:!1}},computed:{mode(){return this.methods.includes("password-reset")?"password-reset":"login"},submitText(){const t=this.isLoading?" …":"";return"password-reset"===this.mode?this.$t("login.reset")+t:this.$t("login")+t}},methods:{async login(){this.$emit("error",null),this.isLoading=!0;try{await this.$api.auth.verifyCode(this.code),this.$panel.notification.success({message:this.$t("welcome")+"!",icon:"smile"}),"password-reset"===this.mode?this.$go("reset-password"):this.$reload()}catch(t){this.$emit("error",t)}finally{this.isLoading=!1}}}},(function(){var t=this,e=t._self._c;return e("form",{staticClass:"k-login-form k-login-code-form",on:{submit:function(e){return e.preventDefault(),t.login.apply(null,arguments)}}},[t.pending.email?e("k-user-info",{attrs:{user:t.pending.email}}):t._e(),e("k-text-field",{attrs:{autofocus:!0,counter:!1,help:t.$t("login.code.text."+t.pending.challenge),label:t.$t("login.code.label."+t.mode),novalidate:!0,placeholder:t.$t("login.code.placeholder."+t.pending.challenge),required:!0,value:t.code,autocomplete:"one-time-code",icon:"unlock",name:"code"},on:{input:function(e){t.code=e}}}),e("footer",{staticClass:"k-login-buttons"},[e("k-button",{staticClass:"k-login-button k-login-back-button",attrs:{icon:"angle-left",link:"/logout",size:"lg",variant:"filled"}},[t._v(" "+t._s(t.$t("back"))+" ")]),e("k-button",{staticClass:"k-login-button",attrs:{icon:"check",size:"lg",type:"submit",theme:"positive",variant:"filled"}},[t._v(" "+t._s(t.submitText)+" ")])],1)],1)}),[],!1,null,null,null,null).exports,wa={props:{methods:{type:Array,default:()=>[]},value:{type:Object,default:()=>({})}}};const xa=ut({mixins:[wa],emits:["error"],data(){return{mode:null,isLoading:!1,user:{email:"",password:"",remember:!1,...this.value}}},computed:{alternateMode(){return"email-password"===this.form?"email":"email-password"},canToggle(){return null!==this.codeMode&&(!1!==this.methods.includes("password")&&(!0===this.methods.includes("password-reset")||!0===this.methods.includes("code")))},codeMode(){return!0===this.methods.includes("password-reset")?"password-reset":!0===this.methods.includes("code")?"code":null},fields(){const t={email:{autofocus:!0,label:this.$t("email"),type:"email",required:!0,link:!1}};return"email-password"===this.form&&(t.password={label:this.$t("password"),type:"password",minLength:8,required:!0,autocomplete:"current-password",counter:!1}),t},form(){return this.mode?this.mode:"password"===this.methods[0]?"email-password":"email"},isResetForm(){return"password-reset"===this.codeMode&&"email"===this.form},submitText(){const t=this.isLoading?" …":"";return this.isResetForm?this.$t("login.reset")+t:this.$t("login")+t},toggleText(){return this.$t("login.toggleText."+this.codeMode+"."+this.alternateMode)}},methods:{async login(){this.$emit("error",null),this.isLoading=!0;const t={...this.user};"email"===this.mode&&(t.password=null),!0===this.isResetForm&&(t.remember=!1);try{await this.$api.auth.login(t),this.$reload({globals:["$system","$translation"]}),this.$panel.notification.success({message:this.$t("welcome")+"!",icon:"smile"})}catch(e){this.$emit("error",e)}finally{this.isLoading=!1}},toggle(){this.mode=this.alternateMode,this.$refs.fieldset.focus("email")}}},(function(){var t=this,e=t._self._c;return e("form",{staticClass:"k-login-form",on:{submit:function(e){return e.preventDefault(),t.login.apply(null,arguments)}}},[e("div",{staticClass:"k-login-fields"},[!0===t.canToggle?e("button",{staticClass:"k-login-toggler",attrs:{type:"button"},on:{click:t.toggle}},[t._v(" "+t._s(t.toggleText)+" ")]):t._e(),e("k-fieldset",{ref:"fieldset",attrs:{novalidate:!0,fields:t.fields,value:t.user},on:{input:function(e){t.user=e}}})],1),e("footer",{staticClass:"k-login-buttons"},[!1===t.isResetForm?e("k-checkbox-input",{attrs:{label:t.$t("login.remember"),checked:t.user.remember,value:t.user.remember},on:{input:function(e){t.user.remember=e}}}):t._e(),e("k-button",{staticClass:"k-login-button",attrs:{icon:"check",size:"lg",theme:"positive",type:"submit",variant:"filled"}},[t._v(" "+t._s(t.submitText)+" ")])],1)])}),[],!1,null,null,null,null).exports;const _a=ut({components:{"k-login-plugin-form":window.panel.plugins.login},mixins:[ya,wa],props:{value:{type:Object,default:()=>({code:"",email:"",password:""})}},data:()=>({issue:""}),computed:{component:()=>window.panel.plugins.login?"k-login-plugin-form":"k-login-form",form(){return this.pending.email?"code":"login"}},mounted(){this.$store.dispatch("content/clear")},methods:{async onError(t){null!==t?(!0===t.details.challengeDestroyed&&await this.$reload({globals:["$system"]}),this.issue=t.message):this.issue=null}}},(function(){var t=this,e=t._self._c;return e("k-panel-outside",{class:"code"===t.form?"k-login-code-view":"k-login-view"},[e("div",{staticClass:"k-dialog k-login k-login-dialog"},[e("h1",{staticClass:"sr-only"},[t._v(" "+t._s(t.$t("login"))+" ")]),t.issue?e("k-login-alert",{nativeOn:{click:function(e){t.issue=null}}},[t._v(" "+t._s(t.issue)+" ")]):t._e(),e("k-dialog-body",["code"===t.form?e("k-login-code-form",t._b({on:{error:t.onError}},"k-login-code-form",{methods:t.methods,pending:t.pending,value:t.value.code},!1)):e(t.component,t._b({tag:"component",on:{error:t.onError}},"component",{methods:t.methods,value:t.value},!1))],1)],1)])}),[],!1,null,null,null,null).exports,Ca={install(t){t.component("k-login-alert",va),t.component("k-login-code-form",$a),t.component("k-login-form",xa),t.component("k-login-view",_a),t.component("k-login",xa),t.component("k-login-code",$a)}};const Sa=ut({extends:ua,props:{status:Object},computed:{protectedFields:()=>["title"],statusBtn(){return{...this.$helper.page.status.call(this,this.model.status,!this.permissions.changeStatus||this.isLocked),responsive:!0,size:"sm",text:this.status.label,variant:"filled"}}}},(function(){var t=this,e=t._self._c;return e("k-panel-inside",{staticClass:"k-page-view",attrs:{"data-has-tabs":t.tabs.length>1,"data-id":t.model.id,"data-locked":t.isLocked,"data-template":t.blueprint},scopedSlots:t._u([{key:"topbar",fn:function(){return[t.model.id?e("k-prev-next",{attrs:{prev:t.prev,next:t.next}}):t._e()]},proxy:!0}])},[e("k-header",{staticClass:"k-page-view-header",attrs:{editable:t.permissions.changeTitle&&!t.isLocked},on:{edit:function(e){return t.$dialog(t.id+"/changeTitle")}},scopedSlots:t._u([{key:"buttons",fn:function(){return[e("k-button-group",[t.permissions.preview&&t.model.previewUrl?e("k-button",{staticClass:"k-page-view-preview",attrs:{link:t.model.previewUrl,title:t.$t("open"),icon:"open",target:"_blank",variant:"filled",size:"sm"}}):t._e(),e("k-button",{staticClass:"k-page-view-options",attrs:{disabled:!0===t.isLocked,dropdown:!0,title:t.$t("settings"),icon:"cog",variant:"filled",size:"sm"},on:{click:function(e){return t.$refs.settings.toggle()}}}),e("k-dropdown-content",{ref:"settings",attrs:{options:t.$dropdown(t.id),"align-x":"end"}}),e("k-languages-dropdown"),t.status?e("k-button",t._b({staticClass:"k-page-view-status",on:{click:function(e){return t.$dialog(t.id+"/changeStatus")}}},"k-button",t.statusBtn,!1)):t._e()],1),e("k-form-buttons",{attrs:{lock:t.lock}})]},proxy:!0}])},[t._v(" "+t._s(t.model.title)+" ")]),e("k-model-tabs",{attrs:{tab:t.tab.name,tabs:t.tabs}}),e("k-sections",{attrs:{blueprint:t.blueprint,empty:t.$t("page.blueprint",{blueprint:t.$esc(t.blueprint)}),lock:t.lock,parent:t.id,tab:t.tab}})],1)}),[],!1,null,null,null,null).exports;const Oa=ut({extends:ua,emits:["submit"],computed:{protectedFields:()=>["title"]}},(function(){var t=this,e=t._self._c;return e("k-panel-inside",{staticClass:"k-site-view",attrs:{"data-has-tabs":t.tabs.length>1,"data-locked":t.isLocked,"data-id":"/","data-template":"site"}},[e("k-header",{staticClass:"k-site-view-header",attrs:{editable:t.permissions.changeTitle&&!t.isLocked},on:{edit:function(e){return t.$dialog("site/changeTitle")}},scopedSlots:t._u([{key:"buttons",fn:function(){return[e("k-button-group",[e("k-button",{staticClass:"k-site-view-preview",attrs:{link:t.model.previewUrl,title:t.$t("open"),icon:"open",target:"_blank",variant:"filled",size:"sm"}}),e("k-languages-dropdown")],1),e("k-form-buttons",{attrs:{lock:t.lock}})]},proxy:!0}])},[t._v(" "+t._s(t.model.title)+" ")]),e("k-model-tabs",{attrs:{tab:t.tab.name,tabs:t.tabs}}),e("k-sections",{attrs:{blueprint:t.blueprint,empty:t.$t("site.blueprint"),lock:t.lock,tab:t.tab,parent:"site"},on:{submit:function(e){return t.$emit("submit",e)}}})],1)}),[],!1,null,null,null,null).exports,Ma={install(t){t.component("k-page-view",Sa),t.component("k-site-view",Oa)}};const Aa=ut({extends:ua},(function(){var t=this,e=t._self._c;return e("k-panel-inside",{staticClass:"k-user-view",attrs:{"data-has-tabs":t.tabs.length>1,"data-id":t.model.id,"data-locked":t.isLocked,"data-template":t.blueprint},scopedSlots:t._u([{key:"topbar",fn:function(){return[e("k-prev-next",{attrs:{prev:t.prev,next:t.next}})]},proxy:!0}])},[e("k-header",{staticClass:"k-user-view-header",attrs:{editable:t.permissions.changeName&&!t.isLocked},on:{edit:function(e){return t.$dialog(t.id+"/changeName")}},scopedSlots:t._u([{key:"buttons",fn:function(){return[e("k-button-group",[e("k-button",{staticClass:"k-user-view-options",attrs:{disabled:t.isLocked,dropdown:!0,title:t.$t("settings"),icon:"cog",size:"sm",variant:"filled"},on:{click:function(e){return t.$refs.settings.toggle()}}}),e("k-dropdown-content",{ref:"settings",attrs:{"align-x":"end",options:t.$dropdown(t.id)}}),e("k-languages-dropdown")],1),e("k-form-buttons",{attrs:{lock:t.lock}})]},proxy:!0}])},[t.model.name&&0!==t.model.name.length?[t._v(" "+t._s(t.model.name)+" ")]:e("span",{staticClass:"k-user-name-placeholder"},[t._v(" "+t._s(t.$t("name"))+" … ")])],2),e("k-user-profile",{attrs:{"is-locked":t.isLocked,model:t.model,permissions:t.permissions}}),e("k-model-tabs",{attrs:{tab:t.tab.name,tabs:t.tabs}}),e("k-sections",{attrs:{blueprint:t.blueprint,empty:t.$t("user.blueprint",{blueprint:t.$esc(t.blueprint)}),lock:t.lock,parent:t.id,tab:t.tab}})],1)}),[],!1,null,null,null,null).exports;const ja=ut({extends:Aa,prevnext:!1},null,null,!1,null,null,null,null).exports;const Ia=ut({data:()=>({isLoading:!1,values:{password:null,passwordConfirmation:null}}),computed:{fields(){return{password:{autofocus:!0,label:this.$t("user.changePassword.new"),icon:"key",type:"password",width:"1/2"},passwordConfirmation:{label:this.$t("user.changePassword.new.confirm"),icon:"key",type:"password",width:"1/2"}}}},mounted(){this.$panel.title=this.$t("view.resetPassword")},methods:{async submit(){if(!this.values.password||this.values.password.length<8)return this.$panel.notification.error(this.$t("error.user.password.invalid"));if(this.values.password!==this.values.passwordConfirmation)return this.$panel.notification.error(this.$t("error.user.password.notSame"));this.isLoading=!0;try{await this.$api.users.changePassword(this.$panel.user.id,this.values.password),this.$panel.notification.success(),this.$go("/")}catch(t){this.$panel.notification.error(t)}finally{this.isLoading=!1}}}},(function(){var t=this,e=t._self._c;return e("k-panel-inside",{staticClass:"k-password-reset-view"},[e("form",{on:{submit:function(e){return e.preventDefault(),t.submit.apply(null,arguments)}}},[e("k-header",{scopedSlots:t._u([{key:"buttons",fn:function(){return[e("k-button",{attrs:{icon:"check",theme:"notice",type:"submit",variant:"filled",size:"sm"}},[t._v(" "+t._s(t.$t("change"))+" "),t.isLoading?[t._v(" … ")]:t._e()],2)]},proxy:!0}])},[t._v(" "+t._s(t.$t("view.resetPassword"))+" ")]),e("k-user-info",{attrs:{user:t.$panel.user}}),e("k-fieldset",{attrs:{fields:t.fields,value:t.values}})],1)])}),[],!1,null,null,null,null).exports;const Da=ut({props:{model:Object},methods:{open(){this.model.avatar?this.$refs.dropdown.toggle():this.upload()},async remove(){await this.$api.users.deleteAvatar(this.model.id),this.$panel.notification.success(),this.$reload()},upload(){this.$panel.upload.pick({url:this.$panel.urls.api+"/"+this.model.link+"/avatar",accept:"image/*",immediate:!0,multiple:!1})}}},(function(){var t=this,e=t._self._c;return e("k-button",{staticClass:"k-user-view-image",attrs:{title:t.$t("avatar")},on:{click:t.open}},[t.model.avatar?[e("k-image-frame",{attrs:{cover:!0,src:t.model.avatar}}),e("k-dropdown-content",{ref:"dropdown",attrs:{options:[{icon:"upload",text:t.$t("change"),click:t.upload},{icon:"trash",text:t.$t("delete"),click:t.remove}]}})]:e("k-icon-frame",{attrs:{icon:"user"}})],2)}),[],!1,null,null,null,null).exports;const Ea=ut({props:{user:[Object,String]}},(function(){var t=this,e=t._self._c;return e("div",{staticClass:"k-user-info"},[t.user.avatar?e("k-image-frame",{attrs:{cover:!0,src:t.user.avatar.url,ratio:"1/1"}}):e("k-icon-frame",{attrs:{color:"white",back:"black",icon:"user"}}),t._v(" "+t._s(t.user.name??t.user.email??t.user)+" ")],1)}),[],!1,null,null,null,null).exports;const Ta=ut({props:{isLocked:Boolean,model:Object,permissions:Object}},(function(){var t=this,e=t._self._c;return e("div",{staticClass:"k-user-profile"},[e("k-user-avatar",{attrs:{disabled:t.isLocked,model:t.model}}),e("k-button-group",{attrs:{buttons:[{icon:"email",text:`${t.model.email}`,title:`${t.$t("email")}: ${t.model.email}`,disabled:!t.permissions.changeEmail||t.isLocked,click:()=>t.$dialog(t.model.link+"/changeEmail")},{icon:"bolt",text:`${t.model.role}`,title:`${t.$t("role")}: ${t.model.role}`,disabled:!t.permissions.changeRole||t.isLocked,click:()=>t.$dialog(t.model.link+"/changeRole")},{icon:"translate",text:`${t.model.language}`,title:`${t.$t("language")}: ${t.model.language}`,disabled:!t.permissions.changeLanguage||t.isLocked,click:()=>t.$dialog(t.model.link+"/changeLanguage")}]}})],1)}),[],!1,null,null,null,null).exports;const La=ut({props:{role:Object,roles:Array,search:String,title:String,users:Object},computed:{empty(){return{icon:"users",text:this.$t("role.empty")}},items(){return this.users.data.map((t=>(t.options=this.$dropdown(t.link),t)))},tabs(){const t=[{name:"all",label:this.$t("role.all"),link:"/users"}];for(const e of this.roles)t.push({name:e.id,label:e.title,link:"/users?role="+e.id});return t}},methods:{create(){var t;this.$dialog("users/create",{query:{role:null==(t=this.role)?void 0:t.id}})},paginate(t){this.$reload({query:{page:t.page}})}}},(function(){var t,e=this,i=e._self._c;return i("k-panel-inside",{staticClass:"k-users-view"},[i("k-header",{staticClass:"k-users-view-header",scopedSlots:e._u([{key:"buttons",fn:function(){return[i("k-button",{attrs:{disabled:!e.$panel.permissions.users.create,text:e.$t("user.create"),icon:"add",size:"sm",variant:"filled"},on:{click:e.create}})]},proxy:!0}])},[e._v(" "+e._s(e.$t("view.users"))+" ")]),i("k-tabs",{attrs:{tab:(null==(t=e.role)?void 0:t.id)??"all",tabs:e.tabs}}),i("k-collection",{attrs:{empty:e.empty,items:e.items,pagination:e.users.pagination},on:{paginate:e.paginate}})],1)}),[],!1,null,null,null,null).exports,Ba={install(t){t.component("k-account-view",ja),t.component("k-reset-password-view",Ia),t.component("k-user-avatar",Da),t.component("k-user-info",Ea),t.component("k-user-profile",Ta),t.component("k-user-view",Aa),t.component("k-users-view",La)}};const qa=ut({components:{Plugins:ut({props:{plugins:Array}},(function(){var t=this,e=t._self._c;return t.plugins.length?e("k-section",{attrs:{headline:t.$t("plugins"),link:"https://getkirby.com/plugins"}},[e("k-table",{attrs:{index:!1,columns:{name:{label:t.$t("name"),type:"url",mobile:!0},author:{label:t.$t("author")},license:{label:t.$t("license")},version:{label:t.$t("version"),type:"update-status",mobile:!0,width:"10rem"}},rows:t.plugins}})],1):t._e()}),[],!1,null,null,null,null).exports,Security:ut({props:{exceptions:Array,security:Array,urls:Object},data(){return{issues:structuredClone(this.security)}},async mounted(){console.info("Running system health checks for the Panel system view; failed requests in the following console output are expected behavior.");const t=(Promise.allSettled??Promise.all).bind(Promise),e=Object.entries(this.urls).map(this.check);await t(e),console.info(`System health checks ended. ${this.issues.length-this.security.length} issues with accessible files/folders found (see the security list in the system view).`)},methods:{async check([t,e]){if(!e)return;const{status:i}=await fetch(e,{cache:"no-store"});i<400&&this.issues.push({id:t,text:this.$t("system.issues."+t),link:"https://getkirby.com/security/"+t,icon:"folder"})},retry(){this.$go(window.location.href)}}},(function(){var t=this,e=t._self._c;return t.issues.length?e("k-section",{attrs:{headline:t.$t("security"),buttons:[{title:t.$t("retry"),icon:"refresh",click:t.retry}]}},[e("k-items",{attrs:{items:t.issues.map((t=>({image:{back:"var(--color-red-200)",icon:t.icon??"alert",color:"var(--color-red)"},target:"_blank",...t})))}})],1):t._e()}),[],!1,null,null,null,null).exports},props:{environment:Array,exceptions:Array,info:Object,plugins:Array,security:Array,urls:Object},mounted(){this.exceptions.length>0&&(console.info("The following errors occurred during the update check of Kirby and/or plugins:"),this.exceptions.map((t=>console.warn(t))),console.info("End of errors from the update check."))},methods:{copy(){const t=JSON.stringify({info:this.info,security:this.security.map((t=>t.text)),plugins:this.plugins.map((t=>({name:t.name.text,version:t.version.currentVersion})))},null,2);this.$helper.clipboard.write(t),this.$panel.notification.success({message:this.$t("system.info.copied")})}}},(function(){var t=this,e=t._self._c;return e("k-panel-inside",{staticClass:"k-system-view"},[e("k-header",[t._v(" "+t._s(t.$t("view.system"))+" ")]),e("k-section",{attrs:{headline:t.$t("environment"),buttons:[{text:t.$t("system.info.copy"),icon:"copy",responsive:!0,click:t.copy}]}},[e("k-stats",{staticClass:"k-system-info",attrs:{reports:t.environment,size:"medium"}})],1),e("security",{attrs:{security:t.security,urls:t.urls}}),e("plugins",{attrs:{plugins:t.plugins}})],1)}),[],!1,null,null,null,null).exports;const Pa=ut({props:{value:[String,Object]}},(function(){var t=this,e=t._self._c;return e("div",{staticClass:"k-table-update-status-cell"},["string"==typeof t.value?e("span",{staticClass:"k-table-update-status-cell-version"},[t._v(" "+t._s(t.value)+" ")]):[e("k-button",{staticClass:"k-table-update-status-cell-button",attrs:{dropdown:!0,icon:t.value.icon,href:t.value.url,text:t.value.currentVersion,theme:t.value.theme,size:"xs",variant:"filled"},on:{click:function(e){return e.stopPropagation(),t.$refs.dropdown.toggle()}}}),e("k-dropdown-content",{ref:"dropdown",attrs:{"align-x":"end"}},[e("dl",{staticClass:"k-plugin-info"},[e("dt",[t._v(t._s(t.$t("plugin")))]),e("dd",[t._v(t._s(t.value.pluginName))]),e("dt",[t._v(t._s(t.$t("version.current")))]),e("dd",[t._v(t._s(t.value.currentVersion))]),e("dt",[t._v(t._s(t.$t("version.latest")))]),e("dd",[t._v(t._s(t.value.latestVersion))]),e("dt",[t._v(t._s(t.$t("system.updateStatus")))]),e("dd",{attrs:{"data-theme":t.value.theme}},[t._v(t._s(t.value.label))])]),t.value.url?[e("hr"),e("k-button",{attrs:{icon:"open",link:t.value.url}},[t._v(" "+t._s(t.$t("versionInformation"))+" ")])]:t._e()],2)]],2)}),[],!1,null,null,null,null).exports,Na={install(t){t.component("k-system-view",qa),t.component("k-table-update-status-cell",Pa)}};const za=ut({props:{id:String},mounted(){window.panel.deprecated(" will be removed in a future version.")}},(function(){var t=this._self._c;return t("k-panel-inside",[t("k-"+this.id+"-plugin-view",{tag:"component"})],1)}),[],!1,null,null,null,null).exports,Fa={install(t){t.component("k-error-view",aa),t.component("k-search-view",ra),t.use(ha),t.use(fa),t.use(ba),t.use(Ca),t.use(Ma),t.use(Na),t.use(Ba),t.component("k-plugin-view",za)}},Ya={install(t){t.use(kt),t.use(se),t.use(xe),t.use(Be),t.use(Io),t.use(Lo),t.use(sl),t.use(fl),t.use(El),t.use(Rl),t.use(Wl),t.use(Ql),t.use(la),t.use(Fa),t.use(T)}},Ra={install(t){window.onunhandledrejection=t=>{t.preventDefault(),window.panel.error(t.reason)},t.config.errorHandler=window.panel.error.bind(window.panel)}},Ua=(t={})=>{var e=t.desc?-1:1,i=-e,n=/^0/,s=/\s+/g,o=/^\s+|\s+$/g,l=/[^\x00-\x80]/,a=/^0x[0-9a-f]+$/i,r=/(0x[\da-fA-F]+|(^[\+\-]?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?(?=\D|\s|$))|\d+)/g,u=/(^([\w ]+,?[\w ]+)?[\w ]+,?[\w ]+\d+:\d+(:\d+)?[\w ]?|^\d{1,4}[\/\-]\d{1,4}[\/\-]\d{1,4}|^\w+, \w+ \d+, \d{4})/,c=t.insensitive?function(t){return function(t){if(t.toLocaleLowerCase)return t.toLocaleLowerCase();return t.toLowerCase()}(""+t).replace(o,"")}:function(t){return(""+t).replace(o,"")};function d(t){return t.replace(r,"\0$1\0").replace(/\0$/,"").replace(/^\0/,"").split("\0")}function p(t,e){return(!t.match(n)||1===e)&&parseFloat(t)||t.replace(s," ").replace(o,"")||0}return function(t,n){var s=c(t),o=c(n);if(!s&&!o)return 0;if(!s&&o)return i;if(s&&!o)return e;var r=d(s),h=d(o),m=parseInt(s.match(a),16)||1!==r.length&&Date.parse(s),f=parseInt(o.match(a),16)||m&&o.match(u)&&Date.parse(o)||null;if(f){if(mf)return e}for(var g=r.length,k=h.length,b=0,v=Math.max(g,k);b0)return e;if(w<0)return i;if(b===v-1)return 0}else{if(y<$)return i;if(y>$)return e}}return 0}};function Ha(t){return Array.isArray(t)?t:Object.values(t??{})}RegExp.escape=function(t){return t.replace(new RegExp("[-/\\\\^$*+?.()[\\]{}]","gu"),"\\$&")};function Va(t,e){return t.reduce(((t,i)=>(i===e?t.push([]):t[t.length-1].push(i),t)),[[]])}function Ka(t){return Array.isArray(t)?t:[t]}Array.fromObject=Ha,Object.defineProperty(Array.prototype,"sortBy",{value:function(t){return t(this,t)},enumerable:!1,writable:!0,configurable:!0}),Object.defineProperty(Array.prototype,"split",{value:function(t){return Va(this,t)},enumerable:!1,writable:!0,configurable:!0}),Array.wrap=Ka;const Wa={fromObject:Ha,search:(t,e,i={})=>{if((e??"").length<=(i.min??0))return t;const n=new RegExp(RegExp.escape(e),"ig"),s=i.field??"text",o=t.filter((t=>!!t[s]&&null!==t[s].match(n)));return i.limit?o.slice(0,i.limit):o},sortBy:function(t,e){const i=e.split(" "),n=i[0],s=i[1]??"asc",o=Ua({desc:"desc"===s,insensitive:!0});return t.sort(((t,e)=>{const i=String(t[n]??""),s=String(e[n]??"");return o(i,s)}))},split:Va,wrap:Ka};const Ja={read:function(t,e=!1){if(!t)return null;if("string"==typeof t)return t;if(t instanceof ClipboardEvent){if(t.preventDefault(),!0===e)return t.clipboardData.getData("text/plain");const i=t.clipboardData.getData("text/html")||t.clipboardData.getData("text/plain")||null;if(i)return i.replace(/\u00a0/g," ")}return null},write:function(t,e){if("string"!=typeof t&&(t=JSON.stringify(t,null,2)),e&&e instanceof ClipboardEvent)return e.preventDefault(),e.clipboardData.setData("text/plain",t),!0;const i=document.createElement("textarea");if(i.value=t,document.body.append(i),navigator.userAgent.match(/ipad|ipod|iphone/i)){i.contentEditable=!0,i.readOnly=!0;const t=document.createRange();t.selectNodeContents(i);const e=window.getSelection();e.removeAllRanges(),e.addRange(t),i.setSelectionRange(0,999999)}else i.select();return document.execCommand("copy"),i.remove(),!0}};function Ga(t){if("string"==typeof t){if("pattern"===(t=t.toLowerCase()))return"var(--pattern)";if(!1===t.startsWith("#")&&!1===t.startsWith("var(")){const e="--color-"+t;if(window.getComputedStyle(document.documentElement).getPropertyValue(e))return`var(${e})`}return t}}function Xa(t,e=!1){if(!t.match("youtu"))return!1;let i=null;try{i=new URL(t)}catch{return!1}const n=i.pathname.split("/").filter((t=>""!==t)),s=n[0],o=n[1],l="https://"+(!0===e?"www.youtube-nocookie.com":i.host)+"/embed",a=t=>!!t&&null!==t.match(/^[a-zA-Z0-9_-]+$/);let r=i.searchParams,u=null;switch(n.join("/")){case"embed/videoseries":case"playlist":a(r.get("list"))&&(u=l+"/videoseries");break;case"watch":a(r.get("v"))&&(u=l+"/"+r.get("v"),r.has("t")&&r.set("start",r.get("t")),r.delete("v"),r.delete("t"));break;default:i.host.includes("youtu.be")&&a(s)?(u=!0===e?"https://www.youtube-nocookie.com/embed/"+s:"https://www.youtube.com/embed/"+s,r.has("t")&&r.set("start",r.get("t")),r.delete("t")):["embed","shorts"].includes(s)&&a(o)&&(u=l+"/"+o)}if(!u)return!1;const c=r.toString();return c.length&&(u+="?"+c),u}function Za(t,e=!1){let i=null;try{i=new URL(t)}catch{return!1}const n=i.pathname.split("/").filter((t=>""!==t));let s=i.searchParams,o=null;switch(!0===e&&s.append("dnt",1),i.host){case"vimeo.com":case"www.vimeo.com":o=n[0];break;case"player.vimeo.com":o=n[1]}if(!o||!o.match(/^[0-9]*$/))return!1;let l="https://player.vimeo.com/video/"+o;const a=s.toString();return a.length&&(l+="?"+a),l}const Qa={youtube:Xa,vimeo:Za,video:function(t,e=!1){return!0===t.includes("youtu")?Xa(t,e):!0===t.includes("vimeo")&&Za(t,e)}};function tr(t){var e;if(void 0!==t.default)return structuredClone(t.default);const i=window.panel.app.$options.components[`k-${t.type}-field`],n=null==(e=null==i?void 0:i.options.props)?void 0:e.value;if(void 0===n)return;const s=null==n?void 0:n.default;return"function"==typeof s?s():void 0!==s?s:null}const er={defaultValue:tr,form:function(t){const e={};for(const i in t){const n=tr(t[i]);void 0!==n&&(e[i]=n)}return e},isVisible:function(t,e){if("hidden"===t.type||!0===t.hidden)return!1;if(!t.when)return!0;for(const i in t.when){const n=e[i.toLowerCase()],s=t.when[i];if((void 0!==n||!(""===s||Array.isArray(s)&&0===s.length))&&n!==s)return!1}return!0},subfields:function(t,e){let i={};for(const n in e){const s=e[n];s.section=t.name,t.endpoints&&(s.endpoints={field:t.endpoints.field+"+"+n,section:t.endpoints.section,model:t.endpoints.model}),i[n]=s}return i}},ir=t=>t.split(".").slice(-1).join(""),nr=t=>t.split(".").slice(0,-1).join("."),sr=t=>Intl.NumberFormat("en",{notation:"compact",style:"unit",unit:"byte",unitDisplay:"narrow"}).format(t),or={extension:ir,name:nr,niceSize:sr};function lr(t,e){if("string"==typeof t&&(t=document.querySelector(t)),!t)return!1;if(!e&&t.contains(document.activeElement)&&t!==document.activeElement)return!1;const i=["[autofocus]","[data-autofocus]","input","textarea","select","[contenteditable=true]","[type=submit]","button"];e&&i.unshift(`[name="${e}"]`);const n=function(t,e){for(const i of e){const e=t.querySelector(i);if(!0===ar(e))return e}return null}(t,i);return n?(n.focus(),n):!0===ar(t)&&(t.focus(),t)}function ar(t){return!!t&&(!t.matches("[disabled], [aria-disabled], input[type=hidden]")&&(!t.closest("[aria-disabled]")&&!t.closest("[disabled]")&&"function"==typeof t.focus))}const rr=t=>"function"==typeof window.Vue.options.components[t],ur=t=>!!t.dataTransfer&&(!!t.dataTransfer.types&&(!0===t.dataTransfer.types.includes("Files")&&!1===t.dataTransfer.types.includes("text/plain")));const cr={metaKey:function(){return window.navigator.userAgent.indexOf("Mac")>-1?"cmd":"ctrl"}};function dr(t){return!0===t.startsWith("file://")||!0===t.startsWith("/@/file/")}function pr(t){return"site://"===t||!0===t.startsWith("page://")||!0===t.startsWith("/@/page/")}function hr(t=[]){const e={url:{detect:t=>/^(http|https):\/\//.test(t),icon:"url",id:"url",label:window.panel.$t("url"),link:t=>t,placeholder:window.panel.$t("url.placeholder"),input:"url",value:t=>t},page:{detect:t=>!0===pr(t),icon:"page",id:"page",label:window.panel.$t("page"),link:t=>t,placeholder:window.panel.$t("select")+" …",input:"text",value:t=>t},file:{detect:t=>!0===dr(t),icon:"file",id:"file",label:window.panel.$t("file"),link:t=>t,placeholder:window.panel.$t("select")+" …",value:t=>t},email:{detect:t=>t.startsWith("mailto:"),icon:"email",id:"email",label:window.panel.$t("email"),link:t=>t.replace(/^mailto:/,""),placeholder:window.panel.$t("email.placeholder"),input:"email",value:t=>"mailto:"+t},tel:{detect:t=>t.startsWith("tel:"),icon:"phone",id:"tel",label:window.panel.$t("tel"),link:t=>t.replace(/^tel:/,""),pattern:"[+]{0,1}[0-9]+",placeholder:window.panel.$t("tel.placeholder"),input:"tel",value:t=>"tel:"+t},anchor:{detect:t=>t.startsWith("#"),icon:"anchor",id:"anchor",label:"Anchor",link:t=>t,pattern:"^#.+",placeholder:"#element",input:"text",value:t=>t},custom:{detect:()=>!0,icon:"title",id:"custom",label:window.panel.$t("custom"),link:t=>t,input:"text",value:t=>t}};if(!t.length)return e;const i={};for(const n of t)i[n]=e[n];return i}const mr={detect:function(t,e){if(t=t??"",e=e??hr(),0===t.length)return{type:Object.keys(e)[0]??"url",link:""};for(const i in e)if(!0===e[i].detect(t))return{type:i,link:e[i].link(t)}},getFileUUID:function(t){return t.replace("/@/file/","file://")},getPageUUID:function(t){return t.replace("/@/page/","page://")},isFileUUID:dr,isPageUUID:pr,preview:async function({type:t,link:e},i){return"page"===t&&e?await async function(t,e=["title","panelImage"]){if("site://"===t)return{label:window.panel.$t("view.site")};try{const i=await window.panel.api.pages.get(t,{select:e.join(",")});return{label:i.title,image:i.panelImage}}catch{return null}}(e,i):"file"===t&&e?await async function(t,e=["filename","panelImage"]){try{const i=await window.panel.api.files.get(null,t,{select:e.join(",")});return{label:i.filename,image:i.panelImage}}catch{return null}}(e,i):e?{label:e}:null},types:hr};const fr={status:function(t,e=!1){const i={class:"k-status-icon",icon:"status-"+t,title:window.panel.$t("page.status")+": "+window.panel.$t("page.status."+t),disabled:e,size:"xs",style:"--icon-size: 15px"};return e&&(i.title+=` (${window.panel.$t("disabled")})`),i.theme="draft"===t?"negative-icon":"unlisted"===t?"info-icon":"positive-icon",i}},gr=(t="3/2",e="100%",i=!0)=>{const n=String(t).split("/");if(2!==n.length)return e;const s=Number(n[0]),o=Number(n[1]);let l=100;return 0!==s&&0!==o&&(l=i?l/s*o:l/o*s,l=parseFloat(String(l)).toFixed(2)),l+"%"},kr={"&":"&","<":"<",">":">",'"':""","'":"'","/":"/","`":"`","=":"="};function br(t){return String(t).replace(/[&<>"'`=/]/g,(t=>kr[t]))}function vr(t){return!t||0===String(t).length}function yr(t){const e=String(t);return e.charAt(0).toLowerCase()+e.slice(1)}function $r(t="",e=""){const i=new RegExp(`^(${RegExp.escape(e)})+`,"g");return t.replace(i,"")}function wr(t="",e=""){const i=new RegExp(`(${RegExp.escape(e)})+$`,"g");return t.replace(i,"")}function xr(t,e={}){const i=(t,e={})=>{const n=e[br(t.shift())]??"…";return"…"===n||0===t.length?n:i(t,n)},n="[{]{1,2}[\\s]?",s="[\\s]?[}]{1,2}";return(t=t.replace(new RegExp(`${n}(.*?)${s}`,"gi"),((t,n)=>i(n.split("."),e)))).replace(new RegExp(`${n}.*${s}`,"gi"),"…")}function _r(t){const e=String(t);return e.charAt(0).toUpperCase()+e.slice(1)}function Cr(){let t,e,i="";for(t=0;t<32;t++)e=16*Math.random()|0,8!=t&&12!=t&&16!=t&&20!=t||(i+="-"),i+=(12==t?4:16==t?3&e|8:e).toString(16);return i}const Sr={camelToKebab:function(t){return t.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase()},escapeHTML:br,hasEmoji:function(t){if("string"!=typeof t)return!1;if(!0===/^[a-z0-9_-]+$/.test(t))return!1;const e=t.match(/(?:[\u2700-\u27bf]|(?:\ud83c[\udde6-\uddff]){2}|[\ud800-\udbff][\udc00-\udfff]|[\u0023-\u0039]\ufe0f?\u20e3|\u3299|\u3297|\u303d|\u3030|\u24c2|\ud83c[\udd70-\udd71]|\ud83c[\udd7e-\udd7f]|\ud83c\udd8e|\ud83c[\udd91-\udd9a]|\ud83c[\udde6-\uddff]|[\ud83c\ude01-\ude02]|\ud83c\ude1a|\ud83c\ude2f|[\ud83c\ude32-\ude3a]|[\ud83c\ude50-\ude51]|\u203c|\u2049|[\u25aa-\u25ab]|\u25b6|\u25c0|[\u25fb-\u25fe]|\u00a9|\u00ae|\u2122|\u2139|\ud83c\udc04|[\u2600-\u26FF]|\u2b05|\u2b06|\u2b07|\u2b1b|\u2b1c|\u2b50|\u2b55|\u231a|\u231b|\u2328|\u23cf|[\u23e9-\u23f3]|[\u23f8-\u23fa]|\ud83c\udccf|\u2934|\u2935|[\u2190-\u21ff])/i);return null!==e&&null!==e.length},isEmpty:vr,lcfirst:yr,ltrim:$r,pad:function(t,e=2){t=String(t);let i="";for(;i.length]+)>)/gi,"")},template:xr,ucfirst:_r,ucwords:function(t){return String(t).split(/ /g).map((t=>_r(t))).join(" ")},unescapeHTML:function(t){for(const e in kr)t=String(t).replaceAll(kr[e],e);return t},uuid:Cr},Or=async(t,e)=>new Promise(((i,n)=>{const s={url:"/",field:"file",method:"POST",filename:t.name,headers:{},attributes:{},complete:()=>{},error:()=>{},success:()=>{},progress:()=>{}},o=Object.assign(s,e),l=new XMLHttpRequest,a=new FormData;a.append(o.field,t,o.filename);for(const t in o.attributes){const e=o.attributes[t];null!=e&&a.append(t,e)}const r=e=>{if(e.lengthComputable&&o.progress){const i=Math.max(0,Math.min(100,Math.ceil(e.loaded/e.total*100)));o.progress(l,t,i)}};l.upload.addEventListener("loadstart",r),l.upload.addEventListener("progress",r),l.addEventListener("load",(e=>{let s=null;try{s=JSON.parse(e.target.response)}catch{s={status:"error",message:"The file could not be uploaded"}}"error"===s.status?(o.error(l,t,s),n(s)):(o.progress(l,t,100),o.success(l,t,s),i(s))})),l.addEventListener("error",(e=>{const i=JSON.parse(e.target.response);o.progress(l,t,100),o.error(l,t,i),n(i)})),l.open(o.method,o.url,!0);for(const t in o.headers)l.setRequestHeader(t,o.headers[t]);l.send(a)}));function Mr(){var t;return new URL((null==(t=document.querySelector("base"))?void 0:t.href)??window.location.origin)}function Ar(t={},e={}){e instanceof URL&&(e=e.search);const i=new URLSearchParams(e);for(const[n,s]of Object.entries(t))null!==s&&i.set(n,s);return i}function jr(t="",e={},i){return(t=Lr(t,i)).search=Ar(e,t.search),t}function Ir(t){return null!==String(t).match(/^https?:\/\//)}function Dr(t){return Lr(t).origin===window.location.origin}function Er(t,e){if((t instanceof URL||t instanceof Location)&&(t=t.toString()),"string"!=typeof t)return!1;try{new URL(t,window.location)}catch{return!1}if(!0===e){return/^(?:(?:https?|ftp):\/\/)(?:\S+(?::\S*)?@)?(?:(?!10(?:\.\d{1,3}){3})(?!169\.254(?:\.\d{1,3}){2})(?!192\.168(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:localhost)|(?:(?:[a-z\u00a1-\uffff0-9]+-?)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]+-?)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})))(?::\d{2,5})?(?:\/[^\s]*)?$/i.test(t)}return!0}function Tr(t,e){return!0===Ir(t)?t:(e=e??Mr(),(e=String(e).replaceAll(/\/$/g,""))+"/"+(t=String(t).replaceAll(/^\//g,"")))}function Lr(t,e){return t instanceof URL?t:new URL(Tr(t,e))}const Br={base:Mr,buildQuery:Ar,buildUrl:jr,isAbsolute:Ir,isSameOrigin:Dr,isUrl:Er,makeAbsolute:Tr,toObject:Lr},qr={install(t){t.prototype.$helper={array:Wa,clipboard:Ja,clone:wt.clone,color:Ga,embed:Qa,focus:lr,isComponent:rr,isUploadEvent:ur,debounce:Nt,field:er,file:or,keyboard:cr,link:mr,object:wt,page:fr,pad:Sr.pad,ratio:gr,slug:Sr.slug,sort:Ua,string:Sr,upload:Or,url:Br,uuid:Sr.uuid},t.prototype.$esc=Sr.escapeHTML}},Pr={install(t){const e=(t,e,i)=>{!0!==i.context.disabled?t.dir=window.panel.language.direction:t.dir=null};t.directive("direction",{bind:e,update:e})}},Nr={install(t){window.panel.redirect=window.panel.redirect.bind(window.panel),window.panel.reload=window.panel.reload.bind(window.panel),window.panel.request=window.panel.request.bind(window.panel),window.panel.search=window.panel.search.bind(window.panel);const e=["api","config","direction","events","language","languages","license","menu","multilang","permissions","search","searches","system","t","translation","url","urls","user","view"];for(const i of e){const e=`$${i}`;t.prototype[e]=window.panel[e]=window.panel[i]}window.panel.$vue=window.panel.app}},zr=/^#?([\da-f]{3}){1,2}$/i,Fr=/^#?([\da-f]{4}){1,2}$/i,Yr=/^rgba?\(\s*(\d{1,3})(%?)(?:,|\s)+(\d{1,3})(%?)(?:,|\s)+(\d{1,3})(%?)(?:,|\s|\/)*(\d*(?:\.\d+)?)(%?)\s*\)?$/i,Rr=/^hsla?\(\s*(\d{1,3}\.?\d*)(deg|rad|grad|turn)?(?:,|\s)+(\d{1,3})%(?:,|\s)+(\d{1,3})%(?:,|\s|\/)*(\d*(?:\.\d+)?)(%?)\s*\)?$/i;function Ur(t){return"string"==typeof t&&(zr.test(t)||Fr.test(t))}function Hr(t){return vt(t)&&"r"in t&&"g"in t&&"b"in t}function Vr(t){return vt(t)&&"h"in t&&"s"in t&&"l"in t}function Kr({h:t,s:e,v:i,a:n}){if(0===i)return{h:t,s:0,l:0,a:n};if(0===e&&1===i)return{h:t,s:1,l:1,a:n};const s=i*(2-e)/2;return{h:t,s:e=i*e/(1-Math.abs(2*s-1)),l:s,a:n}}function Wr({h:t,s:e,l:i,a:n}){const s=e*(i<.5?i:1-i);return{h:t,s:e=0===s?0:2*s/(i+s),v:i+s,a:n}}function Jr(t){if(!0===zr.test(t)||!0===Fr.test(t)){"#"===t[0]&&(t=t.slice(1)),3===t.length&&(t=t.split("").reduce(((t,e)=>t+e+e),""));const e=parseInt(t,16);return!0===zr.test(t)?{r:e>>16,g:e>>8&255,b:255&e,a:1}:{r:e>>24&255,g:e>>16&255,b:e>>8&255,a:Math.round((255&e)/255*100)/100}}throw new Error(`unknown hex color: ${t}`)}function Gr({r:t,g:e,b:i,a:n=1}){let s="#"+(1<<24|t<<16|e<<8|i).toString(16).slice(1);return n<1&&(s+=(256|Math.round(255*n)).toString(16).slice(1)),s}function Xr({h:t,s:e,l:i,a:n}){const s=e*Math.min(i,1-i),o=(e,n=(e+t/30)%12)=>i-s*Math.max(Math.min(n-3,9-n,1),-1);return{r:255*o(0),g:255*o(8),b:255*o(4),a:n}}function Zr({r:t,g:e,b:i,a:n}){t/=255,e/=255,i/=255;const s=Math.max(t,e,i),o=s-Math.min(t,e,i),l=1-Math.abs(s+s-o-1);let a=o&&(s==t?(e-i)/o:s==e?2+(i-t)/o:4+(t-e)/o);return a=60*(a<0?a+6:a),{h:a,s:l?o/l:0,l:(s+s-o)/2,a:n}}function Qr(t){return Gr(Xr(t))}function tu(t){return Zr(Jr(t))}function eu(t,e){return t=Number(t),"grad"===e?t*=.9:"rad"===e?t*=180/Math.PI:"turn"===e&&(t*=360),parseInt(t%360)}function iu(t,e){if(!0===Ur(t))switch("#"!==t[0]&&(t="#"+t),e){case"hex":return t;case"rgb":return Jr(t);case"hsl":return tu(t);case"hsv":return Wr(tu(t))}if(!0===Hr(t))switch(e){case"hex":return Gr(t);case"rgb":return t;case"hsl":return Zr(t);case"hsv":return function({r:t,g:e,b:i,a:n}){t/=255,e/=255,i/=255;const s=Math.max(t,e,i),o=s-Math.min(t,e,i);let l=o&&(s==t?(e-i)/o:s==e?2+(i-t)/o:4+(t-e)/o);return l=60*(l<0?l+6:l),{h:l,s:s&&o/s,v:s,a:n}}(t)}if(!0===Vr(t))switch(e){case"hex":return Qr(t);case"rgb":return Xr(t);case"hsl":return t;case"hsv":return Wr(t)}if(!0===function(t){return vt(t)&&"h"in t&&"s"in t&&"v"in t}(t))switch(e){case"hex":return Qr(Kr(t));case"rgb":return function({h:t,s:e,v:i,a:n}){const s=(n,s=(n+t/60)%6)=>i-i*e*Math.max(Math.min(s,4-s,1),0);return{r:255*s(5),g:255*s(3),b:255*s(1),a:n}}(t);case"hsl":return Kr(t);case"hsv":return t}throw new Error(`Invalid color conversion: ${JSON.stringify(t)} -> ${e}`)}function nu(t){let e;if(!t||"string"!=typeof t)return!1;if(!0===Ur(t))return"#"!==t[0]&&(t="#"+t),t;if(e=t.match(Yr)){const t={r:Number(e[1]),g:Number(e[3]),b:Number(e[5]),a:Number(e[7]||1)};return"%"===e[2]&&(t.r=Math.ceil(2.55*t.r)),"%"===e[4]&&(t.g=Math.ceil(2.55*t.g)),"%"===e[6]&&(t.b=Math.ceil(2.55*t.b)),"%"===e[8]&&(t.a=t.a/100),t}if(e=t.match(Rr)){let[t,i,n,s,o]=e.slice(1);const l={h:eu(t,i),s:Number(n)/100,l:Number(s)/100,a:Number(o||1)};return"%"===e[6]&&(l.a=l.a/100),l}return null}const su={convert:iu,parse:nu,parseAs:function(t,e){const i=nu(t);return i&&e?iu(i,e):i},toString:function(t,e,i=!0){var n,s;let o=t;if("string"==typeof o&&(o=nu(t)),o&&e&&(o=iu(o,e)),!0===Ur(o))return!0!==i&&(5===o.length?o=o.slice(0,4):o.length>7&&(o=o.slice(0,7))),o.toLowerCase();if(!0===Hr(o)){const t=o.r.toFixed(),e=o.g.toFixed(),s=o.b.toFixed(),l=null==(n=o.a)?void 0:n.toFixed(2);return i&&l&&l<1?`rgb(${t} ${e} ${s} / ${l})`:`rgb(${t} ${e} ${s})`}if(!0===Vr(o)){const t=o.h.toFixed(),e=(100*o.s).toFixed(),n=(100*o.l).toFixed(),l=null==(s=o.a)?void 0:s.toFixed(2);return i&&l&&l<1?`hsl(${t} ${e}% ${n}% / ${l})`:`hsl(${t} ${e}% ${n}%)`}throw new Error(`Unsupported color: ${JSON.stringify(t)}`)}};L.extend(B),L.extend(((t,e,i)=>{i.interpret=(t,e="date")=>{const n={date:{"YYYY-MM-DD":!0,"YYYY-MM-D":!0,"YYYY-MM-":!0,"YYYY-MM":!0,"YYYY-M-DD":!0,"YYYY-M-D":!0,"YYYY-M-":!0,"YYYY-M":!0,"YYYY-":!0,YYYYMMDD:!0,"MMM DD YYYY":!1,"MMM D YYYY":!1,"MMM DD YY":!1,"MMM D YY":!1,"MMM YYYY":!0,"MMM DD":!1,"MMM D":!1,"MM YYYY":!0,"M YYYY":!0,"MMMM DD YYYY":!0,"MMMM D YYYY":!0,"MMMM DD YY":!0,"MMMM D YY":!0,"MMMM DD, YYYY":!0,"MMMM D, YYYY":!0,"MMMM DD, YY":!0,"MMMM D, YY":!0,"MMMM DD. YYYY":!0,"MMMM D. YYYY":!0,"MMMM DD. YY":!0,"MMMM D. YY":!0,DDMMYYYY:!0,DDMMYY:!0,"DD MMMM YYYY":!1,"DD MMMM YY":!1,"DD MMMM":!1,"D MMMM YYYY":!1,"D MMMM YY":!1,"D MMMM":!1,"DD MMM YYYY":!1,"D MMM YYYY":!1,"DD MMM YY":!1,"D MMM YY":!1,"DD MMM":!1,"D MMM":!1,"DD MM YYYY":!1,"DD M YYYY":!1,"D MM YYYY":!1,"D M YYYY":!1,"DD MM YY":!1,"D MM YY":!1,"DD M YY":!1,"D M YY":!1,YYYY:!0,MMMM:!0,MMM:!0,"DD MM":!1,"DD M":!1,"D MM":!1,"D M":!1,DD:!1,D:!1},time:{"HHmmss a":!1,"HHmm a":!1,"HH a":!1,HHmmss:!1,HHmm:!1,"HH:mm:ss a":!1,"HH:mm:ss":!1,"HH:mm a":!1,"HH:mm":!1,HH:!1}};if("string"==typeof t&&""!==t)for(const s in n[e]){const o=i(t,s,n[e][s]);if(!0===o.isValid())return o}return null}})),L.extend(((t,e,i)=>{const n=t=>"date"===t?"YYYY-MM-DD":"time"===t?"HH:mm:ss":"YYYY-MM-DD HH:mm:ss";e.prototype.toISO=function(t="datetime"){return this.format(n(t))},i.iso=function(t,e){e&&(e=n(e)),e??(e=[n("datetime"),n("date"),n("time")]);const s=i(t,e);return s&&s.isValid()?s:null}})),L.extend(((t,e)=>{e.prototype.merge=function(t,e="date"){let i=this.clone();if(!t||!t.isValid())return this;if("string"==typeof e){const t={date:["year","month","date"],time:["hour","minute","second"]};if(!1===Object.hasOwn(t,e))throw new Error("Invalid merge unit alias");e=t[e]}for(const n of e)i=i.set(n,t.get(n));return i}})),L.extend(((t,e,i)=>{i.pattern=t=>new class{constructor(t,e){this.dayjs=t,this.pattern=e;const i={year:["YY","YYYY"],month:["M","MM","MMM","MMMM"],day:["D","DD"],hour:["h","hh","H","HH"],minute:["m","mm"],second:["s","ss"],meridiem:["a"]};this.parts=this.pattern.split(/\W/).map(((t,e)=>{const n=this.pattern.indexOf(t);return{index:e,unit:Object.keys(i)[Object.values(i).findIndex((e=>e.includes(t)))],start:n,end:n+(t.length-1)}}))}at(t,e=t){const i=this.parts.filter((i=>i.start<=t&&i.end>=e-1));return i[0]?i[0]:this.parts.filter((e=>e.start<=t)).pop()}format(t){return t&&t.isValid()?t.format(this.pattern):null}}(i,t)})),L.extend(((t,e)=>{e.prototype.round=function(t="date",e=1){const i=["second","minute","hour","date","month","year"];if("day"===t&&(t="date"),!1===i.includes(t))throw new Error("Invalid rounding unit");if(["date","month","year"].includes(t)&&1!==e||"hour"===t&&24%e!=0||["second","minute"].includes(t)&&60%e!=0)throw"Invalid rounding size for "+t;let n=this.clone();const s=i.indexOf(t),o=i.slice(0,s),l=o.pop();for(const a of o)n=n.startOf(a);if(l){const e={month:12,date:n.daysInMonth(),hour:24,minute:60,second:60}[l];Math.round(n.get(l)/e)*e===e&&(n=n.add(1,"date"===t?"day":t)),n=n.startOf(t)}return n=n.set(t,Math.round(n.get(t)/e)*e),n}})),L.extend(((t,e,i)=>{e.prototype.validate=function(t,e,n="day"){if(!this.isValid())return!1;if(!t)return!0;t=i.iso(t);const s={min:"isAfter",max:"isBefore"}[e];return this.isSame(t,n)||this[s](t,n)}}));const ou={install(t){t.prototype.$library={autosize:q,colors:su,dayjs:L}}},lu=()=>({close(){sessionStorage.setItem("kirby$activation$card","true"),this.isOpen=!1},isOpen:"true"!==sessionStorage.getItem("kirby$activation$card"),open(){sessionStorage.removeItem("kirby$activation$card"),this.isOpen=!0}}),au=t=>({async changeName(e,i,n){return t.patch(this.url(e,i,"name"),{name:n})},async delete(e,i){return t.delete(this.url(e,i))},async get(e,i,n){let s=await t.get(this.url(e,i),n);return!0===Array.isArray(s.content)&&(s.content={}),s},id:t=>!0===t.startsWith("/@/file/")?t.replace("/@/file/","@"):!0===t.startsWith("file://")?t.replace("file://","@"):t,link(t,e,i){return"/"+this.url(t,e,i)},async update(e,i,n){return t.patch(this.url(e,i),n)},url(t,e,i){let n="files/"+this.id(e);return t&&(n=t+"/"+n),i&&(n+="/"+i),n}}),ru=t=>({async blueprint(e){return t.get("pages/"+this.id(e)+"/blueprint")},async blueprints(e,i){return t.get("pages/"+this.id(e)+"/blueprints",{section:i})},async changeSlug(e,i){return t.patch("pages/"+this.id(e)+"/slug",{slug:i})},async changeStatus(e,i,n){return t.patch("pages/"+this.id(e)+"/status",{status:i,position:n})},async changeTemplate(e,i){return t.patch("pages/"+this.id(e)+"/template",{template:i})},async changeTitle(e,i){return t.patch("pages/"+this.id(e)+"/title",{title:i})},async children(e,i){return t.post("pages/"+this.id(e)+"/children/search",i)},async create(e,i){return null===e||"/"===e?t.post("site/children",i):t.post("pages/"+this.id(e)+"/children",i)},async delete(e,i){return t.delete("pages/"+this.id(e),i)},async duplicate(e,i,n){return t.post("pages/"+this.id(e)+"/duplicate",{slug:i,children:n.children??!1,files:n.files??!1})},async get(e,i){let n=await t.get("pages/"+this.id(e),i);return!0===Array.isArray(n.content)&&(n.content={}),n},id:t=>!0===t.startsWith("/@/page/")?t.replace("/@/page/","@"):!0===t.startsWith("page://")?t.replace("page://","@"):t.replace(/\//g,"+"),async files(e,i){return t.post("pages/"+this.id(e)+"/files/search",i)},link(t){return"/"+this.url(t)},async preview(t){return(await this.get(this.id(t),{select:"previewUrl"})).previewUrl},async search(e,i){return e?t.post("pages/"+this.id(e)+"/children/search?select=id,title,hasChildren",i):t.post("site/children/search?select=id,title,hasChildren",i)},async update(e,i){return t.patch("pages/"+this.id(e),i)},url(t,e){let i=null===t?"pages":"pages/"+String(t).replace(/\//g,"+");return e&&(i+="/"+e),i}});class uu extends Error{constructor(t,{request:e,response:i,cause:n}){super(i.json.message??t,{cause:n}),this.request=e,this.response=i}state(){return this.response.json}}class cu extends uu{}class du extends uu{state(){return{message:this.message,text:this.response.text}}}const pu=t=>(window.location.href=Tr(t),!1),hu=async(t,e={})=>{var i;(e={cache:"no-store",credentials:"same-origin",mode:"same-origin",...e}).body=((i=e.body)instanceof HTMLFormElement&&(i=new FormData(i)),i instanceof FormData&&(i=Object.fromEntries(i)),"object"==typeof i?JSON.stringify(i):i),e.headers=((t={},e={})=>{return{"content-type":"application/json","x-csrf":e.csrf??!1,"x-fiber":!0,"x-fiber-globals":(i=e.globals,!!i&&(!1===Array.isArray(i)?String(i):i.join(","))),"x-fiber-referrer":e.referrer??!1,...$t(t)};var i})(e.headers,e),e.url=jr(t,e.query);const n=new Request(e.url,e);return!1===Dr(n.url)?pu(n.url):await mu(n,await fetch(n))},mu=async(t,e)=>{var i;if(!1===e.headers.get("Content-Type").includes("application/json"))return pu(e.url);try{e.text=await e.text(),e.json=JSON.parse(e.text)}catch(n){throw new du("Invalid JSON response",{cause:n,request:t,response:e})}if(401===e.status)throw new cu("Unauthenticated",{request:t,response:e});if("error"===(null==(i=e.json)?void 0:i.status))throw e.json;if(!1===e.ok)throw new uu(`The request to ${e.url} failed`,{request:t,response:e});return{request:t,response:e}},fu=t=>({blueprint:async e=>t.get("users/"+e+"/blueprint"),blueprints:async(e,i)=>t.get("users/"+e+"/blueprints",{section:i}),changeEmail:async(e,i)=>t.patch("users/"+e+"/email",{email:i}),changeLanguage:async(e,i)=>t.patch("users/"+e+"/language",{language:i}),changeName:async(e,i)=>t.patch("users/"+e+"/name",{name:i}),changePassword:async(e,i)=>t.patch("users/"+e+"/password",{password:i}),changeRole:async(e,i)=>t.patch("users/"+e+"/role",{role:i}),create:async e=>t.post("users",e),delete:async e=>t.delete("users/"+e),deleteAvatar:async e=>t.delete("users/"+e+"/avatar"),link(t,e){return"/"+this.url(t,e)},async list(e){return t.post(this.url(null,"search"),e)},get:async(e,i)=>t.get("users/"+e,i),async roles(e){return(await t.get(this.url(e,"roles"))).data.map((t=>({info:t.description??`(${window.panel.$t("role.description.placeholder")})`,text:t.title,value:t.name})))},search:async e=>t.post("users/search",e),update:async(e,i)=>t.patch("users/"+e,i),url(t,e){let i=t?"users/"+t:"users";return e&&(i+="/"+e),i}}),gu=t=>{const e={csrf:t.system.csrf,endpoint:wr(t.urls.api,"/"),methodOverwrite:!0,ping:null,requests:[],running:0},i=()=>{clearInterval(e.ping),e.ping=setInterval(e.auth.ping,3e5)};return e.request=async(n,s={},o=!1)=>{const l=n+"/"+JSON.stringify(s);e.requests.push(l),!1===o&&(t.isLoading=!0),e.language=t.language.code;try{return await(t=>async(e,i={})=>{i={cache:"no-store",credentials:"same-origin",mode:"same-origin",headers:{"content-type":"application/json","x-csrf":t.csrf,"x-language":t.language,...$t(i.headers??{})},...i},t.methodOverwrite&&"GET"!==i.method&&"POST"!==i.method&&(i.headers["x-http-method-override"]=i.method,i.method="POST"),i.url=wr(t.endpoint,"/")+"/"+$r(e,"/");const n=new Request(i.url,i),{response:s}=await mu(n,await fetch(n));let o=s.json;return o.data&&"model"===o.type&&(o=o.data),o})(e)(n,s)}finally{i(),e.requests=e.requests.filter((t=>t!==l)),0===e.requests.length&&(t.isLoading=!1)}},e.auth=(t=>({async login(e){const i={long:e.remember??!1,email:e.email,password:e.password};return t.post("auth/login",i)},logout:async()=>t.post("auth/logout"),ping:async()=>t.post("auth/ping"),user:async e=>t.get("auth",e),verifyCode:async e=>t.post("auth/code",{code:e})}))(e),e.delete=(t=>async(e,i,n,s=!1)=>t.post(e,i,n,"DELETE",s))(e),e.files=au(e),e.get=(t=>async(e,i,n,s=!1)=>(i&&(e+="?"+Object.keys(i).filter((t=>void 0!==i[t]&&null!==i[t])).map((t=>t+"="+i[t])).join("&")),t.request(e,Object.assign(n??{},{method:"GET"}),s)))(e),e.languages=(t=>({create:async e=>t.post("languages",e),delete:async e=>t.delete("languages/"+e),get:async e=>t.get("languages/"+e),list:async()=>t.get("languages"),update:async(e,i)=>t.patch("languages/"+e,i)}))(e),e.pages=ru(e),e.patch=(t=>async(e,i,n,s=!1)=>t.post(e,i,n,"PATCH",s))(e),e.post=(t=>async(e,i,n,s="POST",o=!1)=>t.request(e,Object.assign(n??{},{method:s,body:JSON.stringify(i)}),o))(e),e.roles=(t=>({list:async e=>t.get("roles",e),get:async e=>t.get("roles/"+e)}))(e),e.system=(t=>({get:async(e={view:"panel"})=>t.get("system",e),install:async e=>(await t.post("system/install",e)).user,register:async e=>t.post("system/register",e)}))(e),e.site=(t=>({blueprint:async()=>t.get("site/blueprint"),blueprints:async()=>t.get("site/blueprints"),changeTitle:async e=>t.patch("site/title",{title:e}),children:async e=>t.post("site/children/search",e),get:async(e={view:"panel"})=>t.get("site",e),update:async e=>t.post("site",e)}))(e),e.translations=(t=>({list:async()=>t.get("translations"),get:async e=>t.get("translations/"+e)}))(e),e.users=fu(e),i(),e},ku=()=>({addEventListener(t,e){"function"==typeof e&&(this.on[t]=e)},addEventListeners(t){if(!1!==vt(t))for(const e in t)this.addEventListener(e,t[e])},emit(t,...e){return this.hasEventListener(t)?this.on[t](...e):()=>{}},hasEventListener(t){return"function"==typeof this.on[t]},listeners(){return this.on},on:{}}),bu=(t,e={})=>({...e,key:()=>t,defaults:()=>e,reset(){return this.set(this.defaults())},set(t){this.validateState(t);for(const e in this.defaults())this[e]=t[e]??this.defaults()[e];return this.state()},state(){const t={};for(const e in this.defaults())t[e]=this[e]??this.defaults()[e];return t},validateState(t){if(!1===vt(t))throw new Error(`Invalid ${this.key()} state`);return!0}}),vu=(t,e,i)=>{const n=bu(e,i);return{...n,...ku(),async load(e,i={}){return!0!==i.silent&&(this.isLoading=!0),await t.open(e,i),this.isLoading=!1,this.addEventListeners(i.on),this.state()},async open(t,e={}){return"function"==typeof e&&(e={on:{submit:e}}),!0===Er(t)?this.load(t,e):(this.set(t),this.addEventListeners(e.on),this.emit("open",t,e),this.state())},async post(e,i={}){var n;if(!this.path)throw new Error(`The ${this.key()} cannot be posted`);this.isLoading=!0,e=e??(null==(n=this.props)?void 0:n.value)??{};try{return await t.post(this.path,e,i)}catch(s){t.error(s)}finally{this.isLoading=!1}return!1},async refresh(e={}){e.url=e.url??this.url();const i=(await t.get(e.url,e))["$"+this.key()];if(i&&i.component===this.component)return this.props=i.props,this.state()},async reload(t={}){if(!this.path)return!1;this.open(this.url(),t)},set(t){return n.set.call(this,t),this.on={},this.addEventListeners(t.on??{}),this.state()},url(){return t.url(this.path,this.query)}}},yu=(t,e,i)=>{const n=vu(t,e,i);return{...n,async cancel(){this.isOpen&&this.emit("cancel"),this.close()},async close(){!1!==this.isOpen&&(this.isOpen=!1,this.emit("close"),this.reset(),0===t.overlays().length&&(document.documentElement.removeAttribute("data-overlay"),document.documentElement.style.removeProperty("--scroll-top")))},focus(t){lr(`.k-${this.key()}-portal`,t)},input(t){!1!==this.isOpen&&(Vue.set(this.props,"value",t),this.emit("input",t))},isOpen:!1,listeners(){return{...this.on,cancel:this.cancel.bind(this),close:this.close.bind(this),input:this.input.bind(this),submit:this.submit.bind(this),success:this.success.bind(this)}},async open(e,i){return!1===this.isOpen&&t.notification.close(),await n.open.call(this,e,i),this.component&&(document.documentElement.setAttribute("data-overlay","true"),document.documentElement.style.setProperty("--scroll-top",window.scrollY+"px"),this.isOpen=!0),this.state()},async submit(t,e={}){if(t=t??this.props.value,this.hasEventListener("submit"))return this.emit("submit",t,e);if(!this.path)return this.close();const i=await this.post(t,e);return!1===vt(i)?i:this.success(i["$"+this.key()]??{})},success(e){return this.hasEventListener("success")?this.emit("success",e):("string"==typeof e&&t.notification.success(e),this.close(),this.successNotification(e),this.successEvents(e),this.successDispatch(e),e.route||e.redirect?this.successRedirect(e):t.view.reload(e.reload),e)},successDispatch(e){if(!1!==vt(e.dispatch))for(const i in e.dispatch){const n=e.dispatch[i];t.app.$store.dispatch(i,!0===Array.isArray(n)?[...n]:n)}},successEvents(e){if(e.event){const i=Array.wrap(e.event);for(const n of i)"string"==typeof n&&t.events.emit(n,e)}!1!==e.emit&&t.events.emit("success",e)},successNotification(e){e.message&&t.notification.success(e.message)},successRedirect(e){const i=e.route??e.redirect;return!!i&&("string"==typeof i?t.open(i):t.open(i.url,i.options))},get value(){var t;return null==(t=this.props)?void 0:t.value}}},$u=t=>{t.events.on("dialog.save",(e=>{var i;null==(i=null==e?void 0:e.preventDefault)||i.call(e),t.dialog.submit()}));const e=yu(t,"dialog",{component:null,isLoading:!1,on:{},path:null,props:{},query:{},referrer:null,timestamp:null,legacy:!1,ref:null});return{...e,async close(){this.ref&&(this.ref.visible=!1),e.close.call(this)},async open(t,i={}){return t instanceof window.Vue?this.openComponent(t):("string"==typeof t&&(t=`/dialogs/${t}`),e.open.call(this,t,i))},async openComponent(i){t.deprecated("Dialog components should no longer be used in your templates");const n=await e.open.call(this,{component:i.$options._componentTag,legacy:!0,props:{...i.$attrs,...i.$props},ref:i}),s=this.listeners();for(const t in s)i.$on(t,s[t]);return i.visible=!0,n}}},wu=()=>({...bu("drag",{type:null,data:{}}),get isDragging(){return null!==this.type},start(t,e){this.type=t,this.data=e},stop(){this.type=null,this.data={}}}),xu=()=>({add(t){if(!t.id)throw new Error("The state needs an ID");!0!==this.has(t.id)&&this.milestones.push(t)},at(t){return this.milestones.at(t)},clear(){this.milestones=[]},get(t=null){return null===t?this.milestones:this.milestones.find((e=>e.id===t))},goto(t){const e=this.index(t);if(-1!==e)return this.milestones=this.milestones.slice(0,e+1),this.milestones[e]},has(t){return void 0!==this.get(t)},index(t){return this.milestones.findIndex((e=>e.id===t))},isEmpty(){return 0===this.milestones.length},last(){return this.milestones.at(-1)},milestones:[],remove(t=null){return null===t?this.removeLast():this.milestones=this.milestones.filter((e=>e.id!==t))},removeLast(){return this.milestones=this.milestones.slice(0,-1)},replace(t,e){-1===t&&(t=this.milestones.length-1),Vue.set(this.milestones,t,e)}}),_u=t=>{const e=yu(t,"drawer",{component:null,isLoading:!1,on:{},path:null,props:{},query:{},referrer:null,timestamp:null,id:null});return t.events.on("drawer.save",(e=>{e.preventDefault(),t.drawer.submit()})),{...e,get breadcrumb(){return this.history.milestones},async close(t){if(!1!==this.isOpen&&(!0===t&&this.history.clear(),void 0===t||t===this.id)){if(this.history.removeLast(),!0!==this.history.isEmpty())return this.open(this.history.last());e.close.call(this)}},goTo(t){const e=this.history.goto(t);void 0!==e&&this.open(e)},history:xu(),get icon(){return this.props.icon??"box"},input(t){Vue.set(this.props,"value",t),this.emit("input",this.props.value)},listeners(){return{...this.on,cancel:this.cancel.bind(this),close:this.close.bind(this),crumb:this.goTo.bind(this),input:this.input.bind(this),submit:this.submit.bind(this),success:this.success.bind(this),tab:this.tab.bind(this)}},async open(t,i={}){"string"==typeof t&&(t=`/drawers/${t}`),await e.open.call(this,t,i),this.tab(t.tab);const n=this.state();return!0===t.replace?this.history.replace(-1,n):this.history.add(n),this.focus(),n},set(t){return e.set.call(this,t),this.id=this.id??Cr(),this.state()},tab(t){const e=this.props.tabs??{};if(!(t=t??Object.keys(e??{})[0]))return!1;Vue.set(this.props,"fields",e[t].fields),Vue.set(this.props,"tab",t),this.emit("tab",t),setTimeout((()=>{this.focus()}))}}},Cu=t=>{const e=vu(t,"dropdown",{component:null,isLoading:!1,on:{},path:null,props:{},query:{},referrer:null,timestamp:null});return{...e,close(){this.emit("close"),this.reset()},open(t,i={}){return"string"==typeof t&&(t=`/dropdowns/${t}`),e.open.call(this,t,i)},openAsync(t,e={}){return async i=>{await this.open(t,e);const n=this.options();if(0===n.length)throw Error("The dropdown is empty");i(n)}},options(){return!1===Array.isArray(this.props.options)?[]:this.props.options.map((e=>e.dialog?(e.click=()=>{const i="string"==typeof e.dialog?e.dialog:e.dialog.url,n="object"==typeof e.dialog?e.dialog:{};return t.app.$dialog(i,n)},e):e))},set(t){return t.options&&(t.props={options:t.options}),e.set.call(this,t)}}},Su=t=>{const e=P();e.on("online",(()=>{t.isOffline=!1})),e.on("offline",(()=>{t.isOffline=!0})),e.on("keydown.cmd.s",(i=>{e.emit(t.context+".save",i)})),e.on("keydown.cmd.shift.f",(()=>t.search())),e.on("keydown.cmd./",(()=>t.search()));const i={document:{blur:!0,click:!1,copy:!0,focus:!0,paste:!0},window:{dragenter:!1,dragexit:!1,dragleave:!1,dragover:!1,drop:!1,keydown:!1,keyup:!1,offline:!1,online:!1,popstate:!1}};return{blur(t){this.emit("blur",t)},click(t){this.emit("click",t)},copy(t){this.emit("copy",t)},dragenter(t){this.entered=t.target,this.prevent(t),this.emit("dragenter",t)},dragexit(t){this.prevent(t),this.entered=null,this.emit("dragexit",t)},dragleave(t){this.prevent(t),this.entered===t.target&&(this.entered=null,this.emit("dragleave",t))},dragover(t){this.prevent(t),this.emit("dragover",t)},drop(t){this.prevent(t),this.entered=null,this.emit("drop",t)},emit:e.emit,entered:null,focus(t){this.emit("focus",t)},keychain(t,e){let i=[t];(e.metaKey||e.ctrlKey)&&i.push("cmd"),!0===e.altKey&&i.push("alt"),!0===e.shiftKey&&i.push("shift");let n=e.key?yr(e.key):null;const s={escape:"esc",arrowUp:"up",arrowDown:"down",arrowLeft:"left",arrowRight:"right"};return s[n]&&(n=s[n]),n&&!1===["alt","control","shift","meta"].includes(n)&&i.push(n),i.join(".")},keydown(t){this.emit(this.keychain("keydown",t),t),this.emit("keydown",t)},keyup(t){this.emit(this.keychain("keyup",t),t),this.emit("keyup",t)},off:e.off,offline(t){this.emit("offline",t)},on:e.on,online(t){this.emit("online",t)},paste(t){this.emit("paste",t)},popstate(t){this.emit("popstate",t)},prevent(t){t.stopPropagation(),t.preventDefault()},subscribe(){for(const t in i.document)document.addEventListener(t,this[t].bind(this),i.document[t]);for(const t in i.window)window.addEventListener(t,this[t].bind(this),i.window[t])},unsubscribe(){for(const t in i.document)document.removeEventListener(t,this[t]);for(const t in i.window)window.removeEventListener(t,this[t])},$on(...t){window.panel.deprecated("`events.$on` will be removed in a future version. Use `events.on` instead."),e.on(...t)},$emit(...t){window.panel.deprecated("`events.$emit` will be removed in a future version. Use `events.emit` instead."),e.emit(...t)},$off(...t){window.panel.deprecated("`events.$off` will be removed in a future version. Use `events.off` instead."),e.off(...t)}}},Ou={interval:null,start(t,e){this.stop(),t&&(this.interval=setInterval(e,t))},stop(){clearInterval(this.interval),this.interval=null}},Mu=(t={})=>({...bu("notification",{context:null,details:null,icon:null,isOpen:!1,message:null,theme:null,timeout:null,type:null}),close(){return this.timer.stop(),this.reset(),this.state()},deprecated(t){console.warn("Deprecated: "+t)},error(e){if(e instanceof cu&&t.user.id)return t.redirect("logout");if(e instanceof du)return this.fatal(e);if(e instanceof uu){const t=Object.values(e.response.json).find((t=>"string"==typeof(null==t?void 0:t.error)));t&&(e.message=t.error)}return"string"==typeof e&&(e={message:e}),e={message:e.message??"Something went wrong",details:e.details??{}},"view"===t.context&&t.dialog.open({component:"k-error-dialog",props:e}),this.open({message:e.message,icon:"alert",theme:"negative",type:"error"})},info(t={}){return"string"==typeof t&&(t={message:t}),this.open({icon:"info",theme:"info",...t})},get isFatal(){return"fatal"===this.type},fatal(t){return"string"==typeof t?this.open({message:t,type:"fatal"}):t instanceof du?this.open({message:t.response.text,type:"fatal"}):this.open({message:t.message??"Something went wrong",type:"fatal"})},open(e){return this.timer.stop(),"string"==typeof e?this.success(e):("error"!==e.type&&"fatal"!==e.type&&(e.timeout??(e.timeout=4e3)),this.set({context:t.context,...e}),this.isOpen=!0,this.timer.start(this.timeout,(()=>this.close())),this.state())},success(t={}){return"string"==typeof t&&(t={message:t}),this.open({icon:"check",theme:"positive",...t})},timer:Ou}),Au=()=>({...bu("language",{code:null,default:!1,direction:"ltr",name:null,rules:null}),get isDefault(){return this.default}}),ju=(t,e,i)=>{if(!i.template&&!i.render&&!i.extends)throw new Error(`Neither template nor render method provided. Nor extending a component when loading plugin component "${e}". The component has not been registered.`);return(i=Iu(t,e,i)).template&&(i.render=null),i=Du(i),!0===rr(e)&&window.console.warn(`Plugin is replacing "${e}"`),t.component(e,i),i},Iu=(t,e,i)=>"string"!=typeof(null==i?void 0:i.extends)?i:!1===rr(i.extends)?(window.console.warn(`Problem with plugin trying to register component "${e}": cannot extend non-existent component "${i.extends}"`),i.extends=null,i):(i.extends=t.options.components[i.extends].extend({options:i,components:{...t.options.components,...i.components??{}}}),i),Du=t=>{if(!1===Array.isArray(t.mixins))return t;const e={dialog:Et,drawer:fe,section:Bl};return t.mixins=t.mixins.map((t=>"string"==typeof t?e[t]:t)),t},Eu=(t,e={})=>((e={components:{},created:[],icons:{},login:null,textareaButtons:{},use:[],thirdParty:{},writerMarks:{},writerNodes:{},...e}).use=((t,e)=>{if(!1===Array.isArray(e))return[];for(const i of e)t.use(i);return e})(t,e.use),e.components=((t,e)=>{if(!1===vt(e))return;const i={};for(const[s,o]of Object.entries(e))try{i[s]=ju(t,s,o)}catch(n){window.console.warn(n.message)}return i})(t,e.components),e),Tu=t=>{var e;const i=bu("menu",{entries:[],hover:!1,isOpen:!1}),n=null==(e=window.matchMedia)?void 0:e.call(window,"(max-width: 60rem)"),s={...i,blur(t){const e=document.querySelector(".k-panel-menu");if(!e||!1===n.matches)return!1;!1===document.querySelector(".k-panel-menu-proxy").contains(t.target)&&!1===e.contains(t.target)&&this.close()},close(){this.isOpen=!1,!1===n.matches&&localStorage.setItem("kirby$menu",!0)},escape(){if(!1===n.matches)return!1;this.close()},open(){this.isOpen=!0,!1===n.matches&&localStorage.removeItem("kirby$menu")},resize(){if(n.matches)return this.close();null!==localStorage.getItem("kirby$menu")?this.isOpen=!1:this.isOpen=!0},set(t){return this.entries=t,this.resize(),this.state()},toggle(){this.isOpen?this.close():this.open()}};return t.events.on("keydown.esc",s.escape.bind(s)),t.events.on("click",s.blur.bind(s)),null==n||n.addEventListener("change",s.resize.bind(s)),s},Lu=()=>{const t=bu("translation",{code:null,data:{},direction:"ltr",name:null});return{...t,set(e){return t.set.call(this,e),document.documentElement.lang=this.code,document.body.dir=this.direction,this.state()},translate(t,e,i=null){if("string"!=typeof t)return;const n=this.data[t]??i;return"string"!=typeof n?n:xr(n,e)}}};const Bu=t=>{const e=bu("upload",{accept:"*",attributes:{},files:[],max:null,multiple:!0,replacing:null,url:null});return{...e,...ku(),input:null,cancel(){this.emit("cancel"),this.completed.length>0&&(this.emit("complete",this.completed),t.view.reload()),this.reset()},get completed(){return this.files.filter((t=>t.completed)).map((t=>t.model))},done(){t.dialog.close(),this.completed.length>0&&(this.emit("done",this.completed),!1===t.drawer.isOpen&&(t.notification.success({context:"view"}),t.view.reload())),this.reset()},findDuplicate(t){return this.files.findLastIndex((e=>e.src.name===t.src.name&&e.src.type===t.src.type&&e.src.size===t.src.size&&e.src.lastModified===t.src.lastModified))},hasUniqueName(t){return this.files.filter((e=>e.name===t.name&&e.extension===t.extension)).length<2},file(t){const e=URL.createObjectURL(t);return{completed:!1,error:null,extension:ir(t.name),filename:t.name,id:Cr(),model:null,name:nr(t.name),niceSize:sr(t.size),progress:0,size:t.size,src:t,type:t.type,url:e}},open(e,i){e instanceof FileList?(this.set(i),this.select(e)):this.set(e);const n={component:"k-upload-dialog",on:{cancel:()=>this.cancel(),submit:async()=>{t.dialog.isLoading=!0,await this.submit(),t.dialog.isLoading=!1}}};this.replacing&&(n.component="k-upload-replace-dialog",n.props={original:this.replacing}),t.dialog.open(n)},pick(t){this.set(t),this.input=document.createElement("input"),this.input.type="file",this.input.classList.add("sr-only"),this.input.value=null,this.input.accept=this.accept,this.input.multiple=this.multiple,this.input.click(),this.input.addEventListener("change",(e=>{!0===(null==t?void 0:t.immediate)?(this.set(t),this.select(e.target.files),this.submit()):this.open(e.target.files,t),this.input.remove()}))},remove(t){this.files=this.files.filter((e=>e.id!==t))},replace(e,i){this.pick({...i,url:t.urls.api+"/"+e.link,accept:"."+e.extension+","+e.mime,multiple:!1,replacing:e})},reset(){e.reset.call(this),this.files.splice(0)},select(t,e){if(this.set(e),t instanceof Event&&(t=t.target.files),t instanceof FileList==!1)throw new Error("Please provide a FileList");t=(t=[...t]).map((t=>this.file(t))),this.files=[...this.files,...t],this.files=this.files.filter(((t,e)=>this.findDuplicate(t)===e)),null!==this.max&&(this.files=this.files.slice(-1*this.max)),this.emit("select",this.files)},set(t){if(t)return e.set.call(this,t),this.on={},this.addEventListeners(t.on??{}),1===this.max&&(this.multiple=!1),!1===this.multiple&&(this.max=1),this.state()},async submit(){var e;if(!this.url)throw new Error("The upload URL is missing");const i=[];for(const n of this.files){if(!0===n.completed)continue;if(!1===this.hasUniqueName(n)){n.error=t.t("error.file.name.unique");continue}n.error=null,n.progress=0;const s={...this.attributes};i.push((async()=>await this.upload(n,s)));const o=null==(e=this.attributes)?void 0:e.sort;null!=o&&this.attributes.sort++}if(await async function(t,e=20){let i=0,n=0;return new Promise((s=>{const o=e=>n=>{t[e]=n,i--,l()},l=()=>{if(i{e.progress=n}});e.completed=!0,e.model=n.data}catch(n){t.error(n,!1),e.error=n.message,e.progress=0}}}},qu=t=>{const e=vu(t,"view",{component:null,isLoading:!1,on:{},path:null,props:{},query:{},referrer:null,timestamp:null,breadcrumb:[],breadcrumbLabel:null,icon:null,id:null,link:null,search:"pages",title:null});return{...e,set(i){e.set.call(this,i),t.title=this.title;const n=this.url().toString();window.location.toString()!==n&&(window.history.pushState(null,null,n),window.scrollTo(0,0))},async submit(){throw new Error("Not yet implemented")}}},Pu={config:{},languages:[],license:"missing",multilang:!1,permissions:{},searches:{},urls:{}},Nu=["dialog","drawer"],zu=["dropdown","language","menu","notification","system","translation","user"],Fu={create(t={}){return this.isLoading=!1,this.isOffline=!1,this.activation=lu(),this.drag=wu(),this.events=Su(this),this.upload=Bu(this),this.language=Au(),this.menu=Tu(this),this.notification=Mu(this),this.system=bu("system",{ascii:{},csrf:null,isLocal:null,locales:{},slugs:[],title:null}),this.translation=Lu(),this.user=bu("user",{email:null,id:null,language:null,role:null,username:null}),this.dropdown=Cu(this),this.view=qu(this),this.drawer=_u(this),this.dialog=$u(this),this.redirect=pu,this.reload=this.view.reload.bind(this.view),this.t=this.translation.translate.bind(this.translation),this.plugins=Eu(window.Vue,t),this.set(window.fiber),this.api=gu(this),Vue.reactive(this)},get context(){return this.dialog.isOpen?"dialog":this.drawer.isOpen?"drawer":"view"},get debug(){return!0===this.config.debug},deprecated(t){this.notification.deprecated(t)},get direction(){return this.translation.direction},error(t,e=!0){if(!0===this.debug&&console.error(t),!0===e)return this.notification.error(t)},async get(t,e={}){const{response:i}=await this.request(t,{method:"GET",...e});return(null==i?void 0:i.json)??{}},async open(t,e={}){try{if(!1===Er(t))this.set(t);else{this.isLoading=!0;const i=await this.get(t,e);this.set(i),this.isLoading=!1}return this.state()}catch(i){return this.error(i)}},overlays(){const t=[];return!0===this.drawer.isOpen&&t.push("drawer"),!0===this.dialog.isOpen&&t.push("dialog"),t},async post(t,e={},i={}){const{response:n}=await this.request(t,{method:"POST",body:e,...i});return n.json},async request(t,e={}){return hu(t,{referrer:this.view.path,csrf:this.system.csrf,...e})},async search(t,e,i){if(!e)return this.menu.escape(),this.dialog.open({component:"k-search-dialog",props:{type:t}});const{$search:n}=await this.get(`/search/${t}`,{query:{query:e,...i}});return n},set(t={}){t=Object.fromEntries(Object.entries(t).map((([t,e])=>[t.replace("$",""),e])));for(const e in Pu){const i=t[e]??this[e]??Pu[e];typeof i==typeof Pu[e]&&(this[e]=i)}for(const e of zu)(vt(t[e])||Array.isArray(t[e]))&&this[e].set(t[e]);for(const e of Nu)if(!0===vt(t[e])){if(t[e].redirect)return this.open(t[e].redirect);this[e].open(t[e])}else void 0!==t[e]&&this[e].close(!0);!0===vt(t.dropdown)?this.dropdown.open(t.dropdown):void 0!==t.dropdown&&this.dropdown.close(),!0===vt(t.view)&&this.view.open(t.view)},state(){const t={};for(const e in Pu)t[e]=this[e]??Pu[e];for(const e of zu)t[e]=this[e].state();for(const e of Nu)t[e]=this[e].state();return t.dropdown=this.dropdown.state(),t.view=this.view.state(),t},get title(){return document.title},set title(t){!1===vr(this.system.title)&&(t+=" | "+this.system.title),document.title=t},url:(t="",e={},i)=>jr(t,e,i)},Yu=(t,e)=>{localStorage.setItem("kirby$content$"+t,JSON.stringify(e))},Ru={namespaced:!0,state:{current:null,models:{},status:{enabled:!0}},getters:{exists:t=>e=>Object.hasOwn(t.models,e),hasChanges:(t,e)=>t=>yt(e.model(t).changes)>0,isCurrent:t=>e=>t.current===e,id:t=>e=>((e=e??t.current)&&!1===e.includes("?language=")&&(e+="?language="+window.panel.language.code),e),model:(t,e)=>i=>(i=e.id(i),!0===e.exists(i)?t.models[i]:{api:null,originals:{},values:{},changes:{}}),originals:(t,e)=>t=>structuredClone(e.model(t).originals),values:(t,e)=>t=>({...e.originals(t),...e.changes(t)}),changes:(t,e)=>t=>structuredClone(e.model(t).changes)},mutations:{CLEAR(t){for(const e in t.models)t.models[e].changes={};for(const e in localStorage)e.startsWith("kirby$content$")&&localStorage.removeItem(e)},CREATE(t,[e,i]){if(!i)return!1;let n=t.models[e]?t.models[e].changes:i.changes;Vue.set(t.models,e,{api:i.api,originals:i.originals,changes:n??{}})},CURRENT(t,e){t.current=e},MOVE(t,[e,i]){const n=structuredClone(t.models[e]);Vue.del(t.models,e),Vue.set(t.models,i,n);const s=localStorage.getItem("kirby$content$"+e);localStorage.removeItem("kirby$content$"+e),localStorage.setItem("kirby$content$"+i,s)},REMOVE(t,e){Vue.del(t.models,e),localStorage.removeItem("kirby$content$"+e)},REVERT(t,e){t.models[e]&&(Vue.set(t.models[e],"changes",{}),localStorage.removeItem("kirby$content$"+e))},STATUS(t,e){Vue.set(t.status,"enabled",e)},UPDATE(t,[e,i,n]){if(!t.models[e])return!1;void 0===n&&(n=null),n=structuredClone(n);const s=JSON.stringify(n);JSON.stringify(t.models[e].originals[i]??null)==s?Vue.del(t.models[e].changes,i):Vue.set(t.models[e].changes,i,n),Yu(e,{api:t.models[e].api,originals:t.models[e].originals,changes:t.models[e].changes})}},actions:{init(t){for(const e in localStorage)if(e.startsWith("kirby$content$")){const i=e.split("kirby$content$")[1],n=localStorage.getItem("kirby$content$"+i);t.commit("CREATE",[i,JSON.parse(n)])}else if(e.startsWith("kirby$form$")){const i=e.split("kirby$form$")[1],n=localStorage.getItem("kirby$form$"+i);let s=null;try{s=JSON.parse(n)}catch{}if(!s||!s.api)return localStorage.removeItem("kirby$form$"+i),!1;const o={api:s.api,originals:s.originals,changes:s.values};t.commit("CREATE",[i,o]),Yu(i,o),localStorage.removeItem("kirby$form$"+i)}},clear(t){t.commit("CLEAR")},create(t,e){const i=structuredClone(e.content);if(Array.isArray(e.ignore))for(const s of e.ignore)delete i[s];e.id=t.getters.id(e.id);const n={api:e.api,originals:i,changes:{}};t.commit("CREATE",[e.id,n]),t.dispatch("current",e.id)},current(t,e){e=t.getters.id(e),t.commit("CURRENT",e)},disable(t){t.commit("STATUS",!1)},enable(t){t.commit("STATUS",!0)},move(t,[e,i]){e=t.getters.id(e),i=t.getters.id(i),t.commit("MOVE",[e,i])},remove(t,e){e=t.getters.id(e),t.commit("REMOVE",e),t.getters.isCurrent(e)&&t.commit("CURRENT",null)},revert(t,e){e=t.getters.id(e),t.commit("REVERT",e)},async save(t,e){if(e=t.getters.id(e),t.getters.isCurrent(e)&&!1===t.state.status.enabled)return!1;t.dispatch("disable");const i=t.getters.model(e),n={...i.originals,...i.changes};try{await window.panel.api.patch(i.api,n),t.commit("CREATE",[e,{...i,originals:n}]),t.dispatch("revert",e)}finally{t.dispatch("enable")}},update(t,[e,i,n]){if(n=n??t.state.current,null===e)for(const s in i)t.commit("UPDATE",[n,s,i[s]]);else t.commit("UPDATE",[n,e,i])}}},Uu={namespaced:!0,actions:{close(t,e){window.panel.deprecated("`$store.drawer` will be removed in a future version. Use `$panel.drawer` instead."),window.panel.drawer.close(e)},goto(t,e){window.panel.deprecated("`$store.drawer` will be removed in a future version. Use `$panel.drawer` instead."),window.panel.drawer.goto(e)},open(t,e){window.panel.deprecated("`$store.drawer` will be removed in a future version. Use `$panel.drawer` instead."),window.panel.drawer.goto(e)}}},Hu={namespaced:!0,actions:{close(){window.panel.deprecated("`$store.notification` will be removed in a future version. Use `$panel.notification` instead."),window.panel.notification.close()},deprecated(t,e){window.panel.deprecated("`$store.notification.deprecated` will be removed in a future version. Use `$panel.deprecated` instead."),window.panel.notification.deprecated(e)},error(t,e){window.panel.deprecated("`$store.notification` will be removed in a future version. Use `$panel.notification` instead."),window.panel.notification.error(e)},open(t,e){window.panel.deprecated("`$store.notification` will be removed in a future version. Use `$panel.notification` instead."),window.panel.notification.open(e)},success(t,e){window.panel.deprecated("`$store.notification` will be removed in a future version. Use `$panel.notification` instead."),window.panel.notification.success(e)}}};Vue.use(N);const Vu=new N.Store({strict:!1,actions:{dialog(t,e){window.panel.deprecated("`$store.dialog` will be removed in a future version. Use `$panel.dialog.open()` instead."),window.panel.dialog.open(e)},drag(t,e){window.panel.deprecated("`$store.drag` will be removed in a future version. Use `$panel.drag.start(type, data)` instead."),window.panel.drag.start(...e)},fatal(t,e){window.panel.deprecated("`$store.fatal` will be removed in a future version. Use `$panel.notification.fatal()` instead."),window.panel.notification.fatal(e)},isLoading(t,e){window.panel.deprecated("`$store.isLoading` will be removed in a future version. Use `$panel.isLoading` instead."),window.panel.isLoading=e},navigate(){window.panel.deprecated("`$store.navigate` will be removed in a future version."),window.panel.dialog.close(),window.panel.drawer.close()}},modules:{content:Ru,drawers:Uu,notification:Hu}});Vue.config.productionTip=!1,Vue.config.devtools=!0,Vue.use(qr),Vue.use(ou),Vue.use(z),Vue.use(Ya),window.panel=Vue.prototype.$panel=Fu.create(window.panel.plugins),Vue.prototype.$dialog=window.panel.dialog.open.bind(window.panel.dialog),Vue.prototype.$drawer=window.panel.drawer.open.bind(window.panel.drawer),Vue.prototype.$dropdown=window.panel.dropdown.openAsync.bind(window.panel.dropdown),Vue.prototype.$go=window.panel.view.open.bind(window.panel.view),Vue.prototype.$reload=window.panel.reload.bind(window.panel),window.panel.app=new Vue({store:Vu,render:()=>Vue.h(R)}),Vue.use(Pr),Vue.use(Ra),Vue.use(Nr),!1===CSS.supports("container","foo / inline-size")&&Y((()=>import("./container-query-polyfill.modern.min.js")),[],import.meta.url),window.panel.app.$mount("#app");export{ut as n}; diff --git a/kirby/panel/dist/js/plugins.js b/kirby/panel/dist/js/plugins.js index 64f6547..4cf1612 100644 --- a/kirby/panel/dist/js/plugins.js +++ b/kirby/panel/dist/js/plugins.js @@ -1,91 +1,75 @@ -window.panel = window.panel ?? {}; +window.panel = window.panel || {}; window.panel.plugins = { - components: {}, - created: [], - icons: {}, - routes: [], - textareaButtons: {}, - thirdParty: {}, - use: [], - views: {}, - writerMarks: {}, - writerNodes: {} + components: {}, + created: [], + icons: {}, + routes: [], + use: [], + views: {}, + thirdParty: {} }; -window.panel.plugin = function (plugin, extensions) { - // Blocks - resolve(extensions, "blocks", (name, options) => { - if (typeof options === "string") { - options = { template: options }; - } +window.panel.plugin = function (plugin, parts) { + // Blocks + resolve(parts, "blocks", function (name, options) { + if (typeof options === "string") { + options = { template: options }; + } - window.panel.plugins.components[`k-block-type-${name}`] = { - extends: "k-block-type-default", - ...options - }; - }); + window.panel.plugins.components[`k-block-type-${name}`] = { + extends: "k-block-type", + ...options + }; + }); - // Components - resolve(extensions, "components", (name, options) => { - window.panel.plugins.components[name] = options; - }); + // Components + resolve(parts, "components", function (name, options) { + window.panel.plugins.components[name] = options; + }); - // Fields - resolve(extensions, "fields", (name, options) => { - window.panel.plugins.components[`k-${name}-field`] = options; - }); + // Fields + resolve(parts, "fields", function (name, options) { + window.panel.plugins.components[`k-${name}-field`] = options; + }); - // Icons - resolve(extensions, "icons", (name, options) => { - window.panel.plugins.icons[name] = options; - }); + // Icons + resolve(parts, "icons", function (name, options) { + window.panel.plugins.icons[name] = options; + }); - // Sections - resolve(extensions, "sections", (name, options) => { - window.panel.plugins.components[`k-${name}-section`] = { - ...options, - mixins: ["section", ...(options.mixins ?? [])] - }; - }); + // Sections + resolve(parts, "sections", function (name, options) { + window.panel.plugins.components[`k-${name}-section`] = { + ...options, + mixins: ["section", ...(options.mixins || [])] + }; + }); - // `Vue.use` - resolve(extensions, "use", (name, options) => { - window.panel.plugins.use.push(options); - }); + // `Vue.use` + resolve(parts, "use", function (name, options) { + window.panel.plugins.use.push(options); + }); - // Vue `created` callback - if (extensions["created"]) { - window.panel.plugins.created.push(extensions["created"]); - } + // Vue `created` callback + if (parts["created"]) { + window.panel.plugins.created.push(parts["created"]); + } - // Login - if (extensions.login) { - window.panel.plugins.login = extensions.login; - } + // Login + if (parts.login) { + window.panel.plugins.login = parts.login; + } - // Textarea custom toolbar buttons - resolve(extensions, "textareaButtons", (name, options) => { - window.panel.plugins.textareaButtons[name] = options; - }); - - // Third-party plugins - resolve(extensions, "thirdParty", (name, options) => { - window.panel.plugins.thirdParty[name] = options; - }); - - // Writer custom marks - resolve(extensions, "writerMarks", (name, options) => { - window.panel.plugins.writerMarks[name] = options; - }); - - // Writer custom nodes - resolve(extensions, "writerNodes", function (name, options) { - window.panel.plugins.writerNodes[name] = options; - }); + // Third-party plugins + resolve(parts, "thirdParty", function (name, options) { + window.panel.plugins.thirdParty[name] = options; + }); }; -const resolve = (extensions, type, callback) => { - for (const [name, options] of Object.entries(extensions[type] ?? {})) { - callback(name, options); - } -}; +function resolve(object, type, callback) { + if (object[type]) { + for (const [name, options] of Object.entries(object[type])) { + callback(name, options); + } + } +} diff --git a/kirby/panel/dist/js/vendor.js b/kirby/panel/dist/js/vendor.js new file mode 100644 index 0000000..e918936 --- /dev/null +++ b/kirby/panel/dist/js/vendor.js @@ -0,0 +1,12 @@ +/*! + * Vue.js v2.7.10 + * (c) 2014-2022 Evan You + * Released under the MIT License. + */ +var t=Object.freeze({}),e=Array.isArray;function n(t){return null==t}function r(t){return null!=t}function i(t){return!0===t}function o(t){return"string"==typeof t||"number"==typeof t||"symbol"==typeof t||"boolean"==typeof t}function s(t){return"function"==typeof t}function a(t){return null!==t&&"object"==typeof t}var l=Object.prototype.toString;function c(t){return"[object Object]"===l.call(t)}function u(t){var e=parseFloat(String(t));return e>=0&&Math.floor(e)===e&&isFinite(t)}function d(t){return r(t)&&"function"==typeof t.then&&"function"==typeof t.catch}function f(t){return null==t?"":Array.isArray(t)||c(t)&&t.toString===l?JSON.stringify(t,null,2):String(t)}function h(t){var e=parseFloat(t);return isNaN(e)?t:e}function p(t,e){for(var n=Object.create(null),r=t.split(","),i=0;i-1)return t.splice(n,1)}}var y=Object.prototype.hasOwnProperty;function b(t,e){return y.call(t,e)}function w(t){var e=Object.create(null);return function(n){return e[n]||(e[n]=t(n))}}var x=/-(\w)/g,S=w((function(t){return t.replace(x,(function(t,e){return e?e.toUpperCase():""}))})),k=w((function(t){return t.charAt(0).toUpperCase()+t.slice(1)})),O=/\B([A-Z])/g,_=w((function(t){return t.replace(O,"-$1").toLowerCase()}));var M=Function.prototype.bind?function(t,e){return t.bind(e)}:function(t,e){function n(n){var r=arguments.length;return r?r>1?t.apply(e,arguments):t.call(e,n):t.call(e)}return n._length=t.length,n};function C(t,e){e=e||0;for(var n=t.length-e,r=new Array(n);n--;)r[n]=t[n+e];return r}function $(t,e){for(var n in e)t[n]=e[n];return t}function T(t){for(var e={},n=0;n0,Y=K&&K.indexOf("edge/")>0;K&&K.indexOf("android");var G=K&&/iphone|ipad|ipod|ios/.test(K);K&&/chrome\/\d+/.test(K),K&&/phantomjs/.test(K);var Z,X=K&&K.match(/firefox\/(\d+)/),Q={}.watch,tt=!1;if(J)try{var et={};Object.defineProperty(et,"passive",{get:function(){tt=!0}}),window.addEventListener("test-passive",null,et)}catch(_g){}var nt=function(){return void 0===Z&&(Z=!J&&"undefined"!=typeof global&&(global.process&&"server"===global.process.env.VUE_ENV)),Z},rt=J&&window.__VUE_DEVTOOLS_GLOBAL_HOOK__;function it(t){return"function"==typeof t&&/native code/.test(t.toString())}var ot,st="undefined"!=typeof Symbol&&it(Symbol)&&"undefined"!=typeof Reflect&&it(Reflect.ownKeys);ot="undefined"!=typeof Set&&it(Set)?Set:function(){function t(){this.set=Object.create(null)}return t.prototype.has=function(t){return!0===this.set[t]},t.prototype.add=function(t){this.set[t]=!0},t.prototype.clear=function(){this.set=Object.create(null)},t}();var at=null;function lt(t){void 0===t&&(t=null),t||at&&at._scope.off(),at=t,t&&t._scope.on()}var ct=function(){function t(t,e,n,r,i,o,s,a){this.tag=t,this.data=e,this.children=n,this.text=r,this.elm=i,this.ns=void 0,this.context=o,this.fnContext=void 0,this.fnOptions=void 0,this.fnScopeId=void 0,this.key=e&&e.key,this.componentOptions=s,this.componentInstance=void 0,this.parent=void 0,this.raw=!1,this.isStatic=!1,this.isRootInsert=!0,this.isComment=!1,this.isCloned=!1,this.isOnce=!1,this.asyncFactory=a,this.asyncMeta=void 0,this.isAsyncPlaceholder=!1}return Object.defineProperty(t.prototype,"child",{get:function(){return this.componentInstance},enumerable:!1,configurable:!0}),t}(),ut=function(t){void 0===t&&(t="");var e=new ct;return e.text=t,e.isComment=!0,e};function dt(t){return new ct(void 0,void 0,void 0,String(t))}function ft(t){var e=new ct(t.tag,t.data,t.children&&t.children.slice(),t.text,t.elm,t.context,t.componentOptions,t.asyncFactory);return e.ns=t.ns,e.isStatic=t.isStatic,e.key=t.key,e.isComment=t.isComment,e.fnContext=t.fnContext,e.fnOptions=t.fnOptions,e.fnScopeId=t.fnScopeId,e.asyncMeta=t.asyncMeta,e.isCloned=!0,e}var ht=0,pt=function(){function t(){this.id=ht++,this.subs=[]}return t.prototype.addSub=function(t){this.subs.push(t)},t.prototype.removeSub=function(t){v(this.subs,t)},t.prototype.depend=function(e){t.target&&t.target.addDep(this)},t.prototype.notify=function(t){for(var e=this.subs.slice(),n=0,r=e.length;n0&&(Bt((l=Vt(l,"".concat(s||"","_").concat(a)))[0])&&Bt(u)&&(d[c]=dt(u.text+l[0].text),l.shift()),d.push.apply(d,l)):o(l)?Bt(u)?d[c]=dt(u.text+l):""!==l&&d.push(dt(l)):Bt(l)&&Bt(u)?d[c]=dt(u.text+l.text):(i(t._isVList)&&r(l.tag)&&n(l.key)&&r(s)&&(l.key="__vlist".concat(s,"_").concat(a,"__")),d.push(l)));return d}function Wt(t,n,l,c,u,d){return(e(l)||o(l))&&(u=c,c=l,l=void 0),i(d)&&(u=2),function(t,n,i,o,l){if(r(i)&&r(i.__ob__))return ut();r(i)&&r(i.is)&&(n=i.is);if(!n)return ut();e(o)&&s(o[0])&&((i=i||{}).scopedSlots={default:o[0]},o.length=0);2===l?o=Lt(o):1===l&&(o=function(t){for(var n=0;n0,a=n?!!n.$stable:!s,l=n&&n.$key;if(n){if(n._normalized)return n._normalized;if(a&&i&&i!==t&&l===i.$key&&!s&&!i.$hasNormal)return i;for(var c in o={},n)n[c]&&"$"!==c[0]&&(o[c]=ue(e,r,c,n[c]))}else o={};for(var u in r)u in o||(o[u]=de(r,u));return n&&Object.isExtensible(n)&&(n._normalized=o),V(o,"$stable",a),V(o,"$key",l),V(o,"$hasNormal",s),o}function ue(t,n,r,i){var o=function(){var n=at;lt(t);var r=arguments.length?i.apply(null,arguments):i({}),o=(r=r&&"object"==typeof r&&!e(r)?[r]:Lt(r))&&r[0];return lt(n),r&&(!o||1===r.length&&o.isComment&&!le(o))?void 0:r};return i.proxy&&Object.defineProperty(n,r,{get:o,enumerable:!0,configurable:!0}),o}function de(t,e){return function(){return t[e]}}function fe(e){var n=e.$options,r=n.setup;if(r){var i=e._setupContext=function(e){return{get attrs(){if(!e._attrsProxy){var n=e._attrsProxy={};V(n,"_v_attr_proxy",!0),he(n,e.$attrs,t,e,"$attrs")}return e._attrsProxy},get listeners(){e._listenersProxy||he(e._listenersProxy={},e.$listeners,t,e,"$listeners");return e._listenersProxy},get slots(){return function(t){t._slotsProxy||me(t._slotsProxy={},t.$scopedSlots);return t._slotsProxy}(e)},emit:M(e.$emit,e),expose:function(t){t&&Object.keys(t).forEach((function(n){return Pt(e,t,n)}))}}}(e);lt(e),gt();var o=qe(r,null,[e._props||Nt({}),i],e,"setup");if(vt(),lt(),s(o))n.render=o;else if(a(o))if(e._setupState=o,o.__sfc){var l=e._setupProxy={};for(var c in o)"__sfc"!==c&&Pt(l,o,c)}else for(var c in o)B(c)||Pt(e,o,c)}}function he(t,e,n,r,i){var o=!1;for(var s in e)s in t?e[s]!==n[s]&&(o=!0):(o=!0,pe(t,s,r,i));for(var s in t)s in e||(o=!0,delete t[s]);return o}function pe(t,e,n,r){Object.defineProperty(t,e,{enumerable:!0,configurable:!0,get:function(){return n[r][e]}})}function me(t,e){for(var n in e)t[n]=e[n];for(var n in t)n in e||delete t[n]}var ge,ve=null;function ye(t,e){return(t.__esModule||st&&"Module"===t[Symbol.toStringTag])&&(t=t.default),a(t)?e.extend(t):t}function be(t){if(e(t))for(var n=0;ndocument.createEvent("Event").timeStamp&&(ze=function(){return je.now()})}var Fe,Le=function(t,e){if(t.post){if(!e.post)return 1}else if(e.post)return-1;return t.id-e.id};function Be(){var t,e;for(Re=ze(),Pe=!0,De.sort(Le),Ie=0;IeIe&&De[n].id>t.id;)n--;De.splice(n+1,0,t)}else De.push(t);Ee||(Ee=!0,nn(Be))}}(this)},t.prototype.run=function(){if(this.active){var t=this.get();if(t!==this.value||a(t)||this.deep){var e=this.value;if(this.value=t,this.user){var n='callback for watcher "'.concat(this.expression,'"');qe(this.cb,this.vm,[t,e],this.vm,n)}else this.cb.call(this.vm,t,e)}}},t.prototype.evaluate=function(){this.value=this.get(),this.dirty=!1},t.prototype.depend=function(){for(var t=this.deps.length;t--;)this.deps[t].depend()},t.prototype.teardown=function(){if(this.vm&&!this.vm._isBeingDestroyed&&v(this.vm._scope.effects,this),this.active){for(var t=this.deps.length;t--;)this.deps[t].removeSub(this);this.active=!1,this.onStop&&this.onStop()}},t}(),cn={enumerable:!0,configurable:!0,get:D,set:D};function un(t,e,n){cn.get=function(){return this[e][n]},cn.set=function(t){this[e][n]=t},Object.defineProperty(t,n,cn)}function dn(t){var n=t.$options;if(n.props&&function(t,e){var n=t.$options.propsData||{},r=t._props=Nt({}),i=t.$options._propKeys=[];t.$parent&&kt(!1);var o=function(o){i.push(o);var s=jn(o,e,n,t);Ct(r,o,s),o in t||un(t,"_props",o)};for(var s in e)o(s);kt(!0)}(t,n.props),fe(t),n.methods&&function(t,e){for(var n in t.$options.props,e)t[n]="function"!=typeof e[n]?D:M(e[n],t)}(t,n.methods),n.data)!function(t){var e=t.$options.data;c(e=t._data=s(e)?function(t,e){gt();try{return t.call(e,e)}catch(_g){return We(_g,e,"data()"),{}}finally{vt()}}(e,t):e||{})||(e={});var n=Object.keys(e),r=t.$options.props;t.$options.methods;var i=n.length;for(;i--;){var o=n[i];r&&b(r,o)||B(o)||un(t,"_data",o)}var a=Mt(e);a&&a.vmCount++}(t);else{var r=Mt(t._data={});r&&r.vmCount++}n.computed&&function(t,e){var n=t._computedWatchers=Object.create(null),r=nt();for(var i in e){var o=e[i],a=s(o)?o:o.get;r||(n[i]=new ln(t,a||D,D,fn)),i in t||hn(t,i,o)}}(t,n.computed),n.watch&&n.watch!==Q&&function(t,n){for(var r in n){var i=n[r];if(e(i))for(var o=0;o-1)if(o&&!b(i,"default"))a=!1;else if(""===a||a===_(t)){var c=Vn(String,i.type);(c<0||l-1:"string"==typeof t?t.split(",").indexOf(n)>-1:(r=t,"[object RegExp]"===l.call(r)&&t.test(n));var r}function Hn(t,e){var n=t.cache,r=t.keys,i=t._vnode;for(var o in n){var s=n[o];if(s){var a=s.name;a&&!e(a)&&Un(n,o,r,i)}}}function Un(t,e,n,r){var i=t[e];!i||r&&i.tag===r.tag||i.componentInstance.$destroy(),t[e]=null,v(n,e)}Wn.prototype._init=function(e){var n=this;n._uid=bn++,n._isVue=!0,n.__v_skip=!0,n._scope=new Ve(!0),n._scope._vm=!0,e&&e._isComponent?function(t,e){var n=t.$options=Object.create(t.constructor.options),r=e._parentVnode;n.parent=e.parent,n._parentVnode=r;var i=r.componentOptions;n.propsData=i.propsData,n._parentListeners=i.listeners,n._renderChildren=i.children,n._componentTag=i.tag,e.render&&(n.render=e.render,n.staticRenderFns=e.staticRenderFns)}(n,e):n.$options=Rn(wn(n.constructor),e||{},n),n._renderProxy=n,n._self=n,function(t){var e=t.$options,n=e.parent;if(n&&!e.abstract){for(;n.$options.abstract&&n.$parent;)n=n.$parent;n.$children.push(t)}t.$parent=n,t.$root=n?n.$root:t,t.$children=[],t.$refs={},t._provided=n?n._provided:Object.create(null),t._watcher=null,t._inactive=null,t._directInactive=!1,t._isMounted=!1,t._isDestroyed=!1,t._isBeingDestroyed=!1}(n),function(t){t._events=Object.create(null),t._hasHookEvent=!1;var e=t.$options._parentListeners;e&&ke(t,e)}(n),function(e){e._vnode=null,e._staticTrees=null;var n=e.$options,r=e.$vnode=n._parentVnode,i=r&&r.context;e.$slots=se(n._renderChildren,i),e.$scopedSlots=r?ce(e.$parent,r.data.scopedSlots,e.$slots):t,e._c=function(t,n,r,i){return Wt(e,t,n,r,i,!1)},e.$createElement=function(t,n,r,i){return Wt(e,t,n,r,i,!0)};var o=r&&r.data;Ct(e,"$attrs",o&&o.attrs||t,null,!0),Ct(e,"$listeners",n._parentListeners||t,null,!0)}(n),Te(n,"beforeCreate",void 0,!1),function(t){var e=yn(t.$options.inject,t);e&&(kt(!1),Object.keys(e).forEach((function(n){Ct(t,n,e[n])})),kt(!0))}(n),dn(n),vn(n),Te(n,"created"),n.$options.el&&n.$mount(n.$options.el)},function(t){var e={get:function(){return this._data}},n={get:function(){return this._props}};Object.defineProperty(t.prototype,"$data",e),Object.defineProperty(t.prototype,"$props",n),t.prototype.$set=$t,t.prototype.$delete=Tt,t.prototype.$watch=function(t,e,n){var r=this;if(c(e))return gn(r,t,e,n);(n=n||{}).user=!0;var i=new ln(r,t,e,n);if(n.immediate){var o='callback for immediate watcher "'.concat(i.expression,'"');gt(),qe(e,r,[i.value],r,o),vt()}return function(){i.teardown()}}}(Wn),function(t){var n=/^hook:/;t.prototype.$on=function(t,r){var i=this;if(e(t))for(var o=0,s=t.length;o1?C(n):n;for(var r=C(arguments,1),i='event handler for "'.concat(t,'"'),o=0,s=n.length;oparseInt(this.max)&&Un(e,n[0],n,this._vnode),this.vnodeToCache=null}}},created:function(){this.cache=Object.create(null),this.keys=[]},destroyed:function(){for(var t in this.cache)Un(this.cache,t,this.keys)},mounted:function(){var t=this;this.cacheVNode(),this.$watch("include",(function(e){Hn(t,(function(t){return Kn(e,t)}))})),this.$watch("exclude",(function(e){Hn(t,(function(t){return!Kn(e,t)}))}))},updated:function(){this.cacheVNode()},render:function(){var t=this.$slots.default,e=be(t),n=e&&e.componentOptions;if(n){var r=Jn(n),i=this.include,o=this.exclude;if(i&&(!r||!Kn(i,r))||o&&r&&Kn(o,r))return e;var s=this.cache,a=this.keys,l=null==e.key?n.Ctor.cid+(n.tag?"::".concat(n.tag):""):e.key;s[l]?(e.componentInstance=s[l].componentInstance,v(a,l),a.push(l)):(this.vnodeToCache=e,this.keyToCache=l),e.data.keepAlive=!0}return e||t&&t[0]}}};!function(t){var e={get:function(){return F}};Object.defineProperty(t,"config",e),t.util={warn:Tn,extend:$,mergeOptions:Rn,defineReactive:Ct},t.set=$t,t.delete=Tt,t.nextTick=nn,t.observable=function(t){return Mt(t),t},t.options=Object.create(null),z.forEach((function(e){t.options[e+"s"]=Object.create(null)})),t.options._base=t,$(t.options.components,Gn),function(t){t.use=function(t){var e=this._installedPlugins||(this._installedPlugins=[]);if(e.indexOf(t)>-1)return this;var n=C(arguments,1);return n.unshift(this),s(t.install)?t.install.apply(t,n):s(t)&&t.apply(null,n),e.push(t),this}}(t),function(t){t.mixin=function(t){return this.options=Rn(this.options,t),this}}(t),qn(t),function(t){z.forEach((function(e){t[e]=function(t,n){return n?("component"===e&&c(n)&&(n.name=n.name||t,n=this.options._base.extend(n)),"directive"===e&&s(n)&&(n={bind:n,update:n}),this.options[e+"s"][t]=n,n):this.options[e+"s"][t]}}))}(t)}(Wn),Object.defineProperty(Wn.prototype,"$isServer",{get:nt}),Object.defineProperty(Wn.prototype,"$ssrContext",{get:function(){return this.$vnode&&this.$vnode.ssrContext}}),Object.defineProperty(Wn,"FunctionalRenderContext",{value:xn}),Wn.version="2.7.10";var Zn=p("style,class"),Xn=p("input,textarea,option,select,progress"),Qn=function(t,e,n){return"value"===n&&Xn(t)&&"button"!==e||"selected"===n&&"option"===t||"checked"===n&&"input"===t||"muted"===n&&"video"===t},tr=p("contenteditable,draggable,spellcheck"),er=p("events,caret,typing,plaintext-only"),nr=p("allowfullscreen,async,autofocus,autoplay,checked,compact,controls,declare,default,defaultchecked,defaultmuted,defaultselected,defer,disabled,enabled,formnovalidate,hidden,indeterminate,inert,ismap,itemscope,loop,multiple,muted,nohref,noresize,noshade,novalidate,nowrap,open,pauseonexit,readonly,required,reversed,scoped,seamless,selected,sortable,truespeed,typemustmatch,visible"),rr="http://www.w3.org/1999/xlink",ir=function(t){return":"===t.charAt(5)&&"xlink"===t.slice(0,5)},or=function(t){return ir(t)?t.slice(6,t.length):""},sr=function(t){return null==t||!1===t};function ar(t){for(var e=t.data,n=t,i=t;r(i.componentInstance);)(i=i.componentInstance._vnode)&&i.data&&(e=lr(i.data,e));for(;r(n=n.parent);)n&&n.data&&(e=lr(e,n.data));return function(t,e){if(r(t)||r(e))return cr(t,ur(e));return""}(e.staticClass,e.class)}function lr(t,e){return{staticClass:cr(t.staticClass,e.staticClass),class:r(t.class)?[t.class,e.class]:e.class}}function cr(t,e){return t?e?t+" "+e:t:e||""}function ur(t){return Array.isArray(t)?function(t){for(var e,n="",i=0,o=t.length;i-1?Rr(t,e,n):nr(e)?sr(n)?t.removeAttribute(e):(n="allowfullscreen"===e&&"EMBED"===t.tagName?"true":e,t.setAttribute(e,n)):tr(e)?t.setAttribute(e,function(t,e){return sr(e)||"false"===e?"false":"contenteditable"===t&&er(e)?e:"true"}(e,n)):ir(e)?sr(n)?t.removeAttributeNS(rr,or(e)):t.setAttributeNS(rr,e,n):Rr(t,e,n)}function Rr(t,e,n){if(sr(n))t.removeAttribute(e);else{if(H&&!U&&"TEXTAREA"===t.tagName&&"placeholder"===e&&""!==n&&!t.__ieph){var r=function(e){e.stopImmediatePropagation(),t.removeEventListener("input",r)};t.addEventListener("input",r),t.__ieph=!0}t.setAttribute(e,n)}}var zr={create:Pr,update:Pr};function jr(t,e){var i=e.elm,o=e.data,s=t.data;if(!(n(o.staticClass)&&n(o.class)&&(n(s)||n(s.staticClass)&&n(s.class)))){var a=ar(e),l=i._transitionClasses;r(l)&&(a=cr(a,ur(l))),a!==i._prevClass&&(i.setAttribute("class",a),i._prevClass=a)}}var Fr,Lr,Br,Vr,Wr,qr,Jr={create:jr,update:jr},Kr=/[\w).+\-_$\]]/;function Hr(t){var e,n,r,i,o,s=!1,a=!1,l=!1,c=!1,u=0,d=0,f=0,h=0;for(r=0;r=0&&" "===(m=t.charAt(p));p--);m&&Kr.test(m)||(c=!0)}}else void 0===i?(h=r+1,i=t.slice(0,r).trim()):g();function g(){(o||(o=[])).push(t.slice(h,r).trim()),h=r+1}if(void 0===i?i=t.slice(0,r).trim():0!==h&&g(),o)for(r=0;r-1?{exp:t.slice(0,Vr),key:'"'+t.slice(Vr+1)+'"'}:{exp:t,key:null};Lr=t,Vr=Wr=qr=0;for(;!ui();)di(Br=ci())?hi(Br):91===Br&&fi(Br);return{exp:t.slice(0,Wr),key:t.slice(Wr+1,qr)}}(t);return null===n.key?"".concat(t,"=").concat(e):"$set(".concat(n.exp,", ").concat(n.key,", ").concat(e,")")}function ci(){return Lr.charCodeAt(++Vr)}function ui(){return Vr>=Fr}function di(t){return 34===t||39===t}function fi(t){var e=1;for(Wr=Vr;!ui();)if(di(t=ci()))hi(t);else if(91===t&&e++,93===t&&e--,0===e){qr=Vr;break}}function hi(t){for(var e=t;!ui()&&(t=ci())!==e;);}var pi;function mi(t,e,n){var r=pi;return function i(){var o=e.apply(null,arguments);null!==o&&yi(t,i,n,r)}}var gi=Ue&&!(X&&Number(X[1])<=53);function vi(t,e,n,r){if(gi){var i=Re,o=e;e=o._wrapper=function(t){if(t.target===t.currentTarget||t.timeStamp>=i||t.timeStamp<=0||t.target.ownerDocument!==document)return o.apply(this,arguments)}}pi.addEventListener(t,e,tt?{capture:n,passive:r}:n)}function yi(t,e,n,r){(r||pi).removeEventListener(t,e._wrapper||e,n)}function bi(t,e){if(!n(t.data.on)||!n(e.data.on)){var i=e.data.on||{},o=t.data.on||{};pi=e.elm||t.elm,function(t){if(r(t.__r)){var e=H?"change":"input";t[e]=[].concat(t.__r,t[e]||[]),delete t.__r}r(t.__c)&&(t.change=[].concat(t.__c,t.change||[]),delete t.__c)}(i),zt(i,o,vi,yi,mi,e.context),pi=void 0}}var wi,xi={create:bi,update:bi,destroy:function(t){return bi(t,kr)}};function Si(t,e){if(!n(t.data.domProps)||!n(e.data.domProps)){var o,s,a=e.elm,l=t.data.domProps||{},c=e.data.domProps||{};for(o in(r(c.__ob__)||i(c._v_attr_proxy))&&(c=e.data.domProps=$({},c)),l)o in c||(a[o]="");for(o in c){if(s=c[o],"textContent"===o||"innerHTML"===o){if(e.children&&(e.children.length=0),s===l[o])continue;1===a.childNodes.length&&a.removeChild(a.childNodes[0])}if("value"===o&&"PROGRESS"!==a.tagName){a._value=s;var u=n(s)?"":String(s);ki(a,u)&&(a.value=u)}else if("innerHTML"===o&&hr(a.tagName)&&n(a.innerHTML)){(wi=wi||document.createElement("div")).innerHTML="".concat(s,"");for(var d=wi.firstChild;a.firstChild;)a.removeChild(a.firstChild);for(;d.firstChild;)a.appendChild(d.firstChild)}else if(s!==l[o])try{a[o]=s}catch(_g){}}}}function ki(t,e){return!t.composing&&("OPTION"===t.tagName||function(t,e){var n=!0;try{n=document.activeElement!==t}catch(_g){}return n&&t.value!==e}(t,e)||function(t,e){var n=t.value,i=t._vModifiers;if(r(i)){if(i.number)return h(n)!==h(e);if(i.trim)return n.trim()!==e.trim()}return n!==e}(t,e))}var Oi={create:Si,update:Si},_i=w((function(t){var e={},n=/:(.+)/;return t.split(/;(?![^(]*\))/g).forEach((function(t){if(t){var r=t.split(n);r.length>1&&(e[r[0].trim()]=r[1].trim())}})),e}));function Mi(t){var e=Ci(t.style);return t.staticStyle?$(t.staticStyle,e):e}function Ci(t){return Array.isArray(t)?T(t):"string"==typeof t?_i(t):t}var $i,Ti=/^--/,Di=/\s*!important$/,Ni=function(t,e,n){if(Ti.test(e))t.style.setProperty(e,n);else if(Di.test(n))t.style.setProperty(_(e),n.replace(Di,""),"important");else{var r=Ei(e);if(Array.isArray(n))for(var i=0,o=n.length;i-1?e.split(Ri).forEach((function(e){return t.classList.add(e)})):t.classList.add(e);else{var n=" ".concat(t.getAttribute("class")||""," ");n.indexOf(" "+e+" ")<0&&t.setAttribute("class",(n+e).trim())}}function ji(t,e){if(e&&(e=e.trim()))if(t.classList)e.indexOf(" ")>-1?e.split(Ri).forEach((function(e){return t.classList.remove(e)})):t.classList.remove(e),t.classList.length||t.removeAttribute("class");else{for(var n=" ".concat(t.getAttribute("class")||""," "),r=" "+e+" ";n.indexOf(r)>=0;)n=n.replace(r," ");(n=n.trim())?t.setAttribute("class",n):t.removeAttribute("class")}}function Fi(t){if(t){if("object"==typeof t){var e={};return!1!==t.css&&$(e,Li(t.name||"v")),$(e,t),e}return"string"==typeof t?Li(t):void 0}}var Li=w((function(t){return{enterClass:"".concat(t,"-enter"),enterToClass:"".concat(t,"-enter-to"),enterActiveClass:"".concat(t,"-enter-active"),leaveClass:"".concat(t,"-leave"),leaveToClass:"".concat(t,"-leave-to"),leaveActiveClass:"".concat(t,"-leave-active")}})),Bi=J&&!U,Vi="transition",Wi="transitionend",qi="animation",Ji="animationend";Bi&&(void 0===window.ontransitionend&&void 0!==window.onwebkittransitionend&&(Vi="WebkitTransition",Wi="webkitTransitionEnd"),void 0===window.onanimationend&&void 0!==window.onwebkitanimationend&&(qi="WebkitAnimation",Ji="webkitAnimationEnd"));var Ki=J?window.requestAnimationFrame?window.requestAnimationFrame.bind(window):setTimeout:function(t){return t()};function Hi(t){Ki((function(){Ki(t)}))}function Ui(t,e){var n=t._transitionClasses||(t._transitionClasses=[]);n.indexOf(e)<0&&(n.push(e),zi(t,e))}function Yi(t,e){t._transitionClasses&&v(t._transitionClasses,e),ji(t,e)}function Gi(t,e,n){var r=Xi(t,e),i=r.type,o=r.timeout,s=r.propCount;if(!i)return n();var a="transition"===i?Wi:Ji,l=0,c=function(){t.removeEventListener(a,u),n()},u=function(e){e.target===t&&++l>=s&&c()};setTimeout((function(){l0&&(n="transition",u=s,d=o.length):"animation"===e?c>0&&(n="animation",u=c,d=l.length):d=(n=(u=Math.max(s,c))>0?s>c?"transition":"animation":null)?"transition"===n?o.length:l.length:0,{type:n,timeout:u,propCount:d,hasTransform:"transition"===n&&Zi.test(r[Vi+"Property"])}}function Qi(t,e){for(;t.length1}function oo(t,e){!0!==e.data.show&&eo(e)}var so=function(t){var s,a,l={},c=t.modules,u=t.nodeOps;for(s=0;sp?w(t,n(i[v+1])?null:i[v+1].elm,i,h,v,o):h>v&&S(e,d,p)}(d,m,g,o,c):r(g)?(r(t.text)&&u.setTextContent(d,""),w(d,null,g,0,g.length-1,o)):r(m)?S(m,0,m.length-1):r(t.text)&&u.setTextContent(d,""):t.text!==e.text&&u.setTextContent(d,e.text),r(p)&&r(h=p.hook)&&r(h=h.postpatch)&&h(t,e)}}}function M(t,e,n){if(i(n)&&r(t.parent))t.parent.data.pendingInsert=e;else for(var o=0;o-1,s.selected!==o&&(s.selected=o);else if(E(fo(s),r))return void(t.selectedIndex!==a&&(t.selectedIndex=a));i||(t.selectedIndex=-1)}}function uo(t,e){return e.every((function(e){return!E(e,t)}))}function fo(t){return"_value"in t?t._value:t.value}function ho(t){t.target.composing=!0}function po(t){t.target.composing&&(t.target.composing=!1,mo(t.target,"input"))}function mo(t,e){var n=document.createEvent("HTMLEvents");n.initEvent(e,!0,!0),t.dispatchEvent(n)}function go(t){return!t.componentInstance||t.data&&t.data.transition?t:go(t.componentInstance._vnode)}var vo={model:ao,show:{bind:function(t,e,n){var r=e.value,i=(n=go(n)).data&&n.data.transition,o=t.__vOriginalDisplay="none"===t.style.display?"":t.style.display;r&&i?(n.data.show=!0,eo(n,(function(){t.style.display=o}))):t.style.display=r?o:"none"},update:function(t,e,n){var r=e.value;!r!=!e.oldValue&&((n=go(n)).data&&n.data.transition?(n.data.show=!0,r?eo(n,(function(){t.style.display=t.__vOriginalDisplay})):no(n,(function(){t.style.display="none"}))):t.style.display=r?t.__vOriginalDisplay:"none")},unbind:function(t,e,n,r,i){i||(t.style.display=t.__vOriginalDisplay)}}},yo={name:String,appear:Boolean,css:Boolean,mode:String,type:String,enterClass:String,leaveClass:String,enterToClass:String,leaveToClass:String,enterActiveClass:String,leaveActiveClass:String,appearClass:String,appearActiveClass:String,appearToClass:String,duration:[Number,String,Object]};function bo(t){var e=t&&t.componentOptions;return e&&e.Ctor.options.abstract?bo(be(e.children)):t}function wo(t){var e={},n=t.$options;for(var r in n.propsData)e[r]=t[r];var i=n._parentListeners;for(var r in i)e[S(r)]=i[r];return e}function xo(t,e){if(/\d-keep-alive$/.test(e.tag))return t("keep-alive",{props:e.componentOptions.propsData})}var So=function(t){return t.tag||le(t)},ko=function(t){return"show"===t.name},Oo={name:"transition",props:yo,abstract:!0,render:function(t){var e=this,n=this.$slots.default;if(n&&(n=n.filter(So)).length){var r=this.mode,i=n[0];if(function(t){for(;t=t.parent;)if(t.data.transition)return!0}(this.$vnode))return i;var s=bo(i);if(!s)return i;if(this._leaving)return xo(t,i);var a="__transition-".concat(this._uid,"-");s.key=null==s.key?s.isComment?a+"comment":a+s.tag:o(s.key)?0===String(s.key).indexOf(a)?s.key:a+s.key:s.key;var l=(s.data||(s.data={})).transition=wo(this),c=this._vnode,u=bo(c);if(s.data.directives&&s.data.directives.some(ko)&&(s.data.show=!0),u&&u.data&&!function(t,e){return e.key===t.key&&e.tag===t.tag}(s,u)&&!le(u)&&(!u.componentInstance||!u.componentInstance._vnode.isComment)){var d=u.data.transition=$({},l);if("out-in"===r)return this._leaving=!0,jt(d,"afterLeave",(function(){e._leaving=!1,e.$forceUpdate()})),xo(t,i);if("in-out"===r){if(le(s))return c;var f,h=function(){f()};jt(l,"afterEnter",h),jt(l,"enterCancelled",h),jt(d,"delayLeave",(function(t){f=t}))}}return i}}},_o=$({tag:String,moveClass:String},yo);delete _o.mode;var Mo={props:_o,beforeMount:function(){var t=this,e=this._update;this._update=function(n,r){var i=_e(t);t.__patch__(t._vnode,t.kept,!1,!0),t._vnode=t.kept,i(),e.call(t,n,r)}},render:function(t){for(var e=this.tag||this.$vnode.data.tag||"span",n=Object.create(null),r=this.prevChildren=this.children,i=this.$slots.default||[],o=this.children=[],s=wo(this),a=0;a-1?gr[t]=e.constructor===window.HTMLUnknownElement||e.constructor===window.HTMLElement:gr[t]=/HTMLUnknownElement/.test(e.toString())},$(Wn.options.directives,vo),$(Wn.options.components,Do),Wn.prototype.__patch__=J?so:D,Wn.prototype.$mount=function(t,e){return function(t,e,n){var r;t.$el=e,t.$options.render||(t.$options.render=ut),Te(t,"beforeMount"),r=function(){t._update(t._render(),n)},new ln(t,r,D,{before:function(){t._isMounted&&!t._isDestroyed&&Te(t,"beforeUpdate")}},!0),n=!1;var i=t._preWatchers;if(i)for(var o=0;o\/=]+)(?:\s*(=)\s*(?:"([^"]*)"+|'([^']*)'+|([^\s"'=<>`]+)))?/,Vo=/^\s*((?:v-[\w-]+:|@|:|#)\[[^=]+?\][^\s"'<>\/=]*)(?:\s*(=)\s*(?:"([^"]*)"+|'([^']*)'+|([^\s"'=<>`]+)))?/,Wo="[a-zA-Z_][\\-\\.0-9_a-zA-Z".concat(L.source,"]*"),qo="((?:".concat(Wo,"\\:)?").concat(Wo,")"),Jo=new RegExp("^<".concat(qo)),Ko=/^\s*(\/?)>/,Ho=new RegExp("^<\\/".concat(qo,"[^>]*>")),Uo=/^]+>/i,Yo=/^",""":'"',"&":"&"," ":"\n"," ":"\t","'":"'"},ts=/&(?:lt|gt|quot|amp|#39);/g,es=/&(?:lt|gt|quot|amp|#39|#10|#9);/g,ns=p("pre,textarea",!0),rs=function(t,e){return t&&ns(t)&&"\n"===e[0]};function is(t,e){var n=e?es:ts;return t.replace(n,(function(t){return Qo[t]}))}function ss(t,e){for(var n,r,i=[],o=e.expectHTML,s=e.isUnaryTag||N,a=e.canBeLeftOpenTag||N,l=0,c=function(){if(n=t,r&&Zo(r)){var c=0,f=r.toLowerCase(),h=Xo[f]||(Xo[f]=new RegExp("([\\s\\S]*?)(]*>)","i"));S=t.replace(h,(function(t,n,r){return c=r.length,Zo(f)||"noscript"===f||(n=n.replace(//g,"$1").replace(//g,"$1")),rs(f,n)&&(n=n.slice(1)),e.chars&&e.chars(n),""}));l+=t.length-S.length,t=S,d(f,l-c,l)}else{var p=t.indexOf("<");if(0===p){if(Yo.test(t)){var m=t.indexOf("--\x3e");if(m>=0)return e.shouldKeepComment&&e.comment&&e.comment(t.substring(4,m),l,l+m+3),u(m+3),"continue"}if(Go.test(t)){var g=t.indexOf("]>");if(g>=0)return u(g+2),"continue"}var v=t.match(Uo);if(v)return u(v[0].length),"continue";var y=t.match(Ho);if(y){var b=l;return u(y[0].length),d(y[1],b,l),"continue"}var w=function(){var e=t.match(Jo);if(e){var n={tagName:e[1],attrs:[],start:l};u(e[0].length);for(var r=void 0,i=void 0;!(r=t.match(Ko))&&(i=t.match(Vo)||t.match(Bo));)i.start=l,u(i[0].length),i.end=l,n.attrs.push(i);if(r)return n.unarySlash=r[1],u(r[0].length),n.end=l,n}}();if(w)return function(t){var n=t.tagName,l=t.unarySlash;o&&("p"===r&&Lo(n)&&d(r),a(n)&&r===n&&d(n));for(var c=s(n)||!!l,u=t.attrs.length,f=new Array(u),h=0;h=0){for(S=t.slice(p);!(Ho.test(S)||Jo.test(S)||Yo.test(S)||Go.test(S)||(k=S.indexOf("<",1))<0);)p+=k,S=t.slice(p);x=t.substring(0,p)}p<0&&(x=t),x&&u(x.length),e.chars&&x&&e.chars(x,l-x.length,l)}if(t===n)return e.chars&&e.chars(t),"break"};t;){if("break"===c())break}function u(e){l+=e,t=t.substring(e)}function d(t,n,o){var s,a;if(null==n&&(n=l),null==o&&(o=l),t)for(a=t.toLowerCase(),s=i.length-1;s>=0&&i[s].lowerCasedTag!==a;s--);else s=0;if(s>=0){for(var c=i.length-1;c>=s;c--)e.end&&e.end(i[c].tag,n,o);i.length=s,r=s&&i[s-1].tag}else"br"===a?e.start&&e.start(t,[],!0,n,o):"p"===a&&(e.start&&e.start(t,[],!1,n,o),e.end&&e.end(t,n,o))}d()}var as,ls,cs,us,ds,fs,hs,ps,ms=/^@|^v-on:/,gs=/^v-|^@|^:|^#/,vs=/([\s\S]*?)\s+(?:in|of)\s+([\s\S]*)/,ys=/,([^,\}\]]*)(?:,([^,\}\]]*))?$/,bs=/^\(|\)$/g,ws=/^\[.*\]$/,xs=/:(.*)$/,Ss=/^:|^\.|^v-bind:/,ks=/\.[^.\]]+(?=[^\]]*$)/g,Os=/^v-slot(:|$)|^#/,_s=/[\r\n]/,Ms=/[ \f\t\r\n]+/g,Cs=w(zo);function $s(t,e,n){return{type:1,tag:t,attrsList:e,attrsMap:Is(e),rawAttrsMap:{},parent:n,children:[]}}function Ts(t,e){as=e.warn||Yr,fs=e.isPreTag||N,hs=e.mustUseProp||N,ps=e.getTagNamespace||N,e.isReservedTag,cs=Gr(e.modules,"transformNode"),us=Gr(e.modules,"preTransformNode"),ds=Gr(e.modules,"postTransformNode"),ls=e.delimiters;var n,r,i=[],o=!1!==e.preserveWhitespace,s=e.whitespace,a=!1,l=!1;function c(t){if(u(t),a||t.processed||(t=Ds(t,e)),i.length||t===n||n.if&&(t.elseif||t.else)&&As(n,{exp:t.elseif,block:t}),r&&!t.forbidden)if(t.elseif||t.else)s=t,c=function(t){for(var e=t.length;e--;){if(1===t[e].type)return t[e];t.pop()}}(r.children),c&&c.if&&As(c,{exp:s.elseif,block:s});else{if(t.slotScope){var o=t.slotTarget||'"default"';(r.scopedSlots||(r.scopedSlots={}))[o]=t}r.children.push(t),t.parent=r}var s,c;t.children=t.children.filter((function(t){return!t.slotScope})),u(t),t.pre&&(a=!1),fs(t.tag)&&(l=!1);for(var d=0;dl&&(a.push(o=t.slice(l,i)),s.push(JSON.stringify(o)));var c=Hr(r[1].trim());s.push("_s(".concat(c,")")),a.push({"@binding":c}),l=i+r[0].length}return l-1")+("true"===o?":(".concat(e,")"):":_q(".concat(e,",").concat(o,")"))),ni(t,"change","var $$a=".concat(e,",")+"$$el=$event.target,"+"$$c=$$el.checked?(".concat(o,"):(").concat(s,");")+"if(Array.isArray($$a)){"+"var $$v=".concat(r?"_n("+i+")":i,",")+"$$i=_i($$a,$$v);"+"if($$el.checked){$$i<0&&(".concat(li(e,"$$a.concat([$$v])"),")}")+"else{$$i>-1&&(".concat(li(e,"$$a.slice(0,$$i).concat($$a.slice($$i+1))"),")}")+"}else{".concat(li(e,"$$c"),"}"),null,!0)}(t,r,i);else if("input"===o&&"radio"===s)!function(t,e,n){var r=n&&n.number,i=ri(t,"value")||"null";i=r?"_n(".concat(i,")"):i,Zr(t,"checked","_q(".concat(e,",").concat(i,")")),ni(t,"change",li(e,i),null,!0)}(t,r,i);else if("input"===o||"textarea"===o)!function(t,e,n){var r=t.attrsMap.type,i=n||{},o=i.lazy,s=i.number,a=i.trim,l=!o&&"range"!==r,c=o?"change":"range"===r?"__r":"input",u="$event.target.value";a&&(u="$event.target.value.trim()");s&&(u="_n(".concat(u,")"));var d=li(e,u);l&&(d="if($event.target.composing)return;".concat(d));Zr(t,"value","(".concat(e,")")),ni(t,c,d,null,!0),(a||s)&&ni(t,"blur","$forceUpdate()")}(t,r,i);else if(!F.isReservedTag(o))return ai(t,r,i),!1;return!0},text:function(t,e){e.value&&Zr(t,"textContent","_s(".concat(e.value,")"),e)},html:function(t,e){e.value&&Zr(t,"innerHTML","_s(".concat(e.value,")"),e)}},qs={expectHTML:!0,modules:Fs,directives:Ws,isPreTag:function(t){return"pre"===t},isUnaryTag:jo,mustUseProp:Qn,canBeLeftOpenTag:Fo,isReservedTag:pr,getTagNamespace:mr,staticKeys:(Ls=Fs,Ls.reduce((function(t,e){return t.concat(e.staticKeys||[])}),[]).join(","))},Js=w((function(t){return p("type,tag,attrsList,attrsMap,plain,parent,children,attrs,start,end,rawAttrsMap"+(t?","+t:""))}));function Ks(t,e){t&&(Bs=Js(e.staticKeys||""),Vs=e.isReservedTag||N,Hs(t),Us(t,!1))}function Hs(t){if(t.static=function(t){if(2===t.type)return!1;if(3===t.type)return!0;return!(!t.pre&&(t.hasBindings||t.if||t.for||m(t.tag)||!Vs(t.tag)||function(t){for(;t.parent;){if("template"!==(t=t.parent).tag)return!1;if(t.for)return!0}return!1}(t)||!Object.keys(t).every(Bs)))}(t),1===t.type){if(!Vs(t.tag)&&"slot"!==t.tag&&null==t.attrsMap["inline-template"])return;for(var e=0,n=t.children.length;e|^function(?:\s+[\w$]+)?\s*\(/,Gs=/\([^)]*?\);*$/,Zs=/^[A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*|\['[^']*?']|\["[^"]*?"]|\[\d+]|\[[A-Za-z_$][\w$]*])*$/,Xs={esc:27,tab:9,enter:13,space:32,up:38,left:37,right:39,down:40,delete:[8,46]},Qs={esc:["Esc","Escape"],tab:"Tab",enter:"Enter",space:[" ","Spacebar"],up:["Up","ArrowUp"],left:["Left","ArrowLeft"],right:["Right","ArrowRight"],down:["Down","ArrowDown"],delete:["Backspace","Delete","Del"]},ta=function(t){return"if(".concat(t,")return null;")},ea={stop:"$event.stopPropagation();",prevent:"$event.preventDefault();",self:ta("$event.target !== $event.currentTarget"),ctrl:ta("!$event.ctrlKey"),shift:ta("!$event.shiftKey"),alt:ta("!$event.altKey"),meta:ta("!$event.metaKey"),left:ta("'button' in $event && $event.button !== 0"),middle:ta("'button' in $event && $event.button !== 1"),right:ta("'button' in $event && $event.button !== 2")};function na(t,e){var n=e?"nativeOn:":"on:",r="",i="";for(var o in t){var s=ra(t[o]);t[o]&&t[o].dynamic?i+="".concat(o,",").concat(s,","):r+='"'.concat(o,'":').concat(s,",")}return r="{".concat(r.slice(0,-1),"}"),i?n+"_d(".concat(r,",[").concat(i.slice(0,-1),"])"):n+r}function ra(t){if(!t)return"function(){}";if(Array.isArray(t))return"[".concat(t.map((function(t){return ra(t)})).join(","),"]");var e=Zs.test(t.value),n=Ys.test(t.value),r=Zs.test(t.value.replace(Gs,""));if(t.modifiers){var i="",o="",s=[],a=function(e){if(ea[e])o+=ea[e],Xs[e]&&s.push(e);else if("exact"===e){var n=t.modifiers;o+=ta(["ctrl","shift","alt","meta"].filter((function(t){return!n[t]})).map((function(t){return"$event.".concat(t,"Key")})).join("||"))}else s.push(e)};for(var l in t.modifiers)a(l);s.length&&(i+=function(t){return"if(!$event.type.indexOf('key')&&"+"".concat(t.map(ia).join("&&"),")return null;")}(s)),o&&(i+=o);var c=e?"return ".concat(t.value,".apply(null, arguments)"):n?"return (".concat(t.value,").apply(null, arguments)"):r?"return ".concat(t.value):t.value;return"function($event){".concat(i).concat(c,"}")}return e||n?t.value:"function($event){".concat(r?"return ".concat(t.value):t.value,"}")}function ia(t){var e=parseInt(t,10);if(e)return"$event.keyCode!==".concat(e);var n=Xs[t],r=Qs[t];return"_k($event.keyCode,"+"".concat(JSON.stringify(t),",")+"".concat(JSON.stringify(n),",")+"$event.key,"+"".concat(JSON.stringify(r))+")"}var oa={on:function(t,e){t.wrapListeners=function(t){return"_g(".concat(t,",").concat(e.value,")")}},bind:function(t,e){t.wrapData=function(n){return"_b(".concat(n,",'").concat(t.tag,"',").concat(e.value,",").concat(e.modifiers&&e.modifiers.prop?"true":"false").concat(e.modifiers&&e.modifiers.sync?",true":"",")")}},cloak:D},sa=function(t){this.options=t,this.warn=t.warn||Yr,this.transforms=Gr(t.modules,"transformCode"),this.dataGenFns=Gr(t.modules,"genData"),this.directives=$($({},oa),t.directives);var e=t.isReservedTag||N;this.maybeComponent=function(t){return!!t.component||!e(t.tag)},this.onceId=0,this.staticRenderFns=[],this.pre=!1};function aa(t,e){var n=new sa(e),r=t?"script"===t.tag?"null":la(t,n):'_c("div")';return{render:"with(this){return ".concat(r,"}"),staticRenderFns:n.staticRenderFns}}function la(t,e){if(t.parent&&(t.pre=t.pre||t.parent.pre),t.staticRoot&&!t.staticProcessed)return ca(t,e);if(t.once&&!t.onceProcessed)return ua(t,e);if(t.for&&!t.forProcessed)return ha(t,e);if(t.if&&!t.ifProcessed)return da(t,e);if("template"!==t.tag||t.slotTarget||e.pre){if("slot"===t.tag)return function(t,e){var n=t.slotName||'"default"',r=va(t,e),i="_t(".concat(n).concat(r?",function(){return ".concat(r,"}"):""),o=t.attrs||t.dynamicAttrs?wa((t.attrs||[]).concat(t.dynamicAttrs||[]).map((function(t){return{name:S(t.name),value:t.value,dynamic:t.dynamic}}))):null,s=t.attrsMap["v-bind"];!o&&!s||r||(i+=",null");o&&(i+=",".concat(o));s&&(i+="".concat(o?"":",null",",").concat(s));return i+")"}(t,e);var n=void 0;if(t.component)n=function(t,e,n){var r=e.inlineTemplate?null:va(e,n,!0);return"_c(".concat(t,",").concat(pa(e,n)).concat(r?",".concat(r):"",")")}(t.component,t,e);else{var r=void 0,i=e.maybeComponent(t);(!t.plain||t.pre&&i)&&(r=pa(t,e));var o=void 0,s=e.options.bindings;i&&s&&!1!==s.__isScriptSetup&&(o=function(t,e){var n=S(e),r=k(n),i=function(i){return t[e]===i?e:t[n]===i?n:t[r]===i?r:void 0},o=i("setup-const")||i("setup-reactive-const");if(o)return o;var s=i("setup-let")||i("setup-ref")||i("setup-maybe-ref");if(s)return s}(s,t.tag)),o||(o="'".concat(t.tag,"'"));var a=t.inlineTemplate?null:va(t,e,!0);n="_c(".concat(o).concat(r?",".concat(r):"").concat(a?",".concat(a):"",")")}for(var l=0;l>>0}(s)):"",")")}(t,t.scopedSlots,e),",")),t.model&&(n+="model:{value:".concat(t.model.value,",callback:").concat(t.model.callback,",expression:").concat(t.model.expression,"},")),t.inlineTemplate){var o=function(t,e){var n=t.children[0];if(n&&1===n.type){var r=aa(n,e.options);return"inlineTemplate:{render:function(){".concat(r.render,"},staticRenderFns:[").concat(r.staticRenderFns.map((function(t){return"function(){".concat(t,"}")})).join(","),"]}")}}(t,e);o&&(n+="".concat(o,","))}return n=n.replace(/,$/,"")+"}",t.dynamicAttrs&&(n="_b(".concat(n,',"').concat(t.tag,'",').concat(wa(t.dynamicAttrs),")")),t.wrapData&&(n=t.wrapData(n)),t.wrapListeners&&(n=t.wrapListeners(n)),n}function ma(t){return 1===t.type&&("slot"===t.tag||t.children.some(ma))}function ga(t,e){var n=t.attrsMap["slot-scope"];if(t.if&&!t.ifProcessed&&!n)return da(t,e,ga,"null");if(t.for&&!t.forProcessed)return ha(t,e,ga);var r="_empty_"===t.slotScope?"":String(t.slotScope),i="function(".concat(r,"){")+"return ".concat("template"===t.tag?t.if&&n?"(".concat(t.if,")?").concat(va(t,e)||"undefined",":undefined"):va(t,e)||"undefined":la(t,e),"}"),o=r?"":",proxy:true";return"{key:".concat(t.slotTarget||'"default"',",fn:").concat(i).concat(o,"}")}function va(t,e,n,r,i){var o=t.children;if(o.length){var s=o[0];if(1===o.length&&s.for&&"template"!==s.tag&&"slot"!==s.tag){var a=n?e.maybeComponent(s)?",1":",0":"";return"".concat((r||la)(s,e)).concat(a)}var l=n?function(t,e){for(var n=0,r=0;r':'

      ',_a.innerHTML.indexOf(" ")>0}var Ta=!!J&&$a(!1),Da=!!J&&$a(!0),Na=w((function(t){var e=yr(t);return e&&e.innerHTML})),Aa=Wn.prototype.$mount;Wn.prototype.$mount=function(t,e){if((t=t&&yr(t))===document.body||t===document.documentElement)return this;var n=this.$options;if(!n.render){var r=n.template;if(r)if("string"==typeof r)"#"===r.charAt(0)&&(r=Na(r));else{if(!r.nodeType)return this;r=r.innerHTML}else t&&(r=function(t){if(t.outerHTML)return t.outerHTML;var e=document.createElement("div");return e.appendChild(t.cloneNode(!0)),e.innerHTML}(t));if(r){var i=Ca(r,{outputSourceRange:!1,shouldDecodeNewlines:Ta,shouldDecodeNewlinesForHref:Da,delimiters:n.delimiters,comments:n.comments},this),o=i.render,s=i.staticRenderFns;n.render=o,n.staticRenderFns=s}}return Aa.call(this,t,e)},Wn.compile=Ca;var Ea=("undefined"!=typeof window?window:"undefined"!=typeof global?global:{}).__VUE_DEVTOOLS_GLOBAL_HOOK__;function Pa(t,e){if(void 0===e&&(e=[]),null===t||"object"!=typeof t)return t;var n,r=(n=function(e){return e.original===t},e.filter(n)[0]);if(r)return r.copy;var i=Array.isArray(t)?[]:{};return e.push({original:t,copy:i}),Object.keys(t).forEach((function(n){i[n]=Pa(t[n],e)})),i}function Ia(t,e){Object.keys(t).forEach((function(n){return e(t[n],n)}))}function Ra(t){return null!==t&&"object"==typeof t}var za=function(t,e){this.runtime=e,this._children=Object.create(null),this._rawModule=t;var n=t.state;this.state=("function"==typeof n?n():n)||{}},ja={namespaced:{configurable:!0}};ja.namespaced.get=function(){return!!this._rawModule.namespaced},za.prototype.addChild=function(t,e){this._children[t]=e},za.prototype.removeChild=function(t){delete this._children[t]},za.prototype.getChild=function(t){return this._children[t]},za.prototype.hasChild=function(t){return t in this._children},za.prototype.update=function(t){this._rawModule.namespaced=t.namespaced,t.actions&&(this._rawModule.actions=t.actions),t.mutations&&(this._rawModule.mutations=t.mutations),t.getters&&(this._rawModule.getters=t.getters)},za.prototype.forEachChild=function(t){Ia(this._children,t)},za.prototype.forEachGetter=function(t){this._rawModule.getters&&Ia(this._rawModule.getters,t)},za.prototype.forEachAction=function(t){this._rawModule.actions&&Ia(this._rawModule.actions,t)},za.prototype.forEachMutation=function(t){this._rawModule.mutations&&Ia(this._rawModule.mutations,t)},Object.defineProperties(za.prototype,ja);var Fa,La=function(t){this.register([],t,!1)};function Ba(t,e,n){if(e.update(n),n.modules)for(var r in n.modules){if(!e.getChild(r))return;Ba(t.concat(r),e.getChild(r),n.modules[r])}}La.prototype.get=function(t){return t.reduce((function(t,e){return t.getChild(e)}),this.root)},La.prototype.getNamespace=function(t){var e=this.root;return t.reduce((function(t,n){return t+((e=e.getChild(n)).namespaced?n+"/":"")}),"")},La.prototype.update=function(t){Ba([],this.root,t)},La.prototype.register=function(t,e,n){var r=this;void 0===n&&(n=!0);var i=new za(e,n);0===t.length?this.root=i:this.get(t.slice(0,-1)).addChild(t[t.length-1],i);e.modules&&Ia(e.modules,(function(e,i){r.register(t.concat(i),e,n)}))},La.prototype.unregister=function(t){var e=this.get(t.slice(0,-1)),n=t[t.length-1],r=e.getChild(n);r&&r.runtime&&e.removeChild(n)},La.prototype.isRegistered=function(t){var e=this.get(t.slice(0,-1)),n=t[t.length-1];return!!e&&e.hasChild(n)};var Va=function(t){var e=this;void 0===t&&(t={}),!Fa&&"undefined"!=typeof window&&window.Vue&&Ga(window.Vue);var n=t.plugins;void 0===n&&(n=[]);var r=t.strict;void 0===r&&(r=!1),this._committing=!1,this._actions=Object.create(null),this._actionSubscribers=[],this._mutations=Object.create(null),this._wrappedGetters=Object.create(null),this._modules=new La(t),this._modulesNamespaceMap=Object.create(null),this._subscribers=[],this._watcherVM=new Fa,this._makeLocalGettersCache=Object.create(null);var i=this,o=this.dispatch,s=this.commit;this.dispatch=function(t,e){return o.call(i,t,e)},this.commit=function(t,e,n){return s.call(i,t,e,n)},this.strict=r;var a=this._modules.root.state;Ha(this,a,[],this._modules.root),Ka(this,a),n.forEach((function(t){return t(e)})),(void 0!==t.devtools?t.devtools:Fa.config.devtools)&&function(t){Ea&&(t._devtoolHook=Ea,Ea.emit("vuex:init",t),Ea.on("vuex:travel-to-state",(function(e){t.replaceState(e)})),t.subscribe((function(t,e){Ea.emit("vuex:mutation",t,e)}),{prepend:!0}),t.subscribeAction((function(t,e){Ea.emit("vuex:action",t,e)}),{prepend:!0}))}(this)},Wa={state:{configurable:!0}};function qa(t,e,n){return e.indexOf(t)<0&&(n&&n.prepend?e.unshift(t):e.push(t)),function(){var n=e.indexOf(t);n>-1&&e.splice(n,1)}}function Ja(t,e){t._actions=Object.create(null),t._mutations=Object.create(null),t._wrappedGetters=Object.create(null),t._modulesNamespaceMap=Object.create(null);var n=t.state;Ha(t,n,[],t._modules.root,!0),Ka(t,n,e)}function Ka(t,e,n){var r=t._vm;t.getters={},t._makeLocalGettersCache=Object.create(null);var i=t._wrappedGetters,o={};Ia(i,(function(e,n){o[n]=function(t,e){return function(){return t(e)}}(e,t),Object.defineProperty(t.getters,n,{get:function(){return t._vm[n]},enumerable:!0})}));var s=Fa.config.silent;Fa.config.silent=!0,t._vm=new Fa({data:{$$state:e},computed:o}),Fa.config.silent=s,t.strict&&function(t){t._vm.$watch((function(){return this._data.$$state}),(function(){}),{deep:!0,sync:!0})}(t),r&&(n&&t._withCommit((function(){r._data.$$state=null})),Fa.nextTick((function(){return r.$destroy()})))}function Ha(t,e,n,r,i){var o=!n.length,s=t._modules.getNamespace(n);if(r.namespaced&&(t._modulesNamespaceMap[s],t._modulesNamespaceMap[s]=r),!o&&!i){var a=Ua(e,n.slice(0,-1)),l=n[n.length-1];t._withCommit((function(){Fa.set(a,l,r.state)}))}var c=r.context=function(t,e,n){var r=""===e,i={dispatch:r?t.dispatch:function(n,r,i){var o=Ya(n,r,i),s=o.payload,a=o.options,l=o.type;return a&&a.root||(l=e+l),t.dispatch(l,s)},commit:r?t.commit:function(n,r,i){var o=Ya(n,r,i),s=o.payload,a=o.options,l=o.type;a&&a.root||(l=e+l),t.commit(l,s,a)}};return Object.defineProperties(i,{getters:{get:r?function(){return t.getters}:function(){return function(t,e){if(!t._makeLocalGettersCache[e]){var n={},r=e.length;Object.keys(t.getters).forEach((function(i){if(i.slice(0,r)===e){var o=i.slice(r);Object.defineProperty(n,o,{get:function(){return t.getters[i]},enumerable:!0})}})),t._makeLocalGettersCache[e]=n}return t._makeLocalGettersCache[e]}(t,e)}},state:{get:function(){return Ua(t.state,n)}}}),i}(t,s,n);r.forEachMutation((function(e,n){!function(t,e,n,r){(t._mutations[e]||(t._mutations[e]=[])).push((function(e){n.call(t,r.state,e)}))}(t,s+n,e,c)})),r.forEachAction((function(e,n){var r=e.root?n:s+n,i=e.handler||e;!function(t,e,n,r){(t._actions[e]||(t._actions[e]=[])).push((function(e){var i,o=n.call(t,{dispatch:r.dispatch,commit:r.commit,getters:r.getters,state:r.state,rootGetters:t.getters,rootState:t.state},e);return(i=o)&&"function"==typeof i.then||(o=Promise.resolve(o)),t._devtoolHook?o.catch((function(e){throw t._devtoolHook.emit("vuex:error",e),e})):o}))}(t,r,i,c)})),r.forEachGetter((function(e,n){!function(t,e,n,r){if(t._wrappedGetters[e])return;t._wrappedGetters[e]=function(t){return n(r.state,r.getters,t.state,t.getters)}}(t,s+n,e,c)})),r.forEachChild((function(r,o){Ha(t,e,n.concat(o),r,i)}))}function Ua(t,e){return e.reduce((function(t,e){return t[e]}),t)}function Ya(t,e,n){return Ra(t)&&t.type&&(n=e,e=t,t=t.type),{type:t,payload:e,options:n}}function Ga(t){Fa&&t===Fa|| +/*! + * vuex v3.6.2 + * (c) 2021 Evan You + * @license MIT + */ +function(t){if(Number(t.version.split(".")[0])>=2)t.mixin({beforeCreate:n});else{var e=t.prototype._init;t.prototype._init=function(t){void 0===t&&(t={}),t.init=t.init?[n].concat(t.init):n,e.call(this,t)}}function n(){var t=this.$options;t.store?this.$store="function"==typeof t.store?t.store():t.store:t.parent&&t.parent.$store&&(this.$store=t.parent.$store)}}(Fa=t)}Wa.state.get=function(){return this._vm._data.$$state},Wa.state.set=function(t){},Va.prototype.commit=function(t,e,n){var r=this,i=Ya(t,e,n),o=i.type,s=i.payload,a={type:o,payload:s},l=this._mutations[o];l&&(this._withCommit((function(){l.forEach((function(t){t(s)}))})),this._subscribers.slice().forEach((function(t){return t(a,r.state)})))},Va.prototype.dispatch=function(t,e){var n=this,r=Ya(t,e),i=r.type,o=r.payload,s={type:i,payload:o},a=this._actions[i];if(a){try{this._actionSubscribers.slice().filter((function(t){return t.before})).forEach((function(t){return t.before(s,n.state)}))}catch(_g){}var l=a.length>1?Promise.all(a.map((function(t){return t(o)}))):a[0](o);return new Promise((function(t,e){l.then((function(e){try{n._actionSubscribers.filter((function(t){return t.after})).forEach((function(t){return t.after(s,n.state)}))}catch(_g){}t(e)}),(function(t){try{n._actionSubscribers.filter((function(t){return t.error})).forEach((function(e){return e.error(s,n.state,t)}))}catch(_g){}e(t)}))}))}},Va.prototype.subscribe=function(t,e){return qa(t,this._subscribers,e)},Va.prototype.subscribeAction=function(t,e){return qa("function"==typeof t?{before:t}:t,this._actionSubscribers,e)},Va.prototype.watch=function(t,e,n){var r=this;return this._watcherVM.$watch((function(){return t(r.state,r.getters)}),e,n)},Va.prototype.replaceState=function(t){var e=this;this._withCommit((function(){e._vm._data.$$state=t}))},Va.prototype.registerModule=function(t,e,n){void 0===n&&(n={}),"string"==typeof t&&(t=[t]),this._modules.register(t,e),Ha(this,this.state,t,this._modules.get(t),n.preserveState),Ka(this,this.state)},Va.prototype.unregisterModule=function(t){var e=this;"string"==typeof t&&(t=[t]),this._modules.unregister(t),this._withCommit((function(){var n=Ua(e.state,t.slice(0,-1));Fa.delete(n,t[t.length-1])})),Ja(this)},Va.prototype.hasModule=function(t){return"string"==typeof t&&(t=[t]),this._modules.isRegistered(t)},Va.prototype.hotUpdate=function(t){this._modules.update(t),Ja(this,!0)},Va.prototype._withCommit=function(t){var e=this._committing;this._committing=!0,t(),this._committing=e},Object.defineProperties(Va.prototype,Wa);var Za=nl((function(t,e){var n={};return el(e).forEach((function(e){var r=e.key,i=e.val;n[r]=function(){var e=this.$store.state,n=this.$store.getters;if(t){var r=rl(this.$store,"mapState",t);if(!r)return;e=r.context.state,n=r.context.getters}return"function"==typeof i?i.call(this,e,n):e[i]},n[r].vuex=!0})),n})),Xa=nl((function(t,e){var n={};return el(e).forEach((function(e){var r=e.key,i=e.val;n[r]=function(){for(var e=[],n=arguments.length;n--;)e[n]=arguments[n];var r=this.$store.commit;if(t){var o=rl(this.$store,"mapMutations",t);if(!o)return;r=o.context.commit}return"function"==typeof i?i.apply(this,[r].concat(e)):r.apply(this.$store,[i].concat(e))}})),n})),Qa=nl((function(t,e){var n={};return el(e).forEach((function(e){var r=e.key,i=e.val;i=t+i,n[r]=function(){if(!t||rl(this.$store,"mapGetters",t))return this.$store.getters[i]},n[r].vuex=!0})),n})),tl=nl((function(t,e){var n={};return el(e).forEach((function(e){var r=e.key,i=e.val;n[r]=function(){for(var e=[],n=arguments.length;n--;)e[n]=arguments[n];var r=this.$store.dispatch;if(t){var o=rl(this.$store,"mapActions",t);if(!o)return;r=o.context.dispatch}return"function"==typeof i?i.apply(this,[r].concat(e)):r.apply(this.$store,[i].concat(e))}})),n}));function el(t){return function(t){return Array.isArray(t)||Ra(t)}(t)?Array.isArray(t)?t.map((function(t){return{key:t,val:t}})):Object.keys(t).map((function(e){return{key:e,val:t[e]}})):[]}function nl(t){return function(e,n){return"string"!=typeof e?(n=e,e=""):"/"!==e.charAt(e.length-1)&&(e+="/"),t(e,n)}}function rl(t,e,n){return t._modulesNamespaceMap[n]}function il(t,e,n){var r=n?t.groupCollapsed:t.group;try{r.call(t,e)}catch(_g){t.log(e)}}function ol(t){try{t.groupEnd()}catch(_g){t.log("—— log end ——")}}function sl(){var t=new Date;return" @ "+al(t.getHours(),2)+":"+al(t.getMinutes(),2)+":"+al(t.getSeconds(),2)+"."+al(t.getMilliseconds(),3)}function al(t,e){return n="0",r=e-t.toString().length,new Array(r+1).join(n)+t;var n,r}const ll={Store:Va,install:Ga,version:"3.6.2",mapState:Za,mapMutations:Xa,mapGetters:Qa,mapActions:tl,createNamespacedHelpers:function(t){return{mapState:Za.bind(null,t),mapGetters:Qa.bind(null,t),mapMutations:Xa.bind(null,t),mapActions:tl.bind(null,t)}},createLogger:function(t){void 0===t&&(t={});var e=t.collapsed;void 0===e&&(e=!0);var n=t.filter;void 0===n&&(n=function(t,e,n){return!0});var r=t.transformer;void 0===r&&(r=function(t){return t});var i=t.mutationTransformer;void 0===i&&(i=function(t){return t});var o=t.actionFilter;void 0===o&&(o=function(t,e){return!0});var s=t.actionTransformer;void 0===s&&(s=function(t){return t});var a=t.logMutations;void 0===a&&(a=!0);var l=t.logActions;void 0===l&&(l=!0);var c=t.logger;return void 0===c&&(c=console),function(t){var u=Pa(t.state);void 0!==c&&(a&&t.subscribe((function(t,o){var s=Pa(o);if(n(t,u,s)){var a=sl(),l=i(t),d="mutation "+t.type+a;il(c,d,e),c.log("%c prev state","color: #9E9E9E; font-weight: bold",r(u)),c.log("%c mutation","color: #03A9F4; font-weight: bold",l),c.log("%c next state","color: #4CAF50; font-weight: bold",r(s)),ol(c)}u=s})),l&&t.subscribeAction((function(t,n){if(o(t,n)){var r=sl(),i=s(t),a="action "+t.type+r;il(c,a,e),c.log("%c action","color: #03A9F4; font-weight: bold",i),ol(c)}})))}}};function cl(t){return{all:t=t||new Map,on:function(e,n){var r=t.get(e);r?r.push(n):t.set(e,[n])},off:function(e,n){var r=t.get(e);r&&(n?r.splice(r.indexOf(n)>>>0,1):t.set(e,[]))},emit:function(e,n){var r=t.get(e);r&&r.slice().map((function(t){t(n)})),(r=t.get("*"))&&r.slice().map((function(t){t(e,n)}))}}}var ul,dl,fl="function"==typeof Map?new Map:(ul=[],dl=[],{has:function(t){return ul.indexOf(t)>-1},get:function(t){return dl[ul.indexOf(t)]},set:function(t,e){-1===ul.indexOf(t)&&(ul.push(t),dl.push(e))},delete:function(t){var e=ul.indexOf(t);e>-1&&(ul.splice(e,1),dl.splice(e,1))}}),hl=function(t){return new Event(t,{bubbles:!0})};try{new Event("test")}catch(_g){hl=function(t){var e=document.createEvent("Event");return e.initEvent(t,!0,!1),e}}function pl(t){var e=fl.get(t);e&&e.destroy()}function ml(t){var e=fl.get(t);e&&e.update()}var gl=null;"undefined"==typeof window||"function"!=typeof window.getComputedStyle?((gl=function(t){return t}).destroy=function(t){return t},gl.update=function(t){return t}):((gl=function(t,e){return t&&Array.prototype.forEach.call(t.length?t:[t],(function(t){return function(t){if(t&&t.nodeName&&"TEXTAREA"===t.nodeName&&!fl.has(t)){var e,n=null,r=null,i=null,o=function(){t.clientWidth!==r&&c()},s=function(e){window.removeEventListener("resize",o,!1),t.removeEventListener("input",c,!1),t.removeEventListener("keyup",c,!1),t.removeEventListener("autosize:destroy",s,!1),t.removeEventListener("autosize:update",c,!1),Object.keys(e).forEach((function(n){t.style[n]=e[n]})),fl.delete(t)}.bind(t,{height:t.style.height,resize:t.style.resize,overflowY:t.style.overflowY,overflowX:t.style.overflowX,wordWrap:t.style.wordWrap});t.addEventListener("autosize:destroy",s,!1),"onpropertychange"in t&&"oninput"in t&&t.addEventListener("keyup",c,!1),window.addEventListener("resize",o,!1),t.addEventListener("input",c,!1),t.addEventListener("autosize:update",c,!1),t.style.overflowX="hidden",t.style.wordWrap="break-word",fl.set(t,{destroy:s,update:c}),"vertical"===(e=window.getComputedStyle(t,null)).resize?t.style.resize="none":"both"===e.resize&&(t.style.resize="horizontal"),n="content-box"===e.boxSizing?-(parseFloat(e.paddingTop)+parseFloat(e.paddingBottom)):parseFloat(e.borderTopWidth)+parseFloat(e.borderBottomWidth),isNaN(n)&&(n=0),c()}function a(e){var n=t.style.width;t.style.width="0px",t.style.width=n,t.style.overflowY=e}function l(){if(0!==t.scrollHeight){var e=function(t){for(var e=[];t&&t.parentNode&&t.parentNode instanceof Element;)t.parentNode.scrollTop&&e.push({node:t.parentNode,scrollTop:t.parentNode.scrollTop}),t=t.parentNode;return e}(t),i=document.documentElement&&document.documentElement.scrollTop;t.style.height="",t.style.height=t.scrollHeight+n+"px",r=t.clientWidth,e.forEach((function(t){t.node.scrollTop=t.scrollTop})),i&&(document.documentElement.scrollTop=i)}}function c(){l();var e=Math.round(parseFloat(t.style.height)),n=window.getComputedStyle(t,null),r="content-box"===n.boxSizing?Math.round(parseFloat(n.height)):t.offsetHeight;if(r=e?t:""+Array(e+1-r.length).join(n)+t},y={s:v,z:function(t){var e=-t.utcOffset(),n=Math.abs(e),r=Math.floor(n/60),i=n%60;return(e<=0?"+":"-")+v(r,2,"0")+":"+v(i,2,"0")},m:function t(e,n){if(e.date()1)return t(s[0])}else{var a=e.name;w[a]=e,i=a}return!r&&i&&(b=i),i||!r&&b},k=function(t,e){if(x(t))return t.clone();var n="object"==typeof e?e:{};return n.date=t,n.args=arguments,new _(n)},O=y;O.l=S,O.i=x,O.w=function(t,e){return k(t,{locale:e.$L,utc:e.$u,x:e.$x,$offset:e.$offset})};var _=function(){function g(t){this.$L=S(t.locale,null,!0),this.parse(t)}var v=g.prototype;return v.parse=function(t){this.$d=function(t){var e=t.date,n=t.utc;if(null===e)return new Date(NaN);if(O.u(e))return new Date;if(e instanceof Date)return new Date(e);if("string"==typeof e&&!/Z$/i.test(e)){var r=e.match(p);if(r){var i=r[2]-1||0,o=(r[7]||"0").substring(0,3);return n?new Date(Date.UTC(r[1],i,r[3]||1,r[4]||0,r[5]||0,r[6]||0,o)):new Date(r[1],i,r[3]||1,r[4]||0,r[5]||0,r[6]||0,o)}}return new Date(e)}(t),this.$x=t.x||{},this.init()},v.init=function(){var t=this.$d;this.$y=t.getFullYear(),this.$M=t.getMonth(),this.$D=t.getDate(),this.$W=t.getDay(),this.$H=t.getHours(),this.$m=t.getMinutes(),this.$s=t.getSeconds(),this.$ms=t.getMilliseconds()},v.$utils=function(){return O},v.isValid=function(){return!(this.$d.toString()===h)},v.isSame=function(t,e){var n=k(t);return this.startOf(e)<=n&&n<=this.endOf(e)},v.isAfter=function(t,e){return k(t)68?1900:2e3)},a=function(t){return function(e){this[t]=+e}},l=[/[+-]\d\d:?(\d\d)?|Z/,function(t){(this.zone||(this.zone={})).offset=function(t){if(!t)return 0;if("Z"===t)return 0;var e=t.match(/([+-]|\d\d)/g),n=60*e[1]+(+e[2]||0);return 0===n?0:"+"===e[0]?-n:n}(t)}],c=function(t){var e=o[t];return e&&(e.indexOf?e:e.s.concat(e.f))},u=function(t,e){var n,r=o.meridiem;if(r){for(var i=1;i<=24;i+=1)if(t.indexOf(r(i,0,e))>-1){n=i>12;break}}else n=t===(e?"pm":"PM");return n},d={A:[i,function(t){this.afternoon=u(t,!1)}],a:[i,function(t){this.afternoon=u(t,!0)}],S:[/\d/,function(t){this.milliseconds=100*+t}],SS:[n,function(t){this.milliseconds=10*+t}],SSS:[/\d{3}/,function(t){this.milliseconds=+t}],s:[r,a("seconds")],ss:[r,a("seconds")],m:[r,a("minutes")],mm:[r,a("minutes")],H:[r,a("hours")],h:[r,a("hours")],HH:[r,a("hours")],hh:[r,a("hours")],D:[r,a("day")],DD:[n,a("day")],Do:[i,function(t){var e=o.ordinal,n=t.match(/\d+/);if(this.day=n[0],e)for(var r=1;r<=31;r+=1)e(r).replace(/\[|\]/g,"")===t&&(this.day=r)}],M:[r,a("month")],MM:[n,a("month")],MMM:[i,function(t){var e=c("months"),n=(c("monthsShort")||e.map((function(t){return t.slice(0,3)}))).indexOf(t)+1;if(n<1)throw new Error;this.month=n%12||n}],MMMM:[i,function(t){var e=c("months").indexOf(t)+1;if(e<1)throw new Error;this.month=e%12||e}],Y:[/[+-]?\d+/,a("year")],YY:[n,function(t){this.year=s(t)}],YYYY:[/\d{4}/,a("year")],Z:l,ZZ:l};function f(n){var r,i;r=n,i=o&&o.formats;for(var s=(n=r.replace(/(\[[^\]]+])|(LTS?|l{1,4}|L{1,4})/g,(function(e,n,r){var o=r&&r.toUpperCase();return n||i[r]||t[r]||i[o].replace(/(\[[^\]]+])|(MMMM|MM|DD|dddd)/g,(function(t,e,n){return e||n.slice(1)}))}))).match(e),a=s.length,l=0;l-1)return new Date(("X"===e?1e3:1)*t);var r=f(e)(t),i=r.year,o=r.month,s=r.day,a=r.hours,l=r.minutes,c=r.seconds,u=r.milliseconds,d=r.zone,h=new Date,p=s||(i||o?1:h.getDate()),m=i||h.getFullYear(),g=0;i&&!o||(g=o>0?o-1:h.getMonth());var v=a||0,y=l||0,b=c||0,w=u||0;return d?new Date(Date.UTC(m,g,p,v,y,b,w+60*d.offset*1e3)):n?new Date(Date.UTC(m,g,p,v,y,b,w)):new Date(m,g,p,v,y,b,w)}catch(x){return new Date("")}}(e,a,r),this.init(),d&&!0!==d&&(this.$L=this.locale(d).$L),u&&e!=this.format(a)&&(this.$d=new Date("")),o={}}else if(a instanceof Array)for(var h=a.length,p=1;p<=h;p+=1){s[1]=a[p-1];var m=n.apply(this,s);if(m.isValid()){this.$d=m.$d,this.$L=m.$L,this.init();break}p===h&&(this.$d=new Date(""))}else i.call(this,t)}}}();function kl(t){return(kl="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}var Ol={selector:"vue-portal-target-".concat(((t=21)=>{let e="",n=t;for(;n--;)e+="useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict"[64*Math.random()|0];return e})())},_l=function(t){return Ol.selector=t},Ml="undefined"!=typeof window&&void 0!==("undefined"==typeof document?"undefined":kl(document)),Cl=Wn.extend({abstract:!0,name:"PortalOutlet",props:["nodes","tag"],data:function(t){return{updatedNodes:t.nodes}},render:function(t){var e=this.updatedNodes&&this.updatedNodes();return e?1!==e.length||e[0].text?t(this.tag||"DIV",e):e:t()},destroyed:function(){var t=this.$el;t&&t.parentNode.removeChild(t)}}),$l=Wn.extend({name:"VueSimplePortal",props:{disabled:{type:Boolean},prepend:{type:Boolean},selector:{type:String,default:function(){return"#".concat(Ol.selector)}},tag:{type:String,default:"DIV"}},render:function(t){if(this.disabled){var e=this.$scopedSlots&&this.$scopedSlots.default();return e?e.length<2&&!e[0].text?e:t(this.tag,e):t()}return t()},created:function(){this.getTargetEl()||this.insertTargetEl()},updated:function(){var t=this;this.$nextTick((function(){t.disabled||t.slotFn===t.$scopedSlots.default||(t.container.updatedNodes=t.$scopedSlots.default),t.slotFn=t.$scopedSlots.default}))},beforeDestroy:function(){this.unmount()},watch:{disabled:{immediate:!0,handler:function(t){t?this.unmount():this.$nextTick(this.mount)}}},methods:{getTargetEl:function(){if(Ml)return document.querySelector(this.selector)},insertTargetEl:function(){if(Ml){var t=document.querySelector("body"),e=document.createElement(this.tag);e.id=this.selector.substring(1),t.appendChild(e)}},mount:function(){if(Ml){var t=this.getTargetEl(),e=document.createElement("DIV");this.prepend&&t.firstChild?t.insertBefore(e,t.firstChild):t.appendChild(e),this.container=new Cl({el:e,parent:this,propsData:{tag:this.tag,nodes:this.$scopedSlots.default}})}},unmount:function(){this.container&&(this.container.$destroy(),delete this.container)}}});function Tl(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};t.component(e.name||"portal",$l),e.defaultSelector&&_l(e.defaultSelector)}"undefined"!=typeof window&&window.Vue&&window.Vue===Wn&&Wn.use(Tl);var Dl={},Nl={};function Al(t){return null==t}function El(t){return null!=t}function Pl(t,e){return e.tag===t.tag&&e.key===t.key}function Il(t){var e=t.tag;t.vm=new e({data:t.args})}function Rl(t,e,n){var r,i,o={};for(r=e;r<=n;++r)El(i=t[r].key)&&(o[i]=r);return o}function zl(t,e,n){for(;e<=n;++e)Il(t[e])}function jl(t,e,n){for(;e<=n;++e){var r=t[e];El(r)&&(r.vm.$destroy(),r.vm=null)}}function Fl(t,e){t!==e&&(e.vm=t.vm,function(t){for(var e=Object.keys(t.args),n=0;na?zl(e,s,u):s>u&&jl(t,o,a)}(t,e):El(e)?zl(e,0,e.length-1):El(t)&&jl(t,0,t.length-1)};var Ll={};function Bl(t,e){var n=Object.keys(t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(t);e&&(r=r.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),n.push.apply(n,r)}return n}function Vl(t){for(var e=1;et.length)&&(e=t.length);for(var n=0,r=new Array(e);n1?a:a.$sub[0]:null}}},computed:{run:function(){var t=this,e=this.lazyParentModel();if(Array.isArray(e)&&e.__ob__){var n=e.__ob__.dep;n.depend();var r=n.constructor.target;if(!this._indirectWatcher){var i=r.constructor;this._indirectWatcher=new i(this,(function(){return t.runRule(e)}),null,{lazy:!0})}var o=this.getModel();if(!this._indirectWatcher.dirty&&this._lastModel===o)return this._indirectWatcher.depend(),r.value;this._lastModel=o,this._indirectWatcher.evaluate(),this._indirectWatcher.depend()}else this._indirectWatcher&&(this._indirectWatcher.teardown(),this._indirectWatcher=null);return this._indirectWatcher?this._indirectWatcher.value:this.runRule(e)},$params:function(){return this.run.params},proxy:function(){var t=this.run.output;return t.__isVuelidateAsyncVm?!!t.v:!!t},$pending:function(){var t=this.run.output;return!!t.__isVuelidateAsyncVm&&t.p}},destroyed:function(){this._indirectWatcher&&(this._indirectWatcher.teardown(),this._indirectWatcher=null)}}),a=i.extend({data:function(){return{dirty:!1,validations:null,lazyModel:null,model:null,prop:null,lazyParentModel:null,rootModel:null}},methods:s(s({},g),{},{refProxy:function(t){return this.getRef(t).proxy},getRef:function(t){return this.refs[t]},isNested:function(t){return"function"!=typeof this.validations[t]}}),computed:s(s({},p),{},{nestedKeys:function(){return this.keys.filter(this.isNested)},ruleKeys:function(){var t=this;return this.keys.filter((function(e){return!t.isNested(e)}))},keys:function(){return Object.keys(this.validations).filter((function(t){return"$params"!==t}))},proxy:function(){var t=this,e=u(this.keys,(function(e){return{enumerable:!0,configurable:!0,get:function(){return t.refProxy(e)}}})),n=u(v,(function(e){return{enumerable:!0,configurable:!0,get:function(){return t[e]}}})),r=u(y,(function(e){return{enumerable:!1,configurable:!0,get:function(){return t[e]}}})),i=this.hasIter()?{$iter:{enumerable:!0,value:Object.defineProperties({},s({},e))}}:{};return Object.defineProperties({},s(s(s(s({},e),i),{},{$model:{enumerable:!0,get:function(){var e=t.lazyParentModel();return null!=e?e[t.prop]:null},set:function(e){var n=t.lazyParentModel();null!=n&&(n[t.prop]=e,t.$touch())}}},n),r))},children:function(){var t=this;return[].concat(r(this.nestedKeys.map((function(e){return w(t,e)}))),r(this.ruleKeys.map((function(e){return x(t,e)})))).filter(Boolean)}})}),l=a.extend({methods:{isNested:function(t){return void 0!==this.validations[t]()},getRef:function(t){var e=this;return{get proxy(){return e.validations[t]()||!1}}}}}),m=a.extend({computed:{keys:function(){var t=this.getModel();return f(t)?Object.keys(t):[]},tracker:function(){var t=this,e=this.validations.$trackBy;return e?function(n){return"".concat(h(t.rootModel,t.getModelKey(n),e))}:function(t){return"".concat(t)}},getModelLazy:function(){var t=this;return function(){return t.getModel()}},children:function(){var t=this,n=this.validations,r=this.getModel(),i=s({},n);delete i.$trackBy;var o={};return this.keys.map((function(n){var s=t.tracker(n);return o.hasOwnProperty(s)?null:(o[s]=!0,(0,e.h)(a,s,{validations:i,prop:n,lazyParentModel:t.getModelLazy,model:r[n],rootModel:t.rootModel}))})).filter(Boolean)}},methods:{isNested:function(){return!0},getRef:function(t){return this.refs[this.tracker(t)]},hasIter:function(){return!0}}}),w=function(t,n){if("$each"===n)return(0,e.h)(m,n,{validations:t.validations[n],lazyParentModel:t.lazyParentModel,prop:n,lazyModel:t.getModel,rootModel:t.rootModel});var r=t.validations[n];if(Array.isArray(r)){var i=t.rootModel,o=u(r,(function(t){return function(){return h(i,i.$v,t)}}),(function(t){return Array.isArray(t)?t.join("."):t}));return(0,e.h)(l,n,{validations:o,lazyParentModel:c,prop:n,lazyModel:c,rootModel:i})}return(0,e.h)(a,n,{validations:r,lazyParentModel:t.getModel,prop:n,lazyModel:t.getModelKey,rootModel:t.rootModel})},x=function(t,n){return(0,e.h)(o,n,{rule:t.validations[n],lazyParentModel:t.lazyParentModel,lazyModel:t.getModel,rootModel:t.rootModel})};return b={VBase:i,Validation:a}},x=null;var S=function(t,n){var r=function(t){if(x)return x;for(var e=t.constructor;e.super;)e=e.super;return x=e,e}(t),i=w(r),o=i.Validation;return new(0,i.VBase)({computed:{children:function(){var r="function"==typeof n?n.call(t):n;return[(0,e.h)(o,"$v",{validations:r,lazyParentModel:c,prop:"$v",model:t,rootModel:t})]}}})},k={data:function(){var t=this.$options.validations;return t&&(this._vuelidate=S(this,t)),{}},beforeCreate:function(){var t=this.$options;t.validations&&(t.computed||(t.computed={}),t.computed.$v||(t.computed.$v=function(){return this._vuelidate?this._vuelidate.refs.$v.proxy:null}))},beforeDestroy:function(){this._vuelidate&&(this._vuelidate.$destroy(),this._vuelidate=null)}};function O(t){t.mixin(k)}t.validationMixin=k;var _=O;t.default=_}(Dl);const Zl=yl(Dl);function Xl(t){this.content=t}function Ql(t,e,n){for(let r=0;;r++){if(r==t.childCount||r==e.childCount)return t.childCount==e.childCount?null:n;let i=t.child(r),o=e.child(r);if(i!=o){if(!i.sameMarkup(o))return n;if(i.isText&&i.text!=o.text){for(let t=0;i.text[t]==o.text[t];t++)n++;return n}if(i.content.size||o.content.size){let t=Ql(i.content,o.content,n+1);if(null!=t)return t}n+=i.nodeSize}else n+=i.nodeSize}}function tc(t,e,n,r){for(let i=t.childCount,o=e.childCount;;){if(0==i||0==o)return i==o?null:{a:n,b:r};let s=t.child(--i),a=e.child(--o),l=s.nodeSize;if(s!=a){if(!s.sameMarkup(a))return{a:n,b:r};if(s.isText&&s.text!=a.text){let t=0,e=Math.min(s.text.length,a.text.length);for(;t>1}},Xl.from=function(t){if(t instanceof Xl)return t;var e=[];if(t)for(var n in t)e.push(n,t[n]);return new Xl(e)};class ec{constructor(t,e){if(this.content=t,this.size=e||0,null==e)for(let n=0;nt&&!1!==n(a,r+s,i||null,o)&&a.content.size){let i=s+1;a.nodesBetween(Math.max(0,t-i),Math.min(a.content.size,e-i),n,r+i)}s=l}}descendants(t){this.nodesBetween(0,this.size,t)}textBetween(t,e,n,r){let i="",o=!0;return this.nodesBetween(t,e,((s,a)=>{s.isText?(i+=s.text.slice(Math.max(t,a)-a,e-a),o=!n):s.isLeaf?(r?i+="function"==typeof r?r(s):r:s.type.spec.leafText&&(i+=s.type.spec.leafText(s)),o=!n):!o&&s.isBlock&&(i+=n,o=!0)}),0),i}append(t){if(!t.size)return this;if(!this.size)return t;let e=this.lastChild,n=t.firstChild,r=this.content.slice(),i=0;for(e.isText&&e.sameMarkup(n)&&(r[r.length-1]=e.withText(e.text+n.text),i=1);it)for(let i=0,o=0;ot&&((oe)&&(s=s.isText?s.cut(Math.max(0,t-o),Math.min(s.text.length,e-o)):s.cut(Math.max(0,t-o-1),Math.min(s.content.size,e-o-1))),n.push(s),r+=s.nodeSize),o=a}return new ec(n,r)}cutByIndex(t,e){return t==e?ec.empty:0==t&&e==this.content.length?this:new ec(this.content.slice(t,e))}replaceChild(t,e){let n=this.content[t];if(n==e)return this;let r=this.content.slice(),i=this.size+e.nodeSize-n.nodeSize;return r[t]=e,new ec(r,i)}addToStart(t){return new ec([t].concat(this.content),this.size+t.nodeSize)}addToEnd(t){return new ec(this.content.concat(t),this.size+t.nodeSize)}eq(t){if(this.content.length!=t.content.length)return!1;for(let e=0;ethis.size||t<0)throw new RangeError(`Position ${t} outside of fragment (${this})`);for(let n=0,r=0;;n++){let i=r+this.child(n).nodeSize;if(i>=t)return i==t||e>0?rc(n+1,i):rc(n,r);r=i}}toString(){return"<"+this.toStringInner()+">"}toStringInner(){return this.content.join(", ")}toJSON(){return this.content.length?this.content.map((t=>t.toJSON())):null}static fromJSON(t,e){if(!e)return ec.empty;if(!Array.isArray(e))throw new RangeError("Invalid input for Fragment.fromJSON");return new ec(e.map(t.nodeFromJSON))}static fromArray(t){if(!t.length)return ec.empty;let e,n=0;for(let r=0;rthis.type.rank&&(e||(e=t.slice(0,r)),e.push(this),n=!0),e&&e.push(i)}}return e||(e=t.slice()),n||e.push(this),e}removeFromSet(t){for(let e=0;et.type.rank-e.type.rank)),e}}oc.none=[];class sc extends Error{}class ac{constructor(t,e,n){this.content=t,this.openStart=e,this.openEnd=n}get size(){return this.content.size-this.openStart-this.openEnd}insertAt(t,e){let n=cc(this.content,t+this.openStart,e);return n&&new ac(n,this.openStart,this.openEnd)}removeBetween(t,e){return new ac(lc(this.content,t+this.openStart,e+this.openStart),this.openStart,this.openEnd)}eq(t){return this.content.eq(t.content)&&this.openStart==t.openStart&&this.openEnd==t.openEnd}toString(){return this.content+"("+this.openStart+","+this.openEnd+")"}toJSON(){if(!this.content.size)return null;let t={content:this.content.toJSON()};return this.openStart>0&&(t.openStart=this.openStart),this.openEnd>0&&(t.openEnd=this.openEnd),t}static fromJSON(t,e){if(!e)return ac.empty;let n=e.openStart||0,r=e.openEnd||0;if("number"!=typeof n||"number"!=typeof r)throw new RangeError("Invalid input for Slice.fromJSON");return new ac(ec.fromJSON(t,e.content),n,r)}static maxOpen(t,e=!0){let n=0,r=0;for(let i=t.firstChild;i&&!i.isLeaf&&(e||!i.type.spec.isolating);i=i.firstChild)n++;for(let i=t.lastChild;i&&!i.isLeaf&&(e||!i.type.spec.isolating);i=i.lastChild)r++;return new ac(t,n,r)}}function lc(t,e,n){let{index:r,offset:i}=t.findIndex(e),o=t.maybeChild(r),{index:s,offset:a}=t.findIndex(n);if(i==e||o.isText){if(a!=n&&!t.child(s).isText)throw new RangeError("Removing non-flat range");return t.cut(0,e).append(t.cut(n))}if(r!=s)throw new RangeError("Removing non-flat range");return t.replaceChild(r,o.copy(lc(o.content,e-i-1,n-i-1)))}function cc(t,e,n,r){let{index:i,offset:o}=t.findIndex(e),s=t.maybeChild(i);if(o==e||s.isText)return r&&!r.canReplace(i,i,n)?null:t.cut(0,e).append(n).append(t.cut(e));let a=cc(s.content,e-o-1,n);return a&&t.replaceChild(i,s.copy(a))}function uc(t,e,n){if(n.openStart>t.depth)throw new sc("Inserted content deeper than insertion position");if(t.depth-n.openStart!=e.depth-n.openEnd)throw new sc("Inconsistent open depths");return dc(t,e,n,0)}function dc(t,e,n,r){let i=t.index(r),o=t.node(r);if(i==e.index(r)&&r=0;i--)r=e.node(i).copy(ec.from(r));return{start:r.resolveNoCache(t.openStart+n),end:r.resolveNoCache(r.content.size-t.openEnd-n)}}(n,t);return gc(o,vc(t,i,s,e,r))}{let r=t.parent,i=r.content;return gc(r,i.cut(0,t.parentOffset).append(n.content).append(i.cut(e.parentOffset)))}}return gc(o,yc(t,e,r))}function fc(t,e){if(!e.type.compatibleContent(t.type))throw new sc("Cannot join "+e.type.name+" onto "+t.type.name)}function hc(t,e,n){let r=t.node(n);return fc(r,e.node(n)),r}function pc(t,e){let n=e.length-1;n>=0&&t.isText&&t.sameMarkup(e[n])?e[n]=t.withText(e[n].text+t.text):e.push(t)}function mc(t,e,n,r){let i=(e||t).node(n),o=0,s=e?e.index(n):i.childCount;t&&(o=t.index(n),t.depth>n?o++:t.textOffset&&(pc(t.nodeAfter,r),o++));for(let a=o;ai&&hc(t,e,i+1),s=r.depth>i&&hc(n,r,i+1),a=[];return mc(null,t,i,a),o&&s&&e.index(i)==n.index(i)?(fc(o,s),pc(gc(o,vc(t,e,n,r,i+1)),a)):(o&&pc(gc(o,yc(t,e,i+1)),a),mc(e,n,i,a),s&&pc(gc(s,yc(n,r,i+1)),a)),mc(r,null,i,a),new ec(a)}function yc(t,e,n){let r=[];if(mc(null,t,n,r),t.depth>n){pc(gc(hc(t,e,n+1),yc(t,e,n+1)),r)}return mc(e,null,n,r),new ec(r)}ac.empty=new ac(ec.empty,0,0);class bc{constructor(t,e,n){this.pos=t,this.path=e,this.parentOffset=n,this.depth=e.length/3-1}resolveDepth(t){return null==t?this.depth:t<0?this.depth+t:t}get parent(){return this.node(this.depth)}get doc(){return this.node(0)}node(t){return this.path[3*this.resolveDepth(t)]}index(t){return this.path[3*this.resolveDepth(t)+1]}indexAfter(t){return t=this.resolveDepth(t),this.index(t)+(t!=this.depth||this.textOffset?1:0)}start(t){return 0==(t=this.resolveDepth(t))?0:this.path[3*t-1]+1}end(t){return t=this.resolveDepth(t),this.start(t)+this.node(t).content.size}before(t){if(!(t=this.resolveDepth(t)))throw new RangeError("There is no position before the top-level node");return t==this.depth+1?this.pos:this.path[3*t-1]}after(t){if(!(t=this.resolveDepth(t)))throw new RangeError("There is no position after the top-level node");return t==this.depth+1?this.pos:this.path[3*t-1]+this.path[3*t].nodeSize}get textOffset(){return this.pos-this.path[this.path.length-1]}get nodeAfter(){let t=this.parent,e=this.index(this.depth);if(e==t.childCount)return null;let n=this.pos-this.path[this.path.length-1],r=t.child(e);return n?t.child(e).cut(n):r}get nodeBefore(){let t=this.index(this.depth),e=this.pos-this.path[this.path.length-1];return e?this.parent.child(t).cut(0,e):0==t?null:this.parent.child(t-1)}posAtIndex(t,e){e=this.resolveDepth(e);let n=this.path[3*e],r=0==e?0:this.path[3*e-1]+1;for(let i=0;i0;e--)if(this.start(e)<=t&&this.end(e)>=t)return e;return 0}blockRange(t=this,e){if(t.pos=0;n--)if(t.pos<=this.end(n)&&(!e||e(this.node(n))))return new kc(this,t,n);return null}sameParent(t){return this.pos-this.parentOffset==t.pos-t.parentOffset}max(t){return t.pos>this.pos?t:this}min(t){return t.pos=0&&e<=t.content.size))throw new RangeError("Position "+e+" out of range");let n=[],r=0,i=e;for(let o=t;;){let{index:t,offset:e}=o.content.findIndex(i),s=i-e;if(n.push(o,t,r+e),!s)break;if(o=o.child(t),o.isText)break;i=s-1,r+=e+1}return new bc(e,n,i)}static resolveCached(t,e){for(let r=0;rt&&this.nodesBetween(t,e,(t=>(n.isInSet(t.marks)&&(r=!0),!r))),r}get isBlock(){return this.type.isBlock}get isTextblock(){return this.type.isTextblock}get inlineContent(){return this.type.inlineContent}get isInline(){return this.type.isInline}get isText(){return this.type.isText}get isLeaf(){return this.type.isLeaf}get isAtom(){return this.type.isAtom}toString(){if(this.type.spec.toDebugString)return this.type.spec.toDebugString(this);let t=this.type.name;return this.content.size&&(t+="("+this.content.toStringInner()+")"),Cc(this.marks,t)}contentMatchAt(t){let e=this.type.contentMatch.matchFragment(this.content,0,t);if(!e)throw new Error("Called contentMatchAt on a node with invalid content");return e}canReplace(t,e,n=ec.empty,r=0,i=n.childCount){let o=this.contentMatchAt(t).matchFragment(n,r,i),s=o&&o.matchFragment(this.content,e);if(!s||!s.validEnd)return!1;for(let a=r;at.type.name))}`);this.content.forEach((t=>t.check()))}toJSON(){let t={type:this.type.name};for(let e in this.attrs){t.attrs=this.attrs;break}return this.content.size&&(t.content=this.content.toJSON()),this.marks.length&&(t.marks=this.marks.map((t=>t.toJSON()))),t}static fromJSON(t,e){if(!e)throw new RangeError("Invalid input for Node.fromJSON");let n=null;if(e.marks){if(!Array.isArray(e.marks))throw new RangeError("Invalid mark data for Node.fromJSON");n=e.marks.map(t.markFromJSON)}if("text"==e.type){if("string"!=typeof e.text)throw new RangeError("Invalid text node in JSON");return t.text(e.text,n)}let r=ec.fromJSON(t,e.content);return t.nodeType(e.type).create(e.attrs,r,n)}}_c.prototype.text=void 0;class Mc extends _c{constructor(t,e,n,r){if(super(t,e,null,r),!n)throw new RangeError("Empty text nodes are not allowed");this.text=n}toString(){return this.type.spec.toDebugString?this.type.spec.toDebugString(this):Cc(this.marks,JSON.stringify(this.text))}get textContent(){return this.text}textBetween(t,e){return this.text.slice(t,e)}get nodeSize(){return this.text.length}mark(t){return t==this.marks?this:new Mc(this.type,this.attrs,this.text,t)}withText(t){return t==this.text?this:new Mc(this.type,this.attrs,t,this.marks)}cut(t=0,e=this.text.length){return 0==t&&e==this.text.length?this:this.withText(this.text.slice(t,e))}eq(t){return this.sameMarkup(t)&&this.text==t.text}toJSON(){let t=super.toJSON();return t.text=this.text,t}}function Cc(t,e){for(let n=t.length-1;n>=0;n--)e=t[n].type.name+"("+e+")";return e}class $c{constructor(t){this.validEnd=t,this.next=[],this.wrapCache=[]}static parse(t,e){let n=new Tc(t,e);if(null==n.next)return $c.empty;let r=Dc(n);n.next&&n.err("Unexpected trailing text");let i=function(t){let e=Object.create(null);return n(Rc(t,0));function n(r){let i=[];r.forEach((e=>{t[e].forEach((({term:e,to:n})=>{if(!e)return;let r;for(let t=0;t{r||i.push([e,r=[]]),-1==r.indexOf(t)&&r.push(t)}))}))}));let o=e[r.join(",")]=new $c(r.indexOf(t.length-1)>-1);for(let t=0;tt.to=e))}function o(t,e){if("choice"==t.type)return t.exprs.reduce(((t,n)=>t.concat(o(n,e))),[]);if("seq"!=t.type){if("star"==t.type){let s=n();return r(e,s),i(o(t.expr,s),s),[r(s)]}if("plus"==t.type){let s=n();return i(o(t.expr,e),s),i(o(t.expr,s),s),[r(s)]}if("opt"==t.type)return[r(e)].concat(o(t.expr,e));if("range"==t.type){let s=e;for(let e=0;et.createAndFill())));for(let t=0;t=this.next.length)throw new RangeError(`There's no ${t}th edge in this content match`);return this.next[t]}toString(){let t=[];return function e(n){t.push(n);for(let r=0;r{let r=n+(e.validEnd?"*":" ")+" ";for(let i=0;i"+t.indexOf(e.next[i].next);return r})).join("\n")}}$c.empty=new $c(!0);class Tc{constructor(t,e){this.string=t,this.nodeTypes=e,this.inline=null,this.pos=0,this.tokens=t.split(/\s*(?=\b|\W|$)/),""==this.tokens[this.tokens.length-1]&&this.tokens.pop(),""==this.tokens[0]&&this.tokens.shift()}get next(){return this.tokens[this.pos]}eat(t){return this.next==t&&(this.pos++||!0)}err(t){throw new SyntaxError(t+" (in content expression '"+this.string+"')")}}function Dc(t){let e=[];do{e.push(Nc(t))}while(t.eat("|"));return 1==e.length?e[0]:{type:"choice",exprs:e}}function Nc(t){let e=[];do{e.push(Ac(t))}while(t.next&&")"!=t.next&&"|"!=t.next);return 1==e.length?e[0]:{type:"seq",exprs:e}}function Ac(t){let e=function(t){if(t.eat("(")){let e=Dc(t);return t.eat(")")||t.err("Missing closing paren"),e}if(!/\W/.test(t.next)){let e=function(t,e){let n=t.nodeTypes,r=n[e];if(r)return[r];let i=[];for(let o in n){let t=n[o];t.groups.indexOf(e)>-1&&i.push(t)}0==i.length&&t.err("No node type or group '"+e+"' found");return i}(t,t.next).map((e=>(null==t.inline?t.inline=e.isInline:t.inline!=e.isInline&&t.err("Mixing inline and block content"),{type:"name",value:e})));return t.pos++,1==e.length?e[0]:{type:"choice",exprs:e}}t.err("Unexpected token '"+t.next+"'")}(t);for(;;)if(t.eat("+"))e={type:"plus",expr:e};else if(t.eat("*"))e={type:"star",expr:e};else if(t.eat("?"))e={type:"opt",expr:e};else{if(!t.eat("{"))break;e=Pc(t,e)}return e}function Ec(t){/\D/.test(t.next)&&t.err("Expected number, got '"+t.next+"'");let e=Number(t.next);return t.pos++,e}function Pc(t,e){let n=Ec(t),r=n;return t.eat(",")&&(r="}"!=t.next?Ec(t):-1),t.eat("}")||t.err("Unclosed braced range"),{type:"range",min:n,max:r,expr:e}}function Ic(t,e){return e-t}function Rc(t,e){let n=[];return function e(r){let i=t[r];if(1==i.length&&!i[0].term)return e(i[0].to);n.push(r);for(let t=0;t-1}allowsMarks(t){if(null==this.markSet)return!0;for(let e=0;en[t]=new Lc(t,e,r)));let r=e.spec.topNode||"doc";if(!n[r])throw new RangeError("Schema is missing its top node type ('"+r+"')");if(!n.text)throw new RangeError("Every schema needs a 'text' type");for(let i in n.text.attrs)throw new RangeError("The text node type should not have attributes");return n}}class Bc{constructor(t){this.hasDefault=Object.prototype.hasOwnProperty.call(t,"default"),this.default=t.default}get isRequired(){return!this.hasDefault}}class Vc{constructor(t,e,n,r){this.name=t,this.rank=e,this.schema=n,this.spec=r,this.attrs=Fc(r.attrs),this.excluded=null;let i=zc(this.attrs);this.instance=i?new oc(this,i):null}create(t=null){return!t&&this.instance?this.instance:new oc(this,jc(this.attrs,t))}static compile(t,e){let n=Object.create(null),r=0;return t.forEach(((t,i)=>n[t]=new Vc(t,r++,e,i))),n}removeFromSet(t){for(var e=0;e-1}}class Wc{constructor(t){this.cached=Object.create(null),this.spec={nodes:Xl.from(t.nodes),marks:Xl.from(t.marks||{}),topNode:t.topNode},this.nodes=Lc.compile(this.spec.nodes,this),this.marks=Vc.compile(this.spec.marks,this);let e=Object.create(null);for(let n in this.nodes){if(n in this.marks)throw new RangeError(n+" can not be both a node and a mark");let t=this.nodes[n],r=t.spec.content||"",i=t.spec.marks;t.contentMatch=e[r]||(e[r]=$c.parse(r,this.nodes)),t.inlineContent=t.contentMatch.inlineContent,t.markSet="_"==i?null:i?qc(this,i.split(" ")):""!=i&&t.inlineContent?null:[]}for(let n in this.marks){let t=this.marks[n],e=t.spec.excludes;t.excluded=null==e?[t]:""==e?[]:qc(this,e.split(" "))}this.nodeFromJSON=this.nodeFromJSON.bind(this),this.markFromJSON=this.markFromJSON.bind(this),this.topNodeType=this.nodes[this.spec.topNode||"doc"],this.cached.wrappings=Object.create(null)}node(t,e=null,n,r){if("string"==typeof t)t=this.nodeType(t);else{if(!(t instanceof Lc))throw new RangeError("Invalid node type: "+t);if(t.schema!=this)throw new RangeError("Node type from different schema used ("+t.name+")")}return t.createChecked(e,n,r)}text(t,e){let n=this.nodes.text;return new Mc(n,n.defaultAttrs,t,oc.setFrom(e))}mark(t,e){return"string"==typeof t&&(t=this.marks[t]),t.create(e)}nodeFromJSON(t){return _c.fromJSON(this,t)}markFromJSON(t){return oc.fromJSON(this,t)}nodeType(t){let e=this.nodes[t];if(!e)throw new RangeError("Unknown node type: "+t);return e}}function qc(t,e){let n=[];for(let r=0;r-1)&&n.push(s=r)}if(!s)throw new SyntaxError("Unknown mark type: '"+e[r]+"'")}return n}class Jc{constructor(t,e){this.schema=t,this.rules=e,this.tags=[],this.styles=[],e.forEach((t=>{t.tag?this.tags.push(t):t.style&&this.styles.push(t)})),this.normalizeLists=!this.tags.some((e=>{if(!/^(ul|ol)\b/.test(e.tag)||!e.node)return!1;let n=t.nodes[e.node];return n.contentMatch.matchType(n)}))}parse(t,e={}){let n=new Zc(this,e,!1);return n.addAll(t,e.from,e.to),n.finish()}parseSlice(t,e={}){let n=new Zc(this,e,!0);return n.addAll(t,e.from,e.to),ac.maxOpen(n.finish())}matchTag(t,e,n){for(let r=n?this.tags.indexOf(n)+1:0;rt.length&&(61!=o.charCodeAt(t.length)||o.slice(t.length+1)!=e))){if(r.getAttrs){let t=r.getAttrs(e);if(!1===t)continue;r.attrs=t||void 0}return r}}}static schemaRules(t){let e=[];function n(t){let n=null==t.priority?50:t.priority,r=0;for(;r{n(t=Qc(t)),t.mark=r}))}for(let r in t.nodes){let e=t.nodes[r].spec.parseDOM;e&&e.forEach((t=>{n(t=Qc(t)),t.node=r}))}return e}static fromSchema(t){return t.cached.domParser||(t.cached.domParser=new Jc(t,Jc.schemaRules(t)))}}const Kc={address:!0,article:!0,aside:!0,blockquote:!0,canvas:!0,dd:!0,div:!0,dl:!0,fieldset:!0,figcaption:!0,figure:!0,footer:!0,form:!0,h1:!0,h2:!0,h3:!0,h4:!0,h5:!0,h6:!0,header:!0,hgroup:!0,hr:!0,li:!0,noscript:!0,ol:!0,output:!0,p:!0,pre:!0,section:!0,table:!0,tfoot:!0,ul:!0},Hc={head:!0,noscript:!0,object:!0,script:!0,style:!0,title:!0},Uc={ol:!0,ul:!0};function Yc(t,e,n){return null!=e?(e?1:0)|("full"===e?2:0):t&&"pre"==t.whitespace?3:-5&n}class Gc{constructor(t,e,n,r,i,o,s){this.type=t,this.attrs=e,this.marks=n,this.pendingMarks=r,this.solid=i,this.options=s,this.content=[],this.activeMarks=oc.none,this.stashMarks=[],this.match=o||(4&s?null:t.contentMatch)}findWrapping(t){if(!this.match){if(!this.type)return[];let e=this.type.contentMatch.fillBefore(ec.from(t));if(!e){let e,n=this.type.contentMatch;return(e=n.findWrapping(t.type))?(this.match=n,e):null}this.match=this.type.contentMatch.matchFragment(e)}return this.match.findWrapping(t.type)}finish(t){if(!(1&this.options)){let t,e=this.content[this.content.length-1];if(e&&e.isText&&(t=/[ \t\r\n\u000c]+$/.exec(e.text))){let n=e;e.text.length==t[0].length?this.content.pop():this.content[this.content.length-1]=n.withText(n.text.slice(0,n.text.length-t[0].length))}}let e=ec.from(this.content);return!t&&this.match&&(e=e.append(this.match.fillBefore(ec.empty,!0))),this.type?this.type.create(this.attrs,e,this.marks):e}popFromStashMark(t){for(let e=this.stashMarks.length-1;e>=0;e--)if(t.eq(this.stashMarks[e]))return this.stashMarks.splice(e,1)[0]}applyPending(t){for(let e=0,n=this.pendingMarks;ethis.insertNode(t)));else{let n=t;"string"==typeof e.contentElement?n=t.querySelector(e.contentElement):"function"==typeof e.contentElement?n=e.contentElement(t):e.contentElement&&(n=e.contentElement),this.findAround(t,n,!0),this.addAll(n)}r&&this.sync(s)&&this.open--,o&&this.removePendingMark(o,s)}addAll(t,e,n){let r=e||0;for(let i=e?t.childNodes[e]:t.firstChild,o=null==n?null:t.childNodes[n];i!=o;i=i.nextSibling,++r)this.findAtPoint(t,r),this.addDOM(i);this.findAtPoint(t,r)}findPlace(t){let e,n;for(let r=this.open;r>=0;r--){let i=this.nodes[r],o=i.findWrapping(t);if(o&&(!e||e.length>o.length)&&(e=o,n=i,!o.length))break;if(i.solid)break}if(!e)return!1;this.sync(n);for(let r=0;rthis.open){for(;e>this.open;e--)this.nodes[e-1].content.push(this.nodes[e].finish(t));this.nodes.length=this.open+1}}finish(){return this.open=0,this.closeExtra(this.isOpen),this.nodes[0].finish(this.isOpen||this.options.topOpen)}sync(t){for(let e=this.open;e>=0;e--)if(this.nodes[e]==t)return this.open=e,!0;return!1}get currentPos(){this.closeExtra();let t=0;for(let e=this.open;e>=0;e--){let n=this.nodes[e].content;for(let e=n.length-1;e>=0;e--)t+=n[e].nodeSize;e&&t++}return t}findAtPoint(t,e){if(this.find)for(let n=0;n-1)return t.split(/\s*\|\s*/).some(this.matchesContext,this);let e=t.split("/"),n=this.options.context,r=!(this.isOpen||n&&n.parent.type!=this.nodes[0].type),i=-(n?n.depth+1:0)+(r?0:1),o=(t,s)=>{for(;t>=0;t--){let a=e[t];if(""==a){if(t==e.length-1||0==t)continue;for(;s>=i;s--)if(o(t-1,s))return!0;return!1}{let t=s>0||0==s&&r?this.nodes[s].type:n&&s>=i?n.node(s-i).type:null;if(!t||t.name!=a&&-1==t.groups.indexOf(a))return!1;s--}}return!0};return o(e.length-1,this.open)}textblockFromContext(){let t=this.options.context;if(t)for(let e=t.depth;e>=0;e--){let n=t.node(e).contentMatchAt(t.indexAfter(e)).defaultType;if(n&&n.isTextblock&&n.defaultAttrs)return n}for(let e in this.parser.schema.nodes){let t=this.parser.schema.nodes[e];if(t.isTextblock&&t.defaultAttrs)return t}}addPendingMark(t){let e=function(t,e){for(let n=0;n=0;n--){let r=this.nodes[n];if(r.pendingMarks.lastIndexOf(t)>-1)r.pendingMarks=t.removeFromSet(r.pendingMarks);else{r.activeMarks=t.removeFromSet(r.activeMarks);let e=r.popFromStashMark(t);e&&r.type&&r.type.allowsMarkType(e.type)&&(r.activeMarks=e.addToSet(r.activeMarks))}if(r==e)break}}}function Xc(t,e){return(t.matches||t.msMatchesSelector||t.webkitMatchesSelector||t.mozMatchesSelector).call(t,e)}function Qc(t){let e={};for(let n in t)e[n]=t[n];return e}function tu(t,e){let n=e.schema.nodes;for(let r in n){let i=n[r];if(!i.allowsMarkType(t))continue;let o=[],s=t=>{o.push(t);for(let n=0;n{if(i.length||t.marks.length){let n=0,o=0;for(;n=0;r--){let i=this.serializeMark(t.marks[r],t.isInline,e);i&&((i.contentDOM||i.dom).appendChild(n),n=i.dom)}return n}serializeMark(t,e,n={}){let r=this.marks[t.type.name];return r&&eu.renderSpec(ru(n),r(t,e))}static renderSpec(t,e,n=null){if("string"==typeof e)return{dom:t.createTextNode(e)};if(null!=e.nodeType)return{dom:e};if(e.dom&&null!=e.dom.nodeType)return e;let r,i=e[0],o=i.indexOf(" ");o>0&&(n=i.slice(0,o),i=i.slice(o+1));let s=n?t.createElementNS(n,i):t.createElement(i),a=e[1],l=1;if(a&&"object"==typeof a&&null==a.nodeType&&!Array.isArray(a)){l=2;for(let t in a)if(null!=a[t]){let e=t.indexOf(" ");e>0?s.setAttributeNS(t.slice(0,e),t.slice(e+1),a[t]):s.setAttribute(t,a[t])}}for(let c=l;cl)throw new RangeError("Content hole must be the only child of its parent node");return{dom:s,contentDOM:s}}{let{dom:e,contentDOM:o}=eu.renderSpec(t,i,n);if(s.appendChild(e),o){if(r)throw new RangeError("Multiple content holes");r=o}}}return{dom:s,contentDOM:r}}static fromSchema(t){return t.cached.domSerializer||(t.cached.domSerializer=new eu(this.nodesFromSchema(t),this.marksFromSchema(t)))}static nodesFromSchema(t){let e=nu(t.nodes);return e.text||(e.text=t=>t.text),e}static marksFromSchema(t){return nu(t.marks)}}function nu(t){let e={};for(let n in t){let r=t[n].spec.toDOM;r&&(e[n]=r)}return e}function ru(t){return t.document||window.document}const iu=Math.pow(2,16);function ou(t){return 65535&t}class su{constructor(t,e=!1,n=null){this.pos=t,this.deleted=e,this.recover=n}}class au{constructor(t,e=!1){if(this.ranges=t,this.inverted=e,!t.length&&au.empty)return au.empty}recover(t){let e=0,n=ou(t);if(!this.inverted)for(let r=0;rt)break;let l=this.ranges[s+i],c=this.ranges[s+o],u=a+l;if(t<=u){let i=a+r+((l?t==a?-1:t==u?1:e:e)<0?0:c);if(n)return i;let o=t==(e<0?a:u)?null:s/3+(t-a)*iu;return new su(i,e<0?t!=a:t!=u,o)}r+=c-l}return n?t+r:new su(t+r)}touches(t,e){let n=0,r=ou(e),i=this.inverted?2:1,o=this.inverted?1:2;for(let s=0;st)break;let a=this.ranges[s+i];if(t<=e+a&&s==3*r)return!0;n+=this.ranges[s+o]-a}return!1}forEach(t){let e=this.inverted?2:1,n=this.inverted?1:2;for(let r=0,i=0;r=0;e--){let r=t.getMirror(e);this.appendMap(t.maps[e].invert(),null!=r&&r>e?n-r-1:void 0)}}invert(){let t=new lu;return t.appendMappingInverted(this),t}map(t,e=1){if(this.mirror)return this._map(t,e,!0);for(let n=this.from;ni&&et.isAtom&&e.type.allowsMarkType(this.mark.type)?t.mark(this.mark.addToSet(t.marks)):t),r),e.openStart,e.openEnd);return du.fromReplace(t,this.from,this.to,i)}invert(){return new pu(this.from,this.to,this.mark)}map(t){let e=t.mapResult(this.from,1),n=t.mapResult(this.to,-1);return e.deleted&&n.deleted||e.pos>=n.pos?null:new hu(e.pos,n.pos,this.mark)}merge(t){return t instanceof hu&&t.mark.eq(this.mark)&&this.from<=t.to&&this.to>=t.from?new hu(Math.min(this.from,t.from),Math.max(this.to,t.to),this.mark):null}toJSON(){return{stepType:"addMark",mark:this.mark.toJSON(),from:this.from,to:this.to}}static fromJSON(t,e){if("number"!=typeof e.from||"number"!=typeof e.to)throw new RangeError("Invalid input for AddMarkStep.fromJSON");return new hu(e.from,e.to,t.markFromJSON(e.mark))}}uu.jsonID("addMark",hu);class pu extends uu{constructor(t,e,n){super(),this.from=t,this.to=e,this.mark=n}apply(t){let e=t.slice(this.from,this.to),n=new ac(fu(e.content,(t=>t.mark(this.mark.removeFromSet(t.marks))),t),e.openStart,e.openEnd);return du.fromReplace(t,this.from,this.to,n)}invert(){return new hu(this.from,this.to,this.mark)}map(t){let e=t.mapResult(this.from,1),n=t.mapResult(this.to,-1);return e.deleted&&n.deleted||e.pos>=n.pos?null:new pu(e.pos,n.pos,this.mark)}merge(t){return t instanceof pu&&t.mark.eq(this.mark)&&this.from<=t.to&&this.to>=t.from?new pu(Math.min(this.from,t.from),Math.max(this.to,t.to),this.mark):null}toJSON(){return{stepType:"removeMark",mark:this.mark.toJSON(),from:this.from,to:this.to}}static fromJSON(t,e){if("number"!=typeof e.from||"number"!=typeof e.to)throw new RangeError("Invalid input for RemoveMarkStep.fromJSON");return new pu(e.from,e.to,t.markFromJSON(e.mark))}}uu.jsonID("removeMark",pu);class mu extends uu{constructor(t,e,n,r=!1){super(),this.from=t,this.to=e,this.slice=n,this.structure=r}apply(t){return this.structure&&vu(t,this.from,this.to)?du.fail("Structure replace would overwrite content"):du.fromReplace(t,this.from,this.to,this.slice)}getMap(){return new au([this.from,this.to-this.from,this.slice.size])}invert(t){return new mu(this.from,this.from+this.slice.size,t.slice(this.from,this.to))}map(t){let e=t.mapResult(this.from,1),n=t.mapResult(this.to,-1);return e.deleted&&n.deleted?null:new mu(e.pos,Math.max(e.pos,n.pos),this.slice)}merge(t){if(!(t instanceof mu)||t.structure||this.structure)return null;if(this.from+this.slice.size!=t.from||this.slice.openEnd||t.slice.openStart){if(t.to!=this.from||this.slice.openStart||t.slice.openEnd)return null;{let e=this.slice.size+t.slice.size==0?ac.empty:new ac(t.slice.content.append(this.slice.content),t.slice.openStart,this.slice.openEnd);return new mu(t.from,this.to,e,this.structure)}}{let e=this.slice.size+t.slice.size==0?ac.empty:new ac(this.slice.content.append(t.slice.content),this.slice.openStart,t.slice.openEnd);return new mu(this.from,this.to+(t.to-t.from),e,this.structure)}}toJSON(){let t={stepType:"replace",from:this.from,to:this.to};return this.slice.size&&(t.slice=this.slice.toJSON()),this.structure&&(t.structure=!0),t}static fromJSON(t,e){if("number"!=typeof e.from||"number"!=typeof e.to)throw new RangeError("Invalid input for ReplaceStep.fromJSON");return new mu(e.from,e.to,ac.fromJSON(t,e.slice),!!e.structure)}}uu.jsonID("replace",mu);class gu extends uu{constructor(t,e,n,r,i,o,s=!1){super(),this.from=t,this.to=e,this.gapFrom=n,this.gapTo=r,this.slice=i,this.insert=o,this.structure=s}apply(t){if(this.structure&&(vu(t,this.from,this.gapFrom)||vu(t,this.gapTo,this.to)))return du.fail("Structure gap-replace would overwrite content");let e=t.slice(this.gapFrom,this.gapTo);if(e.openStart||e.openEnd)return du.fail("Gap is not a flat range");let n=this.slice.insertAt(this.insert,e.content);return n?du.fromReplace(t,this.from,this.to,n):du.fail("Content does not fit in gap")}getMap(){return new au([this.from,this.gapFrom-this.from,this.insert,this.gapTo,this.to-this.gapTo,this.slice.size-this.insert])}invert(t){let e=this.gapTo-this.gapFrom;return new gu(this.from,this.from+this.slice.size+e,this.from+this.insert,this.from+this.insert+e,t.slice(this.from,this.to).removeBetween(this.gapFrom-this.from,this.gapTo-this.from),this.gapFrom-this.from,this.structure)}map(t){let e=t.mapResult(this.from,1),n=t.mapResult(this.to,-1),r=t.map(this.gapFrom,-1),i=t.map(this.gapTo,1);return e.deleted&&n.deleted||rn.pos?null:new gu(e.pos,n.pos,r,i,this.slice,this.insert,this.structure)}toJSON(){let t={stepType:"replaceAround",from:this.from,to:this.to,gapFrom:this.gapFrom,gapTo:this.gapTo,insert:this.insert};return this.slice.size&&(t.slice=this.slice.toJSON()),this.structure&&(t.structure=!0),t}static fromJSON(t,e){if("number"!=typeof e.from||"number"!=typeof e.to||"number"!=typeof e.gapFrom||"number"!=typeof e.gapTo||"number"!=typeof e.insert)throw new RangeError("Invalid input for ReplaceAroundStep.fromJSON");return new gu(e.from,e.to,e.gapFrom,e.gapTo,ac.fromJSON(t,e.slice),e.insert,!!e.structure)}}function vu(t,e,n){let r=t.resolve(e),i=n-e,o=r.depth;for(;i>0&&o>0&&r.indexAfter(o)==r.node(o).childCount;)o--,i--;if(i>0){let t=r.node(o).maybeChild(r.indexAfter(o));for(;i>0;){if(!t||t.isLeaf)return!0;t=t.firstChild,i--}}return!1}function yu(t,e,n){return(0==e||t.canReplace(e,t.childCount))&&(n==t.childCount||t.canReplace(0,n))}function bu(t){let e=t.parent.content.cutByIndex(t.startIndex,t.endIndex);for(let n=t.depth;;--n){let r=t.$from.node(n),i=t.$from.index(n),o=t.$to.indexAfter(n);if(no;c--,u--){let t=i.node(c),e=i.index(c);if(t.type.spec.isolating)return!1;let n=t.content.cutByIndex(e,t.childCount),o=r&&r[u]||t;if(o!=t&&(n=n.replaceChild(0,o.type.create(o.attrs))),!t.canReplace(e+1,t.childCount)||!o.type.validContent(n))return!1}let a=i.indexAfter(o),l=r&&r[0];return i.node(o).canReplaceWith(a,a,l?l.type:i.node(o+1).type)}function ku(t,e){let n=t.resolve(e),r=n.index();return i=n.nodeBefore,o=n.nodeAfter,!(!i||!o||i.isLeaf||!i.canAppend(o))&&n.parent.canReplace(r,r+1);var i,o}function Ou(t,e,n=e,r=ac.empty){if(e==n&&!r.size)return null;let i=t.resolve(e),o=t.resolve(n);return _u(i,o,r)?new mu(e,n,r):new Mu(i,o,r).fit()}function _u(t,e,n){return!n.openStart&&!n.openEnd&&t.start()==e.start()&&t.parent.canReplace(t.index(),e.index(),n.content)}uu.jsonID("replaceAround",gu);class Mu{constructor(t,e,n){this.$from=t,this.$to=e,this.unplaced=n,this.frontier=[],this.placed=ec.empty;for(let r=0;r<=t.depth;r++){let e=t.node(r);this.frontier.push({type:e.type,match:e.contentMatchAt(t.indexAfter(r))})}for(let r=t.depth;r>0;r--)this.placed=ec.from(t.node(r).copy(this.placed))}get depth(){return this.frontier.length-1}fit(){for(;this.unplaced.size;){let t=this.findFittable();t?this.placeNodes(t):this.openMore()||this.dropNode()}let t=this.mustMoveInline(),e=this.placed.size-this.depth-this.$from.depth,n=this.$from,r=this.close(t<0?this.$to:n.doc.resolve(t));if(!r)return null;let i=this.placed,o=n.depth,s=r.depth;for(;o&&s&&1==i.childCount;)i=i.firstChild.content,o--,s--;let a=new ac(i,o,s);return t>-1?new gu(n.pos,t,this.$to.pos,this.$to.end(),a,e):a.size||n.pos!=this.$to.pos?new mu(n.pos,r.pos,a):null}findFittable(){for(let t=1;t<=2;t++)for(let e=this.unplaced.openStart;e>=0;e--){let n,r=null;e?(r=Tu(this.unplaced.content,e-1).firstChild,n=r.content):n=this.unplaced.content;let i=n.firstChild;for(let o=this.depth;o>=0;o--){let n,{type:s,match:a}=this.frontier[o],l=null;if(1==t&&(i?a.matchType(i.type)||(l=a.fillBefore(ec.from(i),!1)):r&&s.compatibleContent(r.type)))return{sliceDepth:e,frontierDepth:o,parent:r,inject:l};if(2==t&&i&&(n=a.findWrapping(i.type)))return{sliceDepth:e,frontierDepth:o,parent:r,wrap:n};if(r&&a.matchType(r.type))break}}}openMore(){let{content:t,openStart:e,openEnd:n}=this.unplaced,r=Tu(t,e);return!(!r.childCount||r.firstChild.isLeaf)&&(this.unplaced=new ac(t,e+1,Math.max(n,r.size+e>=t.size-n?e+1:0)),!0)}dropNode(){let{content:t,openStart:e,openEnd:n}=this.unplaced,r=Tu(t,e);if(r.childCount<=1&&e>0){let i=t.size-e<=e+r.size;this.unplaced=new ac(Cu(t,e-1,1),e-1,i?e-1:n)}else this.unplaced=new ac(Cu(t,e,1),e,n)}placeNodes({sliceDepth:t,frontierDepth:e,parent:n,inject:r,wrap:i}){for(;this.depth>e;)this.closeFrontierNode();if(i)for(let p=0;p1||0==a||t.content.size)&&(u=e,c.push(Du(t.mark(d.allowedMarks(t.marks)),1==l?a:0,l==s.childCount?f:-1)))}let h=l==s.childCount;h||(f=-1),this.placed=$u(this.placed,e,ec.from(c)),this.frontier[e].match=u,h&&f<0&&n&&n.type==this.frontier[this.depth].type&&this.frontier.length>1&&this.closeFrontierNode();for(let p=0,m=s;p1&&r==this.$to.end(--n);)++r;return r}findCloseLevel(t){t:for(let e=Math.min(this.depth,t.depth);e>=0;e--){let{match:n,type:r}=this.frontier[e],i=e=0;n--){let{match:e,type:r}=this.frontier[n],i=Nu(t,n,r,e,!0);if(!i||i.childCount)continue t}return{depth:e,fit:o,move:i?t.doc.resolve(t.after(e+1)):t}}}}close(t){let e=this.findCloseLevel(t);if(!e)return null;for(;this.depth>e.depth;)this.closeFrontierNode();e.fit.childCount&&(this.placed=$u(this.placed,e.depth,e.fit)),t=e.move;for(let n=e.depth+1;n<=t.depth;n++){let e=t.node(n),r=e.type.contentMatch.fillBefore(e.content,!0,t.index(n));this.openFrontierNode(e.type,e.attrs,r)}return t}openFrontierNode(t,e=null,n){let r=this.frontier[this.depth];r.match=r.match.matchType(t),this.placed=$u(this.placed,this.depth,ec.from(t.create(e,n))),this.frontier.push({type:t,match:t.contentMatch})}closeFrontierNode(){let t=this.frontier.pop().match.fillBefore(ec.empty,!0);t.childCount&&(this.placed=$u(this.placed,this.frontier.length,t))}}function Cu(t,e,n){return 0==e?t.cutByIndex(n,t.childCount):t.replaceChild(0,t.firstChild.copy(Cu(t.firstChild.content,e-1,n)))}function $u(t,e,n){return 0==e?t.append(n):t.replaceChild(t.childCount-1,t.lastChild.copy($u(t.lastChild.content,e-1,n)))}function Tu(t,e){for(let n=0;n1&&(r=r.replaceChild(0,Du(r.firstChild,e-1,1==r.childCount?n-1:0))),e>0&&(r=t.type.contentMatch.fillBefore(r).append(r),n<=0&&(r=r.append(t.type.contentMatch.matchFragment(r).fillBefore(ec.empty,!0)))),t.copy(r)}function Nu(t,e,n,r,i){let o=t.node(e),s=i?t.indexAfter(e):t.index(e);if(s==o.childCount&&!n.compatibleContent(o.type))return null;let a=r.fillBefore(o.content,!0,s);return a&&!function(t,e,n){for(let r=n;rr){let e=i.contentMatchAt(0),n=e.fillBefore(t).append(t);t=n.append(e.matchFragment(n).fillBefore(ec.empty,!0))}return t}function Pu(t,e){let n=[];for(let r=Math.min(t.depth,e.depth);r>=0;r--){let i=t.start(r);if(ie.pos+(e.depth-r)||t.node(r).type.spec.isolating||e.node(r).type.spec.isolating)break;(i==e.start(r)||r==t.depth&&r==e.depth&&t.parent.inlineContent&&e.parent.inlineContent&&r&&e.start(r-1)==i-1)&&n.push(r)}return n}let Iu=class extends Error{};Iu=function t(e){let n=Error.call(this,e);return n.__proto__=t.prototype,n},(Iu.prototype=Object.create(Error.prototype)).constructor=Iu,Iu.prototype.name="TransformError";const Ru=Object.create(null);class zu{constructor(t,e,n){this.$anchor=t,this.$head=e,this.ranges=n||[new ju(t.min(e),t.max(e))]}get anchor(){return this.$anchor.pos}get head(){return this.$head.pos}get from(){return this.$from.pos}get to(){return this.$to.pos}get $from(){return this.ranges[0].$from}get $to(){return this.ranges[0].$to}get empty(){let t=this.ranges;for(let e=0;e=0;i--){let r=e<0?Hu(t.node(0),t.node(i),t.before(i+1),t.index(i),e,n):Hu(t.node(0),t.node(i),t.after(i+1),t.index(i)+1,e,n);if(r)return r}return null}static near(t,e=1){return this.findFrom(t,e)||this.findFrom(t,-e)||new Ju(t.node(0))}static atStart(t){return Hu(t,t,0,0,1)||new Ju(t)}static atEnd(t){return Hu(t,t,t.content.size,t.childCount,-1)||new Ju(t)}static fromJSON(t,e){if(!e||!e.type)throw new RangeError("Invalid input for Selection.fromJSON");let n=Ru[e.type];if(!n)throw new RangeError(`No selection type ${e.type} defined`);return n.fromJSON(t,e)}static jsonID(t,e){if(t in Ru)throw new RangeError("Duplicate use of selection JSON ID "+t);return Ru[t]=e,e.prototype.jsonID=t,e}getBookmark(){return Bu.between(this.$anchor,this.$head).getBookmark()}}zu.prototype.visible=!0;class ju{constructor(t,e){this.$from=t,this.$to=e}}let Fu=!1;function Lu(t){Fu||t.parent.inlineContent||(Fu=!0,console.warn("TextSelection endpoint not pointing into a node with inline content ("+t.parent.type.name+")"))}class Bu extends zu{constructor(t,e=t){Lu(t),Lu(e),super(t,e)}get $cursor(){return this.$anchor.pos==this.$head.pos?this.$head:null}map(t,e){let n=t.resolve(e.map(this.head));if(!n.parent.inlineContent)return zu.near(n);let r=t.resolve(e.map(this.anchor));return new Bu(r.parent.inlineContent?r:n,n)}replace(t,e=ac.empty){if(super.replace(t,e),e==ac.empty){let e=this.$from.marksAcross(this.$to);e&&t.ensureMarks(e)}}eq(t){return t instanceof Bu&&t.anchor==this.anchor&&t.head==this.head}getBookmark(){return new Vu(this.anchor,this.head)}toJSON(){return{type:"text",anchor:this.anchor,head:this.head}}static fromJSON(t,e){if("number"!=typeof e.anchor||"number"!=typeof e.head)throw new RangeError("Invalid input for TextSelection.fromJSON");return new Bu(t.resolve(e.anchor),t.resolve(e.head))}static create(t,e,n=e){let r=t.resolve(e);return new this(r,n==e?r:t.resolve(n))}static between(t,e,n){let r=t.pos-e.pos;if(n&&!r||(n=r>=0?1:-1),!e.parent.inlineContent){let t=zu.findFrom(e,n,!0)||zu.findFrom(e,-n,!0);if(!t)return zu.near(e,n);e=t.$head}return t.parent.inlineContent||(0==r||(t=(zu.findFrom(t,-n,!0)||zu.findFrom(t,n,!0)).$anchor).posnew Ju(t)};function Hu(t,e,n,r,i,o=!1){if(e.inlineContent)return Bu.create(t,n);for(let s=r-(i>0?0:1);i>0?s=0;s+=i){let r=e.child(s);if(r.isAtom){if(!o&&Wu.isSelectable(r))return Wu.create(t,n-(i<0?r.nodeSize:0))}else{let e=Hu(t,r,n+i,i<0?r.childCount:0,i,o);if(e)return e}n+=r.nodeSize*i}return null}function Uu(t,e,n){let r=t.steps.length-1;if(r{null==i&&(i=r)})),t.setSelection(zu.near(t.doc.resolve(i),n)))}class Yu extends class{constructor(t){this.doc=t,this.steps=[],this.docs=[],this.mapping=new lu}get before(){return this.docs.length?this.docs[0]:this.doc}step(t){let e=this.maybeStep(t);if(e.failed)throw new Iu(e.failed);return this}maybeStep(t){let e=t.apply(this.doc);return e.failed||this.addStep(t,e.doc),e}get docChanged(){return this.steps.length>0}addStep(t,e){this.docs.push(this.doc),this.steps.push(t),this.mapping.appendMap(t.getMap()),this.doc=e}replace(t,e=t,n=ac.empty){let r=Ou(this.doc,t,e,n);return r&&this.step(r),this}replaceWith(t,e,n){return this.replace(t,e,new ac(ec.from(n),0,0))}delete(t,e){return this.replace(t,e,ac.empty)}insert(t,e){return this.replaceWith(t,t,e)}replaceRange(t,e,n){return function(t,e,n,r){if(!r.size)return t.deleteRange(e,n);let i=t.doc.resolve(e),o=t.doc.resolve(n);if(_u(i,o,r))return t.step(new mu(e,n,r));let s=Pu(i,t.doc.resolve(n));0==s[s.length-1]&&s.pop();let a=-(i.depth+1);s.unshift(a);for(let f=i.depth,h=i.pos-1;f>0;f--,h--){let t=i.node(f).type.spec;if(t.defining||t.definingAsContext||t.isolating)break;s.indexOf(f)>-1?a=f:i.before(f)==h&&s.splice(1,0,-f)}let l=s.indexOf(a),c=[],u=r.openStart;for(let f=r.content,h=0;;h++){let t=f.firstChild;if(c.push(t),h==r.openStart)break;f=t.content}for(let f=u-1;f>=0;f--){let t=c[f].type,e=Au(t);if(e&&i.node(l).type!=t)u=f;else if(e||!t.isTextblock)break}for(let f=r.openStart;f>=0;f--){let e=(f+u+1)%(r.openStart+1),a=c[e];if(a)for(let c=0;c=0&&(t.replace(e,n,r),!(t.steps.length>d));f--){let t=s[f];t<0||(e=i.before(t),n=o.after(t))}}(this,t,e,n),this}replaceRangeWith(t,e,n){return function(t,e,n,r){if(!r.isInline&&e==n&&t.doc.resolve(e).parent.content.size){let i=function(t,e,n){let r=t.resolve(e);if(r.parent.canReplaceWith(r.index(),r.index(),n))return e;if(0==r.parentOffset)for(let i=r.depth-1;i>=0;i--){let t=r.index(i);if(r.node(i).canReplaceWith(t,t,n))return r.before(i+1);if(t>0)return null}if(r.parentOffset==r.parent.content.size)for(let i=r.depth-1;i>=0;i--){let t=r.indexAfter(i);if(r.node(i).canReplaceWith(t,t,n))return r.after(i+1);if(t0&&(n||r.node(e-1).canReplace(r.index(e-1),i.indexAfter(e-1))))return t.delete(r.before(e),i.after(e))}for(let s=1;s<=r.depth&&s<=i.depth;s++)if(e-r.start(s)==r.depth-s&&n>r.end(s)&&i.end(s)-n!=i.depth-s)return t.delete(r.before(s),n);t.delete(e,n)}(this,t,e),this}lift(t,e){return function(t,e,n){let{$from:r,$to:i,depth:o}=e,s=r.before(o+1),a=i.after(o+1),l=s,c=a,u=ec.empty,d=0;for(let p=o,m=!1;p>n;p--)m||r.index(p)>0?(m=!0,u=ec.from(r.node(p).copy(u)),d++):l--;let f=ec.empty,h=0;for(let p=o,m=!1;p>n;p--)m||i.after(p+1)=0;s--){if(r.size){let t=n[s].type.contentMatch.matchFragment(r);if(!t||!t.validEnd)throw new RangeError("Wrapper type given to Transform.wrap does not form valid content of its parent wrapper")}r=ec.from(n[s].type.create(n[s].attrs,r))}let i=e.start,o=e.end;t.step(new gu(i,o,i,o,new ac(r,0,0),n.length,!0))}(this,t,e),this}setBlockType(t,e=t,n,r=null){return function(t,e,n,r,i){if(!r.isTextblock)throw new RangeError("Type given to setBlockType should be a textblock");let o=t.steps.length;t.doc.nodesBetween(e,n,((e,n)=>{if(e.isTextblock&&!e.hasMarkup(r,i)&&function(t,e,n){let r=t.resolve(e),i=r.index();return r.parent.canReplaceWith(i,i+1,n)}(t.doc,t.mapping.slice(o).map(n),r)){t.clearIncompatible(t.mapping.slice(o).map(n,1),r);let s=t.mapping.slice(o),a=s.map(n,1),l=s.map(n+e.nodeSize,1);return t.step(new gu(a,l,a+1,l-1,new ac(ec.from(r.create(i,null,e.marks)),0,0),1,!0)),!1}}))}(this,t,e,n,r),this}setNodeMarkup(t,e,n=null,r=[]){return function(t,e,n,r,i){let o=t.doc.nodeAt(e);if(!o)throw new RangeError("No node at given position");n||(n=o.type);let s=n.create(r,null,i||o.marks);if(o.isLeaf)return t.replaceWith(e,e+o.nodeSize,s);if(!n.validContent(o.content))throw new RangeError("Invalid content for node type "+n.name);t.step(new gu(e,e+o.nodeSize,e+1,e+o.nodeSize-1,new ac(ec.from(s),0,0),1,!0))}(this,t,e,n,r),this}split(t,e=1,n){return function(t,e,n=1,r){let i=t.doc.resolve(e),o=ec.empty,s=ec.empty;for(let a=i.depth,l=i.depth-n,c=n-1;a>l;a--,c--){o=ec.from(i.node(a).copy(o));let t=r&&r[c];s=ec.from(t?t.type.create(t.attrs,s):i.node(a).copy(s))}t.step(new mu(e,e,new ac(o.append(s),n,n),!0))}(this,t,e,n),this}addMark(t,e,n){return function(t,e,n,r){let i,o,s=[],a=[];t.doc.nodesBetween(e,n,((t,l,c)=>{if(!t.isInline)return;let u=t.marks;if(!r.isInSet(u)&&c.type.allowsMarkType(r.type)){let c=Math.max(l,e),d=Math.min(l+t.nodeSize,n),f=r.addToSet(u);for(let t=0;tt.step(e))),a.forEach((e=>t.step(e)))}(this,t,e,n),this}removeMark(t,e,n){return function(t,e,n,r){let i=[],o=0;t.doc.nodesBetween(e,n,((t,s)=>{if(!t.isInline)return;o++;let a=null;if(r instanceof Vc){let e,n=t.marks;for(;e=r.isInSet(n);)(a||(a=[])).push(e),n=e.removeFromSet(n)}else r?r.isInSet(t.marks)&&(a=[r]):a=t.marks;if(a&&a.length){let r=Math.min(s+t.nodeSize,n);for(let t=0;tt.step(new pu(e.from,e.to,e.style))))}(this,t,e,n),this}clearIncompatible(t,e,n){return function(t,e,n,r=n.contentMatch){let i=t.doc.nodeAt(e),o=[],s=e+1;for(let a=0;a=0;a--)t.step(o[a])}(this,t,e,n),this}}{constructor(t){super(t.doc),this.curSelectionFor=0,this.updated=0,this.meta=Object.create(null),this.time=Date.now(),this.curSelection=t.selection,this.storedMarks=t.storedMarks}get selection(){return this.curSelectionFor0}setStoredMarks(t){return this.storedMarks=t,this.updated|=2,this}ensureMarks(t){return oc.sameSet(this.storedMarks||this.selection.$from.marks(),t)||this.setStoredMarks(t),this}addStoredMark(t){return this.ensureMarks(t.addToSet(this.storedMarks||this.selection.$head.marks()))}removeStoredMark(t){return this.ensureMarks(t.removeFromSet(this.storedMarks||this.selection.$head.marks()))}get storedMarksSet(){return(2&this.updated)>0}addStep(t,e){super.addStep(t,e),this.updated=-3&this.updated,this.storedMarks=null}setTime(t){return this.time=t,this}replaceSelection(t){return this.selection.replace(this,t),this}replaceSelectionWith(t,e=!0){let n=this.selection;return e&&(t=t.mark(this.storedMarks||(n.empty?n.$from.marks():n.$from.marksAcross(n.$to)||oc.none))),n.replaceWith(this,t),this}deleteSelection(){return this.selection.replace(this),this}insertText(t,e,n){let r=this.doc.type.schema;if(null==e)return t?this.replaceSelectionWith(r.text(t),!0):this.deleteSelection();{if(null==n&&(n=e),n=null==n?e:n,!t)return this.deleteRange(e,n);let i=this.storedMarks;if(!i){let t=this.doc.resolve(e);i=n==e?t.marks():t.marksAcross(this.doc.resolve(n))}return this.replaceRangeWith(e,n,r.text(t,i)),this.selection.empty||this.setSelection(zu.near(this.selection.$to)),this}}setMeta(t,e){return this.meta["string"==typeof t?t:t.key]=e,this}getMeta(t){return this.meta["string"==typeof t?t:t.key]}get isGeneric(){for(let t in this.meta)return!1;return!0}scrollIntoView(){return this.updated|=4,this}get scrolledIntoView(){return(4&this.updated)>0}}function Gu(t,e){return e&&t?t.bind(e):t}class Zu{constructor(t,e,n){this.name=t,this.init=Gu(e.init,n),this.apply=Gu(e.apply,n)}}const Xu=[new Zu("doc",{init:t=>t.doc||t.schema.topNodeType.createAndFill(),apply:t=>t.doc}),new Zu("selection",{init:(t,e)=>t.selection||zu.atStart(e.doc),apply:t=>t.selection}),new Zu("storedMarks",{init:t=>t.storedMarks||null,apply:(t,e,n,r)=>r.selection.$cursor?t.storedMarks:null}),new Zu("scrollToSelection",{init:()=>0,apply:(t,e)=>t.scrolledIntoView?e+1:e})];class Qu{constructor(t,e){this.schema=t,this.plugins=[],this.pluginsByKey=Object.create(null),this.fields=Xu.slice(),e&&e.forEach((t=>{if(this.pluginsByKey[t.key])throw new RangeError("Adding different instances of a keyed plugin ("+t.key+")");this.plugins.push(t),this.pluginsByKey[t.key]=t,t.spec.state&&this.fields.push(new Zu(t.key,t.spec.state,t))}))}}class td{constructor(t){this.config=t}get schema(){return this.config.schema}get plugins(){return this.config.plugins}apply(t){return this.applyTransaction(t).state}filterTransaction(t,e=-1){for(let n=0;nt.toJSON()))),t&&"object"==typeof t)for(let n in t){if("doc"==n||"selection"==n)throw new RangeError("The JSON fields `doc` and `selection` are reserved");let r=t[n],i=r.spec.state;i&&i.toJSON&&(e[n]=i.toJSON.call(r,this[r.key]))}return e}static fromJSON(t,e,n){if(!e)throw new RangeError("Invalid input for EditorState.fromJSON");if(!t.schema)throw new RangeError("Required config field 'schema' missing");let r=new Qu(t.schema,t.plugins),i=new td(r);return r.fields.forEach((r=>{if("doc"==r.name)i.doc=_c.fromJSON(t.schema,e.doc);else if("selection"==r.name)i.selection=zu.fromJSON(i.doc,e.selection);else if("storedMarks"==r.name)e.storedMarks&&(i.storedMarks=e.storedMarks.map(t.schema.markFromJSON));else{if(n)for(let o in n){let s=n[o],a=s.spec.state;if(s.key==r.name&&a&&a.fromJSON&&Object.prototype.hasOwnProperty.call(e,o))return void(i[r.name]=a.fromJSON.call(s,t,e[o],i))}i[r.name]=r.init(t,i)}})),i}}function ed(t,e,n){for(let r in t){let i=t[r];i instanceof Function?i=i.bind(e):"handleDOMEvents"==r&&(i=ed(i,e,{})),n[r]=i}return n}class nd{constructor(t){this.spec=t,this.props={},t.props&&ed(t.props,this,this.props),this.key=t.key?t.key.key:id("plugin")}getState(t){return t[this.key]}}const rd=Object.create(null);function id(t){return t in rd?t+"$"+ ++rd[t]:(rd[t]=0,t+"$")}class od{constructor(t="key"){this.key=id(t)}get(t){return t.config.pluginsByKey[this.key]}getState(t){return t[this.key]}}const sd="undefined"!=typeof navigator?navigator:null,ad="undefined"!=typeof document?document:null,ld=sd&&sd.userAgent||"",cd=/Edge\/(\d+)/.exec(ld),ud=/MSIE \d/.exec(ld),dd=/Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(ld),fd=!!(ud||dd||cd),hd=ud?document.documentMode:dd?+dd[1]:cd?+cd[1]:0,pd=!fd&&/gecko\/(\d+)/i.test(ld);pd&&(/Firefox\/(\d+)/.exec(ld)||[0,0])[1];const md=!fd&&/Chrome\/(\d+)/.exec(ld),gd=!!md,vd=md?+md[1]:0,yd=!fd&&!!sd&&/Apple Computer/.test(sd.vendor),bd=yd&&(/Mobile\/\w+/.test(ld)||!!sd&&sd.maxTouchPoints>2),wd=bd||!!sd&&/Mac/.test(sd.platform),xd=/Android \d/.test(ld),Sd=!!ad&&"webkitFontSmoothing"in ad.documentElement.style,kd=Sd?+(/\bAppleWebKit\/(\d+)/.exec(navigator.userAgent)||[0,0])[1]:0,Od=function(t){for(var e=0;;e++)if(!(t=t.previousSibling))return e},_d=function(t){let e=t.assignedSlot||t.parentNode;return e&&11==e.nodeType?e.host:e};let Md=null;const Cd=function(t,e,n){let r=Md||(Md=document.createRange());return r.setEnd(t,null==n?t.nodeValue.length:n),r.setStart(t,e||0),r},$d=function(t,e,n,r){return n&&(Dd(t,e,n,r,-1)||Dd(t,e,n,r,1))},Td=/^(img|br|input|textarea|hr)$/i;function Dd(t,e,n,r,i){for(;;){if(t==n&&e==r)return!0;if(e==(i<0?0:Nd(t))){let n=t.parentNode;if(!n||1!=n.nodeType||Ad(t)||Td.test(t.nodeName)||"false"==t.contentEditable)return!1;e=Od(t)+(i<0?0:1),t=n}else{if(1!=t.nodeType)return!1;if("false"==(t=t.childNodes[e+(i<0?-1:0)]).contentEditable)return!1;e=i<0?Nd(t):0}}}function Nd(t){return 3==t.nodeType?t.nodeValue.length:t.childNodes.length}function Ad(t){let e;for(let n=t;n&&!(e=n.pmViewDesc);n=n.parentNode);return e&&e.node&&e.node.isBlock&&(e.dom==t||e.contentDOM==t)}const Ed=function(t){let e=t.isCollapsed;return e&&gd&&t.rangeCount&&!t.getRangeAt(0).collapsed&&(e=!1),e};function Pd(t,e){let n=document.createEvent("Event");return n.initEvent("keydown",!0,!0),n.keyCode=t,n.key=n.code=e,n}function Id(t){return{left:0,right:t.documentElement.clientWidth,top:0,bottom:t.documentElement.clientHeight}}function Rd(t,e){return"number"==typeof t?t:t[e]}function zd(t){let e=t.getBoundingClientRect(),n=e.width/t.offsetWidth||1,r=e.height/t.offsetHeight||1;return{left:e.left,right:e.left+t.clientWidth*n,top:e.top,bottom:e.top+t.clientHeight*r}}function jd(t,e,n){let r=t.someProp("scrollThreshold")||0,i=t.someProp("scrollMargin")||5,o=t.dom.ownerDocument;for(let s=n||t.dom;s;s=_d(s)){if(1!=s.nodeType)continue;let t=s,n=t==o.body,a=n?Id(o):zd(t),l=0,c=0;if(e.topa.bottom-Rd(r,"bottom")&&(c=e.bottom-a.bottom+Rd(i,"bottom")),e.lefta.right-Rd(r,"right")&&(l=e.right-a.right+Rd(i,"right")),l||c)if(n)o.defaultView.scrollBy(l,c);else{let n=t.scrollLeft,r=t.scrollTop;c&&(t.scrollTop+=c),l&&(t.scrollLeft+=l);let i=t.scrollLeft-n,o=t.scrollTop-r;e={left:e.left-i,top:e.top-o,right:e.right-i,bottom:e.bottom-o}}if(n)break}}function Fd(t){let e=[],n=t.ownerDocument;for(let r=t;r&&(e.push({dom:r,top:r.scrollTop,left:r.scrollLeft}),t!=n);r=_d(r));return e}function Ld(t,e){for(let n=0;n=a){s=Math.max(d.bottom,s),a=Math.min(d.top,a);let t=d.left>e.left?d.left-e.left:d.right=(d.left+d.right)/2?1:0));continue}}!n&&(e.left>=d.right&&e.top>=d.top||e.left>=d.left&&e.top>=d.bottom)&&(o=c+1)}}return n&&3==n.nodeType?function(t,e){let n=t.nodeValue.length,r=document.createRange();for(let i=0;i=(n.left+n.right)/2?1:0)}}return{node:t,offset:0}}(n,r):!n||i&&1==n.nodeType?{node:t,offset:o}:Vd(n,r)}function Wd(t,e){return t.left>=e.left-1&&t.left<=e.right+1&&t.top>=e.top-1&&t.top<=e.bottom+1}function qd(t,e,n){let r=t.childNodes.length;if(r&&n.tope.top&&i++}n==t.dom&&i==n.childNodes.length-1&&1==n.lastChild.nodeType&&e.top>n.lastChild.getBoundingClientRect().bottom?o=t.state.doc.content.size:0!=i&&1==n.nodeType&&"BR"==n.childNodes[i-1].nodeName||(o=function(t,e,n,r){let i=-1;for(let o=e;o!=t.dom;){let e=t.docView.nearestDesc(o,!0);if(!e)return null;if(e.node.isBlock&&e.parent){let t=e.dom.getBoundingClientRect();if(t.left>r.left||t.top>r.top)i=e.posBefore;else{if(!(t.right-1?i:t.docView.posFromDOM(e,n,1)}(t,n,i,e))}null==o&&(o=function(t,e,n){let{node:r,offset:i}=Vd(e,n),o=-1;if(1==r.nodeType&&!r.firstChild){let t=r.getBoundingClientRect();o=t.left!=t.right&&n.left>(t.left+t.right)/2?1:-1}return t.docView.posFromDOM(r,i,o)}(t,s,e));let a=t.docView.nearestDesc(s,!0);return{pos:o,inside:a?a.posAtStart-a.border:-1}}function Kd(t,e){let n=t.getClientRects();return n.length?n[e<0?0:n.length-1]:t.getBoundingClientRect()}const Hd=/[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac]/;function Ud(t,e,n){let{node:r,offset:i,atom:o}=t.docView.domFromPos(e,n<0?-1:1),s=Sd||pd;if(3==r.nodeType){if(!s||!Hd.test(r.nodeValue)&&(n<0?i:i!=r.nodeValue.length)){let t=i,e=i,o=n<0?1:-1;return n<0&&!i?(e++,o=-1):n>=0&&i==r.nodeValue.length?(t--,o=1):n<0?t--:e++,Yd(Kd(Cd(r,t,e),o),o<0)}{let t=Kd(Cd(r,i,i),n);if(pd&&i&&/\s/.test(r.nodeValue[i-1])&&i=0)}if(null==o&&i&&(n<0||i==Nd(r))){let t=r.childNodes[i-1],e=3==t.nodeType?Cd(t,Nd(t)-(s?0:1)):1!=t.nodeType||"BR"==t.nodeName&&t.nextSibling?null:t;if(e)return Yd(Kd(e,1),!1)}if(null==o&&i=0)}function Yd(t,e){if(0==t.width)return t;let n=e?t.left:t.right;return{top:t.top,bottom:t.bottom,left:n,right:n}}function Gd(t,e){if(0==t.height)return t;let n=e?t.top:t.bottom;return{top:n,bottom:n,left:t.left,right:t.right}}function Zd(t,e,n){let r=t.state,i=t.root.activeElement;r!=e&&t.updateState(e),i!=t.dom&&t.focus();try{return n()}finally{r!=e&&t.updateState(r),i!=t.dom&&i&&i.focus()}}const Xd=/[\u0590-\u08ac]/;let Qd=null,tf=null,ef=!1;function nf(t,e,n){return Qd==e&&tf==n?ef:(Qd=e,tf=n,ef="up"==n||"down"==n?function(t,e,n){let r=e.selection,i="up"==n?r.$from:r.$to;return Zd(t,e,(()=>{let{node:e}=t.docView.domFromPos(i.pos,"up"==n?-1:1);for(;;){let n=t.docView.nearestDesc(e,!0);if(!n)break;if(n.node.isBlock){e=n.dom;break}e=n.dom.parentNode}let r=Ud(t,i.pos,1);for(let t=e.firstChild;t;t=t.nextSibling){let e;if(1==t.nodeType)e=t.getClientRects();else{if(3!=t.nodeType)continue;e=Cd(t,0,t.nodeValue.length).getClientRects()}for(let t=0;ti.top+1&&("up"==n?r.top-i.top>2*(i.bottom-r.top):i.bottom-r.bottom>2*(r.bottom-i.top)))return!1}}return!0}))}(t,e,n):function(t,e,n){let{$head:r}=e.selection;if(!r.parent.isTextblock)return!1;let i=r.parentOffset,o=!i,s=i==r.parent.content.size,a=t.domSelection();return Xd.test(r.parent.textContent)&&a.modify?Zd(t,e,(()=>{let e=a.getRangeAt(0),i=a.focusNode,o=a.focusOffset,s=a.caretBidiLevel;a.modify("move",n,"character");let l=!(r.depth?t.docView.domAfterPos(r.before()):t.dom).contains(1==a.focusNode.nodeType?a.focusNode:a.focusNode.parentNode)||i==a.focusNode&&o==a.focusOffset;return a.removeAllRanges(),a.addRange(e),null!=s&&(a.caretBidiLevel=s),l})):"left"==n||"backward"==n?o:s}(t,e,n))}class rf{constructor(t,e,n,r){this.parent=t,this.children=e,this.dom=n,this.contentDOM=r,this.dirty=0,n.pmViewDesc=this}matchesWidget(t){return!1}matchesMark(t){return!1}matchesNode(t,e,n){return!1}matchesHack(t){return!1}parseRule(){return null}stopEvent(t){return!1}get size(){let t=0;for(let e=0;eOd(this.contentDOM);else if(this.contentDOM&&this.contentDOM!=this.dom&&this.dom.contains(this.contentDOM))r=2&t.compareDocumentPosition(this.contentDOM);else if(this.dom.firstChild){if(0==e)for(let e=t;;e=e.parentNode){if(e==this.dom){r=!1;break}if(e.previousSibling)break}if(null==r&&e==t.childNodes.length)for(let e=t;;e=e.parentNode){if(e==this.dom){r=!0;break}if(e.nextSibling)break}}return(null==r?n>0:r)?this.posAtEnd:this.posAtStart}nearestDesc(t,e=!1){for(let n=!0,r=t;r;r=r.parentNode){let i,o=this.getDesc(r);if(o&&(!e||o.node)){if(!n||!(i=o.nodeDOM)||(1==i.nodeType?i.contains(1==t.nodeType?t:t.parentNode):i==t))return o;n=!1}}}getDesc(t){let e=t.pmViewDesc;for(let n=e;n;n=n.parent)if(n==this)return e}posFromDOM(t,e,n){for(let r=t;r;r=r.parentNode){let i=this.getDesc(r);if(i)return i.localPosFromDOM(t,e,n)}return-1}descAt(t){for(let e=0,n=0;et||e instanceof df){i=t-o;break}o=n}if(i)return this.children[r].domFromPos(i-this.children[r].border,e);for(;r&&!(n=this.children[r-1]).size&&n instanceof of&&n.side>=0;r--);if(e<=0){let t,n=!0;for(;t=r?this.children[r-1]:null,t&&t.dom.parentNode!=this.contentDOM;r--,n=!1);return t&&e&&n&&!t.border&&!t.domAtom?t.domFromPos(t.size,e):{node:this.contentDOM,offset:t?Od(t.dom)+1:0}}{let t,n=!0;for(;t=r=i&&e<=a-n.border&&n.node&&n.contentDOM&&this.contentDOM.contains(n.contentDOM))return n.parseRange(t,e,i);t=o;for(let e=s;e>0;e--){let n=this.children[e-1];if(n.size&&n.dom.parentNode==this.contentDOM&&!n.emptyChildAt(1)){r=Od(n.dom)+1;break}t-=n.size}-1==r&&(r=0)}if(r>-1&&(a>e||s==this.children.length-1)){e=a;for(let t=s+1;th&&oe){let t=s;s=a,a=t}let n=document.createRange();n.setEnd(a.node,a.offset),n.setStart(s.node,s.offset),l.removeAllRanges(),l.addRange(n)}}ignoreMutation(t){return!this.contentDOM&&"selection"!=t.type}get contentLost(){return this.contentDOM&&this.contentDOM!=this.dom&&!this.dom.contains(this.contentDOM)}markDirty(t,e){for(let n=0,r=0;r=n:tn){let r=n+i.border,s=o-i.border;if(t>=r&&e<=s)return this.dirty=t==n||e==o?2:1,void(t!=r||e!=s||!i.contentLost&&i.dom.parentNode==this.contentDOM?i.markDirty(t-r,e-r):i.dirty=3);i.dirty=i.dom!=i.contentDOM||i.dom.parentNode!=this.contentDOM||i.children.length?3:2}n=o}this.dirty=2}markParentsDirty(){let t=1;for(let e=this.parent;e;e=e.parent,t++){let n=1==t?2:1;e.dirtyi?i.parent?i.parent.posBeforeChild(i):void 0:r))),!e.type.spec.raw){if(1!=o.nodeType){let t=document.createElement("span");t.appendChild(o),o=t}o.contentEditable="false",o.classList.add("ProseMirror-widget")}super(t,[],o,null),this.widget=e,this.widget=e,i=this}matchesWidget(t){return 0==this.dirty&&t.type.eq(this.widget.type)}parseRule(){return{ignore:!0}}stopEvent(t){let e=this.widget.spec.stopEvent;return!!e&&e(t)}ignoreMutation(t){return"selection"!=t.type||this.widget.spec.ignoreSelection}destroy(){this.widget.type.destroy(this.dom),super.destroy()}get domAtom(){return!0}get side(){return this.widget.type.side}}class sf extends rf{constructor(t,e,n,r){super(t,[],e,null),this.textDOM=n,this.text=r}get size(){return this.text.length}localPosFromDOM(t,e){return t!=this.textDOM?this.posAtStart+(e?this.size:0):this.posAtStart+e}domFromPos(t){return{node:this.textDOM,offset:t}}ignoreMutation(t){return"characterData"===t.type&&t.target.nodeValue==t.oldValue}}class af extends rf{constructor(t,e,n,r){super(t,[],n,r),this.mark=e}static create(t,e,n,r){let i=r.nodeViews[e.type.name],o=i&&i(e,r,n);return o&&o.dom||(o=eu.renderSpec(document,e.type.spec.toDOM(e,n))),new af(t,e,o.dom,o.contentDOM||o.dom)}parseRule(){return 3&this.dirty||this.mark.type.spec.reparseInView?null:{mark:this.mark.type.name,attrs:this.mark.attrs,contentElement:this.contentDOM||void 0}}matchesMark(t){return 3!=this.dirty&&this.mark.eq(t)}markDirty(t,e){if(super.markDirty(t,e),0!=this.dirty){let t=this.parent;for(;!t.node;)t=t.parent;t.dirty0&&(i=Of(i,0,t,n));for(let s=0;ss?s.parent?s.parent.posBeforeChild(s):void 0:o),n,r),c=l&&l.dom,u=l&&l.contentDOM;if(e.isText)if(c){if(3!=c.nodeType)throw new RangeError("Text must be rendered as a DOM text node")}else c=document.createTextNode(e.text);else c||({dom:c,contentDOM:u}=eu.renderSpec(document,e.type.spec.toDOM(e)));u||e.isText||"BR"==c.nodeName||(c.hasAttribute("contenteditable")||(c.contentEditable="false"),e.type.spec.draggable&&(c.draggable=!0));let d=c;return c=bf(c,n,e),l?s=new ff(t,e,n,r,c,u||null,d,l,i,o+1):e.isText?new uf(t,e,n,r,c,d,i):new lf(t,e,n,r,c,u||null,d,i,o+1)}parseRule(){if(this.node.type.spec.reparseInView)return null;let t={node:this.node.type.name,attrs:this.node.attrs};if("pre"==this.node.type.whitespace&&(t.preserveWhitespace="full"),this.contentDOM)if(this.contentLost){for(let e=this.children.length-1;e>=0;e--){let n=this.children[e];if(this.dom.contains(n.dom.parentNode)){t.contentElement=n.dom.parentNode;break}}t.contentElement||(t.getContent=()=>ec.empty)}else t.contentElement=this.contentDOM;else t.getContent=()=>this.node.content;return t}matchesNode(t,e,n){return 0==this.dirty&&t.eq(this.node)&&wf(e,this.outerDeco)&&n.eq(this.innerDeco)}get size(){return this.node.nodeSize}get border(){return this.node.isLeaf?0:1}updateChildren(t,e){let n=this.node.inlineContent,r=e,i=t.composing?this.localCompositionInfo(t,e):null,o=i&&i.pos>-1?i:null,s=i&&i.pos<0,a=new Sf(this,o&&o.node);!function(t,e,n,r){let i=e.locals(t),o=0;if(0==i.length){for(let n=0;no;)a.push(i[s++]);let f=o+u.nodeSize;if(u.isText){let t=f;s!t.inline)):a.slice(),e.forChild(o,u),d),o=f}}(this.node,this.innerDeco,((e,i,o)=>{e.spec.marks?a.syncToMarks(e.spec.marks,n,t):e.type.side>=0&&!o&&a.syncToMarks(i==this.node.childCount?oc.none:this.node.child(i).marks,n,t),a.placeWidget(e,t,r)}),((e,o,l,c)=>{let u;a.syncToMarks(e.marks,n,t),a.findNodeMatch(e,o,l,c)||s&&t.state.selection.from>r&&t.state.selection.to-1&&a.updateNodeAt(e,o,l,u,t)||a.updateNextNode(e,o,l,t,c)||a.addNode(e,o,l,t,r),r+=e.nodeSize})),a.syncToMarks([],n,t),this.node.isTextblock&&a.addTextblockHacks(),a.destroyRest(),(a.changed||2==this.dirty)&&(o&&this.protectLocalComposition(t,o),hf(this.contentDOM,this.children,t),bd&&function(t){if("UL"==t.nodeName||"OL"==t.nodeName){let e=t.style.cssText;t.style.cssText=e+"; list-style: square !important",window.getComputedStyle(t).listStyle,t.style.cssText=e}}(this.dom))}localCompositionInfo(t,e){let{from:n,to:r}=t.state.selection;if(!(t.state.selection instanceof Bu)||ne+this.node.content.size)return null;let i=t.domSelection(),o=function(t,e){for(;;){if(3==t.nodeType)return t;if(1==t.nodeType&&e>0){if(t.childNodes.length>e&&3==t.childNodes[e].nodeType)return t.childNodes[e];e=Nd(t=t.childNodes[e-1])}else{if(!(1==t.nodeType&&e=n){let t=a=0&&t+e.length+a>=n)return a+t;if(n==r&&l.length>=r+e.length-a&&l.slice(r-a,r-a+e.length)==e)return r}}return-1}(this.node.content,t,n-e,r-e);return i<0?null:{node:o,pos:i,text:t}}return{node:o,pos:-1,text:""}}protectLocalComposition(t,{node:e,pos:n,text:r}){if(this.getDesc(e))return;let i=e;for(;i.parentNode!=this.contentDOM;i=i.parentNode){for(;i.previousSibling;)i.parentNode.removeChild(i.previousSibling);for(;i.nextSibling;)i.parentNode.removeChild(i.nextSibling);i.pmViewDesc&&(i.pmViewDesc=void 0)}let o=new sf(this,i,e,r);t.input.compositionNodes.push(o),this.children=Of(this.children,n,n+r.length,t,o)}update(t,e,n,r){return!(3==this.dirty||!t.sameMarkup(this.node))&&(this.updateInner(t,e,n,r),!0)}updateInner(t,e,n,r){this.updateOuterDeco(e),this.node=t,this.innerDeco=n,this.contentDOM&&this.updateChildren(r,this.posAtStart),this.dirty=0}updateOuterDeco(t){if(wf(t,this.outerDeco))return;let e=1!=this.nodeDOM.nodeType,n=this.dom;this.dom=vf(this.dom,this.nodeDOM,gf(this.outerDeco,this.node,e),gf(t,this.node,e)),this.dom!=n&&(n.pmViewDesc=void 0,this.dom.pmViewDesc=this),this.outerDeco=t}selectNode(){1==this.nodeDOM.nodeType&&this.nodeDOM.classList.add("ProseMirror-selectednode"),!this.contentDOM&&this.node.type.spec.draggable||(this.dom.draggable=!0)}deselectNode(){1==this.nodeDOM.nodeType&&this.nodeDOM.classList.remove("ProseMirror-selectednode"),!this.contentDOM&&this.node.type.spec.draggable||this.dom.removeAttribute("draggable")}get domAtom(){return this.node.isAtom}}function cf(t,e,n,r,i){return bf(r,e,t),new lf(void 0,t,e,n,r,r,r,i,0)}class uf extends lf{constructor(t,e,n,r,i,o,s){super(t,e,n,r,i,null,o,s,0)}parseRule(){let t=this.nodeDOM.parentNode;for(;t&&t!=this.dom&&!t.pmIsDeco;)t=t.parentNode;return{skip:t||!0}}update(t,e,n,r){return!(3==this.dirty||0!=this.dirty&&!this.inParent()||!t.sameMarkup(this.node))&&(this.updateOuterDeco(e),0==this.dirty&&t.text==this.node.text||t.text==this.nodeDOM.nodeValue||(this.nodeDOM.nodeValue=t.text,r.trackWrites==this.nodeDOM&&(r.trackWrites=null)),this.node=t,this.dirty=0,!0)}inParent(){let t=this.parent.contentDOM;for(let e=this.nodeDOM;e;e=e.parentNode)if(e==t)return!0;return!1}domFromPos(t){return{node:this.nodeDOM,offset:t}}localPosFromDOM(t,e,n){return t==this.nodeDOM?this.posAtStart+Math.min(e,this.node.text.length):super.localPosFromDOM(t,e,n)}ignoreMutation(t){return"characterData"!=t.type&&"selection"!=t.type}slice(t,e,n){let r=this.node.cut(t,e),i=document.createTextNode(r.text);return new uf(this.parent,r,this.outerDeco,this.innerDeco,i,i,n)}markDirty(t,e){super.markDirty(t,e),this.dom==this.nodeDOM||0!=t&&e!=this.nodeDOM.nodeValue.length||(this.dirty=3)}get domAtom(){return!1}}class df extends rf{parseRule(){return{ignore:!0}}matchesHack(t){return 0==this.dirty&&this.dom.nodeName==t}get domAtom(){return!0}get ignoreForCoords(){return"IMG"==this.dom.nodeName}}class ff extends lf{constructor(t,e,n,r,i,o,s,a,l,c){super(t,e,n,r,i,o,s,l,c),this.spec=a}update(t,e,n,r){if(3==this.dirty)return!1;if(this.spec.update){let i=this.spec.update(t,e,n);return i&&this.updateInner(t,e,n,r),i}return!(!this.contentDOM&&!t.isLeaf)&&super.update(t,e,n,r)}selectNode(){this.spec.selectNode?this.spec.selectNode():super.selectNode()}deselectNode(){this.spec.deselectNode?this.spec.deselectNode():super.deselectNode()}setSelection(t,e,n,r){this.spec.setSelection?this.spec.setSelection(t,e,n):super.setSelection(t,e,n,r)}destroy(){this.spec.destroy&&this.spec.destroy(),super.destroy()}stopEvent(t){return!!this.spec.stopEvent&&this.spec.stopEvent(t)}ignoreMutation(t){return this.spec.ignoreMutation?this.spec.ignoreMutation(t):super.ignoreMutation(t)}}function hf(t,e,n){let r=t.firstChild,i=!1;for(let o=0;o0;){let a;for(;;)if(r){let t=n.children[r-1];if(!(t instanceof af)){a=t,r--;break}n=t,r=t.children.length}else{if(n==e)break t;r=n.parent.children.indexOf(n),n=n.parent}let l=a.node;if(l){if(l!=t.child(i-1))break;--i,o.set(a,i),s.push(a)}}return{index:i,matched:o,matches:s.reverse()}}(t.node.content,t)}destroyBetween(t,e){if(t!=e){for(let n=t;n>1,o=Math.min(i,t.length);for(;r-1)r>this.index&&(this.changed=!0,this.destroyBetween(this.index,r)),this.top=this.top.children[this.index];else{let r=af.create(this.top,t[i],e,n);this.top.children.splice(this.index,0,r),this.top=r,this.changed=!0}this.index=0,i++}}findNodeMatch(t,e,n,r){let i,o=-1;if(r>=this.preMatch.index&&(i=this.preMatch.matches[r-this.preMatch.index]).parent==this.top&&i.matchesNode(t,e,n))o=this.top.children.indexOf(i,this.index);else for(let s=this.index,a=Math.min(this.top.children.length,s+5);s=n||u<=e?o.push(l):(cn&&o.push(l.slice(n-c,l.size,r)))}return o}function _f(t,e=null){let n=t.domSelection(),r=t.state.doc;if(!n.focusNode)return null;let i=t.docView.nearestDesc(n.focusNode),o=i&&0==i.size,s=t.docView.posFromDOM(n.focusNode,n.focusOffset,1);if(s<0)return null;let a,l,c=r.resolve(s);if(Ed(n)){for(a=c;i&&!i.node;)i=i.parent;let t=i.node;if(i&&t.isAtom&&Wu.isSelectable(t)&&i.parent&&(!t.isInline||!function(t,e,n){for(let r=0==e,i=e==Nd(t);r||i;){if(t==n)return!0;let e=Od(t);if(!(t=t.parentNode))return!1;r=r&&0==e,i=i&&e==Nd(t)}}(n.focusNode,n.focusOffset,i.dom))){let t=i.posBefore;l=new Wu(s==t?c:r.resolve(t))}}else{let e=t.docView.posFromDOM(n.anchorNode,n.anchorOffset,1);if(e<0)return null;a=r.resolve(e)}if(!l){l=Pf(t,a,c,"pointer"==e||t.state.selection.head{n.anchorNode==r&&n.anchorOffset==i||(e.removeEventListener("selectionchange",t.input.hideSelectionGuard),setTimeout((()=>{Mf(t)&&!t.state.selection.visible||t.dom.classList.remove("ProseMirror-hideselection")}),20))})}(t))}t.domObserver.setCurSelection(),t.domObserver.connectSelection()}}const $f=yd||gd&&vd<63;function Tf(t,e){let{node:n,offset:r}=t.docView.domFromPos(e,0),i=rr(t,e,n)))||Bu.between(e,n,r)}function If(t){return(!t.editable||t.root.activeElement==t.dom)&&Rf(t)}function Rf(t){let e=t.domSelection();if(!e.anchorNode)return!1;try{return t.dom.contains(3==e.anchorNode.nodeType?e.anchorNode.parentNode:e.anchorNode)&&(t.editable||t.dom.contains(3==e.focusNode.nodeType?e.focusNode.parentNode:e.focusNode))}catch(n){return!1}}function zf(t,e){let{$anchor:n,$head:r}=t.selection,i=e>0?n.max(r):n.min(r),o=i.parent.inlineContent?i.depth?t.doc.resolve(e>0?i.after():i.before()):null:i;return o&&zu.findFrom(o,e)}function jf(t,e){return t.dispatch(t.state.tr.setSelection(e).scrollIntoView()),!0}function Ff(t,e,n){let r=t.state.selection;if(!(r instanceof Bu)){if(r instanceof Wu&&r.node.isInline)return jf(t,new Bu(e>0?r.$to:r.$from));{let n=zf(t.state,e);return!!n&&jf(t,n)}}if(!r.empty||n.indexOf("s")>-1)return!1;if(t.endOfTextblock(e>0?"right":"left")){let n=zf(t.state,e);return!!(n&&n instanceof Wu)&&jf(t,n)}if(!(wd&&n.indexOf("m")>-1)){let n,i=r.$head,o=i.textOffset?null:e<0?i.nodeBefore:i.nodeAfter;if(!o||o.isText)return!1;let s=e<0?i.pos-o.nodeSize:i.pos;return!!(o.isAtom||(n=t.docView.descAt(s))&&!n.contentDOM)&&(Wu.isSelectable(o)?jf(t,new Wu(e<0?t.state.doc.resolve(i.pos-o.nodeSize):i)):!!Sd&&jf(t,new Bu(t.state.doc.resolve(e<0?s:s+o.nodeSize))))}}function Lf(t){return 3==t.nodeType?t.nodeValue.length:t.childNodes.length}function Bf(t){let e=t.pmViewDesc;return e&&0==e.size&&(t.nextSibling||"BR"!=t.nodeName)}function Vf(t){let e=t.domSelection(),n=e.focusNode,r=e.focusOffset;if(!n)return;let i,o,s=!1;for(pd&&1==n.nodeType&&r0){if(1!=n.nodeType)break;{let t=n.childNodes[r-1];if(Bf(t))i=n,o=--r;else{if(3!=t.nodeType)break;n=t,r=n.nodeValue.length}}}else{if(qf(n))break;{let e=n.previousSibling;for(;e&&Bf(e);)i=n.parentNode,o=Od(e),e=e.previousSibling;if(e)n=e,r=Lf(n);else{if(n=n.parentNode,n==t.dom)break;r=0}}}s?Jf(t,e,n,r):i&&Jf(t,e,i,o)}function Wf(t){let e=t.domSelection(),n=e.focusNode,r=e.focusOffset;if(!n)return;let i,o,s=Lf(n);for(;;)if(r{t.state==i&&Cf(t)}),50)}function Kf(t,e,n){let r=t.state.selection;if(r instanceof Bu&&!r.empty||n.indexOf("s")>-1)return!1;if(wd&&n.indexOf("m")>-1)return!1;let{$from:i,$to:o}=r;if(!i.parent.inlineContent||t.endOfTextblock(e<0?"up":"down")){let n=zf(t.state,e);if(n&&n instanceof Wu)return jf(t,n)}if(!i.parent.inlineContent){let n=e<0?i:o,s=r instanceof Ju?zu.near(n,e):zu.findFrom(n,e);return!!s&&jf(t,s)}return!1}function Hf(t,e){if(!(t.state.selection instanceof Bu))return!0;let{$head:n,$anchor:r,empty:i}=t.state.selection;if(!n.sameParent(r))return!0;if(!i)return!1;if(t.endOfTextblock(e>0?"forward":"backward"))return!0;let o=!n.textOffset&&(e<0?n.nodeBefore:n.nodeAfter);if(o&&!o.isText){let r=t.state.tr;return e<0?r.delete(n.pos-o.nodeSize,n.pos):r.delete(n.pos,n.pos+o.nodeSize),t.dispatch(r),!0}return!1}function Uf(t,e,n){t.domObserver.stop(),e.contentEditable=n,t.domObserver.start()}function Yf(t,e){let n=e.keyCode,r=function(t){let e="";return t.ctrlKey&&(e+="c"),t.metaKey&&(e+="m"),t.altKey&&(e+="a"),t.shiftKey&&(e+="s"),e}(e);return 8==n||wd&&72==n&&"c"==r?Hf(t,-1)||Vf(t):46==n||wd&&68==n&&"c"==r?Hf(t,1)||Wf(t):13==n||27==n||(37==n||wd&&66==n&&"c"==r?Ff(t,-1,r)||Vf(t):39==n||wd&&70==n&&"c"==r?Ff(t,1,r)||Wf(t):38==n||wd&&80==n&&"c"==r?Kf(t,-1,r)||Vf(t):40==n||wd&&78==n&&"c"==r?function(t){if(!yd||t.state.selection.$head.parentOffset>0)return!1;let{focusNode:e,focusOffset:n}=t.domSelection();if(e&&1==e.nodeType&&0==n&&e.firstChild&&"false"==e.firstChild.contentEditable){let n=e.firstChild;Uf(t,n,"true"),setTimeout((()=>Uf(t,n,"false")),20)}return!1}(t)||Kf(t,1,r)||Wf(t):r==(wd?"m":"c")&&(66==n||73==n||89==n||90==n))}function Gf(t,e){let n=[],{content:r,openStart:i,openEnd:o}=e;for(;i>1&&o>1&&1==r.childCount&&1==r.firstChild.childCount;){i--,o--;let t=r.firstChild;n.push(t.type.name,t.attrs!=t.type.defaultAttrs?t.attrs:null),r=t.content}let s=t.someProp("clipboardSerializer")||eu.fromSchema(t.state.schema),a=sh(),l=a.createElement("div");l.appendChild(s.serializeFragment(r,{document:a}));let c,u=l.firstChild,d=0;for(;u&&1==u.nodeType&&(c=ih[u.nodeName.toLowerCase()]);){for(let t=c.length-1;t>=0;t--){let e=a.createElement(c[t]);for(;l.firstChild;)e.appendChild(l.firstChild);l.appendChild(e),d++}u=l.firstChild}return u&&1==u.nodeType&&u.setAttribute("data-pm-slice",`${i} ${o}${d?` -${d}`:""} ${JSON.stringify(n)}`),{dom:l,text:t.someProp("clipboardTextSerializer",(t=>t(e)))||e.content.textBetween(0,e.content.size,"\n\n")}}function Zf(t,e,n,r,i){let o,s,a=i.parent.type.spec.code;if(!n&&!e)return null;let l=e&&(r||a||!n);if(l){if(t.someProp("transformPastedText",(t=>{e=t(e,a||r)})),a)return e?new ac(ec.from(t.state.schema.text(e.replace(/\r\n?/g,"\n"))),0,0):ac.empty;let n=t.someProp("clipboardTextParser",(t=>t(e,i,r)));if(n)s=n;else{let n=i.marks(),{schema:r}=t.state,s=eu.fromSchema(r);o=document.createElement("div"),e.split(/(?:\r\n?|\n)+/).forEach((t=>{let e=o.appendChild(document.createElement("p"));t&&e.appendChild(s.serializeNode(r.text(t,n)))}))}}else t.someProp("transformPastedHTML",(t=>{n=t(n)})),o=function(t){let e=/^(\s*]*>)*/.exec(t);e&&(t=t.slice(e[0].length));let n,r=sh().createElement("div"),i=/<([a-z][^>\s]+)/i.exec(t);(n=i&&ih[i[1].toLowerCase()])&&(t=n.map((t=>"<"+t+">")).join("")+t+n.map((t=>"")).reverse().join(""));if(r.innerHTML=t,n)for(let o=0;o0&&o.firstChild;d--)o=o.firstChild;if(!s){let e=t.someProp("clipboardParser")||t.someProp("domParser")||Jc.fromSchema(t.state.schema);s=e.parseSlice(o,{preserveWhitespace:!(!l&&!u),context:i,ruleFromNode:t=>"BR"!=t.nodeName||t.nextSibling||!t.parentNode||Xf.test(t.parentNode.nodeName)?null:{ignore:!0}})}if(u)s=function(t,e){if(!t.size)return t;let n,r=t.content.firstChild.type.schema;try{n=JSON.parse(e)}catch(_g){return t}let{content:i,openStart:o,openEnd:s}=t;for(let a=n.length-2;a>=0;a-=2){let t=r.nodes[n[a]];if(!t||t.hasRequiredAttrs())break;i=ec.from(t.create(n[a+1],i)),o++,s++}return new ac(i,o,s)}(rh(s,+u[1],+u[2]),u[4]);else if(s=ac.maxOpen(function(t,e){if(t.childCount<2)return t;for(let n=e.depth;n>=0;n--){let r,i=e.node(n).contentMatchAt(e.index(n)),o=[];if(t.forEach((t=>{if(!o)return;let e,n=i.findWrapping(t.type);if(!n)return o=null;if(e=o.length&&r.length&&th(n,r,t,o[o.length-1],0))o[o.length-1]=e;else{o.length&&(o[o.length-1]=eh(o[o.length-1],r.length));let e=Qf(t,n);o.push(e),i=i.matchType(e.type),r=n}})),o)return ec.from(o)}return t}(s.content,i),!0),s.openStart||s.openEnd){let t=0,e=0;for(let n=s.content.firstChild;t{s=t(s)})),s}const Xf=/^(a|abbr|acronym|b|cite|code|del|em|i|ins|kbd|label|output|q|ruby|s|samp|span|strong|sub|sup|time|u|tt|var)$/i;function Qf(t,e,n=0){for(let r=e.length-1;r>=n;r--)t=e[r].create(null,ec.from(t));return t}function th(t,e,n,r,i){if(i=n&&(a=e<0?s.contentMatchAt(0).fillBefore(a,t.childCount>1||o<=i).append(a):a.append(s.contentMatchAt(s.childCount).fillBefore(ec.empty,!0))),t.replaceChild(e<0?0:t.childCount-1,s.copy(a))}function rh(t,e,n){return e{for(let n in e)t.input.eventHandlers[n]||t.dom.addEventListener(n,t.input.eventHandlers[n]=e=>fh(t,e))}))}function fh(t,e){return t.someProp("handleDOMEvents",(n=>{let r=n[e.type];return!!r&&(r(t,e)||e.defaultPrevented)}))}function hh(t,e){if(!e.bubbles)return!0;if(e.defaultPrevented)return!1;for(let n=e.target;n!=t.dom;n=n.parentNode)if(!n||11==n.nodeType||n.pmViewDesc&&n.pmViewDesc.stopEvent(e))return!1;return!0}function ph(t){return{left:t.clientX,top:t.clientY}}function mh(t,e,n,r,i){if(-1==r)return!1;let o=t.state.doc.resolve(r);for(let s=o.depth+1;s>0;s--)if(t.someProp(e,(e=>s>o.depth?e(t,n,o.nodeAfter,o.before(s),i,!0):e(t,n,o.node(s),o.before(s),i,!1))))return!0;return!1}function gh(t,e,n){t.focused||t.focus();let r=t.state.tr.setSelection(e);"pointer"==n&&r.setMeta("pointer",!0),t.dispatch(r)}function vh(t,e,n,r,i){return mh(t,"handleClickOn",e,n,r)||t.someProp("handleClick",(n=>n(t,e,r)))||(i?function(t,e){if(-1==e)return!1;let n,r,i=t.state.selection;i instanceof Wu&&(n=i.node);let o=t.state.doc.resolve(e);for(let s=o.depth+1;s>0;s--){let t=s>o.depth?o.nodeAfter:o.node(s);if(Wu.isSelectable(t)){r=n&&i.$from.depth>0&&s>=i.$from.depth&&o.before(i.$from.depth+1)==i.$from.pos?o.before(i.$from.depth):o.before(s);break}}return null!=r&&(gh(t,Wu.create(t.state.doc,r),"pointer"),!0)}(t,n):function(t,e){if(-1==e)return!1;let n=t.state.doc.resolve(e),r=n.nodeAfter;return!!(r&&r.isAtom&&Wu.isSelectable(r))&&(gh(t,new Wu(n),"pointer"),!0)}(t,n))}function yh(t,e,n,r){return mh(t,"handleDoubleClickOn",e,n,r)||t.someProp("handleDoubleClick",(n=>n(t,e,r)))}function bh(t,e,n,r){return mh(t,"handleTripleClickOn",e,n,r)||t.someProp("handleTripleClick",(n=>n(t,e,r)))||function(t,e,n){if(0!=n.button)return!1;let r=t.state.doc;if(-1==e)return!!r.inlineContent&&(gh(t,Bu.create(r,0,r.content.size),"pointer"),!0);let i=r.resolve(e);for(let o=i.depth+1;o>0;o--){let e=o>i.depth?i.nodeAfter:i.node(o),n=i.before(o);if(e.inlineContent)gh(t,Bu.create(r,n+1,n+1+e.content.size),"pointer");else{if(!Wu.isSelectable(e))continue;gh(t,Wu.create(r,n),"pointer")}return!0}}(t,n,r)}function wh(t){return Ch(t)}lh.keydown=(t,e)=>{let n=e;if(t.input.shiftKey=16==n.keyCode||n.shiftKey,!kh(t,n)&&(t.input.lastKeyCode=n.keyCode,t.input.lastKeyCodeTime=Date.now(),!xd||!gd||13!=n.keyCode))if(229!=n.keyCode&&t.domObserver.forceFlush(),!bd||13!=n.keyCode||n.ctrlKey||n.altKey||n.metaKey)t.someProp("handleKeyDown",(e=>e(t,n)))||Yf(t,n)?n.preventDefault():uh(t,"key");else{let e=Date.now();t.input.lastIOSEnter=e,t.input.lastIOSEnterFallbackTimeout=setTimeout((()=>{t.input.lastIOSEnter==e&&(t.someProp("handleKeyDown",(e=>e(t,Pd(13,"Enter")))),t.input.lastIOSEnter=0)}),200)}},lh.keyup=(t,e)=>{16==e.keyCode&&(t.input.shiftKey=!1)},lh.keypress=(t,e)=>{let n=e;if(kh(t,n)||!n.charCode||n.ctrlKey&&!n.altKey||wd&&n.metaKey)return;if(t.someProp("handleKeyPress",(e=>e(t,n))))return void n.preventDefault();let r=t.state.selection;if(!(r instanceof Bu&&r.$from.sameParent(r.$to))){let e=String.fromCharCode(n.charCode);t.someProp("handleTextInput",(n=>n(t,r.$from.pos,r.$to.pos,e)))||t.dispatch(t.state.tr.insertText(e).scrollIntoView()),n.preventDefault()}};const xh=wd?"metaKey":"ctrlKey";ah.mousedown=(t,e)=>{let n=e;t.input.shiftKey=n.shiftKey;let r=wh(t),i=Date.now(),o="singleClick";i-t.input.lastClick.time<500&&function(t,e){let n=e.x-t.clientX,r=e.y-t.clientY;return n*n+r*r<100}(n,t.input.lastClick)&&!n[xh]&&("singleClick"==t.input.lastClick.type?o="doubleClick":"doubleClick"==t.input.lastClick.type&&(o="tripleClick")),t.input.lastClick={time:i,x:n.clientX,y:n.clientY,type:o};let s=t.posAtCoords(ph(n));s&&("singleClick"==o?(t.input.mouseDown&&t.input.mouseDown.done(),t.input.mouseDown=new Sh(t,s,n,!!r)):("doubleClick"==o?yh:bh)(t,s.pos,s.inside,n)?n.preventDefault():uh(t,"pointer"))};class Sh{constructor(t,e,n,r){let i,o;if(this.view=t,this.pos=e,this.event=n,this.flushed=r,this.delayedSelectionSync=!1,this.mightDrag=null,this.startDoc=t.state.doc,this.selectNode=!!n[xh],this.allowDefault=n.shiftKey,e.inside>-1)i=t.state.doc.nodeAt(e.inside),o=e.inside;else{let n=t.state.doc.resolve(e.pos);i=n.parent,o=n.depth?n.before():0}const s=r?null:n.target,a=s?t.docView.nearestDesc(s,!0):null;this.target=a?a.dom:null;let{selection:l}=t.state;(0==n.button&&i.type.spec.draggable&&!1!==i.type.spec.selectable||l instanceof Wu&&l.from<=o&&l.to>o)&&(this.mightDrag={node:i,pos:o,addAttr:!(!this.target||this.target.draggable),setUneditable:!(!this.target||!pd||this.target.hasAttribute("contentEditable"))}),this.target&&this.mightDrag&&(this.mightDrag.addAttr||this.mightDrag.setUneditable)&&(this.view.domObserver.stop(),this.mightDrag.addAttr&&(this.target.draggable=!0),this.mightDrag.setUneditable&&setTimeout((()=>{this.view.input.mouseDown==this&&this.target.setAttribute("contentEditable","false")}),20),this.view.domObserver.start()),t.root.addEventListener("mouseup",this.up=this.up.bind(this)),t.root.addEventListener("mousemove",this.move=this.move.bind(this)),uh(t,"pointer")}done(){this.view.root.removeEventListener("mouseup",this.up),this.view.root.removeEventListener("mousemove",this.move),this.mightDrag&&this.target&&(this.view.domObserver.stop(),this.mightDrag.addAttr&&this.target.removeAttribute("draggable"),this.mightDrag.setUneditable&&this.target.removeAttribute("contentEditable"),this.view.domObserver.start()),this.delayedSelectionSync&&setTimeout((()=>Cf(this.view))),this.view.input.mouseDown=null}up(t){if(this.done(),!this.view.dom.contains(t.target))return;let e=this.pos;this.view.state.doc!=this.startDoc&&(e=this.view.posAtCoords(ph(t))),this.allowDefault||!e?uh(this.view,"pointer"):vh(this.view,e.pos,e.inside,t,this.selectNode)?t.preventDefault():0==t.button&&(this.flushed||yd&&this.mightDrag&&!this.mightDrag.node.isAtom||gd&&!(this.view.state.selection instanceof Bu)&&Math.min(Math.abs(e.pos-this.view.state.selection.from),Math.abs(e.pos-this.view.state.selection.to))<=2)?(gh(this.view,zu.near(this.view.state.doc.resolve(e.pos)),"pointer"),t.preventDefault()):uh(this.view,"pointer")}move(t){!this.allowDefault&&(Math.abs(this.event.x-t.clientX)>4||Math.abs(this.event.y-t.clientY)>4)&&(this.allowDefault=!0),uh(this.view,"pointer"),0==t.buttons&&this.done()}}function kh(t,e){return!!t.composing||!!(yd&&Math.abs(e.timeStamp-t.input.compositionEndedAt)<500)&&(t.input.compositionEndedAt=-2e8,!0)}ah.touchdown=t=>{wh(t),uh(t,"pointer")},ah.contextmenu=t=>wh(t);const Oh=xd?5e3:-1;function _h(t,e){clearTimeout(t.input.composingTimeout),e>-1&&(t.input.composingTimeout=setTimeout((()=>Ch(t)),e))}function Mh(t){for(t.composing&&(t.input.composing=!1,t.input.compositionEndedAt=function(){let t=document.createEvent("Event");return t.initEvent("event",!0,!0),t.timeStamp}());t.input.compositionNodes.length>0;)t.input.compositionNodes.pop().markParentsDirty()}function Ch(t,e=!1){if(!(xd&&t.domObserver.flushingSoon>=0)){if(t.domObserver.forceFlush(),Mh(t),e||t.docView&&t.docView.dirty){let e=_f(t);return e&&!e.eq(t.state.selection)?t.dispatch(t.state.tr.setSelection(e)):t.updateState(t.state),!0}return!1}}lh.compositionstart=lh.compositionupdate=t=>{if(!t.composing){t.domObserver.flush();let{state:e}=t,n=e.selection.$from;if(e.selection.empty&&(e.storedMarks||!n.textOffset&&n.parentOffset&&n.nodeBefore.marks.some((t=>!1===t.type.spec.inclusive))))t.markCursor=t.state.storedMarks||n.marks(),Ch(t,!0),t.markCursor=null;else if(Ch(t),pd&&e.selection.empty&&n.parentOffset&&!n.textOffset&&n.nodeBefore.marks.length){let e=t.domSelection();for(let t=e.focusNode,n=e.focusOffset;t&&1==t.nodeType&&0!=n;){let r=n<0?t.lastChild:t.childNodes[n-1];if(!r)break;if(3==r.nodeType){e.collapse(r,r.nodeValue.length);break}t=r,n=-1}}t.input.composing=!0}_h(t,Oh)},lh.compositionend=(t,e)=>{t.composing&&(t.input.composing=!1,t.input.compositionEndedAt=e.timeStamp,_h(t,20))};const $h=fd&&hd<15||bd&&kd<604;function Th(t,e,n,r){let i=Zf(t,e,n,t.input.shiftKey,t.state.selection.$from);if(t.someProp("handlePaste",(e=>e(t,r,i||ac.empty))))return!0;if(!i)return!1;let o=function(t){return 0==t.openStart&&0==t.openEnd&&1==t.content.childCount?t.content.firstChild:null}(i),s=o?t.state.tr.replaceSelectionWith(o,t.input.shiftKey):t.state.tr.replaceSelection(i);return t.dispatch(s.scrollIntoView().setMeta("paste",!0).setMeta("uiEvent","paste")),!0}ah.copy=lh.cut=(t,e)=>{let n=e,r=t.state.selection,i="cut"==n.type;if(r.empty)return;let o=$h?null:n.clipboardData,s=r.content(),{dom:a,text:l}=Gf(t,s);o?(n.preventDefault(),o.clearData(),o.setData("text/html",a.innerHTML),o.setData("text/plain",l)):function(t,e){if(!t.dom.parentNode)return;let n=t.dom.parentNode.appendChild(document.createElement("div"));n.appendChild(e),n.style.cssText="position: fixed; left: -10000px; top: 10px";let r=getSelection(),i=document.createRange();i.selectNodeContents(e),t.dom.blur(),r.removeAllRanges(),r.addRange(i),setTimeout((()=>{n.parentNode&&n.parentNode.removeChild(n),t.focus()}),50)}(t,a),i&&t.dispatch(t.state.tr.deleteSelection().scrollIntoView().setMeta("uiEvent","cut"))},lh.paste=(t,e)=>{let n=e;if(t.composing&&!xd)return;let r=$h?null:n.clipboardData;r&&Th(t,r.getData("text/plain"),r.getData("text/html"),n)?n.preventDefault():function(t,e){if(!t.dom.parentNode)return;let n=t.input.shiftKey||t.state.selection.$from.parent.type.spec.code,r=t.dom.parentNode.appendChild(document.createElement(n?"textarea":"div"));n||(r.contentEditable="true"),r.style.cssText="position: fixed; left: -10000px; top: 10px",r.focus(),setTimeout((()=>{t.focus(),r.parentNode&&r.parentNode.removeChild(r),n?Th(t,r.value,null,e):Th(t,r.textContent,r.innerHTML,e)}),50)}(t,n)};class Dh{constructor(t,e){this.slice=t,this.move=e}}const Nh=wd?"altKey":"ctrlKey";ah.dragstart=(t,e)=>{let n=e,r=t.input.mouseDown;if(r&&r.done(),!n.dataTransfer)return;let i=t.state.selection,o=i.empty?null:t.posAtCoords(ph(n));if(o&&o.pos>=i.from&&o.pos<=(i instanceof Wu?i.to-1:i.to));else if(r&&r.mightDrag)t.dispatch(t.state.tr.setSelection(Wu.create(t.state.doc,r.mightDrag.pos)));else if(n.target&&1==n.target.nodeType){let e=t.docView.nearestDesc(n.target,!0);e&&e.node.type.spec.draggable&&e!=t.docView&&t.dispatch(t.state.tr.setSelection(Wu.create(t.state.doc,e.posBefore)))}let s=t.state.selection.content(),{dom:a,text:l}=Gf(t,s);n.dataTransfer.clearData(),n.dataTransfer.setData($h?"Text":"text/html",a.innerHTML),n.dataTransfer.effectAllowed="copyMove",$h||n.dataTransfer.setData("text/plain",l),t.dragging=new Dh(s,!n[Nh])},ah.dragend=t=>{let e=t.dragging;window.setTimeout((()=>{t.dragging==e&&(t.dragging=null)}),50)},lh.dragover=lh.dragenter=(t,e)=>e.preventDefault(),lh.drop=(t,e)=>{let n=e,r=t.dragging;if(t.dragging=null,!n.dataTransfer)return;let i=t.posAtCoords(ph(n));if(!i)return;let o=t.state.doc.resolve(i.pos);if(!o)return;let s=r&&r.slice;s?t.someProp("transformPasted",(t=>{s=t(s)})):s=Zf(t,n.dataTransfer.getData($h?"Text":"text/plain"),$h?null:n.dataTransfer.getData("text/html"),!1,o);let a=!(!r||n[Nh]);if(t.someProp("handleDrop",(e=>e(t,n,s||ac.empty,a))))return void n.preventDefault();if(!s)return;n.preventDefault();let l=s?function(t,e,n){let r=t.resolve(e);if(!n.content.size)return e;let i=n.content;for(let o=0;o=0;t--){let e=t==r.depth?0:r.pos<=(r.start(t+1)+r.end(t+1))/2?-1:1,n=r.index(t)+(e>0?1:0),s=r.node(t),a=!1;if(1==o)a=s.canReplace(n,n,i);else{let t=s.contentMatchAt(n).findWrapping(i.firstChild.type);a=t&&s.canReplaceWith(n,n,t[0])}if(a)return 0==e?r.pos:e<0?r.before(t+1):r.after(t+1)}return null}(t.state.doc,o.pos,s):o.pos;null==l&&(l=o.pos);let c=t.state.tr;a&&c.deleteSelection();let u=c.mapping.map(l),d=0==s.openStart&&0==s.openEnd&&1==s.content.childCount,f=c.doc;if(d?c.replaceRangeWith(u,u,s.content.firstChild):c.replaceRange(u,u,s),c.doc.eq(f))return;let h=c.doc.resolve(u);if(d&&Wu.isSelectable(s.content.firstChild)&&h.nodeAfter&&h.nodeAfter.sameMarkup(s.content.firstChild))c.setSelection(new Wu(h));else{let e=c.mapping.map(l);c.mapping.maps[c.mapping.maps.length-1].forEach(((t,n,r,i)=>e=i)),c.setSelection(Pf(t,h,c.doc.resolve(e)))}t.focus(),t.dispatch(c.setMeta("uiEvent","drop"))},ah.focus=t=>{t.focused||(t.domObserver.stop(),t.dom.classList.add("ProseMirror-focused"),t.domObserver.start(),t.focused=!0,setTimeout((()=>{t.docView&&t.hasFocus()&&!t.domObserver.currentSelection.eq(t.domSelection())&&Cf(t)}),20))},ah.blur=(t,e)=>{let n=e;t.focused&&(t.domObserver.stop(),t.dom.classList.remove("ProseMirror-focused"),t.domObserver.start(),n.relatedTarget&&t.dom.contains(n.relatedTarget)&&t.domObserver.currentSelection.clear(),t.focused=!1)},ah.beforeinput=(t,e)=>{if(gd&&xd&&"deleteContentBackward"==e.inputType){t.domObserver.flushSoon();let{domChangeCount:e}=t.input;setTimeout((()=>{if(t.input.domChangeCount!=e)return;if(t.dom.blur(),t.focus(),t.someProp("handleKeyDown",(e=>e(t,Pd(8,"Backspace")))))return;let{$cursor:n}=t.state.selection;n&&n.pos>0&&t.dispatch(t.state.tr.delete(n.pos-1,n.pos).scrollIntoView())}),50)}};for(let os in lh)ah[os]=lh[os];function Ah(t,e){if(t==e)return!0;for(let n in t)if(t[n]!==e[n])return!1;for(let n in e)if(!(n in t))return!1;return!0}class Eh{constructor(t,e){this.toDOM=t,this.spec=e||jh,this.side=this.spec.side||0}map(t,e,n,r){let{pos:i,deleted:o}=t.mapResult(e.from+r,this.side<0?-1:1);return o?null:new Rh(i-n,i-n,this)}valid(){return!0}eq(t){return this==t||t instanceof Eh&&(this.spec.key&&this.spec.key==t.spec.key||this.toDOM==t.toDOM&&Ah(this.spec,t.spec))}destroy(t){this.spec.destroy&&this.spec.destroy(t)}}class Ph{constructor(t,e){this.attrs=t,this.spec=e||jh}map(t,e,n,r){let i=t.map(e.from+r,this.spec.inclusiveStart?-1:1)-n,o=t.map(e.to+r,this.spec.inclusiveEnd?1:-1)-n;return i>=o?null:new Rh(i,o,this)}valid(t,e){return e.from=t&&(!i||i(s.spec))&&n.push(s.copy(s.from+r,s.to+r))}for(let o=0;ot){let s=this.children[o]+1;this.children[o+2].findInner(t-s,e-s,n,r+s,i)}}map(t,e,n){return this==Lh||0==t.maps.length?this:this.mapInner(t,e,0,0,n||jh)}mapInner(t,e,n,r,i){let o;for(let s=0;s{for(let s=0;sc+o)continue;let u=a[s]+o;e>=u?a[s+1]=t<=u?-2:-1:n>=i&&(l=r-n-(e-t))&&(a[s]+=l,a[s+1]+=l)}};for(let u=0;u=r.content.size){c=!0;continue}let d=n.map(t[u+1]+o,-1)-i,{index:f,offset:h}=r.content.findIndex(l),p=r.maybeChild(f);if(p&&h==l&&h+p.nodeSize==d){let r=a[u+2].mapInner(n,p,e+1,t[u]+o+1,s);r!=Lh?(a[u]=l,a[u+1]=d,a[u+2]=r):(a[u+1]=-2,c=!0)}else c=!0}if(c){let l=function(t,e,n,r,i,o,s){function a(t,e){for(let o=0;o{let s,a=o+n;if(s=Wh(e,t,a)){for(r||(r=this.children.slice());io&&e.to=t){this.children[s]==t&&(n=this.children[s+2]);break}let i=t+1,o=i+e.content.size;for(let s=0;si&&t.type instanceof Ph){let e=Math.max(i,t.from)-i,n=Math.min(o,t.to)-i;en.map(t,e,jh)));return Bh.from(n)}forChild(t,e){if(e.isLeaf)return Fh.empty;let n=[];for(let r=0;rn&&o.to{let a=Wh(t,e,s+n);if(a){o=!0;let t=Jh(a,e,n+s+1,r);t!=Lh&&i.push(s,s+e.nodeSize,t)}}));let s=Vh(o?qh(t):t,-n).sort(Kh);for(let a=0;a0;)e++;t.splice(e,0,n)}function Yh(t){let e=[];return t.someProp("decorations",(n=>{let r=n(t.state);r&&r!=Lh&&e.push(r)})),t.cursorWrapper&&e.push(Fh.create(t.state.doc,[t.cursorWrapper.deco])),Bh.from(e)}const Gh={childList:!0,characterData:!0,characterDataOldValue:!0,attributes:!0,attributeOldValue:!0,subtree:!0},Zh=fd&&hd<=11;class Xh{constructor(){this.anchorNode=null,this.anchorOffset=0,this.focusNode=null,this.focusOffset=0}set(t){this.anchorNode=t.anchorNode,this.anchorOffset=t.anchorOffset,this.focusNode=t.focusNode,this.focusOffset=t.focusOffset}clear(){this.anchorNode=this.focusNode=null}eq(t){return t.anchorNode==this.anchorNode&&t.anchorOffset==this.anchorOffset&&t.focusNode==this.focusNode&&t.focusOffset==this.focusOffset}}class Qh{constructor(t,e){this.view=t,this.handleDOMChange=e,this.queue=[],this.flushingSoon=-1,this.observer=null,this.currentSelection=new Xh,this.onCharData=null,this.suppressingSelectionUpdates=!1,this.observer=window.MutationObserver&&new window.MutationObserver((t=>{for(let e=0;e"childList"==t.type&&t.removedNodes.length||"characterData"==t.type&&t.oldValue.length>t.target.nodeValue.length))?this.flushSoon():this.flush()})),Zh&&(this.onCharData=t=>{this.queue.push({target:t.target,type:"characterData",oldValue:t.prevValue}),this.flushSoon()}),this.onSelectionChange=this.onSelectionChange.bind(this)}flushSoon(){this.flushingSoon<0&&(this.flushingSoon=window.setTimeout((()=>{this.flushingSoon=-1,this.flush()}),20))}forceFlush(){this.flushingSoon>-1&&(window.clearTimeout(this.flushingSoon),this.flushingSoon=-1,this.flush())}start(){this.observer&&(this.observer.takeRecords(),this.observer.observe(this.view.dom,Gh)),this.onCharData&&this.view.dom.addEventListener("DOMCharacterDataModified",this.onCharData),this.connectSelection()}stop(){if(this.observer){let t=this.observer.takeRecords();if(t.length){for(let e=0;ethis.flush()),20)}this.observer.disconnect()}this.onCharData&&this.view.dom.removeEventListener("DOMCharacterDataModified",this.onCharData),this.disconnectSelection()}connectSelection(){this.view.dom.ownerDocument.addEventListener("selectionchange",this.onSelectionChange)}disconnectSelection(){this.view.dom.ownerDocument.removeEventListener("selectionchange",this.onSelectionChange)}suppressSelectionUpdates(){this.suppressingSelectionUpdates=!0,setTimeout((()=>this.suppressingSelectionUpdates=!1),50)}onSelectionChange(){if(If(this.view)){if(this.suppressingSelectionUpdates)return Cf(this.view);if(fd&&hd<=11&&!this.view.state.selection.empty){let t=this.view.domSelection();if(t.focusNode&&$d(t.focusNode,t.focusOffset,t.anchorNode,t.anchorOffset))return this.flushSoon()}this.flush()}}setCurSelection(){this.currentSelection.set(this.view.domSelection())}ignoreSelectionChange(t){if(0==t.rangeCount)return!0;let e=t.getRangeAt(0).commonAncestorContainer,n=this.view.docView.nearestDesc(e);return n&&n.ignoreMutation({type:"selection",target:3==e.nodeType?e.parentNode:e})?(this.setCurSelection(),!0):void 0}flush(){if(!this.view.docView||this.flushingSoon>-1)return;let t=this.observer?this.observer.takeRecords():[];this.queue.length&&(t=this.queue.concat(t),this.queue.length=0);let e=this.view.domSelection(),n=!this.suppressingSelectionUpdates&&!this.currentSelection.eq(e)&&If(this.view)&&!this.ignoreSelectionChange(e),r=-1,i=-1,o=!1,s=[];if(this.view.editable)for(let a=0;a1){let t=s.filter((t=>"BR"==t.nodeName));if(2==t.length){let e=t[0],n=t[1];e.parentNode&&e.parentNode.parentNode==n.parentNode?n.remove():e.remove()}}(r>-1||n)&&(r>-1&&(this.view.docView.markDirty(r,i),function(t){if(tp)return;tp=!0,"normal"==getComputedStyle(t.dom).whiteSpace&&console.warn("ProseMirror expects the CSS white-space property to be set, preferably to 'pre-wrap'. It is recommended to load style/prosemirror.css from the prosemirror-view package.")}(this.view)),this.handleDOMChange(r,i,o,s),this.view.docView&&this.view.docView.dirty?this.view.updateState(this.view.state):this.currentSelection.eq(e)||Cf(this.view),this.currentSelection.set(e))}registerMutation(t,e){if(e.indexOf(t.target)>-1)return null;let n=this.view.docView.nearestDesc(t.target);if("attributes"==t.type&&(n==this.view.docView||"contenteditable"==t.attributeName||"style"==t.attributeName&&!t.oldValue&&!t.target.getAttribute("style")))return null;if(!n||n.ignoreMutation(t))return null;if("childList"==t.type){for(let n=0;nDate.now()-50?t.input.lastSelectionOrigin:null,n=_f(t,e);if(n&&!t.state.selection.eq(n)){let r=t.state.tr.setSelection(n);"pointer"==e?r.setMeta("pointer",!0):"key"==e&&r.scrollIntoView(),t.dispatch(r)}return}let o=t.state.doc.resolve(e),s=o.sharedDepth(n);e=o.before(s+1),n=t.state.doc.resolve(n).after(s+1);let a=t.state.selection,l=function(t,e,n){let r,{node:i,fromOffset:o,toOffset:s,from:a,to:l}=t.docView.parseRange(e,n),c=t.domSelection(),u=c.anchorNode;if(u&&t.dom.contains(1==u.nodeType?u:u.parentNode)&&(r=[{node:u,offset:c.anchorOffset}],Ed(c)||r.push({node:c.focusNode,offset:c.focusOffset})),gd&&8===t.input.lastKeyCode)for(let g=s;g>o;g--){let t=i.childNodes[g-1],e=t.pmViewDesc;if("BR"==t.nodeName&&!e){s=g;break}if(!e||e.size)break}let d=t.state.doc,f=t.someProp("domParser")||Jc.fromSchema(t.state.schema),h=d.resolve(a),p=null,m=f.parse(i,{topNode:h.parent,topMatch:h.parent.contentMatchAt(h.index()),topOpen:!0,from:o,to:s,preserveWhitespace:"pre"!=h.parent.type.whitespace||"full",findPositions:r,ruleFromNode:ep,context:h});if(r&&null!=r[0].pos){let t=r[0].pos,e=r[1]&&r[1].pos;null==e&&(e=t),p={anchor:t+a,head:e+a}}return{doc:m,sel:p,from:a,to:l}}(t,e,n);if(gd&&t.cursorWrapper&&l.sel&&l.sel.anchor==t.cursorWrapper.deco.from&&l.sel.head==l.sel.anchor){let e=t.cursorWrapper.deco.type.toDOM.nextSibling,n=e&&e.nodeValue?e.nodeValue.length:1;l.sel={anchor:l.sel.anchor+n,head:l.sel.anchor+n}}let c,u,d=t.state.doc,f=d.slice(l.from,l.to);8===t.input.lastKeyCode&&Date.now()-100=s?o-r:0,a=o+(a-s),s=o}else if(a=a?o-r:0,s=o+(s-a),a=o}return{start:o,endA:s,endB:a}}(f.content,l.doc.content,l.from,c,u);if((bd&&t.input.lastIOSEnter>Date.now()-225||xd)&&i.some((t=>"DIV"==t.nodeName||"P"==t.nodeName))&&(!h||h.endA>=h.endB)&&t.someProp("handleKeyDown",(e=>e(t,Pd(13,"Enter")))))return void(t.input.lastIOSEnter=0);if(!h){if(!(r&&a instanceof Bu&&!a.empty&&a.$head.sameParent(a.$anchor))||t.composing||l.sel&&l.sel.anchor!=l.sel.head){if(l.sel){let e=rp(t,t.state.doc,l.sel);e&&!e.eq(t.state.selection)&&t.dispatch(t.state.tr.setSelection(e))}return}h={start:a.from,endA:a.to,endB:a.to}}t.input.domChangeCount++,t.state.selection.fromt.state.selection.from&&h.start<=t.state.selection.from+2&&t.state.selection.from>=l.from?h.start=t.state.selection.from:h.endA=t.state.selection.to-2&&t.state.selection.to<=l.to&&(h.endB+=t.state.selection.to-h.endA,h.endA=t.state.selection.to)),fd&&hd<=11&&h.endB==h.start+1&&h.endA==h.start&&h.start>l.from&&"  "==l.doc.textBetween(h.start-l.from-1,h.start-l.from+1)&&(h.start--,h.endA--,h.endB--);let p,m=l.doc.resolveNoCache(h.start-l.from),g=l.doc.resolveNoCache(h.endB-l.from),v=d.resolve(h.start),y=m.sameParent(g)&&m.parent.inlineContent&&v.end()>=h.endA;if((bd&&t.input.lastIOSEnter>Date.now()-225&&(!y||i.some((t=>"DIV"==t.nodeName||"P"==t.nodeName)))||!y&&m.pose(t,Pd(13,"Enter")))))return void(t.input.lastIOSEnter=0);if(t.state.selection.anchor>h.start&&function(t,e,n,r,i){if(!r.parent.isTextblock||n-e<=i.pos-r.pos||ip(r,!0,!1)n||ip(s,!0,!1)e(t,Pd(8,"Backspace")))))return void(xd&&gd&&t.domObserver.suppressSelectionUpdates());gd&&xd&&h.endB==h.start&&(t.input.lastAndroidDelete=Date.now()),xd&&!y&&m.start()!=g.start()&&0==g.parentOffset&&m.depth==g.depth&&l.sel&&l.sel.anchor==l.sel.head&&l.sel.head==h.endA&&(h.endB-=2,g=l.doc.resolveNoCache(h.endB-l.from),setTimeout((()=>{t.someProp("handleKeyDown",(function(e){return e(t,Pd(13,"Enter"))}))}),20));let b,w,x,S=h.start,k=h.endA;if(y)if(m.pos==g.pos)fd&&hd<=11&&0==m.parentOffset&&(t.domObserver.suppressSelectionUpdates(),setTimeout((()=>Cf(t)),20)),b=t.state.tr.delete(S,k),w=d.resolve(h.start).marksAcross(d.resolve(h.endA));else if(h.endA==h.endB&&(x=function(t,e){let n,r,i,o=t.firstChild.marks,s=e.firstChild.marks,a=o,l=s;for(let u=0;ut.mark(r.addToSet(t.marks));else{if(0!=a.length||1!=l.length)return null;r=l[0],n="remove",i=t=>t.mark(r.removeFromSet(t.marks))}let c=[];for(let u=0;un(t,S,k,e))))return;b=t.state.tr.insertText(e,S,k)}if(b||(b=t.state.tr.replace(S,k,l.doc.slice(h.start-l.from,h.endB-l.from))),l.sel){let e=rp(t,b.doc,l.sel);e&&!(gd&&xd&&t.composing&&e.empty&&(h.start!=h.endB||t.input.lastAndroidDeletee.content.size?null:Pf(t,e.resolve(n.anchor),e.resolve(n.head))}function ip(t,e,n){let r=t.depth,i=e?t.end():t.pos;for(;r>0&&(e||t.indexAfter(r)==t.node(r).childCount);)r--,i++,e=!1;if(n){let e=t.node(r).maybeChild(t.indexAfter(r));for(;e&&!e.isLeaf;)e=e.firstChild,i++}return i}class op{constructor(t,e){this._root=null,this.focused=!1,this.trackWrites=null,this.mounted=!1,this.markCursor=null,this.cursorWrapper=null,this.lastSelectedViewDesc=void 0,this.input=new ch,this.prevDirectPlugins=[],this.pluginViews=[],this.dragging=null,this._props=e,this.state=e.state,this.directPlugins=e.plugins||[],this.directPlugins.forEach(up),this.dispatch=this.dispatch.bind(this),this.dom=t&&t.mount||document.createElement("div"),t&&(t.appendChild?t.appendChild(this.dom):"function"==typeof t?t(this.dom):t.mount&&(this.mounted=!0)),this.editable=lp(this),ap(this),this.nodeViews=cp(this),this.docView=cf(this.state.doc,sp(this),Yh(this),this.dom,this),this.domObserver=new Qh(this,((t,e,n,r)=>np(this,t,e,n,r))),this.domObserver.start(),function(t){for(let e in ah){let n=ah[e];t.dom.addEventListener(e,t.input.eventHandlers[e]=e=>{!hh(t,e)||fh(t,e)||!t.editable&&e.type in lh||n(t,e)})}yd&&t.dom.addEventListener("input",(()=>null)),dh(t)}(this),this.updatePluginViews()}get composing(){return this.input.composing}get props(){if(this._props.state!=this.state){let t=this._props;this._props={};for(let e in t)this._props[e]=t[e];this._props.state=this.state}return this._props}update(t){t.handleDOMEvents!=this._props.handleDOMEvents&&dh(this),this._props=t,t.plugins&&(t.plugins.forEach(up),this.directPlugins=t.plugins),this.updateStateInner(t.state,!0)}setProps(t){let e={};for(let n in this._props)e[n]=this._props[n];e.state=this.state;for(let n in t)e[n]=t[n];this.update(e)}updateState(t){this.updateStateInner(t,this.state.plugins!=t.plugins)}updateStateInner(t,e){let n=this.state,r=!1,i=!1;if(t.storedMarks&&this.composing&&(Mh(this),i=!0),this.state=t,e){let t=cp(this);(function(t,e){let n=0,r=0;for(let i in t){if(t[i]!=e[i])return!0;n++}for(let i in e)r++;return n!=r})(t,this.nodeViews)&&(this.nodeViews=t,r=!0),dh(this)}this.editable=lp(this),ap(this);let o=Yh(this),s=sp(this),a=e?"reset":t.scrollToSelection>n.scrollToSelection?"to selection":"preserve",l=r||!this.docView.matchesNode(t.doc,s,o);!l&&t.selection.eq(n.selection)||(i=!0);let c="preserve"==a&&i&&null==this.dom.style.overflowAnchor&&function(t){let e,n,r=t.dom.getBoundingClientRect(),i=Math.max(0,r.top);for(let o=(r.left+r.right)/2,s=i+1;s=i-20){e=r,n=a.top;break}}return{refDOM:e,refTop:n,stack:Fd(t.dom)}}(this);if(i){this.domObserver.stop();let e=l&&(fd||gd)&&!this.composing&&!n.selection.empty&&!t.selection.empty&&function(t,e){let n=Math.min(t.$anchor.sharedDepth(t.head),e.$anchor.sharedDepth(e.head));return t.$anchor.start(n)!=e.$anchor.start(n)}(n.selection,t.selection);if(l){let n=gd?this.trackWrites=this.domSelection().focusNode:null;!r&&this.docView.update(t.doc,s,o,this)||(this.docView.updateOuterDeco([]),this.docView.destroy(),this.docView=cf(t.doc,s,o,this.dom,this)),n&&!this.trackWrites&&(e=!0)}e||!(this.input.mouseDown&&this.domObserver.currentSelection.eq(this.domSelection())&&function(t){let e=t.docView.domFromPos(t.state.selection.anchor,0),n=t.domSelection();return $d(e.node,e.offset,n.anchorNode,n.anchorOffset)}(this))?Cf(this,e):(Af(this,t.selection),this.domObserver.setCurSelection()),this.domObserver.start()}if(this.updatePluginViews(n),"reset"==a)this.dom.scrollTop=0;else if("to selection"==a){let e=this.domSelection().focusNode;if(this.someProp("handleScrollToSelection",(t=>t(this))));else if(t.selection instanceof Wu){let n=this.docView.domAfterPos(t.selection.from);1==n.nodeType&&jd(this,n.getBoundingClientRect(),e)}else jd(this,this.coordsAtPos(t.selection.head,1),e)}else c&&function({refDOM:t,refTop:e,stack:n}){let r=t?t.getBoundingClientRect().top:0;Ld(n,0==r?0:r-e)}(c)}destroyPluginViews(){let t;for(;t=this.pluginViews.pop();)t.destroy&&t.destroy()}updatePluginViews(t){if(t&&t.plugins==this.state.plugins&&this.directPlugins==this.prevDirectPlugins)for(let e=0;ee.ownerDocument.getSelection()),this._root=e;return t||document}posAtCoords(t){return Jd(this,t)}coordsAtPos(t,e=1){return Ud(this,t,e)}domAtPos(t,e=0){return this.docView.domFromPos(t,e)}nodeDOM(t){let e=this.docView.descAt(t);return e?e.nodeDOM:null}posAtDOM(t,e,n=-1){let r=this.docView.posFromDOM(t,e,n);if(null==r)throw new RangeError("DOM position not inside the editor");return r}endOfTextblock(t,e){return nf(this,e||this.state,t)}destroy(){this.docView&&(!function(t){t.domObserver.stop();for(let e in t.input.eventHandlers)t.dom.removeEventListener(e,t.input.eventHandlers[e]);clearTimeout(t.input.composingTimeout),clearTimeout(t.input.lastIOSEnterFallbackTimeout)}(this),this.destroyPluginViews(),this.mounted?(this.docView.update(this.state.doc,[],Yh(this),this),this.dom.textContent=""):this.dom.parentNode&&this.dom.parentNode.removeChild(this.dom),this.docView.destroy(),this.docView=null)}get isDestroyed(){return null==this.docView}dispatchEvent(t){return function(t,e){fh(t,e)||!ah[e.type]||!t.editable&&e.type in lh||ah[e.type](t,e)}(this,t)}dispatch(t){let e=this._props.dispatchTransaction;e?e.call(this,t):this.updateState(this.state.apply(t))}domSelection(){return this.root.getSelection()}}function sp(t){let e=Object.create(null);return e.class="ProseMirror",e.contenteditable=String(t.editable),e.translate="no",t.someProp("attributes",(n=>{if("function"==typeof n&&(n=n(t.state)),n)for(let t in n)"class"==t&&(e.class+=" "+n[t]),"style"==t?e.style=(e.style?e.style+";":"")+n[t]:e[t]||"contenteditable"==t||"nodeName"==t||(e[t]=String(n[t]))})),[Rh.node(0,t.state.doc.content.size,e)]}function ap(t){if(t.markCursor){let e=document.createElement("img");e.className="ProseMirror-separator",e.setAttribute("mark-placeholder","true"),e.setAttribute("alt",""),t.cursorWrapper={dom:e,deco:Rh.widget(t.state.selection.head,e,{raw:!0,marks:t.markCursor})}}else t.cursorWrapper=null}function lp(t){return!t.someProp("editable",(e=>!1===e(t.state)))}function cp(t){let e=Object.create(null);function n(t){for(let n in t)Object.prototype.hasOwnProperty.call(e,n)||(e[n]=t[n])}return t.someProp("nodeViews",n),t.someProp("markViews",n),e}function up(t){if(t.spec.state||t.spec.filterTransaction||t.spec.appendTransaction)throw new RangeError("Plugins passed directly to the view must not have a state component")}for(var dp={8:"Backspace",9:"Tab",10:"Enter",12:"NumLock",13:"Enter",16:"Shift",17:"Control",18:"Alt",20:"CapsLock",27:"Escape",32:" ",33:"PageUp",34:"PageDown",35:"End",36:"Home",37:"ArrowLeft",38:"ArrowUp",39:"ArrowRight",40:"ArrowDown",44:"PrintScreen",45:"Insert",46:"Delete",59:";",61:"=",91:"Meta",92:"Meta",106:"*",107:"+",108:",",109:"-",110:".",111:"/",144:"NumLock",145:"ScrollLock",160:"Shift",161:"Shift",162:"Control",163:"Control",164:"Alt",165:"Alt",173:"-",186:";",187:"=",188:",",189:"-",190:".",191:"/",192:"`",219:"[",220:"\\",221:"]",222:"'",229:"q"},fp={48:")",49:"!",50:"@",51:"#",52:"$",53:"%",54:"^",55:"&",56:"*",57:"(",59:":",61:"+",173:"_",186:":",187:"+",188:"<",189:"_",190:">",191:"?",192:"~",219:"{",220:"|",221:"}",222:'"',229:"Q"},hp="undefined"!=typeof navigator&&/Chrome\/(\d+)/.exec(navigator.userAgent),pp="undefined"!=typeof navigator&&/Apple Computer/.test(navigator.vendor),mp="undefined"!=typeof navigator&&/Gecko\/\d+/.test(navigator.userAgent),gp="undefined"!=typeof navigator&&/Mac/.test(navigator.platform),vp="undefined"!=typeof navigator&&/MSIE \d|Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(navigator.userAgent),yp=hp&&(gp||+hp[1]<57)||mp&&gp,bp=0;bp<10;bp++)dp[48+bp]=dp[96+bp]=String(bp);for(bp=1;bp<=24;bp++)dp[bp+111]="F"+bp;for(bp=65;bp<=90;bp++)dp[bp]=String.fromCharCode(bp+32),fp[bp]=String.fromCharCode(bp);for(var wp in dp)fp.hasOwnProperty(wp)||(fp[wp]=dp[wp]);const xp="undefined"!=typeof navigator&&/Mac|iP(hone|[oa]d)/.test(navigator.platform);function Sp(t){let e,n,r,i,o=t.split(/-(?!$)/),s=o[o.length-1];"Space"==s&&(s=" ");for(let a=0;a127)&&(r=dp[n.keyCode])&&r!=i){let i=e[kp(r,n,!0)];if(i&&i(t.state,t.dispatch,t))return!0}else if(o&&n.shiftKey){let r=e[kp(i,n,!0)];if(r&&r(t.state,t.dispatch,t))return!0}return!1}}const Mp=(t,e)=>!t.selection.empty&&(e&&e(t.tr.deleteSelection().scrollIntoView()),!0);function Cp(t,e,n=!1){for(let r=t;r;r="start"==e?r.firstChild:r.lastChild){if(r.isTextblock)return!0;if(n&&1!=r.childCount)return!1}return!1}function $p(t){if(!t.parent.type.spec.isolating)for(let e=t.depth-1;e>=0;e--){if(t.index(e)>0)return t.doc.resolve(t.before(e+1));if(t.node(e).type.spec.isolating)break}return null}function Tp(t){if(!t.parent.type.spec.isolating)for(let e=t.depth-1;e>=0;e--){let n=t.node(e);if(t.index(e)+1{let{$head:n,$anchor:r}=t.selection;if(!n.parent.type.spec.code||!n.sameParent(r))return!1;let i=n.node(-1),o=n.indexAfter(-1),s=Dp(i.contentMatchAt(o));if(!s||!i.canReplaceWith(o,o,s))return!1;if(e){let r=n.after(),i=t.tr.replaceWith(r,r,s.createAndFill());i.setSelection(zu.near(i.doc.resolve(r),1)),e(i.scrollIntoView())}return!0};function Ap(t,e,n){let r,i,o=e.nodeBefore,s=e.nodeAfter;if(o.type.spec.isolating||s.type.spec.isolating)return!1;if(function(t,e,n){let r=e.nodeBefore,i=e.nodeAfter,o=e.index();return!(!(r&&i&&r.type.compatibleContent(i.type))||(!r.content.size&&e.parent.canReplace(o-1,o)?(n&&n(t.tr.delete(e.pos-r.nodeSize,e.pos).scrollIntoView()),0):!e.parent.canReplace(o,o+1)||!i.isTextblock&&!ku(t.doc,e.pos)||(n&&n(t.tr.clearIncompatible(e.pos,r.type,r.contentMatchAt(r.childCount)).join(e.pos).scrollIntoView()),0)))}(t,e,n))return!0;let a=e.parent.canReplace(e.index(),e.index()+1);if(a&&(r=(i=o.contentMatchAt(o.childCount)).findWrapping(s.type))&&i.matchType(r[0]||s.type).validEnd){if(n){let i=e.pos+s.nodeSize,a=ec.empty;for(let t=r.length-1;t>=0;t--)a=ec.from(r[t].create(null,a));a=ec.from(o.copy(a));let l=t.tr.step(new gu(e.pos-1,i,e.pos,i,new ac(a,1,0),r.length,!0)),c=i+2*r.length;ku(l.doc,c)&&l.join(c),n(l.scrollIntoView())}return!0}let l=zu.findFrom(e,1),c=l&&l.$from.blockRange(l.$to),u=c&&bu(c);if(null!=u&&u>=e.depth)return n&&n(t.tr.lift(c,u).scrollIntoView()),!0;if(a&&Cp(s,"start",!0)&&Cp(o,"end")){let r=o,i=[];for(;i.push(r),!r.isTextblock;)r=r.lastChild;let a=s,l=1;for(;!a.isTextblock;a=a.firstChild)l++;if(r.canReplace(r.childCount,r.childCount,a.content)){if(n){let r=ec.empty;for(let t=i.length-1;t>=0;t--)r=ec.from(i[t].copy(r));n(t.tr.step(new gu(e.pos-i.length,e.pos+s.nodeSize,e.pos+l,e.pos+s.nodeSize-l,new ac(r,i.length,0),0,!0)).scrollIntoView())}return!0}}return!1}function Ep(t){return function(e,n){let r=e.selection,i=t<0?r.$from:r.$to,o=i.depth;for(;i.node(o).isInline;){if(!o)return!1;o--}return!!i.node(o).isTextblock&&(n&&n(e.tr.setSelection(Bu.create(e.doc,t<0?i.start(o):i.end(o)))),!0)}}const Pp=Ep(-1),Ip=Ep(1);function Rp(t,e=null){return function(n,r){let{from:i,to:o}=n.selection,s=!1;return n.doc.nodesBetween(i,o,((r,i)=>{if(s)return!1;if(r.isTextblock&&!r.hasMarkup(t,e))if(r.type==t)s=!0;else{let e=n.doc.resolve(i),r=e.index();s=e.parent.canReplaceWith(r,r+1,t)}})),!!s&&(r&&r(n.tr.setBlockType(i,o,t,e).scrollIntoView()),!0)}}function zp(t,e=null){return function(n,r){let{empty:i,$cursor:o,ranges:s}=n.selection;if(i&&!o||!function(t,e,n){for(let r=0;r{if(s)return!1;s=t.inlineContent&&t.type.allowsMarkType(n)})),s)return!0}return!1}(n.doc,s,t))return!1;if(r)if(o)t.isInSet(n.storedMarks||o.marks())?r(n.tr.removeStoredMark(t)):r(n.tr.addStoredMark(t.create(e)));else{let i=!1,o=n.tr;for(let e=0;!i&&e{let{$cursor:r}=t.selection;if(!r||(n?!n.endOfTextblock("backward",t):r.parentOffset>0))return!1;let i=$p(r);if(!i){let n=r.blockRange(),i=n&&bu(n);return null!=i&&(e&&e(t.tr.lift(n,i).scrollIntoView()),!0)}let o=i.nodeBefore;if(!o.type.spec.isolating&&Ap(t,i,e))return!0;if(0==r.parent.content.size&&(Cp(o,"end")||Wu.isSelectable(o))){let n=Ou(t.doc,r.before(),r.after(),ac.empty);if(n&&n.slice.size{let{$head:r,empty:i}=t.selection,o=r;if(!i)return!1;if(r.parent.isTextblock){if(n?!n.endOfTextblock("backward",t):r.parentOffset>0)return!1;o=$p(r)}let s=o&&o.nodeBefore;return!(!s||!Wu.isSelectable(s))&&(e&&e(t.tr.setSelection(Wu.create(t.doc,o.pos-s.nodeSize)).scrollIntoView()),!0)})),Lp=jp(Mp,((t,e,n)=>{let{$cursor:r}=t.selection;if(!r||(n?!n.endOfTextblock("forward",t):r.parentOffset{let{$head:r,empty:i}=t.selection,o=r;if(!i)return!1;if(r.parent.isTextblock){if(n?!n.endOfTextblock("forward",t):r.parentOffset{let{$head:n,$anchor:r}=t.selection;return!(!n.parent.type.spec.code||!n.sameParent(r))&&(e&&e(t.tr.insertText("\n").scrollIntoView()),!0)}),((t,e)=>{let n=t.selection,{$from:r,$to:i}=n;if(n instanceof Ju||r.parent.inlineContent||i.parent.inlineContent)return!1;let o=Dp(i.parent.contentMatchAt(i.indexAfter()));if(!o||!o.isTextblock)return!1;if(e){let n=(!r.parentOffset&&i.index(){let{$cursor:n}=t.selection;if(!n||n.parent.content.size)return!1;if(n.depth>1&&n.after()!=n.end(-1)){let r=n.before();if(Su(t.doc,r))return e&&e(t.tr.split(r).scrollIntoView()),!0}let r=n.blockRange(),i=r&&bu(r);return null!=i&&(e&&e(t.tr.lift(r,i).scrollIntoView()),!0)}),((t,e)=>{let{$from:n,$to:r}=t.selection;if(t.selection instanceof Wu&&t.selection.node.isBlock)return!(!n.parentOffset||!Su(t.doc,n.pos))&&(e&&e(t.tr.split(n.pos).scrollIntoView()),!0);if(!n.parent.isBlock)return!1;if(e){let i=r.parentOffset==r.parent.content.size,o=t.tr;(t.selection instanceof Bu||t.selection instanceof Ju)&&o.deleteSelection();let s=0==n.depth?null:Dp(n.node(-1).contentMatchAt(n.indexAfter(-1))),a=i&&s?[{type:s}]:void 0,l=Su(o.doc,o.mapping.map(n.pos),1,a);if(a||l||!Su(o.doc,o.mapping.map(n.pos),1,s?[{type:s}]:void 0)||(s&&(a=[{type:s}]),l=!0),l&&(o.split(o.mapping.map(n.pos),1,a),!i&&!n.parentOffset&&n.parent.type!=s)){let t=o.mapping.map(n.before()),e=o.doc.resolve(t);s&&n.node(-1).canReplaceWith(e.index(),e.index()+1,s)&&o.setNodeMarkup(o.mapping.map(n.before()),s)}e(o.scrollIntoView())}return!0})),"Mod-Enter":Np,Backspace:Fp,"Mod-Backspace":Fp,"Shift-Backspace":Fp,Delete:Lp,"Mod-Delete":Lp,"Mod-a":(t,e)=>(e&&e(t.tr.setSelection(new Ju(t.doc))),!0)},Vp={"Ctrl-h":Bp.Backspace,"Alt-Backspace":Bp["Mod-Backspace"],"Ctrl-d":Bp.Delete,"Ctrl-Alt-Backspace":Bp["Mod-Delete"],"Alt-Delete":Bp["Mod-Delete"],"Alt-d":Bp["Mod-Delete"],"Ctrl-a":Pp,"Ctrl-e":Ip};for(let os in Bp)Vp[os]=Bp[os];const Wp=("undefined"!=typeof navigator?/Mac|iP(hone|[oa]d)/.test(navigator.platform):!("undefined"==typeof os||!os.platform)&&"darwin"==os.platform())?Vp:Bp;class qp{constructor(t,e){var n;this.match=t,this.match=t,this.handler="string"==typeof e?(n=e,function(t,e,r,i){let o=n;if(e[1]){let t=e[0].lastIndexOf(e[1]);o+=e[0].slice(t+e[1].length);let n=(r+=t)-i;n>0&&(o=e[0].slice(t-n,t)+o,r=i)}return t.tr.insertText(o,r,i)}):e}}function Jp({rules:t}){let e=new nd({state:{init:()=>null,apply(t,e){let n=t.getMeta(this);return n||(t.selectionSet||t.docChanged?null:e)}},props:{handleTextInput:(n,r,i,o)=>Kp(n,r,i,o,t,e),handleDOMEvents:{compositionend:n=>{setTimeout((()=>{let{$cursor:r}=n.state.selection;r&&Kp(n,r.pos,r.pos,"",t,e)}))}}},isInputRules:!0});return e}function Kp(t,e,n,r,i,o){if(t.composing)return!1;let s=t.state,a=s.doc.resolve(e);if(a.parent.type.spec.code)return!1;let l=a.parent.textBetween(Math.max(0,a.parentOffset-500),a.parentOffset,null,"")+r;for(let c=0;c{let n=t.plugins;for(let r=0;r=0;t--)n.step(r.steps[t].invert(r.docs[t]));if(i.text){let e=n.doc.resolve(i.from).marks();n.replaceWith(i.from,i.to,t.schema.text(i.text,e))}else n.delete(i.from,i.to);e(n)}return!0}}return!1};function Up(t,e,n=null,r){return new qp(t,((t,i,o,s)=>{let a=n instanceof Function?n(i):n,l=t.tr.delete(o,s),c=l.doc.resolve(o).blockRange(),u=c&&wu(c,e,a);if(!u)return null;l.wrap(c,u);let d=l.doc.resolve(o-1).nodeBefore;return d&&d.type==e&&ku(l.doc,o-1)&&(!r||r(i,d))&&l.join(o-1),l}))}function Yp(t,e,n=null){return new qp(t,((t,r,i,o)=>{let s=t.doc.resolve(i),a=n instanceof Function?n(r):n;return s.node(-1).canReplaceWith(s.index(-1),s.indexAfter(-1),e)?t.tr.delete(i,o).setBlockType(i,i,e,a):null}))}new qp(/--$/,"—"),new qp(/\.\.\.$/,"…"),new qp(/(?:^|[\s\{\[\(\<'"\u2018\u201C])(")$/,"“"),new qp(/"$/,"”"),new qp(/(?:^|[\s\{\[\(\<'"\u2018\u201C])(')$/,"‘"),new qp(/'$/,"’");const Gp=["ol",0],Zp=["ul",0],Xp=["li",0],Qp={attrs:{order:{default:1}},parseDOM:[{tag:"ol",getAttrs:t=>({order:t.hasAttribute("start")?+t.getAttribute("start"):1})}],toDOM:t=>1==t.attrs.order?Gp:["ol",{start:t.attrs.order},0]},tm={parseDOM:[{tag:"ul"}],toDOM:()=>Zp},em={parseDOM:[{tag:"li"}],toDOM:()=>Xp,defining:!0};function nm(t,e){let n={};for(let r in t)n[r]=t[r];for(let r in e)n[r]=e[r];return n}function rm(t,e,n){return t.append({ordered_list:nm(Qp,{content:"list_item+",group:n}),bullet_list:nm(tm,{content:"list_item+",group:n}),list_item:nm(em,{content:e})})}function im(t,e=null){return function(n,r){let{$from:i,$to:o}=n.selection,s=i.blockRange(o),a=!1,l=s;if(!s)return!1;if(s.depth>=2&&i.node(s.depth-1).type.compatibleContent(t)&&0==s.startIndex){if(0==i.index(s.depth-1))return!1;let t=n.doc.resolve(s.start-2);l=new kc(t,t,s.depth),s.endIndex=0;u--)o=ec.from(n[u].type.create(n[u].attrs,o));t.step(new gu(e.start-(r?2:0),e.end,e.start,e.end,new ac(o,0,0),n.length,!0));let s=0;for(let u=0;u=r.depth-3;t--)i=ec.from(r.node(t).copy(i));let s=r.indexAfter(-1){if(c>-1)return!1;t.isTextblock&&0==t.content.size&&(c=e+1)})),c>-1&&l.setSelection(zu.near(l.doc.resolve(c))),n(l.scrollIntoView())}return!0}let a=i.pos==r.end()?s.contentMatchAt(0).defaultType:null,l=e.tr.delete(r.pos,i.pos),c=a?[null,{type:a}]:void 0;return!!Su(l.doc,r.pos,2,c)&&(n&&n(l.split(r.pos,2,c).scrollIntoView()),!0)}}function sm(t){return function(e,n){let{$from:r,$to:i}=e.selection,o=r.blockRange(i,(e=>e.childCount>0&&e.firstChild.type==t));return!!o&&(!n||(r.node(o.depth-1).type==t?function(t,e,n,r){let i=t.tr,o=r.end,s=r.$to.end(r.depth);om;p--)h-=i.child(p).nodeSize,r.delete(h-1,h+1);let o=r.doc.resolve(n.start),s=o.nodeAfter;if(r.mapping.map(n.end)!=n.start+o.nodeAfter.nodeSize)return!1;let a=0==n.startIndex,l=n.endIndex==i.childCount,c=o.node(-1),u=o.index(-1);if(!c.canReplace(u+(a?0:1),u+1,s.content.append(l?ec.empty:ec.from(i))))return!1;let d=o.pos,f=d+s.nodeSize;return r.step(new gu(d-(a?1:0),f+(l?1:0),d+1,f-1,new ac((a?ec.empty:ec.from(i.copy(ec.empty))).append(l?ec.empty:ec.from(i.copy(ec.empty))),a?0:1,l?0:1),a?0:1)),e(r.scrollIntoView()),!0}(e,n,o)))}}function am(t){return function(e,n){let{$from:r,$to:i}=e.selection,o=r.blockRange(i,(e=>e.childCount>0&&e.firstChild.type==t));if(!o)return!1;let s=o.startIndex;if(0==s)return!1;let a=o.parent,l=a.child(s-1);if(l.type!=t)return!1;if(n){let r=l.lastChild&&l.lastChild.type==a.type,i=ec.from(r?t.create():null),s=new ac(ec.from(t.create(null,ec.from(a.type.create(null,i)))),r?3:1,0),c=o.start,u=o.end;n(e.tr.step(new gu(c-(r?3:1),u,c,u,s,1,!0)).scrollIntoView())}return!0}}var lm=function(){};lm.prototype.append=function(t){return t.length?(t=lm.from(t),!this.length&&t||t.length<200&&this.leafAppend(t)||this.length<200&&t.leafPrepend(this)||this.appendInner(t)):this},lm.prototype.prepend=function(t){return t.length?lm.from(t).append(this):this},lm.prototype.appendInner=function(t){return new um(this,t)},lm.prototype.slice=function(t,e){return void 0===t&&(t=0),void 0===e&&(e=this.length),t>=e?lm.empty:this.sliceInner(Math.max(0,t),Math.min(this.length,e))},lm.prototype.get=function(t){if(!(t<0||t>=this.length))return this.getInner(t)},lm.prototype.forEach=function(t,e,n){void 0===e&&(e=0),void 0===n&&(n=this.length),e<=n?this.forEachInner(t,e,n,0):this.forEachInvertedInner(t,e,n,0)},lm.prototype.map=function(t,e,n){void 0===e&&(e=0),void 0===n&&(n=this.length);var r=[];return this.forEach((function(e,n){return r.push(t(e,n))}),e,n),r},lm.from=function(t){return t instanceof lm?t:t&&t.length?new cm(t):lm.empty};var cm=function(t){function e(e){t.call(this),this.values=e}t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e;var n={length:{configurable:!0},depth:{configurable:!0}};return e.prototype.flatten=function(){return this.values},e.prototype.sliceInner=function(t,n){return 0==t&&n==this.length?this:new e(this.values.slice(t,n))},e.prototype.getInner=function(t){return this.values[t]},e.prototype.forEachInner=function(t,e,n,r){for(var i=e;i=n;i--)if(!1===t(this.values[i],r+i))return!1},e.prototype.leafAppend=function(t){if(this.length+t.length<=200)return new e(this.values.concat(t.flatten()))},e.prototype.leafPrepend=function(t){if(this.length+t.length<=200)return new e(t.flatten().concat(this.values))},n.length.get=function(){return this.values.length},n.depth.get=function(){return 0},Object.defineProperties(e.prototype,n),e}(lm);lm.empty=new cm([]);var um=function(t){function e(e,n){t.call(this),this.left=e,this.right=n,this.length=e.length+n.length,this.depth=Math.max(e.depth,n.depth)+1}return t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e,e.prototype.flatten=function(){return this.left.flatten().concat(this.right.flatten())},e.prototype.getInner=function(t){return ti&&!1===this.right.forEachInner(t,Math.max(e-i,0),Math.min(this.length,n)-i,r+i))&&void 0)},e.prototype.forEachInvertedInner=function(t,e,n,r){var i=this.left.length;return!(e>i&&!1===this.right.forEachInvertedInner(t,e-i,Math.max(n,i)-i,r+i))&&(!(n=n?this.right.slice(t-n,e-n):this.left.slice(t,n).append(this.right.slice(0,e-n))},e.prototype.leafAppend=function(t){var n=this.right.leafAppend(t);if(n)return new e(this.left,n)},e.prototype.leafPrepend=function(t){var n=this.left.leafPrepend(t);if(n)return new e(n,this.right)},e.prototype.appendInner=function(t){return this.left.depth>=Math.max(this.right.depth,t.depth)+1?new e(this.left,new e(this.right,t)):new e(this,t)},e}(lm),dm=lm;class fm{constructor(t,e){this.items=t,this.eventCount=e}popEvent(t,e){if(0==this.eventCount)return null;let n,r,i=this.items.length;for(;;i--){if(this.items.get(i-1).selection){--i;break}}e&&(n=this.remapping(i,this.items.length),r=n.maps.length);let o,s,a=t.tr,l=[],c=[];return this.items.forEach(((t,e)=>{if(!t.step)return n||(n=this.remapping(i,e+1),r=n.maps.length),r--,void c.push(t);if(n){c.push(new hm(t.map));let e,i=t.step.map(n.slice(r));i&&a.maybeStep(i).doc&&(e=a.mapping.maps[a.mapping.maps.length-1],l.push(new hm(e,void 0,void 0,l.length+c.length))),r--,e&&n.appendMap(e,r)}else a.maybeStep(t.step);return t.selection?(o=n?t.selection.map(n.slice(r)):t.selection,s=new fm(this.items.slice(0,i).append(c.reverse().concat(l)),this.eventCount-1),!1):void 0}),this.items.length,0),{remaining:s,transform:a,selection:o}}addTransform(t,e,n,r){let i=[],o=this.eventCount,s=this.items,a=!r&&s.length?s.get(s.length-1):null;for(let c=0;cmm&&(s=function(t,e){let n;return t.forEach(((t,r)=>{if(t.selection&&0==e--)return n=r,!1})),t.slice(n)}(s,l),o-=l),new fm(s.append(i),o)}remapping(t,e){let n=new lu;return this.items.forEach(((e,r)=>{let i=null!=e.mirrorOffset&&r-e.mirrorOffset>=t?n.maps.length-e.mirrorOffset:void 0;n.appendMap(e.map,i)}),t,e),n}addMaps(t){return 0==this.eventCount?this:new fm(this.items.append(t.map((t=>new hm(t)))),this.eventCount)}rebased(t,e){if(!this.eventCount)return this;let n=[],r=Math.max(0,this.items.length-e),i=t.mapping,o=t.steps.length,s=this.eventCount;this.items.forEach((t=>{t.selection&&s--}),r);let a=e;this.items.forEach((e=>{let r=i.getMirror(--a);if(null==r)return;o=Math.min(o,r);let l=i.maps[r];if(e.step){let o=t.steps[r].invert(t.docs[r]),c=e.selection&&e.selection.map(i.slice(a+1,r));c&&s++,n.push(new hm(l,o,c))}else n.push(new hm(l))}),r);let l=[];for(let d=e;d500&&(u=u.compress(this.items.length-n.length)),u}emptyItemCount(){let t=0;return this.items.forEach((e=>{e.step||t++})),t}compress(t=this.items.length){let e=this.remapping(0,t),n=e.maps.length,r=[],i=0;return this.items.forEach(((o,s)=>{if(s>=t)r.push(o),o.selection&&i++;else if(o.step){let t=o.step.map(e.slice(n)),s=t&&t.getMap();if(n--,s&&e.appendMap(s,n),t){let a=o.selection&&o.selection.map(e.slice(n));a&&i++;let l,c=new hm(s.invert(),t,a),u=r.length-1;(l=r.length&&r[u].merge(c))?r[u]=l:r.push(c)}}else o.map&&n--}),this.items.length,0),new fm(dm.from(r.reverse()),i)}}fm.empty=new fm(dm.empty,0);class hm{constructor(t,e,n,r){this.map=t,this.step=e,this.selection=n,this.mirrorOffset=r}merge(t){if(this.step&&t.step&&!t.selection){let e=t.step.merge(this.step);if(e)return new hm(e.getMap().invert(),e,this.selection)}}}class pm{constructor(t,e,n,r){this.done=t,this.undone=e,this.prevRanges=n,this.prevTime=r}}const mm=20;function gm(t){let e=[];return t.forEach(((t,n,r,i)=>e.push(r,i))),e}function vm(t,e){if(!t)return null;let n=[];for(let r=0;rnew pm(fm.empty,fm.empty,null,0),apply:(e,n,r)=>function(t,e,n,r){let i,o=n.getMeta(Sm);if(o)return o.historyState;n.getMeta(km)&&(t=new pm(t.done,t.undone,null,0));let s=n.getMeta("appendedTransaction");if(0==n.steps.length)return t;if(s&&s.getMeta(Sm))return s.getMeta(Sm).redo?new pm(t.done.addTransform(n,void 0,r,xm(e)),t.undone,gm(n.mapping.maps[n.steps.length-1]),t.prevTime):new pm(t.done,t.undone.addTransform(n,void 0,r,xm(e)),null,t.prevTime);if(!1===n.getMeta("addToHistory")||s&&!1===s.getMeta("addToHistory"))return(i=n.getMeta("rebased"))?new pm(t.done.rebased(n,i),t.undone.rebased(n,i),vm(t.prevRanges,n.mapping),t.prevTime):new pm(t.done.addMaps(n.mapping.maps),t.undone.addMaps(n.mapping.maps),vm(t.prevRanges,n.mapping),t.prevTime);{let i=0==t.prevTime||!s&&(t.prevTime<(n.time||0)-r.newGroupDelay||!function(t,e){if(!e)return!1;if(!t.docChanged)return!0;let n=!1;return t.mapping.maps[0].forEach(((t,r)=>{for(let i=0;i=e[i]&&(n=!0)})),n}(n,t.prevRanges)),o=s?vm(t.prevRanges,n.mapping):gm(n.mapping.maps[n.steps.length-1]);return new pm(t.done.addTransform(n,i?e.selection.getBookmark():void 0,r,xm(e)),fm.empty,o,n.time)}}(n,r,e,t)},config:t,props:{handleDOMEvents:{beforeinput(t,e){let n=e.inputType,r="historyUndo"==n?_m:"historyRedo"==n?Mm:null;return!!r&&(e.preventDefault(),r(t.state,t.dispatch))}}}})}const _m=(t,e)=>{let n=Sm.getState(t);return!(!n||0==n.done.eventCount)&&(e&&ym(n,t,e,!1),!0)},Mm=(t,e)=>{let n=Sm.getState(t);return!(!n||0==n.undone.eventCount)&&(e&&ym(n,t,e,!0),!0)};function Cm(t){let e=Sm.getState(t);return e?e.done.eventCount:0}function $m(t){let e=Sm.getState(t);return e?e.undone.eventCount:0}var Tm={},Dm={},Nm={},Am={};Object.defineProperty(Am,"__esModule",{value:!0}),Am.default=void 0;var Em=Ll.withParams;Am.default=Em,function(t){Object.defineProperty(t,"__esModule",{value:!0}),t.req=t.regex=t.ref=t.len=void 0,Object.defineProperty(t,"withParams",{enumerable:!0,get:function(){return n.default}});var e,n=(e=Am)&&e.__esModule?e:{default:e};function r(t){return(r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}var i=function(t){if(Array.isArray(t))return!!t.length;if(null==t)return!1;if(!1===t)return!0;if(t instanceof Date)return!isNaN(t.getTime());if("object"===r(t)){for(var e in t)return!0;return!1}return!!String(t).length};t.req=i;t.len=function(t){return Array.isArray(t)?t.length:"object"===r(t)?Object.keys(t).length:String(t).length};t.ref=function(t,e,n){return"function"==typeof t?t.call(e,n):n[t]};t.regex=function(t,e){return(0,n.default)({type:t},(function(t){return!i(t)||e.test(t)}))}}(Nm),Object.defineProperty(Dm,"__esModule",{value:!0}),Dm.default=void 0;var Pm=(0,Nm.regex)("alpha",/^[a-zA-Z]*$/);Dm.default=Pm;var Im={};Object.defineProperty(Im,"__esModule",{value:!0}),Im.default=void 0;var Rm=(0,Nm.regex)("alphaNum",/^[a-zA-Z0-9]*$/);Im.default=Rm;var zm={};Object.defineProperty(zm,"__esModule",{value:!0}),zm.default=void 0;var jm=(0,Nm.regex)("numeric",/^[0-9]*$/);zm.default=jm;var Fm={};Object.defineProperty(Fm,"__esModule",{value:!0}),Fm.default=void 0;var Lm=Nm;Fm.default=function(t,e){return(0,Lm.withParams)({type:"between",min:t,max:e},(function(n){return!(0,Lm.req)(n)||(!/\s/.test(n)||n instanceof Date)&&+t<=+n&&+e>=+n}))};var Bm={};Object.defineProperty(Bm,"__esModule",{value:!0}),Bm.default=void 0;var Vm=(0,Nm.regex)("email",/^(?:[A-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[A-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9]{2,}(?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])$/i);Bm.default=Vm;var Wm={};Object.defineProperty(Wm,"__esModule",{value:!0}),Wm.default=void 0;var qm=Nm,Jm=(0,qm.withParams)({type:"ipAddress"},(function(t){if(!(0,qm.req)(t))return!0;if("string"!=typeof t)return!1;var e=t.split(".");return 4===e.length&&e.every(Km)}));Wm.default=Jm;var Km=function(t){if(t.length>3||0===t.length)return!1;if("0"===t[0]&&"0"!==t)return!1;if(!t.match(/^\d+$/))return!1;var e=0|+t;return e>=0&&e<=255},Hm={};Object.defineProperty(Hm,"__esModule",{value:!0}),Hm.default=void 0;var Um=Nm;Hm.default=function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:":";return(0,Um.withParams)({type:"macAddress"},(function(e){if(!(0,Um.req)(e))return!0;if("string"!=typeof e)return!1;var n="string"==typeof t&&""!==t?e.split(t):12===e.length||16===e.length?e.match(/.{2}/g):null;return null!==n&&(6===n.length||8===n.length)&&n.every(Ym)}))};var Ym=function(t){return t.toLowerCase().match(/^[0-9a-f]{2}$/)},Gm={};Object.defineProperty(Gm,"__esModule",{value:!0}),Gm.default=void 0;var Zm=Nm;Gm.default=function(t){return(0,Zm.withParams)({type:"maxLength",max:t},(function(e){return!(0,Zm.req)(e)||(0,Zm.len)(e)<=t}))};var Xm={};Object.defineProperty(Xm,"__esModule",{value:!0}),Xm.default=void 0;var Qm=Nm;Xm.default=function(t){return(0,Qm.withParams)({type:"minLength",min:t},(function(e){return!(0,Qm.req)(e)||(0,Qm.len)(e)>=t}))};var tg={};Object.defineProperty(tg,"__esModule",{value:!0}),tg.default=void 0;var eg=Nm,ng=(0,eg.withParams)({type:"required"},(function(t){return(0,eg.req)("string"==typeof t?t.trim():t)}));tg.default=ng;var rg={};Object.defineProperty(rg,"__esModule",{value:!0}),rg.default=void 0;var ig=Nm;rg.default=function(t){return(0,ig.withParams)({type:"requiredIf",prop:t},(function(e,n){return!(0,ig.ref)(t,this,n)||(0,ig.req)(e)}))};var og={};Object.defineProperty(og,"__esModule",{value:!0}),og.default=void 0;var sg=Nm;og.default=function(t){return(0,sg.withParams)({type:"requiredUnless",prop:t},(function(e,n){return!!(0,sg.ref)(t,this,n)||(0,sg.req)(e)}))};var ag={};Object.defineProperty(ag,"__esModule",{value:!0}),ag.default=void 0;var lg=Nm;ag.default=function(t){return(0,lg.withParams)({type:"sameAs",eq:t},(function(e,n){return e===(0,lg.ref)(t,this,n)}))};var cg={};Object.defineProperty(cg,"__esModule",{value:!0}),cg.default=void 0;var ug=(0,Nm.regex)("url",/^(?:(?:(?:https?|ftp):)?\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z0-9\u00a1-\uffff][a-z0-9\u00a1-\uffff_-]{0,62})?[a-z0-9\u00a1-\uffff]\.)+(?:[a-z\u00a1-\uffff]{2,}\.?))(?::\d{2,5})?(?:[/?#]\S*)?$/i);cg.default=ug;var dg={};Object.defineProperty(dg,"__esModule",{value:!0}),dg.default=void 0;var fg=Nm;dg.default=function(){for(var t=arguments.length,e=new Array(t),n=0;n0&&e.reduce((function(e,n){return e||n.apply(t,r)}),!1)}))};var hg={};Object.defineProperty(hg,"__esModule",{value:!0}),hg.default=void 0;var pg=Nm;hg.default=function(){for(var t=arguments.length,e=new Array(t),n=0;n0&&e.reduce((function(e,n){return e&&n.apply(t,r)}),!0)}))};var mg={};Object.defineProperty(mg,"__esModule",{value:!0}),mg.default=void 0;var gg=Nm;mg.default=function(t){return(0,gg.withParams)({type:"not"},(function(e,n){return!(0,gg.req)(e)||!t.call(this,e,n)}))};var vg={};Object.defineProperty(vg,"__esModule",{value:!0}),vg.default=void 0;var yg=Nm;vg.default=function(t){return(0,yg.withParams)({type:"minValue",min:t},(function(e){return!(0,yg.req)(e)||(!/\s/.test(e)||e instanceof Date)&&+e>=+t}))};var bg={};Object.defineProperty(bg,"__esModule",{value:!0}),bg.default=void 0;var wg=Nm;bg.default=function(t){return(0,wg.withParams)({type:"maxValue",max:t},(function(e){return!(0,wg.req)(e)||(!/\s/.test(e)||e instanceof Date)&&+e<=+t}))};var xg={};Object.defineProperty(xg,"__esModule",{value:!0}),xg.default=void 0;var Sg=(0,Nm.regex)("integer",/(^[0-9]*$)|(^-[0-9]+$)/);xg.default=Sg;var kg={};Object.defineProperty(kg,"__esModule",{value:!0}),kg.default=void 0;var Og=(0,Nm.regex)("decimal",/^[-]?\d*(\.\d+)?$/);kg.default=Og,function(t){function e(t){return(e="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"alpha",{enumerable:!0,get:function(){return n.default}}),Object.defineProperty(t,"alphaNum",{enumerable:!0,get:function(){return r.default}}),Object.defineProperty(t,"and",{enumerable:!0,get:function(){return v.default}}),Object.defineProperty(t,"between",{enumerable:!0,get:function(){return o.default}}),Object.defineProperty(t,"decimal",{enumerable:!0,get:function(){return S.default}}),Object.defineProperty(t,"email",{enumerable:!0,get:function(){return s.default}}),t.helpers=void 0,Object.defineProperty(t,"integer",{enumerable:!0,get:function(){return x.default}}),Object.defineProperty(t,"ipAddress",{enumerable:!0,get:function(){return a.default}}),Object.defineProperty(t,"macAddress",{enumerable:!0,get:function(){return l.default}}),Object.defineProperty(t,"maxLength",{enumerable:!0,get:function(){return c.default}}),Object.defineProperty(t,"maxValue",{enumerable:!0,get:function(){return w.default}}),Object.defineProperty(t,"minLength",{enumerable:!0,get:function(){return u.default}}),Object.defineProperty(t,"minValue",{enumerable:!0,get:function(){return b.default}}),Object.defineProperty(t,"not",{enumerable:!0,get:function(){return y.default}}),Object.defineProperty(t,"numeric",{enumerable:!0,get:function(){return i.default}}),Object.defineProperty(t,"or",{enumerable:!0,get:function(){return g.default}}),Object.defineProperty(t,"required",{enumerable:!0,get:function(){return d.default}}),Object.defineProperty(t,"requiredIf",{enumerable:!0,get:function(){return f.default}}),Object.defineProperty(t,"requiredUnless",{enumerable:!0,get:function(){return h.default}}),Object.defineProperty(t,"sameAs",{enumerable:!0,get:function(){return p.default}}),Object.defineProperty(t,"url",{enumerable:!0,get:function(){return m.default}});var n=_(Dm),r=_(Im),i=_(zm),o=_(Fm),s=_(Bm),a=_(Wm),l=_(Hm),c=_(Gm),u=_(Xm),d=_(tg),f=_(rg),h=_(og),p=_(ag),m=_(cg),g=_(dg),v=_(hg),y=_(mg),b=_(vg),w=_(bg),x=_(xg),S=_(kg),k=function(t,n){if(!n&&t&&t.__esModule)return t;if(null===t||"object"!==e(t)&&"function"!=typeof t)return{default:t};var r=O(n);if(r&&r.has(t))return r.get(t);var i={},o=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var s in t)if("default"!==s&&Object.prototype.hasOwnProperty.call(t,s)){var a=o?Object.getOwnPropertyDescriptor(t,s):null;a&&(a.get||a.set)?Object.defineProperty(i,s,a):i[s]=t[s]}i.default=t,r&&r.set(t,i);return i}(Nm);function O(t){if("function"!=typeof WeakMap)return null;var e=new WeakMap,n=new WeakMap;return(O=function(t){return t?n:e})(t)}function _(t){return t&&t.__esModule?t:{default:t}}t.helpers=k}(Tm);export{$m as A,Om as B,Tm as C,Jc as D,td as E,ec as F,Tl as G,Zl as H,qp as I,Wu as N,nd as P,ac as S,Bu as T,Wn as V,ll as a,vl as b,Sl as c,wl as d,jp as e,Np as f,Up as g,Yp as h,rm as i,om as j,am as k,sm as l,cl as m,Op as n,Wc as o,Jp as p,op as q,eu as r,Rp as s,zp as t,Hp as u,Wp as v,im as w,_m as x,Mm as y,Cm as z}; diff --git a/kirby/panel/dist/js/vendor.min.js b/kirby/panel/dist/js/vendor.min.js deleted file mode 100644 index 97565ee..0000000 --- a/kirby/panel/dist/js/vendor.min.js +++ /dev/null @@ -1,16 +0,0 @@ -"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self&&self;function e(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}var t={},n={},r={},i={},o={};function s(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function l(e){for(var t=1;t=+n}))};var M={};Object.defineProperty(M,"__esModule",{value:!0}),M.default=void 0;var O=(0,r.regex)("email",/^(?:[A-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[A-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9]{2,}(?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])$/i);M.default=O;var C={};Object.defineProperty(C,"__esModule",{value:!0}),C.default=void 0;var N=r,D=(0,N.withParams)({type:"ipAddress"},(function(e){if(!(0,N.req)(e))return!0;if("string"!=typeof e)return!1;var t=e.split(".");return 4===t.length&&t.every(T)}));C.default=D;var T=function(e){if(e.length>3||0===e.length)return!1;if("0"===e[0]&&"0"!==e)return!1;if(!e.match(/^\d+$/))return!1;var t=0|+e;return t>=0&&t<=255},A={};Object.defineProperty(A,"__esModule",{value:!0}),A.default=void 0;var E=r;A.default=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:":";return(0,E.withParams)({type:"macAddress"},(function(t){if(!(0,E.req)(t))return!0;if("string"!=typeof t)return!1;var n="string"==typeof e&&""!==e?t.split(e):12===t.length||16===t.length?t.match(/.{2}/g):null;return null!==n&&(6===n.length||8===n.length)&&n.every($)}))};var $=function(e){return e.toLowerCase().match(/^[0-9a-f]{2}$/)},P={};Object.defineProperty(P,"__esModule",{value:!0}),P.default=void 0;var I=r;P.default=function(e){return(0,I.withParams)({type:"maxLength",max:e},(function(t){return!(0,I.req)(t)||(0,I.len)(t)<=e}))};var R={};Object.defineProperty(R,"__esModule",{value:!0}),R.default=void 0;var z=r;R.default=function(e){return(0,z.withParams)({type:"minLength",min:e},(function(t){return!(0,z.req)(t)||(0,z.len)(t)>=e}))};var _={};Object.defineProperty(_,"__esModule",{value:!0}),_.default=void 0;var B=r,V=(0,B.withParams)({type:"required"},(function(e){return(0,B.req)("string"==typeof e?e.trim():e)}));_.default=V;var j={};Object.defineProperty(j,"__esModule",{value:!0}),j.default=void 0;var F=r;j.default=function(e){return(0,F.withParams)({type:"requiredIf",prop:e},(function(t,n){return!(0,F.ref)(e,this,n)||(0,F.req)(t)}))};var L={};Object.defineProperty(L,"__esModule",{value:!0}),L.default=void 0;var q=r;L.default=function(e){return(0,q.withParams)({type:"requiredUnless",prop:e},(function(t,n){return!!(0,q.ref)(e,this,n)||(0,q.req)(t)}))};var W={};Object.defineProperty(W,"__esModule",{value:!0}),W.default=void 0;var J=r;W.default=function(e){return(0,J.withParams)({type:"sameAs",eq:e},(function(t,n){return t===(0,J.ref)(e,this,n)}))};var K={};Object.defineProperty(K,"__esModule",{value:!0}),K.default=void 0;var H=(0,r.regex)("url",/^(?:(?:(?:https?|ftp):)?\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z0-9\u00a1-\uffff][a-z0-9\u00a1-\uffff_-]{0,62})?[a-z0-9\u00a1-\uffff]\.)+(?:[a-z\u00a1-\uffff]{2,}\.?))(?::\d{2,5})?(?:[/?#]\S*)?$/i);K.default=H;var Y={};Object.defineProperty(Y,"__esModule",{value:!0}),Y.default=void 0;var U=r;Y.default=function(){for(var e=arguments.length,t=new Array(e),n=0;n0&&t.reduce((function(t,n){return t||n.apply(e,r)}),!1)}))};var G={};Object.defineProperty(G,"__esModule",{value:!0}),G.default=void 0;var Z=r;G.default=function(){for(var e=arguments.length,t=new Array(e),n=0;n0&&t.reduce((function(t,n){return t&&n.apply(e,r)}),!0)}))};var X={};Object.defineProperty(X,"__esModule",{value:!0}),X.default=void 0;var Q=r;X.default=function(e){return(0,Q.withParams)({type:"not"},(function(t,n){return!(0,Q.req)(t)||!e.call(this,t,n)}))};var ee={};Object.defineProperty(ee,"__esModule",{value:!0}),ee.default=void 0;var te=r;ee.default=function(e){return(0,te.withParams)({type:"minValue",min:e},(function(t){return!(0,te.req)(t)||(!/\s/.test(t)||t instanceof Date)&&+t>=+e}))};var ne={};Object.defineProperty(ne,"__esModule",{value:!0}),ne.default=void 0;var re=r;ne.default=function(e){return(0,re.withParams)({type:"maxValue",max:e},(function(t){return!(0,re.req)(t)||(!/\s/.test(t)||t instanceof Date)&&+t<=+e}))};var ie={};Object.defineProperty(ie,"__esModule",{value:!0}),ie.default=void 0;var oe=(0,r.regex)("integer",/(^[0-9]*$)|(^-[0-9]+$)/);ie.default=oe;var se={};Object.defineProperty(se,"__esModule",{value:!0}),se.default=void 0;var le=(0,r.regex)("decimal",/^[-]?\d*(\.\d+)?$/);function ae(e){this.content=e}function ce(e,t,n){for(let r=0;;r++){if(r==e.childCount||r==t.childCount)return e.childCount==t.childCount?null:n;let i=e.child(r),o=t.child(r);if(i!=o){if(!i.sameMarkup(o))return n;if(i.isText&&i.text!=o.text){for(let e=0;i.text[e]==o.text[e];e++)n++;return n}if(i.content.size||o.content.size){let e=ce(i.content,o.content,n+1);if(null!=e)return e}n+=i.nodeSize}else n+=i.nodeSize}}function he(e,t,n,r){for(let i=e.childCount,o=t.childCount;;){if(0==i||0==o)return i==o?null:{a:n,b:r};let s=e.child(--i),l=t.child(--o),a=s.nodeSize;if(s!=l){if(!s.sameMarkup(l))return{a:n,b:r};if(s.isText&&s.text!=l.text){let e=0,t=Math.min(s.text.length,l.text.length);for(;e>1}},ae.from=function(e){if(e instanceof ae)return e;var t=[];if(e)for(var n in e)t.push(n,e[n]);return new ae(t)};class ue{constructor(e,t){if(this.content=e,this.size=t||0,null==t)for(let n=0;ne&&!1!==n(l,r+s,i||null,o)&&l.content.size){let i=s+1;l.nodesBetween(Math.max(0,e-i),Math.min(l.content.size,t-i),n,r+i)}s=a}}descendants(e){this.nodesBetween(0,this.size,e)}textBetween(e,t,n,r){let i="",o=!0;return this.nodesBetween(e,t,((s,l)=>{let a=s.isText?s.text.slice(Math.max(e,l)-l,t-l):s.isLeaf?r?"function"==typeof r?r(s):r:s.type.spec.leafText?s.type.spec.leafText(s):"":"";s.isBlock&&(s.isLeaf&&a||s.isTextblock)&&n&&(o?o=!1:i+=n),i+=a}),0),i}append(e){if(!e.size)return this;if(!this.size)return e;let t=this.lastChild,n=e.firstChild,r=this.content.slice(),i=0;for(t.isText&&t.sameMarkup(n)&&(r[r.length-1]=t.withText(t.text+n.text),i=1);ie)for(let i=0,o=0;oe&&((ot)&&(s=s.isText?s.cut(Math.max(0,e-o),Math.min(s.text.length,t-o)):s.cut(Math.max(0,e-o-1),Math.min(s.content.size,t-o-1))),n.push(s),r+=s.nodeSize),o=l}return new ue(n,r)}cutByIndex(e,t){return e==t?ue.empty:0==e&&t==this.content.length?this:new ue(this.content.slice(e,t))}replaceChild(e,t){let n=this.content[e];if(n==t)return this;let r=this.content.slice(),i=this.size+t.nodeSize-n.nodeSize;return r[e]=t,new ue(r,i)}addToStart(e){return new ue([e].concat(this.content),this.size+e.nodeSize)}addToEnd(e){return new ue(this.content.concat(e),this.size+e.nodeSize)}eq(e){if(this.content.length!=e.content.length)return!1;for(let t=0;tthis.size||e<0)throw new RangeError(`Position ${e} outside of fragment (${this})`);for(let n=0,r=0;;n++){let i=r+this.child(n).nodeSize;if(i>=e)return i==e||t>0?fe(n+1,i):fe(n,r);r=i}}toString(){return"<"+this.toStringInner()+">"}toStringInner(){return this.content.join(", ")}toJSON(){return this.content.length?this.content.map((e=>e.toJSON())):null}static fromJSON(e,t){if(!t)return ue.empty;if(!Array.isArray(t))throw new RangeError("Invalid input for Fragment.fromJSON");return new ue(t.map(e.nodeFromJSON))}static fromArray(e){if(!e.length)return ue.empty;let t,n=0;for(let r=0;rthis.type.rank&&(t||(t=e.slice(0,r)),t.push(this),n=!0),t&&t.push(i)}}return t||(t=e.slice()),n||t.push(this),t}removeFromSet(e){for(let t=0;te.type.rank-t.type.rank)),t}}me.none=[];class ge extends Error{}class ye{constructor(e,t,n){this.content=e,this.openStart=t,this.openEnd=n}get size(){return this.content.size-this.openStart-this.openEnd}insertAt(e,t){let n=we(this.content,e+this.openStart,t);return n&&new ye(n,this.openStart,this.openEnd)}removeBetween(e,t){return new ye(ve(this.content,e+this.openStart,t+this.openStart),this.openStart,this.openEnd)}eq(e){return this.content.eq(e.content)&&this.openStart==e.openStart&&this.openEnd==e.openEnd}toString(){return this.content+"("+this.openStart+","+this.openEnd+")"}toJSON(){if(!this.content.size)return null;let e={content:this.content.toJSON()};return this.openStart>0&&(e.openStart=this.openStart),this.openEnd>0&&(e.openEnd=this.openEnd),e}static fromJSON(e,t){if(!t)return ye.empty;let n=t.openStart||0,r=t.openEnd||0;if("number"!=typeof n||"number"!=typeof r)throw new RangeError("Invalid input for Slice.fromJSON");return new ye(ue.fromJSON(e,t.content),n,r)}static maxOpen(e,t=!0){let n=0,r=0;for(let i=e.firstChild;i&&!i.isLeaf&&(t||!i.type.spec.isolating);i=i.firstChild)n++;for(let i=e.lastChild;i&&!i.isLeaf&&(t||!i.type.spec.isolating);i=i.lastChild)r++;return new ye(e,n,r)}}function ve(e,t,n){let{index:r,offset:i}=e.findIndex(t),o=e.maybeChild(r),{index:s,offset:l}=e.findIndex(n);if(i==t||o.isText){if(l!=n&&!e.child(s).isText)throw new RangeError("Removing non-flat range");return e.cut(0,t).append(e.cut(n))}if(r!=s)throw new RangeError("Removing non-flat range");return e.replaceChild(r,o.copy(ve(o.content,t-i-1,n-i-1)))}function we(e,t,n,r){let{index:i,offset:o}=e.findIndex(t),s=e.maybeChild(i);if(o==t||s.isText)return r&&!r.canReplace(i,i,n)?null:e.cut(0,t).append(n).append(e.cut(t));let l=we(s.content,t-o-1,n);return l&&e.replaceChild(i,s.copy(l))}function be(e,t,n){if(n.openStart>e.depth)throw new ge("Inserted content deeper than insertion position");if(e.depth-n.openStart!=t.depth-n.openEnd)throw new ge("Inconsistent open depths");return xe(e,t,n,0)}function xe(e,t,n,r){let i=e.index(r),o=e.node(r);if(i==t.index(r)&&r=0;i--)r=t.node(i).copy(ue.from(r));return{start:r.resolveNoCache(e.openStart+n),end:r.resolveNoCache(r.content.size-e.openEnd-n)}}(n,e);return Ce(o,Ne(e,i,s,t,r))}{let r=e.parent,i=r.content;return Ce(r,i.cut(0,e.parentOffset).append(n.content).append(i.cut(t.parentOffset)))}}return Ce(o,De(e,t,r))}function Se(e,t){if(!t.type.compatibleContent(e.type))throw new ge("Cannot join "+t.type.name+" onto "+e.type.name)}function ke(e,t,n){let r=e.node(n);return Se(r,t.node(n)),r}function Me(e,t){let n=t.length-1;n>=0&&e.isText&&e.sameMarkup(t[n])?t[n]=e.withText(t[n].text+e.text):t.push(e)}function Oe(e,t,n,r){let i=(t||e).node(n),o=0,s=t?t.index(n):i.childCount;e&&(o=e.index(n),e.depth>n?o++:e.textOffset&&(Me(e.nodeAfter,r),o++));for(let l=o;li&&ke(e,t,i+1),s=r.depth>i&&ke(n,r,i+1),l=[];return Oe(null,e,i,l),o&&s&&t.index(i)==n.index(i)?(Se(o,s),Me(Ce(o,Ne(e,t,n,r,i+1)),l)):(o&&Me(Ce(o,De(e,t,i+1)),l),Oe(t,n,i,l),s&&Me(Ce(s,De(n,r,i+1)),l)),Oe(r,null,i,l),new ue(l)}function De(e,t,n){let r=[];if(Oe(null,e,n,r),e.depth>n){Me(Ce(ke(e,t,n+1),De(e,t,n+1)),r)}return Oe(t,null,n,r),new ue(r)}ye.empty=new ye(ue.empty,0,0);class Te{constructor(e,t,n){this.pos=e,this.path=t,this.parentOffset=n,this.depth=t.length/3-1}resolveDepth(e){return null==e?this.depth:e<0?this.depth+e:e}get parent(){return this.node(this.depth)}get doc(){return this.node(0)}node(e){return this.path[3*this.resolveDepth(e)]}index(e){return this.path[3*this.resolveDepth(e)+1]}indexAfter(e){return e=this.resolveDepth(e),this.index(e)+(e!=this.depth||this.textOffset?1:0)}start(e){return 0==(e=this.resolveDepth(e))?0:this.path[3*e-1]+1}end(e){return e=this.resolveDepth(e),this.start(e)+this.node(e).content.size}before(e){if(!(e=this.resolveDepth(e)))throw new RangeError("There is no position before the top-level node");return e==this.depth+1?this.pos:this.path[3*e-1]}after(e){if(!(e=this.resolveDepth(e)))throw new RangeError("There is no position after the top-level node");return e==this.depth+1?this.pos:this.path[3*e-1]+this.path[3*e].nodeSize}get textOffset(){return this.pos-this.path[this.path.length-1]}get nodeAfter(){let e=this.parent,t=this.index(this.depth);if(t==e.childCount)return null;let n=this.pos-this.path[this.path.length-1],r=e.child(t);return n?e.child(t).cut(n):r}get nodeBefore(){let e=this.index(this.depth),t=this.pos-this.path[this.path.length-1];return t?this.parent.child(e).cut(0,t):0==e?null:this.parent.child(e-1)}posAtIndex(e,t){t=this.resolveDepth(t);let n=this.path[3*t],r=0==t?0:this.path[3*t-1]+1;for(let i=0;i0;t--)if(this.start(t)<=e&&this.end(t)>=e)return t;return 0}blockRange(e=this,t){if(e.pos=0;n--)if(e.pos<=this.end(n)&&(!t||t(this.node(n))))return new Pe(this,e,n);return null}sameParent(e){return this.pos-this.parentOffset==e.pos-e.parentOffset}max(e){return e.pos>this.pos?e:this}min(e){return e.pos=0&&t<=e.content.size))throw new RangeError("Position "+t+" out of range");let n=[],r=0,i=t;for(let o=e;;){let{index:e,offset:t}=o.content.findIndex(i),s=i-t;if(n.push(o,e,r+t),!s)break;if(o=o.child(e),o.isText)break;i=s-1,r+=t+1}return new Te(t,n,i)}static resolveCached(e,t){for(let r=0;re&&this.nodesBetween(e,t,(e=>(n.isInSet(e.marks)&&(r=!0),!r))),r}get isBlock(){return this.type.isBlock}get isTextblock(){return this.type.isTextblock}get inlineContent(){return this.type.inlineContent}get isInline(){return this.type.isInline}get isText(){return this.type.isText}get isLeaf(){return this.type.isLeaf}get isAtom(){return this.type.isAtom}toString(){if(this.type.spec.toDebugString)return this.type.spec.toDebugString(this);let e=this.type.name;return this.content.size&&(e+="("+this.content.toStringInner()+")"),_e(this.marks,e)}contentMatchAt(e){let t=this.type.contentMatch.matchFragment(this.content,0,e);if(!t)throw new Error("Called contentMatchAt on a node with invalid content");return t}canReplace(e,t,n=ue.empty,r=0,i=n.childCount){let o=this.contentMatchAt(e).matchFragment(n,r,i),s=o&&o.matchFragment(this.content,t);if(!s||!s.validEnd)return!1;for(let l=r;le.type.name))}`);this.content.forEach((e=>e.check()))}toJSON(){let e={type:this.type.name};for(let t in this.attrs){e.attrs=this.attrs;break}return this.content.size&&(e.content=this.content.toJSON()),this.marks.length&&(e.marks=this.marks.map((e=>e.toJSON()))),e}static fromJSON(e,t){if(!t)throw new RangeError("Invalid input for Node.fromJSON");let n=null;if(t.marks){if(!Array.isArray(t.marks))throw new RangeError("Invalid mark data for Node.fromJSON");n=t.marks.map(e.markFromJSON)}if("text"==t.type){if("string"!=typeof t.text)throw new RangeError("Invalid text node in JSON");return e.text(t.text,n)}let r=ue.fromJSON(e,t.content);return e.nodeType(t.type).create(t.attrs,r,n)}}Re.prototype.text=void 0;class ze extends Re{constructor(e,t,n,r){if(super(e,t,null,r),!n)throw new RangeError("Empty text nodes are not allowed");this.text=n}toString(){return this.type.spec.toDebugString?this.type.spec.toDebugString(this):_e(this.marks,JSON.stringify(this.text))}get textContent(){return this.text}textBetween(e,t){return this.text.slice(e,t)}get nodeSize(){return this.text.length}mark(e){return e==this.marks?this:new ze(this.type,this.attrs,this.text,e)}withText(e){return e==this.text?this:new ze(this.type,this.attrs,e,this.marks)}cut(e=0,t=this.text.length){return 0==e&&t==this.text.length?this:this.withText(this.text.slice(e,t))}eq(e){return this.sameMarkup(e)&&this.text==e.text}toJSON(){let e=super.toJSON();return e.text=this.text,e}}function _e(e,t){for(let n=e.length-1;n>=0;n--)t=e[n].type.name+"("+t+")";return t}class Be{constructor(e){this.validEnd=e,this.next=[],this.wrapCache=[]}static parse(e,t){let n=new Ve(e,t);if(null==n.next)return Be.empty;let r=je(n);n.next&&n.err("Unexpected trailing text");let i=function(e){let t=Object.create(null);return n(Ke(e,0));function n(r){let i=[];r.forEach((t=>{e[t].forEach((({term:t,to:n})=>{if(!t)return;let r;for(let e=0;e{r||i.push([t,r=[]]),-1==r.indexOf(e)&&r.push(e)}))}))}));let o=t[r.join(",")]=new Be(r.indexOf(e.length-1)>-1);for(let e=0;ee.to=t))}function o(e,t){if("choice"==e.type)return e.exprs.reduce(((e,n)=>e.concat(o(n,t))),[]);if("seq"!=e.type){if("star"==e.type){let s=n();return r(t,s),i(o(e.expr,s),s),[r(s)]}if("plus"==e.type){let s=n();return i(o(e.expr,t),s),i(o(e.expr,s),s),[r(s)]}if("opt"==e.type)return[r(t)].concat(o(e.expr,t));if("range"==e.type){let s=t;for(let t=0;te.createAndFill())));for(let e=0;e=this.next.length)throw new RangeError(`There's no ${e}th edge in this content match`);return this.next[e]}toString(){let e=[];return function t(n){e.push(n);for(let r=0;r{let r=n+(t.validEnd?"*":" ")+" ";for(let i=0;i"+e.indexOf(t.next[i].next);return r})).join("\n")}}Be.empty=new Be(!0);class Ve{constructor(e,t){this.string=e,this.nodeTypes=t,this.inline=null,this.pos=0,this.tokens=e.split(/\s*(?=\b|\W|$)/),""==this.tokens[this.tokens.length-1]&&this.tokens.pop(),""==this.tokens[0]&&this.tokens.shift()}get next(){return this.tokens[this.pos]}eat(e){return this.next==e&&(this.pos++||!0)}err(e){throw new SyntaxError(e+" (in content expression '"+this.string+"')")}}function je(e){let t=[];do{t.push(Fe(e))}while(e.eat("|"));return 1==t.length?t[0]:{type:"choice",exprs:t}}function Fe(e){let t=[];do{t.push(Le(e))}while(e.next&&")"!=e.next&&"|"!=e.next);return 1==t.length?t[0]:{type:"seq",exprs:t}}function Le(e){let t=function(e){if(e.eat("(")){let t=je(e);return e.eat(")")||e.err("Missing closing paren"),t}if(!/\W/.test(e.next)){let t=function(e,t){let n=e.nodeTypes,r=n[t];if(r)return[r];let i=[];for(let o in n){let e=n[o];e.groups.indexOf(t)>-1&&i.push(e)}0==i.length&&e.err("No node type or group '"+t+"' found");return i}(e,e.next).map((t=>(null==e.inline?e.inline=t.isInline:e.inline!=t.isInline&&e.err("Mixing inline and block content"),{type:"name",value:t})));return e.pos++,1==t.length?t[0]:{type:"choice",exprs:t}}e.err("Unexpected token '"+e.next+"'")}(e);for(;;)if(e.eat("+"))t={type:"plus",expr:t};else if(e.eat("*"))t={type:"star",expr:t};else if(e.eat("?"))t={type:"opt",expr:t};else{if(!e.eat("{"))break;t=We(e,t)}return t}function qe(e){/\D/.test(e.next)&&e.err("Expected number, got '"+e.next+"'");let t=Number(e.next);return e.pos++,t}function We(e,t){let n=qe(e),r=n;return e.eat(",")&&(r="}"!=e.next?qe(e):-1),e.eat("}")||e.err("Unclosed braced range"),{type:"range",min:n,max:r,expr:t}}function Je(e,t){return t-e}function Ke(e,t){let n=[];return function t(r){let i=e[r];if(1==i.length&&!i[0].term)return t(i[0].to);n.push(r);for(let e=0;e-1}allowsMarks(e){if(null==this.markSet)return!0;for(let t=0;tr[t]=new e(t,n,i)));let i=n.spec.topNode||"doc";if(!r[i])throw new RangeError("Schema is missing its top node type ('"+i+"')");if(!r.text)throw new RangeError("Every schema needs a 'text' type");for(let e in r.text.attrs)throw new RangeError("The text node type should not have attributes");return r}};class Ze{constructor(e){this.hasDefault=Object.prototype.hasOwnProperty.call(e,"default"),this.default=e.default}get isRequired(){return!this.hasDefault}}class Xe{constructor(e,t,n,r){this.name=e,this.rank=t,this.schema=n,this.spec=r,this.attrs=Ue(r.attrs),this.excluded=null;let i=He(this.attrs);this.instance=i?new me(this,i):null}create(e=null){return!e&&this.instance?this.instance:new me(this,Ye(this.attrs,e))}static compile(e,t){let n=Object.create(null),r=0;return e.forEach(((e,i)=>n[e]=new Xe(e,r++,t,i))),n}removeFromSet(e){for(var t=0;t-1}}class Qe{constructor(e){this.linebreakReplacement=null,this.cached=Object.create(null);let t=this.spec={};for(let r in e)t[r]=e[r];t.nodes=ae.from(e.nodes),t.marks=ae.from(e.marks||{}),this.nodes=Ge.compile(this.spec.nodes,this),this.marks=Xe.compile(this.spec.marks,this);let n=Object.create(null);for(let r in this.nodes){if(r in this.marks)throw new RangeError(r+" can not be both a node and a mark");let e=this.nodes[r],t=e.spec.content||"",i=e.spec.marks;if(e.contentMatch=n[t]||(n[t]=Be.parse(t,this.nodes)),e.inlineContent=e.contentMatch.inlineContent,e.spec.linebreakReplacement){if(this.linebreakReplacement)throw new RangeError("Multiple linebreak nodes defined");if(!e.isInline||!e.isLeaf)throw new RangeError("Linebreak replacement nodes must be inline leaf nodes");this.linebreakReplacement=e}e.markSet="_"==i?null:i?et(this,i.split(" ")):""!=i&&e.inlineContent?null:[]}for(let r in this.marks){let e=this.marks[r],t=e.spec.excludes;e.excluded=null==t?[e]:""==t?[]:et(this,t.split(" "))}this.nodeFromJSON=this.nodeFromJSON.bind(this),this.markFromJSON=this.markFromJSON.bind(this),this.topNodeType=this.nodes[this.spec.topNode||"doc"],this.cached.wrappings=Object.create(null)}node(e,t=null,n,r){if("string"==typeof e)e=this.nodeType(e);else{if(!(e instanceof Ge))throw new RangeError("Invalid node type: "+e);if(e.schema!=this)throw new RangeError("Node type from different schema used ("+e.name+")")}return e.createChecked(t,n,r)}text(e,t){let n=this.nodes.text;return new ze(n,n.defaultAttrs,e,me.setFrom(t))}mark(e,t){return"string"==typeof e&&(e=this.marks[e]),e.create(t)}nodeFromJSON(e){return Re.fromJSON(this,e)}markFromJSON(e){return me.fromJSON(this,e)}nodeType(e){let t=this.nodes[e];if(!t)throw new RangeError("Unknown node type: "+e);return t}}function et(e,t){let n=[];for(let r=0;r-1)&&n.push(s=r)}if(!s)throw new SyntaxError("Unknown mark type: '"+t[r]+"'")}return n}class tt{constructor(e,t){this.schema=e,this.rules=t,this.tags=[],this.styles=[],t.forEach((e=>{!function(e){return null!=e.tag}(e)?function(e){return null!=e.style}(e)&&this.styles.push(e):this.tags.push(e)})),this.normalizeLists=!this.tags.some((t=>{if(!/^(ul|ol)\b/.test(t.tag)||!t.node)return!1;let n=e.nodes[t.node];return n.contentMatch.matchType(n)}))}parse(e,t={}){let n=new lt(this,t,!1);return n.addAll(e,t.from,t.to),n.finish()}parseSlice(e,t={}){let n=new lt(this,t,!0);return n.addAll(e,t.from,t.to),ye.maxOpen(n.finish())}matchTag(e,t,n){for(let r=n?this.tags.indexOf(n)+1:0;re.length&&(61!=o.charCodeAt(e.length)||o.slice(e.length+1)!=t))){if(r.getAttrs){let e=r.getAttrs(t);if(!1===e)continue;r.attrs=e||void 0}return r}}}static schemaRules(e){let t=[];function n(e){let n=null==e.priority?50:e.priority,r=0;for(;r{n(e=ct(e)),e.mark||e.ignore||e.clearMark||(e.mark=r)}))}for(let r in e.nodes){let t=e.nodes[r].spec.parseDOM;t&&t.forEach((e=>{n(e=ct(e)),e.node||e.ignore||e.mark||(e.node=r)}))}return t}static fromSchema(e){return e.cached.domParser||(e.cached.domParser=new tt(e,tt.schemaRules(e)))}}const nt={address:!0,article:!0,aside:!0,blockquote:!0,canvas:!0,dd:!0,div:!0,dl:!0,fieldset:!0,figcaption:!0,figure:!0,footer:!0,form:!0,h1:!0,h2:!0,h3:!0,h4:!0,h5:!0,h6:!0,header:!0,hgroup:!0,hr:!0,li:!0,noscript:!0,ol:!0,output:!0,p:!0,pre:!0,section:!0,table:!0,tfoot:!0,ul:!0},rt={head:!0,noscript:!0,object:!0,script:!0,style:!0,title:!0},it={ol:!0,ul:!0};function ot(e,t,n){return null!=t?(t?1:0)|("full"===t?2:0):e&&"pre"==e.whitespace?3:-5&n}class st{constructor(e,t,n,r,i,o,s){this.type=e,this.attrs=t,this.marks=n,this.pendingMarks=r,this.solid=i,this.options=s,this.content=[],this.activeMarks=me.none,this.stashMarks=[],this.match=o||(4&s?null:e.contentMatch)}findWrapping(e){if(!this.match){if(!this.type)return[];let t=this.type.contentMatch.fillBefore(ue.from(e));if(!t){let t,n=this.type.contentMatch;return(t=n.findWrapping(e.type))?(this.match=n,t):null}this.match=this.type.contentMatch.matchFragment(t)}return this.match.findWrapping(e.type)}finish(e){if(!(1&this.options)){let e,t=this.content[this.content.length-1];if(t&&t.isText&&(e=/[ \t\r\n\u000c]+$/.exec(t.text))){let n=t;t.text.length==e[0].length?this.content.pop():this.content[this.content.length-1]=n.withText(n.text.slice(0,n.text.length-e[0].length))}}let t=ue.from(this.content);return!e&&this.match&&(t=t.append(this.match.fillBefore(ue.empty,!0))),this.type?this.type.create(this.attrs,t,this.marks):t}popFromStashMark(e){for(let t=this.stashMarks.length-1;t>=0;t--)if(e.eq(this.stashMarks[t]))return this.stashMarks.splice(t,1)[0]}applyPending(e){for(let t=0,n=this.pendingMarks;tthis.addAll(e))),t&&this.sync(n),this.needsBlock=o}else this.withStyleRules(e,(()=>{this.addElementByRule(e,i,!1===i.consuming?n:void 0)}))}leafFallback(e){"BR"==e.nodeName&&this.top.type&&this.top.type.inlineContent&&this.addTextNode(e.ownerDocument.createTextNode("\n"))}ignoreFallback(e){"BR"!=e.nodeName||this.top.type&&this.top.type.inlineContent||this.findPlace(this.parser.schema.text("-"))}readStyles(e){let t=me.none,n=me.none;for(let r=0;r{o.clearMark(e)&&(n=e.addToSet(n))})):t=this.parser.schema.marks[o.mark].create(o.attrs).addToSet(t),!1!==o.consuming)break;i=o}return[t,n]}addElementByRule(e,t,n){let r,i,o;if(t.node)i=this.parser.schema.nodes[t.node],i.isLeaf?this.insertNode(i.create(t.attrs))||this.leafFallback(e):r=this.enter(i,t.attrs||null,t.preserveWhitespace);else{o=this.parser.schema.marks[t.mark].create(t.attrs),this.addPendingMark(o)}let s=this.top;if(i&&i.isLeaf)this.findInside(e);else if(n)this.addElement(e,n);else if(t.getContent)this.findInside(e),t.getContent(e,this.parser.schema).forEach((e=>this.insertNode(e)));else{let n=e;"string"==typeof t.contentElement?n=e.querySelector(t.contentElement):"function"==typeof t.contentElement?n=t.contentElement(e):t.contentElement&&(n=t.contentElement),this.findAround(e,n,!0),this.addAll(n)}r&&this.sync(s)&&this.open--,o&&this.removePendingMark(o,s)}addAll(e,t,n){let r=t||0;for(let i=t?e.childNodes[t]:e.firstChild,o=null==n?null:e.childNodes[n];i!=o;i=i.nextSibling,++r)this.findAtPoint(e,r),this.addDOM(i);this.findAtPoint(e,r)}findPlace(e){let t,n;for(let r=this.open;r>=0;r--){let i=this.nodes[r],o=i.findWrapping(e);if(o&&(!t||t.length>o.length)&&(t=o,n=i,!o.length))break;if(i.solid)break}if(!t)return!1;this.sync(n);for(let r=0;rthis.open){for(;t>this.open;t--)this.nodes[t-1].content.push(this.nodes[t].finish(e));this.nodes.length=this.open+1}}finish(){return this.open=0,this.closeExtra(this.isOpen),this.nodes[0].finish(this.isOpen||this.options.topOpen)}sync(e){for(let t=this.open;t>=0;t--)if(this.nodes[t]==e)return this.open=t,!0;return!1}get currentPos(){this.closeExtra();let e=0;for(let t=this.open;t>=0;t--){let n=this.nodes[t].content;for(let t=n.length-1;t>=0;t--)e+=n[t].nodeSize;t&&e++}return e}findAtPoint(e,t){if(this.find)for(let n=0;n-1)return e.split(/\s*\|\s*/).some(this.matchesContext,this);let t=e.split("/"),n=this.options.context,r=!(this.isOpen||n&&n.parent.type!=this.nodes[0].type),i=-(n?n.depth+1:0)+(r?0:1),o=(e,s)=>{for(;e>=0;e--){let l=t[e];if(""==l){if(e==t.length-1||0==e)continue;for(;s>=i;s--)if(o(e-1,s))return!0;return!1}{let e=s>0||0==s&&r?this.nodes[s].type:n&&s>=i?n.node(s-i).type:null;if(!e||e.name!=l&&-1==e.groups.indexOf(l))return!1;s--}}return!0};return o(t.length-1,this.open)}textblockFromContext(){let e=this.options.context;if(e)for(let t=e.depth;t>=0;t--){let n=e.node(t).contentMatchAt(e.indexAfter(t)).defaultType;if(n&&n.isTextblock&&n.defaultAttrs)return n}for(let t in this.parser.schema.nodes){let e=this.parser.schema.nodes[t];if(e.isTextblock&&e.defaultAttrs)return e}}addPendingMark(e){let t=function(e,t){for(let n=0;n=0;n--){let r=this.nodes[n];if(r.pendingMarks.lastIndexOf(e)>-1)r.pendingMarks=e.removeFromSet(r.pendingMarks);else{r.activeMarks=e.removeFromSet(r.activeMarks);let t=r.popFromStashMark(e);t&&r.type&&r.type.allowsMarkType(t.type)&&(r.activeMarks=t.addToSet(r.activeMarks))}if(r==t)break}}}function at(e,t){return(e.matches||e.msMatchesSelector||e.webkitMatchesSelector||e.mozMatchesSelector).call(e,t)}function ct(e){let t={};for(let n in e)t[n]=e[n];return t}function ht(e,t){let n=t.schema.nodes;for(let r in n){let i=n[r];if(!i.allowsMarkType(e))continue;let o=[],s=e=>{o.push(e);for(let n=0;n{if(i.length||e.marks.length){let n=0,o=0;for(;n=0;r--){let i=this.serializeMark(e.marks[r],e.isInline,t);i&&((i.contentDOM||i.dom).appendChild(n),n=i.dom)}return n}serializeMark(e,t,n={}){let r=this.marks[e.type.name];return r&&ut.renderSpec(ft(n),r(e,t))}static renderSpec(e,t,n=null){if("string"==typeof t)return{dom:e.createTextNode(t)};if(null!=t.nodeType)return{dom:t};if(t.dom&&null!=t.dom.nodeType)return t;let r,i=t[0],o=i.indexOf(" ");o>0&&(n=i.slice(0,o),i=i.slice(o+1));let s=n?e.createElementNS(n,i):e.createElement(i),l=t[1],a=1;if(l&&"object"==typeof l&&null==l.nodeType&&!Array.isArray(l)){a=2;for(let e in l)if(null!=l[e]){let t=e.indexOf(" ");t>0?s.setAttributeNS(e.slice(0,t),e.slice(t+1),l[e]):s.setAttribute(e,l[e])}}for(let c=a;ca)throw new RangeError("Content hole must be the only child of its parent node");return{dom:s,contentDOM:s}}{let{dom:t,contentDOM:o}=ut.renderSpec(e,i,n);if(s.appendChild(t),o){if(r)throw new RangeError("Multiple content holes");r=o}}}return{dom:s,contentDOM:r}}static fromSchema(e){return e.cached.domSerializer||(e.cached.domSerializer=new ut(this.nodesFromSchema(e),this.marksFromSchema(e)))}static nodesFromSchema(e){let t=dt(e.nodes);return t.text||(t.text=e=>e.text),t}static marksFromSchema(e){return dt(e.marks)}}function dt(e){let t={};for(let n in e){let r=e[n].spec.toDOM;r&&(t[n]=r)}return t}function ft(e){return e.document||window.document}const pt=Math.pow(2,16);function mt(e){return 65535&e}class gt{constructor(e,t,n){this.pos=e,this.delInfo=t,this.recover=n}get deleted(){return(8&this.delInfo)>0}get deletedBefore(){return(5&this.delInfo)>0}get deletedAfter(){return(6&this.delInfo)>0}get deletedAcross(){return(4&this.delInfo)>0}}class yt{constructor(e,t=!1){if(this.ranges=e,this.inverted=t,!e.length&&yt.empty)return yt.empty}recover(e){let t=0,n=mt(e);if(!this.inverted)for(let r=0;re)break;let a=this.ranges[s+i],c=this.ranges[s+o],h=l+a;if(e<=h){let i=l+r+((a?e==l?-1:e==h?1:t:t)<0?0:c);if(n)return i;let o=e==(t<0?l:h)?null:s/3+(e-l)*pt,u=e==l?2:e==h?1:4;return(t<0?e!=l:e!=h)&&(u|=8),new gt(i,u,o)}r+=c-a}return n?e+r:new gt(e+r,0,null)}touches(e,t){let n=0,r=mt(t),i=this.inverted?2:1,o=this.inverted?1:2;for(let s=0;se)break;let l=this.ranges[s+i];if(e<=t+l&&s==3*r)return!0;n+=this.ranges[s+o]-l}return!1}forEach(e){let t=this.inverted?2:1,n=this.inverted?1:2;for(let r=0,i=0;r=0;t--){let r=e.getMirror(t);this.appendMap(e.maps[t].invert(),null!=r&&r>t?n-r-1:void 0)}}invert(){let e=new vt;return e.appendMappingInverted(this),e}map(e,t=1){if(this.mirror)return this._map(e,t,!0);for(let n=this.from;ni&&te.isAtom&&t.type.allowsMarkType(this.mark.type)?e.mark(this.mark.addToSet(e.marks)):e),r),t.openStart,t.openEnd);return xt.fromReplace(e,this.from,this.to,i)}invert(){return new Mt(this.from,this.to,this.mark)}map(e){let t=e.mapResult(this.from,1),n=e.mapResult(this.to,-1);return t.deleted&&n.deleted||t.pos>=n.pos?null:new kt(t.pos,n.pos,this.mark)}merge(e){return e instanceof kt&&e.mark.eq(this.mark)&&this.from<=e.to&&this.to>=e.from?new kt(Math.min(this.from,e.from),Math.max(this.to,e.to),this.mark):null}toJSON(){return{stepType:"addMark",mark:this.mark.toJSON(),from:this.from,to:this.to}}static fromJSON(e,t){if("number"!=typeof t.from||"number"!=typeof t.to)throw new RangeError("Invalid input for AddMarkStep.fromJSON");return new kt(t.from,t.to,e.markFromJSON(t.mark))}}bt.jsonID("addMark",kt);class Mt extends bt{constructor(e,t,n){super(),this.from=e,this.to=t,this.mark=n}apply(e){let t=e.slice(this.from,this.to),n=new ye(St(t.content,(e=>e.mark(this.mark.removeFromSet(e.marks))),e),t.openStart,t.openEnd);return xt.fromReplace(e,this.from,this.to,n)}invert(){return new kt(this.from,this.to,this.mark)}map(e){let t=e.mapResult(this.from,1),n=e.mapResult(this.to,-1);return t.deleted&&n.deleted||t.pos>=n.pos?null:new Mt(t.pos,n.pos,this.mark)}merge(e){return e instanceof Mt&&e.mark.eq(this.mark)&&this.from<=e.to&&this.to>=e.from?new Mt(Math.min(this.from,e.from),Math.max(this.to,e.to),this.mark):null}toJSON(){return{stepType:"removeMark",mark:this.mark.toJSON(),from:this.from,to:this.to}}static fromJSON(e,t){if("number"!=typeof t.from||"number"!=typeof t.to)throw new RangeError("Invalid input for RemoveMarkStep.fromJSON");return new Mt(t.from,t.to,e.markFromJSON(t.mark))}}bt.jsonID("removeMark",Mt);class Ot extends bt{constructor(e,t){super(),this.pos=e,this.mark=t}apply(e){let t=e.nodeAt(this.pos);if(!t)return xt.fail("No node at mark step's position");let n=t.type.create(t.attrs,null,this.mark.addToSet(t.marks));return xt.fromReplace(e,this.pos,this.pos+1,new ye(ue.from(n),0,t.isLeaf?0:1))}invert(e){let t=e.nodeAt(this.pos);if(t){let e=this.mark.addToSet(t.marks);if(e.length==t.marks.length){for(let n=0;nn.pos?null:new Dt(t.pos,n.pos,r,i,this.slice,this.insert,this.structure)}toJSON(){let e={stepType:"replaceAround",from:this.from,to:this.to,gapFrom:this.gapFrom,gapTo:this.gapTo,insert:this.insert};return this.slice.size&&(e.slice=this.slice.toJSON()),this.structure&&(e.structure=!0),e}static fromJSON(e,t){if("number"!=typeof t.from||"number"!=typeof t.to||"number"!=typeof t.gapFrom||"number"!=typeof t.gapTo||"number"!=typeof t.insert)throw new RangeError("Invalid input for ReplaceAroundStep.fromJSON");return new Dt(t.from,t.to,t.gapFrom,t.gapTo,ye.fromJSON(e,t.slice),t.insert,!!t.structure)}}function Tt(e,t,n){let r=e.resolve(t),i=n-t,o=r.depth;for(;i>0&&o>0&&r.indexAfter(o)==r.node(o).childCount;)o--,i--;if(i>0){let e=r.node(o).maybeChild(r.indexAfter(o));for(;i>0;){if(!e||e.isLeaf)return!0;e=e.firstChild,i--}}return!1}function At(e,t,n){return(0==t||e.canReplace(t,e.childCount))&&(n==e.childCount||e.canReplace(0,n))}function Et(e){let t=e.parent.content.cutByIndex(e.startIndex,e.endIndex);for(let n=e.depth;;--n){let r=e.$from.node(n),i=e.$from.index(n),o=e.$to.indexAfter(n);if(no;c--,h--){let e=i.node(c),t=i.index(c);if(e.type.spec.isolating)return!1;let n=e.content.cutByIndex(t,e.childCount),o=r&&r[h+1];o&&(n=n.replaceChild(0,o.type.create(o.attrs)));let s=r&&r[h]||e;if(!e.canReplace(t+1,e.childCount)||!s.type.validContent(n))return!1}let l=i.indexAfter(o),a=r&&r[0];return i.node(o).canReplaceWith(l,l,a?a.type:i.node(o+1).type)}function Rt(e,t){let n=e.resolve(t),r=n.index();return i=n.nodeBefore,o=n.nodeAfter,!(!i||!o||i.isLeaf||!i.canAppend(o))&&n.parent.canReplace(r,r+1);var i,o}function zt(e,t,n=t,r=ye.empty){if(t==n&&!r.size)return null;let i=e.resolve(t),o=e.resolve(n);return _t(i,o,r)?new Nt(t,n,r):new Bt(i,o,r).fit()}function _t(e,t,n){return!n.openStart&&!n.openEnd&&e.start()==t.start()&&e.parent.canReplace(e.index(),t.index(),n.content)}bt.jsonID("replaceAround",Dt);class Bt{constructor(e,t,n){this.$from=e,this.$to=t,this.unplaced=n,this.frontier=[],this.placed=ue.empty;for(let r=0;r<=e.depth;r++){let t=e.node(r);this.frontier.push({type:t.type,match:t.contentMatchAt(e.indexAfter(r))})}for(let r=e.depth;r>0;r--)this.placed=ue.from(e.node(r).copy(this.placed))}get depth(){return this.frontier.length-1}fit(){for(;this.unplaced.size;){let e=this.findFittable();e?this.placeNodes(e):this.openMore()||this.dropNode()}let e=this.mustMoveInline(),t=this.placed.size-this.depth-this.$from.depth,n=this.$from,r=this.close(e<0?this.$to:n.doc.resolve(e));if(!r)return null;let i=this.placed,o=n.depth,s=r.depth;for(;o&&s&&1==i.childCount;)i=i.firstChild.content,o--,s--;let l=new ye(i,o,s);return e>-1?new Dt(n.pos,e,this.$to.pos,this.$to.end(),l,t):l.size||n.pos!=this.$to.pos?new Nt(n.pos,r.pos,l):null}findFittable(){let e=this.unplaced.openStart;for(let t=this.unplaced.content,n=0,r=this.unplaced.openEnd;n1&&(r=0),i.type.spec.isolating&&r<=n){e=n;break}t=i.content}for(let t=1;t<=2;t++)for(let n=1==t?e:this.unplaced.openStart;n>=0;n--){let e,r=null;n?(r=Ft(this.unplaced.content,n-1).firstChild,e=r.content):e=this.unplaced.content;let i=e.firstChild;for(let o=this.depth;o>=0;o--){let e,{type:s,match:l}=this.frontier[o],a=null;if(1==t&&(i?l.matchType(i.type)||(a=l.fillBefore(ue.from(i),!1)):r&&s.compatibleContent(r.type)))return{sliceDepth:n,frontierDepth:o,parent:r,inject:a};if(2==t&&i&&(e=l.findWrapping(i.type)))return{sliceDepth:n,frontierDepth:o,parent:r,wrap:e};if(r&&l.matchType(r.type))break}}}openMore(){let{content:e,openStart:t,openEnd:n}=this.unplaced,r=Ft(e,t);return!(!r.childCount||r.firstChild.isLeaf)&&(this.unplaced=new ye(e,t+1,Math.max(n,r.size+t>=e.size-n?t+1:0)),!0)}dropNode(){let{content:e,openStart:t,openEnd:n}=this.unplaced,r=Ft(e,t);if(r.childCount<=1&&t>0){let i=e.size-t<=t+r.size;this.unplaced=new ye(Vt(e,t-1,1),t-1,i?t-1:n)}else this.unplaced=new ye(Vt(e,t,1),t,n)}placeNodes({sliceDepth:e,frontierDepth:t,parent:n,inject:r,wrap:i}){for(;this.depth>t;)this.closeFrontierNode();if(i)for(let p=0;p1||0==l||e.content.size)&&(h=t,c.push(Lt(e.mark(u.allowedMarks(e.marks)),1==a?l:0,a==s.childCount?d:-1)))}let f=a==s.childCount;f||(d=-1),this.placed=jt(this.placed,t,ue.from(c)),this.frontier[t].match=h,f&&d<0&&n&&n.type==this.frontier[this.depth].type&&this.frontier.length>1&&this.closeFrontierNode();for(let p=0,m=s;p1&&r==this.$to.end(--n);)++r;return r}findCloseLevel(e){e:for(let t=Math.min(this.depth,e.depth);t>=0;t--){let{match:n,type:r}=this.frontier[t],i=t=0;n--){let{match:t,type:r}=this.frontier[n],i=qt(e,n,r,t,!0);if(!i||i.childCount)continue e}return{depth:t,fit:o,move:i?e.doc.resolve(e.after(t+1)):e}}}}close(e){let t=this.findCloseLevel(e);if(!t)return null;for(;this.depth>t.depth;)this.closeFrontierNode();t.fit.childCount&&(this.placed=jt(this.placed,t.depth,t.fit)),e=t.move;for(let n=t.depth+1;n<=e.depth;n++){let t=e.node(n),r=t.type.contentMatch.fillBefore(t.content,!0,e.index(n));this.openFrontierNode(t.type,t.attrs,r)}return e}openFrontierNode(e,t=null,n){let r=this.frontier[this.depth];r.match=r.match.matchType(e),this.placed=jt(this.placed,this.depth,ue.from(e.create(t,n))),this.frontier.push({type:e,match:e.contentMatch})}closeFrontierNode(){let e=this.frontier.pop().match.fillBefore(ue.empty,!0);e.childCount&&(this.placed=jt(this.placed,this.frontier.length,e))}}function Vt(e,t,n){return 0==t?e.cutByIndex(n,e.childCount):e.replaceChild(0,e.firstChild.copy(Vt(e.firstChild.content,t-1,n)))}function jt(e,t,n){return 0==t?e.append(n):e.replaceChild(e.childCount-1,e.lastChild.copy(jt(e.lastChild.content,t-1,n)))}function Ft(e,t){for(let n=0;n1&&(r=r.replaceChild(0,Lt(r.firstChild,t-1,1==r.childCount?n-1:0))),t>0&&(r=e.type.contentMatch.fillBefore(r).append(r),n<=0&&(r=r.append(e.type.contentMatch.matchFragment(r).fillBefore(ue.empty,!0)))),e.copy(r)}function qt(e,t,n,r,i){let o=e.node(t),s=i?e.indexAfter(t):e.index(t);if(s==o.childCount&&!n.compatibleContent(o.type))return null;let l=r.fillBefore(o.content,!0,s);return l&&!function(e,t,n){for(let r=n;rr){let t=i.contentMatchAt(0),n=t.fillBefore(e).append(e);e=n.append(t.matchFragment(n).fillBefore(ue.empty,!0))}return e}function Kt(e,t){let n=[];for(let r=Math.min(e.depth,t.depth);r>=0;r--){let i=e.start(r);if(it.pos+(t.depth-r)||e.node(r).type.spec.isolating||t.node(r).type.spec.isolating)break;(i==t.start(r)||r==e.depth&&r==t.depth&&e.parent.inlineContent&&t.parent.inlineContent&&r&&t.start(r-1)==i-1)&&n.push(r)}return n}class Ht extends bt{constructor(e,t,n){super(),this.pos=e,this.attr=t,this.value=n}apply(e){let t=e.nodeAt(this.pos);if(!t)return xt.fail("No node at attribute step's position");let n=Object.create(null);for(let i in t.attrs)n[i]=t.attrs[i];n[this.attr]=this.value;let r=t.type.create(n,null,t.marks);return xt.fromReplace(e,this.pos,this.pos+1,new ye(ue.from(r),0,t.isLeaf?0:1))}getMap(){return yt.empty}invert(e){return new Ht(this.pos,this.attr,e.nodeAt(this.pos).attrs[this.attr])}map(e){let t=e.mapResult(this.pos,1);return t.deletedAfter?null:new Ht(t.pos,this.attr,this.value)}toJSON(){return{stepType:"attr",pos:this.pos,attr:this.attr,value:this.value}}static fromJSON(e,t){if("number"!=typeof t.pos||"string"!=typeof t.attr)throw new RangeError("Invalid input for AttrStep.fromJSON");return new Ht(t.pos,t.attr,t.value)}}bt.jsonID("attr",Ht);let Yt=class extends Error{};Yt=function e(t){let n=Error.call(this,t);return n.__proto__=e.prototype,n},(Yt.prototype=Object.create(Error.prototype)).constructor=Yt,Yt.prototype.name="TransformError";class Ut{constructor(e){this.doc=e,this.steps=[],this.docs=[],this.mapping=new vt}get before(){return this.docs.length?this.docs[0]:this.doc}step(e){let t=this.maybeStep(e);if(t.failed)throw new Yt(t.failed);return this}maybeStep(e){let t=e.apply(this.doc);return t.failed||this.addStep(e,t.doc),t}get docChanged(){return this.steps.length>0}addStep(e,t){this.docs.push(this.doc),this.steps.push(e),this.mapping.appendMap(e.getMap()),this.doc=t}replace(e,t=e,n=ye.empty){let r=zt(this.doc,e,t,n);return r&&this.step(r),this}replaceWith(e,t,n){return this.replace(e,t,new ye(ue.from(n),0,0))}delete(e,t){return this.replace(e,t,ye.empty)}insert(e,t){return this.replaceWith(e,e,t)}replaceRange(e,t,n){return function(e,t,n,r){if(!r.size)return e.deleteRange(t,n);let i=e.doc.resolve(t),o=e.doc.resolve(n);if(_t(i,o,r))return e.step(new Nt(t,n,r));let s=Kt(i,e.doc.resolve(n));0==s[s.length-1]&&s.pop();let l=-(i.depth+1);s.unshift(l);for(let d=i.depth,f=i.pos-1;d>0;d--,f--){let e=i.node(d).type.spec;if(e.defining||e.definingAsContext||e.isolating)break;s.indexOf(d)>-1?l=d:i.before(d)==f&&s.splice(1,0,-d)}let a=s.indexOf(l),c=[],h=r.openStart;for(let d=r.content,f=0;;f++){let e=d.firstChild;if(c.push(e),f==r.openStart)break;d=e.content}for(let d=h-1;d>=0;d--){let e=c[d].type,t=Wt(e);if(t&&i.node(a).type!=e)h=d;else if(t||!e.isTextblock)break}for(let d=r.openStart;d>=0;d--){let t=(d+h+1)%(r.openStart+1),l=c[t];if(l)for(let c=0;c=0&&(e.replace(t,n,r),!(e.steps.length>u));d--){let e=s[d];e<0||(t=i.before(e),n=o.after(e))}}(this,e,t,n),this}replaceRangeWith(e,t,n){return function(e,t,n,r){if(!r.isInline&&t==n&&e.doc.resolve(t).parent.content.size){let i=function(e,t,n){let r=e.resolve(t);if(r.parent.canReplaceWith(r.index(),r.index(),n))return t;if(0==r.parentOffset)for(let i=r.depth-1;i>=0;i--){let e=r.index(i);if(r.node(i).canReplaceWith(e,e,n))return r.before(i+1);if(e>0)return null}if(r.parentOffset==r.parent.content.size)for(let i=r.depth-1;i>=0;i--){let e=r.indexAfter(i);if(r.node(i).canReplaceWith(e,e,n))return r.after(i+1);if(e0&&(n||r.node(t-1).canReplace(r.index(t-1),i.indexAfter(t-1))))return e.delete(r.before(t),i.after(t))}for(let s=1;s<=r.depth&&s<=i.depth;s++)if(t-r.start(s)==r.depth-s&&n>r.end(s)&&i.end(s)-n!=i.depth-s)return e.delete(r.before(s),n);e.delete(t,n)}(this,e,t),this}lift(e,t){return function(e,t,n){let{$from:r,$to:i,depth:o}=t,s=r.before(o+1),l=i.after(o+1),a=s,c=l,h=ue.empty,u=0;for(let p=o,m=!1;p>n;p--)m||r.index(p)>0?(m=!0,h=ue.from(r.node(p).copy(h)),u++):a--;let d=ue.empty,f=0;for(let p=o,m=!1;p>n;p--)m||i.after(p+1)=0;s--){if(r.size){let e=n[s].type.contentMatch.matchFragment(r);if(!e||!e.validEnd)throw new RangeError("Wrapper type given to Transform.wrap does not form valid content of its parent wrapper")}r=ue.from(n[s].type.create(n[s].attrs,r))}let i=t.start,o=t.end;e.step(new Dt(i,o,i,o,new ye(r,0,0),n.length,!0))}(this,e,t),this}setBlockType(e,t=e,n,r=null){return function(e,t,n,r,i){if(!r.isTextblock)throw new RangeError("Type given to setBlockType should be a textblock");let o=e.steps.length;e.doc.nodesBetween(t,n,((t,n)=>{if(t.isTextblock&&!t.hasMarkup(r,i)&&function(e,t,n){let r=e.resolve(t),i=r.index();return r.parent.canReplaceWith(i,i+1,n)}(e.doc,e.mapping.slice(o).map(n),r)){e.clearIncompatible(e.mapping.slice(o).map(n,1),r);let s=e.mapping.slice(o),l=s.map(n,1),a=s.map(n+t.nodeSize,1);return e.step(new Dt(l,a,l+1,a-1,new ye(ue.from(r.create(i,null,t.marks)),0,0),1,!0)),!1}}))}(this,e,t,n,r),this}setNodeMarkup(e,t,n=null,r){return function(e,t,n,r,i){let o=e.doc.nodeAt(t);if(!o)throw new RangeError("No node at given position");n||(n=o.type);let s=n.create(r,null,i||o.marks);if(o.isLeaf)return e.replaceWith(t,t+o.nodeSize,s);if(!n.validContent(o.content))throw new RangeError("Invalid content for node type "+n.name);e.step(new Dt(t,t+o.nodeSize,t+1,t+o.nodeSize-1,new ye(ue.from(s),0,0),1,!0))}(this,e,t,n,r),this}setNodeAttribute(e,t,n){return this.step(new Ht(e,t,n)),this}addNodeMark(e,t){return this.step(new Ot(e,t)),this}removeNodeMark(e,t){if(!(t instanceof me)){let n=this.doc.nodeAt(e);if(!n)throw new RangeError("No node at position "+e);if(!(t=t.isInSet(n.marks)))return this}return this.step(new Ct(e,t)),this}split(e,t=1,n){return function(e,t,n=1,r){let i=e.doc.resolve(t),o=ue.empty,s=ue.empty;for(let l=i.depth,a=i.depth-n,c=n-1;l>a;l--,c--){o=ue.from(i.node(l).copy(o));let e=r&&r[c];s=ue.from(e?e.type.create(e.attrs,s):i.node(l).copy(s))}e.step(new Nt(t,t,new ye(o.append(s),n,n),!0))}(this,e,t,n),this}addMark(e,t,n){return function(e,t,n,r){let i,o,s=[],l=[];e.doc.nodesBetween(t,n,((e,a,c)=>{if(!e.isInline)return;let h=e.marks;if(!r.isInSet(h)&&c.type.allowsMarkType(r.type)){let c=Math.max(a,t),u=Math.min(a+e.nodeSize,n),d=r.addToSet(h);for(let e=0;ee.step(t))),l.forEach((t=>e.step(t)))}(this,e,t,n),this}removeMark(e,t,n){return function(e,t,n,r){let i=[],o=0;e.doc.nodesBetween(t,n,((e,s)=>{if(!e.isInline)return;o++;let l=null;if(r instanceof Xe){let t,n=e.marks;for(;t=r.isInSet(n);)(l||(l=[])).push(t),n=t.removeFromSet(n)}else r?r.isInSet(e.marks)&&(l=[r]):l=e.marks;if(l&&l.length){let r=Math.min(s+e.nodeSize,n);for(let e=0;ee.step(new Mt(t.from,t.to,t.style))))}(this,e,t,n),this}clearIncompatible(e,t,n){return function(e,t,n,r=n.contentMatch){let i=e.doc.nodeAt(t),o=[],s=t+1;for(let l=0;l=0;l--)e.step(o[l])}(this,e,t,n),this}}const Gt=Object.create(null);class Zt{constructor(e,t,n){this.$anchor=e,this.$head=t,this.ranges=n||[new Xt(e.min(t),e.max(t))]}get anchor(){return this.$anchor.pos}get head(){return this.$head.pos}get from(){return this.$from.pos}get to(){return this.$to.pos}get $from(){return this.ranges[0].$from}get $to(){return this.ranges[0].$to}get empty(){let e=this.ranges;for(let t=0;t=0;i--){let r=t<0?an(e.node(0),e.node(i),e.before(i+1),e.index(i),t,n):an(e.node(0),e.node(i),e.after(i+1),e.index(i)+1,t,n);if(r)return r}return null}static near(e,t=1){return this.findFrom(e,t)||this.findFrom(e,-t)||new sn(e.node(0))}static atStart(e){return an(e,e,0,0,1)||new sn(e)}static atEnd(e){return an(e,e,e.content.size,e.childCount,-1)||new sn(e)}static fromJSON(e,t){if(!t||!t.type)throw new RangeError("Invalid input for Selection.fromJSON");let n=Gt[t.type];if(!n)throw new RangeError(`No selection type ${t.type} defined`);return n.fromJSON(e,t)}static jsonID(e,t){if(e in Gt)throw new RangeError("Duplicate use of selection JSON ID "+e);return Gt[e]=t,t.prototype.jsonID=e,t}getBookmark(){return tn.between(this.$anchor,this.$head).getBookmark()}}Zt.prototype.visible=!0;class Xt{constructor(e,t){this.$from=e,this.$to=t}}let Qt=!1;function en(e){Qt||e.parent.inlineContent||(Qt=!0,console.warn("TextSelection endpoint not pointing into a node with inline content ("+e.parent.type.name+")"))}class tn extends Zt{constructor(e,t=e){en(e),en(t),super(e,t)}get $cursor(){return this.$anchor.pos==this.$head.pos?this.$head:null}map(e,t){let n=e.resolve(t.map(this.head));if(!n.parent.inlineContent)return Zt.near(n);let r=e.resolve(t.map(this.anchor));return new tn(r.parent.inlineContent?r:n,n)}replace(e,t=ye.empty){if(super.replace(e,t),t==ye.empty){let t=this.$from.marksAcross(this.$to);t&&e.ensureMarks(t)}}eq(e){return e instanceof tn&&e.anchor==this.anchor&&e.head==this.head}getBookmark(){return new nn(this.anchor,this.head)}toJSON(){return{type:"text",anchor:this.anchor,head:this.head}}static fromJSON(e,t){if("number"!=typeof t.anchor||"number"!=typeof t.head)throw new RangeError("Invalid input for TextSelection.fromJSON");return new tn(e.resolve(t.anchor),e.resolve(t.head))}static create(e,t,n=t){let r=e.resolve(t);return new this(r,n==t?r:e.resolve(n))}static between(e,t,n){let r=e.pos-t.pos;if(n&&!r||(n=r>=0?1:-1),!t.parent.inlineContent){let e=Zt.findFrom(t,n,!0)||Zt.findFrom(t,-n,!0);if(!e)return Zt.near(t,n);t=e.$head}return e.parent.inlineContent||(0==r||(e=(Zt.findFrom(e,-n,!0)||Zt.findFrom(e,n,!0)).$anchor).posnew sn(e)};function an(e,t,n,r,i,o=!1){if(t.inlineContent)return tn.create(e,n);for(let s=r-(i>0?0:1);i>0?s=0;s+=i){let r=t.child(s);if(r.isAtom){if(!o&&rn.isSelectable(r))return rn.create(e,n-(i<0?r.nodeSize:0))}else{let t=an(e,r,n+i,i<0?r.childCount:0,i,o);if(t)return t}n+=r.nodeSize*i}return null}function cn(e,t,n){let r=e.steps.length-1;if(r{null==i&&(i=r)})),e.setSelection(Zt.near(e.doc.resolve(i),n)))}class hn extends Ut{constructor(e){super(e.doc),this.curSelectionFor=0,this.updated=0,this.meta=Object.create(null),this.time=Date.now(),this.curSelection=e.selection,this.storedMarks=e.storedMarks}get selection(){return this.curSelectionFor0}setStoredMarks(e){return this.storedMarks=e,this.updated|=2,this}ensureMarks(e){return me.sameSet(this.storedMarks||this.selection.$from.marks(),e)||this.setStoredMarks(e),this}addStoredMark(e){return this.ensureMarks(e.addToSet(this.storedMarks||this.selection.$head.marks()))}removeStoredMark(e){return this.ensureMarks(e.removeFromSet(this.storedMarks||this.selection.$head.marks()))}get storedMarksSet(){return(2&this.updated)>0}addStep(e,t){super.addStep(e,t),this.updated=-3&this.updated,this.storedMarks=null}setTime(e){return this.time=e,this}replaceSelection(e){return this.selection.replace(this,e),this}replaceSelectionWith(e,t=!0){let n=this.selection;return t&&(e=e.mark(this.storedMarks||(n.empty?n.$from.marks():n.$from.marksAcross(n.$to)||me.none))),n.replaceWith(this,e),this}deleteSelection(){return this.selection.replace(this),this}insertText(e,t,n){let r=this.doc.type.schema;if(null==t)return e?this.replaceSelectionWith(r.text(e),!0):this.deleteSelection();{if(null==n&&(n=t),n=null==n?t:n,!e)return this.deleteRange(t,n);let i=this.storedMarks;if(!i){let e=this.doc.resolve(t);i=n==t?e.marks():e.marksAcross(this.doc.resolve(n))}return this.replaceRangeWith(t,n,r.text(e,i)),this.selection.empty||this.setSelection(Zt.near(this.selection.$to)),this}}setMeta(e,t){return this.meta["string"==typeof e?e:e.key]=t,this}getMeta(e){return this.meta["string"==typeof e?e:e.key]}get isGeneric(){for(let e in this.meta)return!1;return!0}scrollIntoView(){return this.updated|=4,this}get scrolledIntoView(){return(4&this.updated)>0}}function un(e,t){return t&&e?e.bind(t):e}class dn{constructor(e,t,n){this.name=e,this.init=un(t.init,n),this.apply=un(t.apply,n)}}const fn=[new dn("doc",{init:e=>e.doc||e.schema.topNodeType.createAndFill(),apply:e=>e.doc}),new dn("selection",{init:(e,t)=>e.selection||Zt.atStart(t.doc),apply:e=>e.selection}),new dn("storedMarks",{init:e=>e.storedMarks||null,apply:(e,t,n,r)=>r.selection.$cursor?e.storedMarks:null}),new dn("scrollToSelection",{init:()=>0,apply:(e,t)=>e.scrolledIntoView?t+1:t})];class pn{constructor(e,t){this.schema=e,this.plugins=[],this.pluginsByKey=Object.create(null),this.fields=fn.slice(),t&&t.forEach((e=>{if(this.pluginsByKey[e.key])throw new RangeError("Adding different instances of a keyed plugin ("+e.key+")");this.plugins.push(e),this.pluginsByKey[e.key]=e,e.spec.state&&this.fields.push(new dn(e.key,e.spec.state,e))}))}}class mn{constructor(e){this.config=e}get schema(){return this.config.schema}get plugins(){return this.config.plugins}apply(e){return this.applyTransaction(e).state}filterTransaction(e,t=-1){for(let n=0;ne.toJSON()))),e&&"object"==typeof e)for(let n in e){if("doc"==n||"selection"==n)throw new RangeError("The JSON fields `doc` and `selection` are reserved");let r=e[n],i=r.spec.state;i&&i.toJSON&&(t[n]=i.toJSON.call(r,this[r.key]))}return t}static fromJSON(e,t,n){if(!t)throw new RangeError("Invalid input for EditorState.fromJSON");if(!e.schema)throw new RangeError("Required config field 'schema' missing");let r=new pn(e.schema,e.plugins),i=new mn(r);return r.fields.forEach((r=>{if("doc"==r.name)i.doc=Re.fromJSON(e.schema,t.doc);else if("selection"==r.name)i.selection=Zt.fromJSON(i.doc,t.selection);else if("storedMarks"==r.name)t.storedMarks&&(i.storedMarks=t.storedMarks.map(e.schema.markFromJSON));else{if(n)for(let o in n){let s=n[o],l=s.spec.state;if(s.key==r.name&&l&&l.fromJSON&&Object.prototype.hasOwnProperty.call(t,o))return void(i[r.name]=l.fromJSON.call(s,e,t[o],i))}i[r.name]=r.init(e,i)}})),i}}function gn(e,t,n){for(let r in e){let i=e[r];i instanceof Function?i=i.bind(t):"handleDOMEvents"==r&&(i=gn(i,t,{})),n[r]=i}return n}class yn{constructor(e){this.spec=e,this.props={},e.props&&gn(e.props,this,this.props),this.key=e.key?e.key.key:wn("plugin")}getState(e){return e[this.key]}}const vn=Object.create(null);function wn(e){return e in vn?e+"$"+ ++vn[e]:(vn[e]=0,e+"$")}class bn{constructor(e="key"){this.key=wn(e)}get(e){return e.config.pluginsByKey[this.key]}getState(e){return e[this.key]}}const xn=function(e){for(var t=0;;t++)if(!(e=e.previousSibling))return t},Sn=function(e){let t=e.assignedSlot||e.parentNode;return t&&11==t.nodeType?t.host:t};let kn=null;const Mn=function(e,t,n){let r=kn||(kn=document.createRange());return r.setEnd(e,null==n?e.nodeValue.length:n),r.setStart(e,t||0),r},On=function(e,t,n,r){return n&&(Nn(e,t,n,r,-1)||Nn(e,t,n,r,1))},Cn=/^(img|br|input|textarea|hr)$/i;function Nn(e,t,n,r,i){for(;;){if(e==n&&t==r)return!0;if(t==(i<0?0:Dn(e))){let n=e.parentNode;if(!n||1!=n.nodeType||Tn(e)||Cn.test(e.nodeName)||"false"==e.contentEditable)return!1;t=xn(e)+(i<0?0:1),e=n}else{if(1!=e.nodeType)return!1;if("false"==(e=e.childNodes[t+(i<0?-1:0)]).contentEditable)return!1;t=i<0?Dn(e):0}}}function Dn(e){return 3==e.nodeType?e.nodeValue.length:e.childNodes.length}function Tn(e){let t;for(let n=e;n&&!(t=n.pmViewDesc);n=n.parentNode);return t&&t.node&&t.node.isBlock&&(t.dom==e||t.contentDOM==e)}const An=function(e){return e.focusNode&&On(e.focusNode,e.focusOffset,e.anchorNode,e.anchorOffset)};function En(e,t){let n=document.createEvent("Event");return n.initEvent("keydown",!0,!0),n.keyCode=e,n.key=n.code=t,n}const $n="undefined"!=typeof navigator?navigator:null,Pn="undefined"!=typeof document?document:null,In=$n&&$n.userAgent||"",Rn=/Edge\/(\d+)/.exec(In),zn=/MSIE \d/.exec(In),_n=/Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(In),Bn=!!(zn||_n||Rn),Vn=zn?document.documentMode:_n?+_n[1]:Rn?+Rn[1]:0,jn=!Bn&&/gecko\/(\d+)/i.test(In);jn&&(/Firefox\/(\d+)/.exec(In)||[0,0])[1];const Fn=!Bn&&/Chrome\/(\d+)/.exec(In),Ln=!!Fn,qn=Fn?+Fn[1]:0,Wn=!Bn&&!!$n&&/Apple Computer/.test($n.vendor),Jn=Wn&&(/Mobile\/\w+/.test(In)||!!$n&&$n.maxTouchPoints>2),Kn=Jn||!!$n&&/Mac/.test($n.platform),Hn=!!$n&&/Win/.test($n.platform),Yn=/Android \d/.test(In),Un=!!Pn&&"webkitFontSmoothing"in Pn.documentElement.style,Gn=Un?+(/\bAppleWebKit\/(\d+)/.exec(navigator.userAgent)||[0,0])[1]:0;function Zn(e){let t=e.defaultView&&e.defaultView.visualViewport;return t?{left:0,right:t.width,top:0,bottom:t.height}:{left:0,right:e.documentElement.clientWidth,top:0,bottom:e.documentElement.clientHeight}}function Xn(e,t){return"number"==typeof e?e:e[t]}function Qn(e){let t=e.getBoundingClientRect(),n=t.width/e.offsetWidth||1,r=t.height/e.offsetHeight||1;return{left:t.left,right:t.left+e.clientWidth*n,top:t.top,bottom:t.top+e.clientHeight*r}}function er(e,t,n){let r=e.someProp("scrollThreshold")||0,i=e.someProp("scrollMargin")||5,o=e.dom.ownerDocument;for(let s=n||e.dom;s;s=Sn(s)){if(1!=s.nodeType)continue;let e=s,n=e==o.body,l=n?Zn(o):Qn(e),a=0,c=0;if(t.topl.bottom-Xn(r,"bottom")&&(c=t.bottom-t.top>l.bottom-l.top?t.top+Xn(i,"top")-l.top:t.bottom-l.bottom+Xn(i,"bottom")),t.leftl.right-Xn(r,"right")&&(a=t.right-l.right+Xn(i,"right")),a||c)if(n)o.defaultView.scrollBy(a,c);else{let n=e.scrollLeft,r=e.scrollTop;c&&(e.scrollTop+=c),a&&(e.scrollLeft+=a);let i=e.scrollLeft-n,o=e.scrollTop-r;t={left:t.left-i,top:t.top-o,right:t.right-i,bottom:t.bottom-o}}if(n||/^(fixed|sticky)$/.test(getComputedStyle(s).position))break}}function tr(e){let t=[],n=e.ownerDocument;for(let r=e;r&&(t.push({dom:r,top:r.scrollTop,left:r.scrollLeft}),e!=n);r=Sn(r));return t}function nr(e,t){for(let n=0;n=c){a=Math.max(f.bottom,a),c=Math.min(f.top,c);let e=f.left>t.left?f.left-t.left:f.right=(f.left+f.right)/2?1:0));continue}}else f.top>t.top&&!i&&f.left<=t.left&&f.right>=t.left&&(i=h,o={left:Math.max(f.left,Math.min(f.right,t.left)),top:f.top});!n&&(t.left>=f.right&&t.top>=f.top||t.left>=f.left&&t.top>=f.bottom)&&(l=u+1)}}return!n&&i&&(n=i,r=o,s=0),n&&3==n.nodeType?function(e,t){let n=e.nodeValue.length,r=document.createRange();for(let i=0;i=(n.left+n.right)/2?1:0)}}return{node:e,offset:0}}(n,r):!n||s&&1==n.nodeType?{node:e,offset:l}:ir(n,r)}function or(e,t){return e.left>=t.left-1&&e.left<=t.right+1&&e.top>=t.top-1&&e.top<=t.bottom+1}function sr(e,t,n){let r=e.childNodes.length;if(r&&n.topt.top&&i++}let r;Un&&i&&1==n.nodeType&&1==(r=n.childNodes[i-1]).nodeType&&"false"==r.contentEditable&&r.getBoundingClientRect().top>=t.top&&i--,n==e.dom&&i==n.childNodes.length-1&&1==n.lastChild.nodeType&&t.top>n.lastChild.getBoundingClientRect().bottom?s=e.state.doc.content.size:0!=i&&1==n.nodeType&&"BR"==n.childNodes[i-1].nodeName||(s=function(e,t,n,r){let i=-1;for(let o=t,s=!1;o!=e.dom;){let t=e.docView.nearestDesc(o,!0);if(!t)return null;if(1==t.dom.nodeType&&(t.node.isBlock&&t.parent||!t.contentDOM)){let e=t.dom.getBoundingClientRect();if(t.node.isBlock&&t.parent&&(!s&&e.left>r.left||e.top>r.top?i=t.posBefore:(!s&&e.right-1?i:e.docView.posFromDOM(t,n,-1)}(e,n,i,t))}null==s&&(s=function(e,t,n){let{node:r,offset:i}=ir(t,n),o=-1;if(1==r.nodeType&&!r.firstChild){let e=r.getBoundingClientRect();o=e.left!=e.right&&n.left>(e.left+e.right)/2?1:-1}return e.docView.posFromDOM(r,i,o)}(e,l,t));let a=e.docView.nearestDesc(l,!0);return{pos:s,inside:a?a.posAtStart-a.border:-1}}function ar(e){return e.top=0&&i==r.nodeValue.length?(e--,o=1):n<0?e--:t++,dr(cr(Mn(r,e,t),o),o<0)}{let e=cr(Mn(r,i,i),n);if(jn&&i&&/\s/.test(r.nodeValue[i-1])&&i=0)}if(null==o&&i&&(n<0||i==Dn(r))){let e=r.childNodes[i-1],t=3==e.nodeType?Mn(e,Dn(e)-(s?0:1)):1!=e.nodeType||"BR"==e.nodeName&&e.nextSibling?null:e;if(t)return dr(cr(t,1),!1)}if(null==o&&i=0)}function dr(e,t){if(0==e.width)return e;let n=t?e.left:e.right;return{top:e.top,bottom:e.bottom,left:n,right:n}}function fr(e,t){if(0==e.height)return e;let n=t?e.top:e.bottom;return{top:n,bottom:n,left:e.left,right:e.right}}function pr(e,t,n){let r=e.state,i=e.root.activeElement;r!=t&&e.updateState(t),i!=e.dom&&e.focus();try{return n()}finally{r!=t&&e.updateState(r),i!=e.dom&&i&&i.focus()}}const mr=/[\u0590-\u08ac]/;let gr=null,yr=null,vr=!1;function wr(e,t,n){return gr==t&&yr==n?vr:(gr=t,yr=n,vr="up"==n||"down"==n?function(e,t,n){let r=t.selection,i="up"==n?r.$from:r.$to;return pr(e,t,(()=>{let{node:t}=e.docView.domFromPos(i.pos,"up"==n?-1:1);for(;;){let n=e.docView.nearestDesc(t,!0);if(!n)break;if(n.node.isBlock){t=n.contentDOM||n.dom;break}t=n.dom.parentNode}let r=ur(e,i.pos,1);for(let e=t.firstChild;e;e=e.nextSibling){let t;if(1==e.nodeType)t=e.getClientRects();else{if(3!=e.nodeType)continue;t=Mn(e,0,e.nodeValue.length).getClientRects()}for(let e=0;ei.top+1&&("up"==n?r.top-i.top>2*(i.bottom-r.top):i.bottom-r.bottom>2*(r.bottom-i.top)))return!1}}return!0}))}(e,t,n):function(e,t,n){let{$head:r}=t.selection;if(!r.parent.isTextblock)return!1;let i=r.parentOffset,o=!i,s=i==r.parent.content.size,l=e.domSelection();return mr.test(r.parent.textContent)&&l.modify?pr(e,t,(()=>{let{focusNode:t,focusOffset:i,anchorNode:o,anchorOffset:s}=e.domSelectionRange(),a=l.caretBidiLevel;l.modify("move",n,"character");let c=r.depth?e.docView.domAfterPos(r.before()):e.dom,{focusNode:h,focusOffset:u}=e.domSelectionRange(),d=h&&!c.contains(1==h.nodeType?h:h.parentNode)||t==h&&i==u;try{l.collapse(o,s),t&&(t!=o||i!=s)&&l.extend&&l.extend(t,i)}catch(f){}return null!=a&&(l.caretBidiLevel=a),d})):"left"==n||"backward"==n?o:s}(e,t,n))}class br{constructor(e,t,n,r){this.parent=e,this.children=t,this.dom=n,this.contentDOM=r,this.dirty=0,n.pmViewDesc=this}matchesWidget(e){return!1}matchesMark(e){return!1}matchesNode(e,t,n){return!1}matchesHack(e){return!1}parseRule(){return null}stopEvent(e){return!1}get size(){let e=0;for(let t=0;txn(this.contentDOM);else if(this.contentDOM&&this.contentDOM!=this.dom&&this.dom.contains(this.contentDOM))r=2&e.compareDocumentPosition(this.contentDOM);else if(this.dom.firstChild){if(0==t)for(let t=e;;t=t.parentNode){if(t==this.dom){r=!1;break}if(t.previousSibling)break}if(null==r&&t==e.childNodes.length)for(let t=e;;t=t.parentNode){if(t==this.dom){r=!0;break}if(t.nextSibling)break}}return(null==r?n>0:r)?this.posAtEnd:this.posAtStart}nearestDesc(e,t=!1){for(let n=!0,r=e;r;r=r.parentNode){let i,o=this.getDesc(r);if(o&&(!t||o.node)){if(!n||!(i=o.nodeDOM)||(1==i.nodeType?i.contains(1==e.nodeType?e:e.parentNode):i==e))return o;n=!1}}}getDesc(e){let t=e.pmViewDesc;for(let n=t;n;n=n.parent)if(n==this)return t}posFromDOM(e,t,n){for(let r=e;r;r=r.parentNode){let i=this.getDesc(r);if(i)return i.localPosFromDOM(e,t,n)}return-1}descAt(e){for(let t=0,n=0;te||t instanceof Nr){r=e-i;break}i=o}if(r)return this.children[n].domFromPos(r-this.children[n].border,t);for(let i;n&&!(i=this.children[n-1]).size&&i instanceof xr&&i.side>=0;n--);if(t<=0){let e,r=!0;for(;e=n?this.children[n-1]:null,e&&e.dom.parentNode!=this.contentDOM;n--,r=!1);return e&&t&&r&&!e.border&&!e.domAtom?e.domFromPos(e.size,t):{node:this.contentDOM,offset:e?xn(e.dom)+1:0}}{let e,r=!0;for(;e=n=i&&t<=l-n.border&&n.node&&n.contentDOM&&this.contentDOM.contains(n.contentDOM))return n.parseRange(e,t,i);e=o;for(let t=s;t>0;t--){let n=this.children[t-1];if(n.size&&n.dom.parentNode==this.contentDOM&&!n.emptyChildAt(1)){r=xn(n.dom)+1;break}e-=n.size}-1==r&&(r=0)}if(r>-1&&(l>t||s==this.children.length-1)){t=l;for(let e=s+1;ef&&ot){let e=s;s=l,l=e}let n=document.createRange();n.setEnd(l.node,l.offset),n.setStart(s.node,s.offset),a.removeAllRanges(),a.addRange(n)}}ignoreMutation(e){return!this.contentDOM&&"selection"!=e.type}get contentLost(){return this.contentDOM&&this.contentDOM!=this.dom&&!this.dom.contains(this.contentDOM)}markDirty(e,t){for(let n=0,r=0;r=n:en){let r=n+i.border,s=o-i.border;if(e>=r&&t<=s)return this.dirty=e==n||t==o?2:1,void(e!=r||t!=s||!i.contentLost&&i.dom.parentNode==this.contentDOM?i.markDirty(e-r,t-r):i.dirty=3);i.dirty=i.dom!=i.contentDOM||i.dom.parentNode!=this.contentDOM||i.children.length?3:2}n=o}this.dirty=2}markParentsDirty(){let e=1;for(let t=this.parent;t;t=t.parent,e++){let n=1==e?2:1;t.dirtyi?i.parent?i.parent.posBeforeChild(i):void 0:r))),!t.type.spec.raw){if(1!=o.nodeType){let e=document.createElement("span");e.appendChild(o),o=e}o.contentEditable="false",o.classList.add("ProseMirror-widget")}super(e,[],o,null),this.widget=t,this.widget=t,i=this}matchesWidget(e){return 0==this.dirty&&e.type.eq(this.widget.type)}parseRule(){return{ignore:!0}}stopEvent(e){let t=this.widget.spec.stopEvent;return!!t&&t(e)}ignoreMutation(e){return"selection"!=e.type||this.widget.spec.ignoreSelection}destroy(){this.widget.type.destroy(this.dom),super.destroy()}get domAtom(){return!0}get side(){return this.widget.type.side}}class Sr extends br{constructor(e,t,n,r){super(e,[],t,null),this.textDOM=n,this.text=r}get size(){return this.text.length}localPosFromDOM(e,t){return e!=this.textDOM?this.posAtStart+(t?this.size:0):this.posAtStart+t}domFromPos(e){return{node:this.textDOM,offset:e}}ignoreMutation(e){return"characterData"===e.type&&e.target.nodeValue==e.oldValue}}class kr extends br{constructor(e,t,n,r){super(e,[],n,r),this.mark=t}static create(e,t,n,r){let i=r.nodeViews[t.type.name],o=i&&i(t,r,n);return o&&o.dom||(o=ut.renderSpec(document,t.type.spec.toDOM(t,n))),new kr(e,t,o.dom,o.contentDOM||o.dom)}parseRule(){return 3&this.dirty||this.mark.type.spec.reparseInView?null:{mark:this.mark.type.name,attrs:this.mark.attrs,contentElement:this.contentDOM}}matchesMark(e){return 3!=this.dirty&&this.mark.eq(e)}markDirty(e,t){if(super.markDirty(e,t),0!=this.dirty){let e=this.parent;for(;!e.node;)e=e.parent;e.dirty0&&(i=jr(i,0,e,n));for(let s=0;ss?s.parent?s.parent.posBeforeChild(s):void 0:o),n,r),c=a&&a.dom,h=a&&a.contentDOM;if(t.isText)if(c){if(3!=c.nodeType)throw new RangeError("Text must be rendered as a DOM text node")}else c=document.createTextNode(t.text);else c||({dom:c,contentDOM:h}=ut.renderSpec(document,t.type.spec.toDOM(t)));h||t.isText||"BR"==c.nodeName||(c.hasAttribute("contenteditable")||(c.contentEditable="false"),t.type.spec.draggable&&(c.draggable=!0));let u=c;return c=Rr(c,n,t),a?s=new Dr(e,t,n,r,c,h||null,u,a,i,o+1):t.isText?new Cr(e,t,n,r,c,u,i):new Mr(e,t,n,r,c,h||null,u,i,o+1)}parseRule(){if(this.node.type.spec.reparseInView)return null;let e={node:this.node.type.name,attrs:this.node.attrs};if("pre"==this.node.type.whitespace&&(e.preserveWhitespace="full"),this.contentDOM)if(this.contentLost){for(let t=this.children.length-1;t>=0;t--){let n=this.children[t];if(this.dom.contains(n.dom.parentNode)){e.contentElement=n.dom.parentNode;break}}e.contentElement||(e.getContent=()=>ue.empty)}else e.contentElement=this.contentDOM;else e.getContent=()=>this.node.content;return e}matchesNode(e,t,n){return 0==this.dirty&&e.eq(this.node)&&zr(t,this.outerDeco)&&n.eq(this.innerDeco)}get size(){return this.node.nodeSize}get border(){return this.node.isLeaf?0:1}updateChildren(e,t){let n=this.node.inlineContent,r=t,i=e.composing?this.localCompositionInfo(e,t):null,o=i&&i.pos>-1?i:null,s=i&&i.pos<0,l=new Br(this,o&&o.node,e);!function(e,t,n,r){let i=t.locals(e),o=0;if(0==i.length){for(let n=0;no;)l.push(i[s++]);let p=o+d.nodeSize;if(d.isText){let e=p;s!e.inline)):l.slice(),t.forChild(o,d),f),o=p}}(this.node,this.innerDeco,((t,i,o)=>{t.spec.marks?l.syncToMarks(t.spec.marks,n,e):t.type.side>=0&&!o&&l.syncToMarks(i==this.node.childCount?me.none:this.node.child(i).marks,n,e),l.placeWidget(t,e,r)}),((t,o,a,c)=>{let h;l.syncToMarks(t.marks,n,e),l.findNodeMatch(t,o,a,c)||s&&e.state.selection.from>r&&e.state.selection.to-1&&l.updateNodeAt(t,o,a,h,e)||l.updateNextNode(t,o,a,e,c,r)||l.addNode(t,o,a,e,r),r+=t.nodeSize})),l.syncToMarks([],n,e),this.node.isTextblock&&l.addTextblockHacks(),l.destroyRest(),(l.changed||2==this.dirty)&&(o&&this.protectLocalComposition(e,o),Tr(this.contentDOM,this.children,e),Jn&&function(e){if("UL"==e.nodeName||"OL"==e.nodeName){let t=e.style.cssText;e.style.cssText=t+"; list-style: square !important",window.getComputedStyle(e).listStyle,e.style.cssText=t}}(this.dom))}localCompositionInfo(e,t){let{from:n,to:r}=e.state.selection;if(!(e.state.selection instanceof tn)||nt+this.node.content.size)return null;let i=e.input.compositionNode;if(!i||!this.dom.contains(i.parentNode))return null;if(this.node.inlineContent){let e=i.nodeValue,o=function(e,t,n,r){for(let i=0,o=0;i=n){if(o>=r&&a.slice(r-t.length-l,r-l)==t)return r-t.length;let e=l=0&&e+t.length+l>=n)return l+e;if(n==r&&a.length>=r+t.length-l&&a.slice(r-l,r-l+t.length)==t)return r}}return-1}(this.node.content,e,n-t,r-t);return o<0?null:{node:i,pos:o,text:e}}return{node:i,pos:-1,text:""}}protectLocalComposition(e,{node:t,pos:n,text:r}){if(this.getDesc(t))return;let i=t;for(;i.parentNode!=this.contentDOM;i=i.parentNode){for(;i.previousSibling;)i.parentNode.removeChild(i.previousSibling);for(;i.nextSibling;)i.parentNode.removeChild(i.nextSibling);i.pmViewDesc&&(i.pmViewDesc=void 0)}let o=new Sr(this,i,t,r);e.input.compositionNodes.push(o),this.children=jr(this.children,n,n+r.length,e,o)}update(e,t,n,r){return!(3==this.dirty||!e.sameMarkup(this.node))&&(this.updateInner(e,t,n,r),!0)}updateInner(e,t,n,r){this.updateOuterDeco(t),this.node=e,this.innerDeco=n,this.contentDOM&&this.updateChildren(r,this.posAtStart),this.dirty=0}updateOuterDeco(e){if(zr(e,this.outerDeco))return;let t=1!=this.nodeDOM.nodeType,n=this.dom;this.dom=Pr(this.dom,this.nodeDOM,$r(this.outerDeco,this.node,t),$r(e,this.node,t)),this.dom!=n&&(n.pmViewDesc=void 0,this.dom.pmViewDesc=this),this.outerDeco=e}selectNode(){1==this.nodeDOM.nodeType&&this.nodeDOM.classList.add("ProseMirror-selectednode"),!this.contentDOM&&this.node.type.spec.draggable||(this.dom.draggable=!0)}deselectNode(){1==this.nodeDOM.nodeType&&(this.nodeDOM.classList.remove("ProseMirror-selectednode"),!this.contentDOM&&this.node.type.spec.draggable||this.dom.removeAttribute("draggable"))}get domAtom(){return this.node.isAtom}}function Or(e,t,n,r,i){Rr(r,t,e);let o=new Mr(void 0,e,t,n,r,r,r,i,0);return o.contentDOM&&o.updateChildren(i,0),o}class Cr extends Mr{constructor(e,t,n,r,i,o,s){super(e,t,n,r,i,null,o,s,0)}parseRule(){let e=this.nodeDOM.parentNode;for(;e&&e!=this.dom&&!e.pmIsDeco;)e=e.parentNode;return{skip:e||!0}}update(e,t,n,r){return!(3==this.dirty||0!=this.dirty&&!this.inParent()||!e.sameMarkup(this.node))&&(this.updateOuterDeco(t),0==this.dirty&&e.text==this.node.text||e.text==this.nodeDOM.nodeValue||(this.nodeDOM.nodeValue=e.text,r.trackWrites==this.nodeDOM&&(r.trackWrites=null)),this.node=e,this.dirty=0,!0)}inParent(){let e=this.parent.contentDOM;for(let t=this.nodeDOM;t;t=t.parentNode)if(t==e)return!0;return!1}domFromPos(e){return{node:this.nodeDOM,offset:e}}localPosFromDOM(e,t,n){return e==this.nodeDOM?this.posAtStart+Math.min(t,this.node.text.length):super.localPosFromDOM(e,t,n)}ignoreMutation(e){return"characterData"!=e.type&&"selection"!=e.type}slice(e,t,n){let r=this.node.cut(e,t),i=document.createTextNode(r.text);return new Cr(this.parent,r,this.outerDeco,this.innerDeco,i,i,n)}markDirty(e,t){super.markDirty(e,t),this.dom==this.nodeDOM||0!=e&&t!=this.nodeDOM.nodeValue.length||(this.dirty=3)}get domAtom(){return!1}isText(e){return this.node.text==e}}class Nr extends br{parseRule(){return{ignore:!0}}matchesHack(e){return 0==this.dirty&&this.dom.nodeName==e}get domAtom(){return!0}get ignoreForCoords(){return"IMG"==this.dom.nodeName}}class Dr extends Mr{constructor(e,t,n,r,i,o,s,l,a,c){super(e,t,n,r,i,o,s,a,c),this.spec=l}update(e,t,n,r){if(3==this.dirty)return!1;if(this.spec.update){let i=this.spec.update(e,t,n);return i&&this.updateInner(e,t,n,r),i}return!(!this.contentDOM&&!e.isLeaf)&&super.update(e,t,n,r)}selectNode(){this.spec.selectNode?this.spec.selectNode():super.selectNode()}deselectNode(){this.spec.deselectNode?this.spec.deselectNode():super.deselectNode()}setSelection(e,t,n,r){this.spec.setSelection?this.spec.setSelection(e,t,n):super.setSelection(e,t,n,r)}destroy(){this.spec.destroy&&this.spec.destroy(),super.destroy()}stopEvent(e){return!!this.spec.stopEvent&&this.spec.stopEvent(e)}ignoreMutation(e){return this.spec.ignoreMutation?this.spec.ignoreMutation(e):super.ignoreMutation(e)}}function Tr(e,t,n){let r=e.firstChild,i=!1;for(let o=0;o0;){let l;for(;;)if(r){let e=n.children[r-1];if(!(e instanceof kr)){l=e,r--;break}n=e,r=e.children.length}else{if(n==t)break e;r=n.parent.children.indexOf(n),n=n.parent}let a=l.node;if(a){if(a!=e.child(i-1))break;--i,o.set(l,i),s.push(l)}}return{index:i,matched:o,matches:s.reverse()}}(e.node.content,e)}destroyBetween(e,t){if(e!=t){for(let n=e;n>1,o=Math.min(i,e.length);for(;r-1)r>this.index&&(this.changed=!0,this.destroyBetween(this.index,r)),this.top=this.top.children[this.index];else{let r=kr.create(this.top,e[i],t,n);this.top.children.splice(this.index,0,r),this.top=r,this.changed=!0}this.index=0,i++}}findNodeMatch(e,t,n,r){let i,o=-1;if(r>=this.preMatch.index&&(i=this.preMatch.matches[r-this.preMatch.index]).parent==this.top&&i.matchesNode(e,t,n))o=this.top.children.indexOf(i,this.index);else for(let s=this.index,l=Math.min(this.top.children.length,s+5);s=n||h<=t?o.push(a):(cn&&o.push(a.slice(n-c,a.size,r)))}return o}function Fr(e,t=null){let n=e.domSelectionRange(),r=e.state.doc;if(!n.focusNode)return null;let i=e.docView.nearestDesc(n.focusNode),o=i&&0==i.size,s=e.docView.posFromDOM(n.focusNode,n.focusOffset,1);if(s<0)return null;let l,a,c=r.resolve(s);if(An(n)){for(l=c;i&&!i.node;)i=i.parent;let e=i.node;if(i&&e.isAtom&&rn.isSelectable(e)&&i.parent&&(!e.isInline||!function(e,t,n){for(let r=0==t,i=t==Dn(e);r||i;){if(e==n)return!0;let t=xn(e);if(!(e=e.parentNode))return!1;r=r&&0==t,i=i&&t==Dn(e)}}(n.focusNode,n.focusOffset,i.dom))){let e=i.posBefore;a=new rn(s==e?c:r.resolve(e))}}else{let t=e.docView.posFromDOM(n.anchorNode,n.anchorOffset,1);if(t<0)return null;l=r.resolve(t)}if(!a){a=Gr(e,l,c,"pointer"==t||e.state.selection.head{n.anchorNode==r&&n.anchorOffset==i||(t.removeEventListener("selectionchange",e.input.hideSelectionGuard),setTimeout((()=>{Lr(e)&&!e.state.selection.visible||e.dom.classList.remove("ProseMirror-hideselection")}),20))})}(e))}e.domObserver.setCurSelection(),e.domObserver.connectSelection()}}const Wr=Wn||Ln&&qn<63;function Jr(e,t){let{node:n,offset:r}=e.docView.domFromPos(t,0),i=rr(e,t,n)))||tn.between(t,n,r)}function Zr(e){return!(e.editable&&!e.hasFocus())&&Xr(e)}function Xr(e){let t=e.domSelectionRange();if(!t.anchorNode)return!1;try{return e.dom.contains(3==t.anchorNode.nodeType?t.anchorNode.parentNode:t.anchorNode)&&(e.editable||e.dom.contains(3==t.focusNode.nodeType?t.focusNode.parentNode:t.focusNode))}catch(n){return!1}}function Qr(e,t){let{$anchor:n,$head:r}=e.selection,i=t>0?n.max(r):n.min(r),o=i.parent.inlineContent?i.depth?e.doc.resolve(t>0?i.after():i.before()):null:i;return o&&Zt.findFrom(o,t)}function ei(e,t){return e.dispatch(e.state.tr.setSelection(t).scrollIntoView()),!0}function ti(e,t,n){let r=e.state.selection;if(!(r instanceof tn)){if(r instanceof rn&&r.node.isInline)return ei(e,new tn(t>0?r.$to:r.$from));{let n=Qr(e.state,t);return!!n&&ei(e,n)}}if(n.indexOf("s")>-1){let{$head:n}=r,i=n.textOffset?null:t<0?n.nodeBefore:n.nodeAfter;if(!i||i.isText||!i.isLeaf)return!1;let o=e.state.doc.resolve(n.pos+i.nodeSize*(t<0?-1:1));return ei(e,new tn(r.$anchor,o))}if(!r.empty)return!1;if(e.endOfTextblock(t>0?"forward":"backward")){let n=Qr(e.state,t);return!!(n&&n instanceof rn)&&ei(e,n)}if(!(Kn&&n.indexOf("m")>-1)){let n,i=r.$head,o=i.textOffset?null:t<0?i.nodeBefore:i.nodeAfter;if(!o||o.isText)return!1;let s=t<0?i.pos-o.nodeSize:i.pos;return!!(o.isAtom||(n=e.docView.descAt(s))&&!n.contentDOM)&&(rn.isSelectable(o)?ei(e,new rn(t<0?e.state.doc.resolve(i.pos-o.nodeSize):i)):!!Un&&ei(e,new tn(e.state.doc.resolve(t<0?s:s+o.nodeSize))))}}function ni(e){return 3==e.nodeType?e.nodeValue.length:e.childNodes.length}function ri(e,t){let n=e.pmViewDesc;return n&&0==n.size&&(t<0||e.nextSibling||"BR"!=e.nodeName)}function ii(e,t){return t<0?function(e){let t=e.domSelectionRange(),n=t.focusNode,r=t.focusOffset;if(!n)return;let i,o,s=!1;jn&&1==n.nodeType&&r0){if(1!=n.nodeType)break;{let e=n.childNodes[r-1];if(ri(e,-1))i=n,o=--r;else{if(3!=e.nodeType)break;n=e,r=n.nodeValue.length}}}else{if(oi(n))break;{let t=n.previousSibling;for(;t&&ri(t,-1);)i=n.parentNode,o=xn(t),t=t.previousSibling;if(t)n=t,r=ni(n);else{if(n=n.parentNode,n==e.dom)break;r=0}}}s?si(e,n,r):i&&si(e,i,o)}(e):function(e){let t=e.domSelectionRange(),n=t.focusNode,r=t.focusOffset;if(!n)return;let i,o,s=ni(n);for(;;)if(r{e.state==i&&qr(e)}),50)}function li(e,t){let n=e.state.doc.resolve(t);if(!Ln&&!Hn&&n.parent.inlineContent){let r=e.coordsAtPos(t);if(t>n.start()){let n=e.coordsAtPos(t-1),i=(n.top+n.bottom)/2;if(i>r.top&&i1)return n.leftr.top&&i1)return n.left>r.left?"ltr":"rtl"}}return"rtl"==getComputedStyle(e.dom).direction?"rtl":"ltr"}function ai(e,t,n){let r=e.state.selection;if(r instanceof tn&&!r.empty||n.indexOf("s")>-1)return!1;if(Kn&&n.indexOf("m")>-1)return!1;let{$from:i,$to:o}=r;if(!i.parent.inlineContent||e.endOfTextblock(t<0?"up":"down")){let n=Qr(e.state,t);if(n&&n instanceof rn)return ei(e,n)}if(!i.parent.inlineContent){let n=t<0?i:o,s=r instanceof sn?Zt.near(n,t):Zt.findFrom(n,t);return!!s&&ei(e,s)}return!1}function ci(e,t){if(!(e.state.selection instanceof tn))return!0;let{$head:n,$anchor:r,empty:i}=e.state.selection;if(!n.sameParent(r))return!0;if(!i)return!1;if(e.endOfTextblock(t>0?"forward":"backward"))return!0;let o=!n.textOffset&&(t<0?n.nodeBefore:n.nodeAfter);if(o&&!o.isText){let r=e.state.tr;return t<0?r.delete(n.pos-o.nodeSize,n.pos):r.delete(n.pos,n.pos+o.nodeSize),e.dispatch(r),!0}return!1}function hi(e,t,n){e.domObserver.stop(),t.contentEditable=n,e.domObserver.start()}function ui(e,t){let n=t.keyCode,r=function(e){let t="";return e.ctrlKey&&(t+="c"),e.metaKey&&(t+="m"),e.altKey&&(t+="a"),e.shiftKey&&(t+="s"),t}(t);if(8==n||Kn&&72==n&&"c"==r)return ci(e,-1)||ii(e,-1);if(46==n&&!t.shiftKey||Kn&&68==n&&"c"==r)return ci(e,1)||ii(e,1);if(13==n||27==n)return!0;if(37==n||Kn&&66==n&&"c"==r){let t=37==n?"ltr"==li(e,e.state.selection.from)?-1:1:-1;return ti(e,t,r)||ii(e,t)}if(39==n||Kn&&70==n&&"c"==r){let t=39==n?"ltr"==li(e,e.state.selection.from)?1:-1:1;return ti(e,t,r)||ii(e,t)}return 38==n||Kn&&80==n&&"c"==r?ai(e,-1,r)||ii(e,-1):40==n||Kn&&78==n&&"c"==r?function(e){if(!Wn||e.state.selection.$head.parentOffset>0)return!1;let{focusNode:t,focusOffset:n}=e.domSelectionRange();if(t&&1==t.nodeType&&0==n&&t.firstChild&&"false"==t.firstChild.contentEditable){let n=t.firstChild;hi(e,n,"true"),setTimeout((()=>hi(e,n,"false")),20)}return!1}(e)||ai(e,1,r)||ii(e,1):r==(Kn?"m":"c")&&(66==n||73==n||89==n||90==n)}function di(e,t){e.someProp("transformCopied",(n=>{t=n(t,e)}));let n=[],{content:r,openStart:i,openEnd:o}=t;for(;i>1&&o>1&&1==r.childCount&&1==r.firstChild.childCount;){i--,o--;let e=r.firstChild;n.push(e.type.name,e.attrs!=e.type.defaultAttrs?e.attrs:null),r=e.content}let s=e.someProp("clipboardSerializer")||ut.fromSchema(e.state.schema),l=Si(),a=l.createElement("div");a.appendChild(s.serializeFragment(r,{document:l}));let c,h=a.firstChild,u=0;for(;h&&1==h.nodeType&&(c=bi[h.nodeName.toLowerCase()]);){for(let e=c.length-1;e>=0;e--){let t=l.createElement(c[e]);for(;a.firstChild;)t.appendChild(a.firstChild);a.appendChild(t),u++}h=a.firstChild}return h&&1==h.nodeType&&h.setAttribute("data-pm-slice",`${i} ${o}${u?` -${u}`:""} ${JSON.stringify(n)}`),{dom:a,text:e.someProp("clipboardTextSerializer",(n=>n(t,e)))||t.content.textBetween(0,t.content.size,"\n\n"),slice:t}}function fi(e,t,n,r,i){let o,s,l=i.parent.type.spec.code;if(!n&&!t)return null;let a=t&&(r||l||!n);if(a){if(e.someProp("transformPastedText",(n=>{t=n(t,l||r,e)})),l)return t?new ye(ue.from(e.state.schema.text(t.replace(/\r\n?/g,"\n"))),0,0):ye.empty;let n=e.someProp("clipboardTextParser",(n=>n(t,i,r,e)));if(n)s=n;else{let n=i.marks(),{schema:r}=e.state,s=ut.fromSchema(r);o=document.createElement("div"),t.split(/(?:\r\n?|\n)+/).forEach((e=>{let t=o.appendChild(document.createElement("p"));e&&t.appendChild(s.serializeNode(r.text(e,n)))}))}}else e.someProp("transformPastedHTML",(t=>{n=t(n,e)})),o=function(e){let t=/^(\s*]*>)*/.exec(e);t&&(e=e.slice(t[0].length));let n,r=Si().createElement("div"),i=/<([a-z][^>\s]+)/i.exec(e);(n=i&&bi[i[1].toLowerCase()])&&(e=n.map((e=>"<"+e+">")).join("")+e+n.map((e=>"")).reverse().join(""));if(r.innerHTML=e,n)for(let o=0;o0;u--){let e=o.firstChild;for(;e&&1!=e.nodeType;)e=e.nextSibling;if(!e)break;o=e}if(!s){let t=e.someProp("clipboardParser")||e.someProp("domParser")||tt.fromSchema(e.state.schema);s=t.parseSlice(o,{preserveWhitespace:!(!a&&!h),context:i,ruleFromNode:e=>"BR"!=e.nodeName||e.nextSibling||!e.parentNode||pi.test(e.parentNode.nodeName)?null:{ignore:!0}})}if(h)s=function(e,t){if(!e.size)return e;let n,r=e.content.firstChild.type.schema;try{n=JSON.parse(t)}catch(l){return e}let{content:i,openStart:o,openEnd:s}=e;for(let a=n.length-2;a>=0;a-=2){let e=r.nodes[n[a]];if(!e||e.hasRequiredAttrs())break;i=ue.from(e.create(n[a+1],i)),o++,s++}return new ye(i,o,s)}(wi(s,+h[1],+h[2]),h[4]);else if(s=ye.maxOpen(function(e,t){if(e.childCount<2)return e;for(let n=t.depth;n>=0;n--){let r,i=t.node(n).contentMatchAt(t.index(n)),o=[];if(e.forEach((e=>{if(!o)return;let t,n=i.findWrapping(e.type);if(!n)return o=null;if(t=o.length&&r.length&&gi(n,r,e,o[o.length-1],0))o[o.length-1]=t;else{o.length&&(o[o.length-1]=yi(o[o.length-1],r.length));let t=mi(e,n);o.push(t),i=i.matchType(t.type),r=n}})),o)return ue.from(o)}return e}(s.content,i),!0),s.openStart||s.openEnd){let e=0,t=0;for(let n=s.content.firstChild;e{s=t(s,e)})),s}const pi=/^(a|abbr|acronym|b|cite|code|del|em|i|ins|kbd|label|output|q|ruby|s|samp|span|strong|sub|sup|time|u|tt|var)$/i;function mi(e,t,n=0){for(let r=t.length-1;r>=n;r--)e=t[r].create(null,ue.from(e));return e}function gi(e,t,n,r,i){if(i1&&(o=0),i=n&&(l=t<0?s.contentMatchAt(0).fillBefore(l,o<=i).append(l):l.append(s.contentMatchAt(s.childCount).fillBefore(ue.empty,!0))),e.replaceChild(t<0?0:e.childCount-1,s.copy(l))}function wi(e,t,n){return t{for(let n in t)e.input.eventHandlers[n]||e.dom.addEventListener(n,e.input.eventHandlers[n]=t=>Ti(e,t))}))}function Ti(e,t){return e.someProp("handleDOMEvents",(n=>{let r=n[t.type];return!!r&&(r(e,t)||t.defaultPrevented)}))}function Ai(e,t){if(!t.bubbles)return!0;if(t.defaultPrevented)return!1;for(let n=t.target;n!=e.dom;n=n.parentNode)if(!n||11==n.nodeType||n.pmViewDesc&&n.pmViewDesc.stopEvent(t))return!1;return!0}function Ei(e){return{left:e.clientX,top:e.clientY}}function $i(e,t,n,r,i){if(-1==r)return!1;let o=e.state.doc.resolve(r);for(let s=o.depth+1;s>0;s--)if(e.someProp(t,(t=>s>o.depth?t(e,n,o.nodeAfter,o.before(s),i,!0):t(e,n,o.node(s),o.before(s),i,!1))))return!0;return!1}function Pi(e,t,n){e.focused||e.focus();let r=e.state.tr.setSelection(t);"pointer"==n&&r.setMeta("pointer",!0),e.dispatch(r)}function Ii(e,t,n,r,i){return $i(e,"handleClickOn",t,n,r)||e.someProp("handleClick",(n=>n(e,t,r)))||(i?function(e,t){if(-1==t)return!1;let n,r,i=e.state.selection;i instanceof rn&&(n=i.node);let o=e.state.doc.resolve(t);for(let s=o.depth+1;s>0;s--){let e=s>o.depth?o.nodeAfter:o.node(s);if(rn.isSelectable(e)){r=n&&i.$from.depth>0&&s>=i.$from.depth&&o.before(i.$from.depth+1)==i.$from.pos?o.before(i.$from.depth):o.before(s);break}}return null!=r&&(Pi(e,rn.create(e.state.doc,r),"pointer"),!0)}(e,n):function(e,t){if(-1==t)return!1;let n=e.state.doc.resolve(t),r=n.nodeAfter;return!!(r&&r.isAtom&&rn.isSelectable(r))&&(Pi(e,new rn(n),"pointer"),!0)}(e,n))}function Ri(e,t,n,r){return $i(e,"handleDoubleClickOn",t,n,r)||e.someProp("handleDoubleClick",(n=>n(e,t,r)))}function zi(e,t,n,r){return $i(e,"handleTripleClickOn",t,n,r)||e.someProp("handleTripleClick",(n=>n(e,t,r)))||function(e,t,n){if(0!=n.button)return!1;let r=e.state.doc;if(-1==t)return!!r.inlineContent&&(Pi(e,tn.create(r,0,r.content.size),"pointer"),!0);let i=r.resolve(t);for(let o=i.depth+1;o>0;o--){let t=o>i.depth?i.nodeAfter:i.node(o),n=i.before(o);if(t.inlineContent)Pi(e,tn.create(r,n+1,n+1+t.content.size),"pointer");else{if(!rn.isSelectable(t))continue;Pi(e,rn.create(r,n),"pointer")}return!0}}(e,n,r)}function _i(e){return Ji(e)}Mi.keydown=(e,t)=>{let n=t;if(e.input.shiftKey=16==n.keyCode||n.shiftKey,!ji(e,n)&&(e.input.lastKeyCode=n.keyCode,e.input.lastKeyCodeTime=Date.now(),!Yn||!Ln||13!=n.keyCode))if(229!=n.keyCode&&e.domObserver.forceFlush(),!Jn||13!=n.keyCode||n.ctrlKey||n.altKey||n.metaKey)e.someProp("handleKeyDown",(t=>t(e,n)))||ui(e,n)?n.preventDefault():Ni(e,"key");else{let t=Date.now();e.input.lastIOSEnter=t,e.input.lastIOSEnterFallbackTimeout=setTimeout((()=>{e.input.lastIOSEnter==t&&(e.someProp("handleKeyDown",(t=>t(e,En(13,"Enter")))),e.input.lastIOSEnter=0)}),200)}},Mi.keyup=(e,t)=>{16==t.keyCode&&(e.input.shiftKey=!1)},Mi.keypress=(e,t)=>{let n=t;if(ji(e,n)||!n.charCode||n.ctrlKey&&!n.altKey||Kn&&n.metaKey)return;if(e.someProp("handleKeyPress",(t=>t(e,n))))return void n.preventDefault();let r=e.state.selection;if(!(r instanceof tn&&r.$from.sameParent(r.$to))){let t=String.fromCharCode(n.charCode);/[\r\n]/.test(t)||e.someProp("handleTextInput",(n=>n(e,r.$from.pos,r.$to.pos,t)))||e.dispatch(e.state.tr.insertText(t).scrollIntoView()),n.preventDefault()}};const Bi=Kn?"metaKey":"ctrlKey";ki.mousedown=(e,t)=>{let n=t;e.input.shiftKey=n.shiftKey;let r=_i(e),i=Date.now(),o="singleClick";i-e.input.lastClick.time<500&&function(e,t){let n=t.x-e.clientX,r=t.y-e.clientY;return n*n+r*r<100}(n,e.input.lastClick)&&!n[Bi]&&("singleClick"==e.input.lastClick.type?o="doubleClick":"doubleClick"==e.input.lastClick.type&&(o="tripleClick")),e.input.lastClick={time:i,x:n.clientX,y:n.clientY,type:o};let s=e.posAtCoords(Ei(n));s&&("singleClick"==o?(e.input.mouseDown&&e.input.mouseDown.done(),e.input.mouseDown=new Vi(e,s,n,!!r)):("doubleClick"==o?Ri:zi)(e,s.pos,s.inside,n)?n.preventDefault():Ni(e,"pointer"))};class Vi{constructor(e,t,n,r){let i,o;if(this.view=e,this.pos=t,this.event=n,this.flushed=r,this.delayedSelectionSync=!1,this.mightDrag=null,this.startDoc=e.state.doc,this.selectNode=!!n[Bi],this.allowDefault=n.shiftKey,t.inside>-1)i=e.state.doc.nodeAt(t.inside),o=t.inside;else{let n=e.state.doc.resolve(t.pos);i=n.parent,o=n.depth?n.before():0}const s=r?null:n.target,l=s?e.docView.nearestDesc(s,!0):null;this.target=l&&1==l.dom.nodeType?l.dom:null;let{selection:a}=e.state;(0==n.button&&i.type.spec.draggable&&!1!==i.type.spec.selectable||a instanceof rn&&a.from<=o&&a.to>o)&&(this.mightDrag={node:i,pos:o,addAttr:!(!this.target||this.target.draggable),setUneditable:!(!this.target||!jn||this.target.hasAttribute("contentEditable"))}),this.target&&this.mightDrag&&(this.mightDrag.addAttr||this.mightDrag.setUneditable)&&(this.view.domObserver.stop(),this.mightDrag.addAttr&&(this.target.draggable=!0),this.mightDrag.setUneditable&&setTimeout((()=>{this.view.input.mouseDown==this&&this.target.setAttribute("contentEditable","false")}),20),this.view.domObserver.start()),e.root.addEventListener("mouseup",this.up=this.up.bind(this)),e.root.addEventListener("mousemove",this.move=this.move.bind(this)),Ni(e,"pointer")}done(){this.view.root.removeEventListener("mouseup",this.up),this.view.root.removeEventListener("mousemove",this.move),this.mightDrag&&this.target&&(this.view.domObserver.stop(),this.mightDrag.addAttr&&this.target.removeAttribute("draggable"),this.mightDrag.setUneditable&&this.target.removeAttribute("contentEditable"),this.view.domObserver.start()),this.delayedSelectionSync&&setTimeout((()=>qr(this.view))),this.view.input.mouseDown=null}up(e){if(this.done(),!this.view.dom.contains(e.target))return;let t=this.pos;this.view.state.doc!=this.startDoc&&(t=this.view.posAtCoords(Ei(e))),this.updateAllowDefault(e),this.allowDefault||!t?Ni(this.view,"pointer"):Ii(this.view,t.pos,t.inside,e,this.selectNode)?e.preventDefault():0==e.button&&(this.flushed||Wn&&this.mightDrag&&!this.mightDrag.node.isAtom||Ln&&!this.view.state.selection.visible&&Math.min(Math.abs(t.pos-this.view.state.selection.from),Math.abs(t.pos-this.view.state.selection.to))<=2)?(Pi(this.view,Zt.near(this.view.state.doc.resolve(t.pos)),"pointer"),e.preventDefault()):Ni(this.view,"pointer")}move(e){this.updateAllowDefault(e),Ni(this.view,"pointer"),0==e.buttons&&this.done()}updateAllowDefault(e){!this.allowDefault&&(Math.abs(this.event.x-e.clientX)>4||Math.abs(this.event.y-e.clientY)>4)&&(this.allowDefault=!0)}}function ji(e,t){return!!e.composing||!!(Wn&&Math.abs(t.timeStamp-e.input.compositionEndedAt)<500)&&(e.input.compositionEndedAt=-2e8,!0)}ki.touchstart=e=>{e.input.lastTouch=Date.now(),_i(e),Ni(e,"pointer")},ki.touchmove=e=>{e.input.lastTouch=Date.now(),Ni(e,"pointer")},ki.contextmenu=e=>_i(e);const Fi=Yn?5e3:-1;function Li(e,t){clearTimeout(e.input.composingTimeout),t>-1&&(e.input.composingTimeout=setTimeout((()=>Ji(e)),t))}function qi(e){for(e.composing&&(e.input.composing=!1,e.input.compositionEndedAt=function(){let e=document.createEvent("Event");return e.initEvent("event",!0,!0),e.timeStamp}());e.input.compositionNodes.length>0;)e.input.compositionNodes.pop().markParentsDirty()}function Wi(e){let t=e.domSelectionRange();if(!t.focusNode)return null;let n=function(e,t){for(;;){if(3==e.nodeType&&t)return e;if(1==e.nodeType&&t>0){if("false"==e.contentEditable)return null;t=Dn(e=e.childNodes[t-1])}else{if(!e.parentNode||Tn(e))return null;t=xn(e),e=e.parentNode}}}(t.focusNode,t.focusOffset),r=function(e,t){for(;;){if(3==e.nodeType&&t=0)){if(e.domObserver.forceFlush(),qi(e),t||e.docView&&e.docView.dirty){let t=Fr(e);return t&&!t.eq(e.state.selection)?e.dispatch(e.state.tr.setSelection(t)):e.updateState(e.state),!0}return!1}}Mi.compositionstart=Mi.compositionupdate=e=>{if(!e.composing){e.domObserver.flush();let{state:t}=e,n=t.selection.$from;if(t.selection.empty&&(t.storedMarks||!n.textOffset&&n.parentOffset&&n.nodeBefore.marks.some((e=>!1===e.type.spec.inclusive))))e.markCursor=e.state.storedMarks||n.marks(),Ji(e,!0),e.markCursor=null;else if(Ji(e),jn&&t.selection.empty&&n.parentOffset&&!n.textOffset&&n.nodeBefore.marks.length){let t=e.domSelectionRange();for(let n=t.focusNode,r=t.focusOffset;n&&1==n.nodeType&&0!=r;){let t=r<0?n.lastChild:n.childNodes[r-1];if(!t)break;if(3==t.nodeType){e.domSelection().collapse(t,t.nodeValue.length);break}n=t,r=-1}}e.input.composing=!0}Li(e,Fi)},Mi.compositionend=(e,t)=>{e.composing&&(e.input.composing=!1,e.input.compositionEndedAt=t.timeStamp,e.input.compositionPendingChanges=e.domObserver.pendingRecords().length?e.input.compositionID:0,e.input.compositionNode=null,e.input.compositionPendingChanges&&Promise.resolve().then((()=>e.domObserver.flush())),e.input.compositionID++,Li(e,20))};const Ki=Bn&&Vn<15||Jn&&Gn<604;function Hi(e,t,n,r,i){let o=fi(e,t,n,r,e.state.selection.$from);if(e.someProp("handlePaste",(t=>t(e,i,o||ye.empty))))return!0;if(!o)return!1;let s=function(e){return 0==e.openStart&&0==e.openEnd&&1==e.content.childCount?e.content.firstChild:null}(o),l=s?e.state.tr.replaceSelectionWith(s,r):e.state.tr.replaceSelection(o);return e.dispatch(l.scrollIntoView().setMeta("paste",!0).setMeta("uiEvent","paste")),!0}function Yi(e){let t=e.getData("text/plain")||e.getData("Text");if(t)return t;let n=e.getData("text/uri-list");return n?n.replace(/\r?\n/g," "):""}ki.copy=Mi.cut=(e,t)=>{let n=t,r=e.state.selection,i="cut"==n.type;if(r.empty)return;let o=Ki?null:n.clipboardData,s=r.content(),{dom:l,text:a}=di(e,s);o?(n.preventDefault(),o.clearData(),o.setData("text/html",l.innerHTML),o.setData("text/plain",a)):function(e,t){if(!e.dom.parentNode)return;let n=e.dom.parentNode.appendChild(document.createElement("div"));n.appendChild(t),n.style.cssText="position: fixed; left: -10000px; top: 10px";let r=getSelection(),i=document.createRange();i.selectNodeContents(t),e.dom.blur(),r.removeAllRanges(),r.addRange(i),setTimeout((()=>{n.parentNode&&n.parentNode.removeChild(n),e.focus()}),50)}(e,l),i&&e.dispatch(e.state.tr.deleteSelection().scrollIntoView().setMeta("uiEvent","cut"))},Mi.paste=(e,t)=>{let n=t;if(e.composing&&!Yn)return;let r=Ki?null:n.clipboardData,i=e.input.shiftKey&&45!=e.input.lastKeyCode;r&&Hi(e,Yi(r),r.getData("text/html"),i,n)?n.preventDefault():function(e,t){if(!e.dom.parentNode)return;let n=e.input.shiftKey||e.state.selection.$from.parent.type.spec.code,r=e.dom.parentNode.appendChild(document.createElement(n?"textarea":"div"));n||(r.contentEditable="true"),r.style.cssText="position: fixed; left: -10000px; top: 10px",r.focus();let i=e.input.shiftKey&&45!=e.input.lastKeyCode;setTimeout((()=>{e.focus(),r.parentNode&&r.parentNode.removeChild(r),n?Hi(e,r.value,null,i,t):Hi(e,r.textContent,r.innerHTML,i,t)}),50)}(e,n)};class Ui{constructor(e,t,n){this.slice=e,this.move=t,this.node=n}}const Gi=Kn?"altKey":"ctrlKey";ki.dragstart=(e,t)=>{let n=t,r=e.input.mouseDown;if(r&&r.done(),!n.dataTransfer)return;let i,o=e.state.selection,s=o.empty?null:e.posAtCoords(Ei(n));if(s&&s.pos>=o.from&&s.pos<=(o instanceof rn?o.to-1:o.to));else if(r&&r.mightDrag)i=rn.create(e.state.doc,r.mightDrag.pos);else if(n.target&&1==n.target.nodeType){let t=e.docView.nearestDesc(n.target,!0);t&&t.node.type.spec.draggable&&t!=e.docView&&(i=rn.create(e.state.doc,t.posBefore))}let l=(i||e.state.selection).content(),{dom:a,text:c,slice:h}=di(e,l);n.dataTransfer.clearData(),n.dataTransfer.setData(Ki?"Text":"text/html",a.innerHTML),n.dataTransfer.effectAllowed="copyMove",Ki||n.dataTransfer.setData("text/plain",c),e.dragging=new Ui(h,!n[Gi],i)},ki.dragend=e=>{let t=e.dragging;window.setTimeout((()=>{e.dragging==t&&(e.dragging=null)}),50)},Mi.dragover=Mi.dragenter=(e,t)=>t.preventDefault(),Mi.drop=(e,t)=>{let n=t,r=e.dragging;if(e.dragging=null,!n.dataTransfer)return;let i=e.posAtCoords(Ei(n));if(!i)return;let o=e.state.doc.resolve(i.pos),s=r&&r.slice;s?e.someProp("transformPasted",(t=>{s=t(s,e)})):s=fi(e,Yi(n.dataTransfer),Ki?null:n.dataTransfer.getData("text/html"),!1,o);let l=!(!r||n[Gi]);if(e.someProp("handleDrop",(t=>t(e,n,s||ye.empty,l))))return void n.preventDefault();if(!s)return;n.preventDefault();let a=s?function(e,t,n){let r=e.resolve(t);if(!n.content.size)return t;let i=n.content;for(let o=0;o=0;e--){let t=e==r.depth?0:r.pos<=(r.start(e+1)+r.end(e+1))/2?-1:1,n=r.index(e)+(t>0?1:0),s=r.node(e),l=!1;if(1==o)l=s.canReplace(n,n,i);else{let e=s.contentMatchAt(n).findWrapping(i.firstChild.type);l=e&&s.canReplaceWith(n,n,e[0])}if(l)return 0==t?r.pos:t<0?r.before(e+1):r.after(e+1)}return null}(e.state.doc,o.pos,s):o.pos;null==a&&(a=o.pos);let c=e.state.tr;if(l){let{node:e}=r;e?e.replace(c):c.deleteSelection()}let h=c.mapping.map(a),u=0==s.openStart&&0==s.openEnd&&1==s.content.childCount,d=c.doc;if(u?c.replaceRangeWith(h,h,s.content.firstChild):c.replaceRange(h,h,s),c.doc.eq(d))return;let f=c.doc.resolve(h);if(u&&rn.isSelectable(s.content.firstChild)&&f.nodeAfter&&f.nodeAfter.sameMarkup(s.content.firstChild))c.setSelection(new rn(f));else{let t=c.mapping.map(a);c.mapping.maps[c.mapping.maps.length-1].forEach(((e,n,r,i)=>t=i)),c.setSelection(Gr(e,f,c.doc.resolve(t)))}e.focus(),e.dispatch(c.setMeta("uiEvent","drop"))},ki.focus=e=>{e.input.lastFocus=Date.now(),e.focused||(e.domObserver.stop(),e.dom.classList.add("ProseMirror-focused"),e.domObserver.start(),e.focused=!0,setTimeout((()=>{e.docView&&e.hasFocus()&&!e.domObserver.currentSelection.eq(e.domSelectionRange())&&qr(e)}),20))},ki.blur=(e,t)=>{let n=t;e.focused&&(e.domObserver.stop(),e.dom.classList.remove("ProseMirror-focused"),e.domObserver.start(),n.relatedTarget&&e.dom.contains(n.relatedTarget)&&e.domObserver.currentSelection.clear(),e.focused=!1)},ki.beforeinput=(e,t)=>{if(Ln&&Yn&&"deleteContentBackward"==t.inputType){e.domObserver.flushSoon();let{domChangeCount:t}=e.input;setTimeout((()=>{if(e.input.domChangeCount!=t)return;if(e.dom.blur(),e.focus(),e.someProp("handleKeyDown",(t=>t(e,En(8,"Backspace")))))return;let{$cursor:n}=e.state.selection;n&&n.pos>0&&e.dispatch(e.state.tr.delete(n.pos-1,n.pos).scrollIntoView())}),50)}};for(let os in Mi)ki[os]=Mi[os];function Zi(e,t){if(e==t)return!0;for(let n in e)if(e[n]!==t[n])return!1;for(let n in t)if(!(n in e))return!1;return!0}class Xi{constructor(e,t){this.toDOM=e,this.spec=t||ro,this.side=this.spec.side||0}map(e,t,n,r){let{pos:i,deleted:o}=e.mapResult(t.from+r,this.side<0?-1:1);return o?null:new to(i-n,i-n,this)}valid(){return!0}eq(e){return this==e||e instanceof Xi&&(this.spec.key&&this.spec.key==e.spec.key||this.toDOM==e.toDOM&&Zi(this.spec,e.spec))}destroy(e){this.spec.destroy&&this.spec.destroy(e)}}class Qi{constructor(e,t){this.attrs=e,this.spec=t||ro}map(e,t,n,r){let i=e.map(t.from+r,this.spec.inclusiveStart?-1:1)-n,o=e.map(t.to+r,this.spec.inclusiveEnd?1:-1)-n;return i>=o?null:new to(i,o,this)}valid(e,t){return t.from=e&&(!i||i(s.spec))&&n.push(s.copy(s.from+r,s.to+r))}for(let o=0;oe){let s=this.children[o]+1;this.children[o+2].findInner(e-s,t-s,n,r+s,i)}}map(e,t,n){return this==oo||0==e.maps.length?this:this.mapInner(e,t,0,0,n||ro)}mapInner(e,t,n,r,i){let o;for(let s=0;s{let o=i-r-(n-t);for(let s=0;sr+h-e)continue;let i=l[s]+h-e;n>=i?l[s+1]=t<=i?-2:-1:t>=h&&o&&(l[s]+=o,l[s+1]+=o)}e+=o})),h=n.maps[c].map(h,-1)}let a=!1;for(let c=0;c=r.content.size){a=!0;continue}let u=n.map(e[c+1]+o,-1)-i,{index:d,offset:f}=r.content.findIndex(h),p=r.maybeChild(d);if(p&&f==h&&f+p.nodeSize==u){let r=l[c+2].mapInner(n,p,t+1,e[c]+o+1,s);r!=oo?(l[c]=h,l[c+1]=u,l[c+2]=r):(l[c+1]=-2,a=!0)}else a=!0}if(a){let a=function(e,t,n,r,i,o,s){function l(e,t){for(let o=0;o{let s,l=o+n;if(s=ao(t,e,l)){for(r||(r=this.children.slice());io&&t.to=e){this.children[s]==e&&(n=this.children[s+2]);break}let i=e+1,o=i+t.content.size;for(let s=0;si&&e.type instanceof Qi){let t=Math.max(i,e.from)-i,n=Math.min(o,e.to)-i;tn.map(e,t,ro)));return so.from(n)}forChild(e,t){if(t.isLeaf)return io.empty;let n=[];for(let r=0;re instanceof io))?e:e.reduce(((e,t)=>e.concat(t instanceof io?t:t.members)),[]))}}}function lo(e,t){if(!t||!e.length)return e;let n=[];for(let r=0;rn&&o.to{let l=ao(e,t,s+n);if(l){o=!0;let e=ho(l,t,n+s+1,r);e!=oo&&i.push(s,s+t.nodeSize,e)}}));let s=lo(o?co(e):e,-n).sort(uo);for(let l=0;l0;)t++;e.splice(t,0,n)}function mo(e){let t=[];return e.someProp("decorations",(n=>{let r=n(e.state);r&&r!=oo&&t.push(r)})),e.cursorWrapper&&t.push(io.create(e.state.doc,[e.cursorWrapper.deco])),so.from(t)}const go={childList:!0,characterData:!0,characterDataOldValue:!0,attributes:!0,attributeOldValue:!0,subtree:!0},yo=Bn&&Vn<=11;class vo{constructor(){this.anchorNode=null,this.anchorOffset=0,this.focusNode=null,this.focusOffset=0}set(e){this.anchorNode=e.anchorNode,this.anchorOffset=e.anchorOffset,this.focusNode=e.focusNode,this.focusOffset=e.focusOffset}clear(){this.anchorNode=this.focusNode=null}eq(e){return e.anchorNode==this.anchorNode&&e.anchorOffset==this.anchorOffset&&e.focusNode==this.focusNode&&e.focusOffset==this.focusOffset}}class wo{constructor(e,t){this.view=e,this.handleDOMChange=t,this.queue=[],this.flushingSoon=-1,this.observer=null,this.currentSelection=new vo,this.onCharData=null,this.suppressingSelectionUpdates=!1,this.observer=window.MutationObserver&&new window.MutationObserver((e=>{for(let t=0;t"childList"==e.type&&e.removedNodes.length||"characterData"==e.type&&e.oldValue.length>e.target.nodeValue.length))?this.flushSoon():this.flush()})),yo&&(this.onCharData=e=>{this.queue.push({target:e.target,type:"characterData",oldValue:e.prevValue}),this.flushSoon()}),this.onSelectionChange=this.onSelectionChange.bind(this)}flushSoon(){this.flushingSoon<0&&(this.flushingSoon=window.setTimeout((()=>{this.flushingSoon=-1,this.flush()}),20))}forceFlush(){this.flushingSoon>-1&&(window.clearTimeout(this.flushingSoon),this.flushingSoon=-1,this.flush())}start(){this.observer&&(this.observer.takeRecords(),this.observer.observe(this.view.dom,go)),this.onCharData&&this.view.dom.addEventListener("DOMCharacterDataModified",this.onCharData),this.connectSelection()}stop(){if(this.observer){let e=this.observer.takeRecords();if(e.length){for(let t=0;tthis.flush()),20)}this.observer.disconnect()}this.onCharData&&this.view.dom.removeEventListener("DOMCharacterDataModified",this.onCharData),this.disconnectSelection()}connectSelection(){this.view.dom.ownerDocument.addEventListener("selectionchange",this.onSelectionChange)}disconnectSelection(){this.view.dom.ownerDocument.removeEventListener("selectionchange",this.onSelectionChange)}suppressSelectionUpdates(){this.suppressingSelectionUpdates=!0,setTimeout((()=>this.suppressingSelectionUpdates=!1),50)}onSelectionChange(){if(Zr(this.view)){if(this.suppressingSelectionUpdates)return qr(this.view);if(Bn&&Vn<=11&&!this.view.state.selection.empty){let e=this.view.domSelectionRange();if(e.focusNode&&On(e.focusNode,e.focusOffset,e.anchorNode,e.anchorOffset))return this.flushSoon()}this.flush()}}setCurSelection(){this.currentSelection.set(this.view.domSelectionRange())}ignoreSelectionChange(e){if(!e.focusNode)return!0;let t,n=new Set;for(let i=e.focusNode;i;i=Sn(i))n.add(i);for(let i=e.anchorNode;i;i=Sn(i))if(n.has(i)){t=i;break}let r=t&&this.view.docView.nearestDesc(t);return r&&r.ignoreMutation({type:"selection",target:3==t.nodeType?t.parentNode:t})?(this.setCurSelection(),!0):void 0}pendingRecords(){if(this.observer)for(let e of this.observer.takeRecords())this.queue.push(e);return this.queue}flush(){let{view:e}=this;if(!e.docView||this.flushingSoon>-1)return;let t=this.pendingRecords();t.length&&(this.queue=[]);let n=e.domSelectionRange(),r=!this.suppressingSelectionUpdates&&!this.currentSelection.eq(n)&&Zr(e)&&!this.ignoreSelectionChange(n),i=-1,o=-1,s=!1,l=[];if(e.editable)for(let c=0;c"BR"==e.nodeName));if(2==t.length){let[e,n]=t;e.parentNode&&e.parentNode.parentNode==n.parentNode?n.remove():e.remove()}else{let{focusNode:n}=this.currentSelection;for(let r of t){let t=r.parentNode;!t||"LI"!=t.nodeName||n&&ko(e,n)==t||r.remove()}}}let a=null;i<0&&r&&e.input.lastFocus>Date.now()-200&&Math.max(e.input.lastTouch,e.input.lastClick.time)-1||r)&&(i>-1&&(e.docView.markDirty(i,o),function(e){if(bo.has(e))return;if(bo.set(e,null),-1!==["normal","nowrap","pre-line"].indexOf(getComputedStyle(e.dom).whiteSpace)){if(e.requiresGeckoHackNode=jn,xo)return;console.warn("ProseMirror expects the CSS white-space property to be set, preferably to 'pre-wrap'. It is recommended to load style/prosemirror.css from the prosemirror-view package."),xo=!0}}(e)),this.handleDOMChange(i,o,s,l),e.docView&&e.docView.dirty?e.updateState(e.state):this.currentSelection.eq(n)||qr(e),this.currentSelection.set(n))}registerMutation(e,t){if(t.indexOf(e.target)>-1)return null;let n=this.view.docView.nearestDesc(e.target);if("attributes"==e.type&&(n==this.view.docView||"contenteditable"==e.attributeName||"style"==e.attributeName&&!e.oldValue&&!e.target.getAttribute("style")))return null;if(!n||n.ignoreMutation(e))return null;if("childList"==e.type){for(let n=0;nDate.now()-50?e.input.lastSelectionOrigin:null,n=Fr(e,t);if(n&&!e.state.selection.eq(n)){if(Ln&&Yn&&13===e.input.lastKeyCode&&Date.now()-100t(e,En(13,"Enter")))))return;let r=e.state.tr.setSelection(n);"pointer"==t?r.setMeta("pointer",!0):"key"==t&&r.scrollIntoView(),o&&r.setMeta("composition",o),e.dispatch(r)}return}let s=e.state.doc.resolve(t),l=s.sharedDepth(n);t=s.before(l+1),n=e.state.doc.resolve(n).after(l+1);let a,c,h=e.state.selection,u=function(e,t,n){let r,{node:i,fromOffset:o,toOffset:s,from:l,to:a}=e.docView.parseRange(t,n),c=e.domSelectionRange(),h=c.anchorNode;if(h&&e.dom.contains(1==h.nodeType?h:h.parentNode)&&(r=[{node:h,offset:c.anchorOffset}],An(c)||r.push({node:c.focusNode,offset:c.focusOffset})),Ln&&8===e.input.lastKeyCode)for(let g=s;g>o;g--){let e=i.childNodes[g-1],t=e.pmViewDesc;if("BR"==e.nodeName&&!t){s=g;break}if(!t||t.size)break}let u=e.state.doc,d=e.someProp("domParser")||tt.fromSchema(e.state.schema),f=u.resolve(l),p=null,m=d.parse(i,{topNode:f.parent,topMatch:f.parent.contentMatchAt(f.index()),topOpen:!0,from:o,to:s,preserveWhitespace:"pre"!=f.parent.type.whitespace||"full",findPositions:r,ruleFromNode:Mo,context:f});if(r&&null!=r[0].pos){let e=r[0].pos,t=r[1]&&r[1].pos;null==t&&(t=e),p={anchor:e+l,head:t+l}}return{doc:m,sel:p,from:l,to:a}}(e,t,n),d=e.state.doc,f=d.slice(u.from,u.to);8===e.input.lastKeyCode&&Date.now()-100=s?o-r:0;o-=e,o&&o=l?o-r:0;o-=t,o&&oDate.now()-225||Yn)&&i.some((e=>1==e.nodeType&&!Oo.test(e.nodeName)))&&(!p||p.endA>=p.endB)&&e.someProp("handleKeyDown",(t=>t(e,En(13,"Enter")))))return void(e.input.lastIOSEnter=0);if(!p){if(!(r&&h instanceof tn&&!h.empty&&h.$head.sameParent(h.$anchor))||e.composing||u.sel&&u.sel.anchor!=u.sel.head){if(u.sel){let t=No(e,e.state.doc,u.sel);if(t&&!t.eq(e.state.selection)){let n=e.state.tr.setSelection(t);o&&n.setMeta("composition",o),e.dispatch(n)}}return}p={start:h.from,endA:h.to,endB:h.to}}e.input.domChangeCount++,e.state.selection.frome.state.selection.from&&p.start<=e.state.selection.from+2&&e.state.selection.from>=u.from?p.start=e.state.selection.from:p.endA=e.state.selection.to-2&&e.state.selection.to<=u.to&&(p.endB+=e.state.selection.to-p.endA,p.endA=e.state.selection.to)),Bn&&Vn<=11&&p.endB==p.start+1&&p.endA==p.start&&p.start>u.from&&"  "==u.doc.textBetween(p.start-u.from-1,p.start-u.from+1)&&(p.start--,p.endA--,p.endB--);let m,g=u.doc.resolveNoCache(p.start-u.from),y=u.doc.resolveNoCache(p.endB-u.from),v=d.resolve(p.start),w=g.sameParent(y)&&g.parent.inlineContent&&v.end()>=p.endA;if((Jn&&e.input.lastIOSEnter>Date.now()-225&&(!w||i.some((e=>"DIV"==e.nodeName||"P"==e.nodeName)))||!w&&g.post(e,En(13,"Enter")))))return void(e.input.lastIOSEnter=0);if(e.state.selection.anchor>p.start&&function(e,t,n,r,i){if(n-t<=i.pos-r.pos||Do(r,!0,!1)n||Do(s,!0,!1)t(e,En(8,"Backspace")))))return void(Yn&&Ln&&e.domObserver.suppressSelectionUpdates());Ln&&Yn&&p.endB==p.start&&(e.input.lastAndroidDelete=Date.now()),Yn&&!w&&g.start()!=y.start()&&0==y.parentOffset&&g.depth==y.depth&&u.sel&&u.sel.anchor==u.sel.head&&u.sel.head==p.endA&&(p.endB-=2,y=u.doc.resolveNoCache(p.endB-u.from),setTimeout((()=>{e.someProp("handleKeyDown",(function(t){return t(e,En(13,"Enter"))}))}),20));let b,x,S,k=p.start,M=p.endA;if(w)if(g.pos==y.pos)Bn&&Vn<=11&&0==g.parentOffset&&(e.domObserver.suppressSelectionUpdates(),setTimeout((()=>qr(e)),20)),b=e.state.tr.delete(k,M),x=d.resolve(p.start).marksAcross(d.resolve(p.endA));else if(p.endA==p.endB&&(S=function(e,t){let n,r,i,o=e.firstChild.marks,s=t.firstChild.marks,l=o,a=s;for(let h=0;he.mark(r.addToSet(e.marks));else{if(0!=l.length||1!=a.length)return null;r=a[0],n="remove",i=e=>e.mark(r.removeFromSet(e.marks))}let c=[];for(let h=0;hn(e,k,M,t))))return;b=e.state.tr.insertText(t,k,M)}if(b||(b=e.state.tr.replace(k,M,u.doc.slice(p.start-u.from,p.endB-u.from))),u.sel){let t=No(e,b.doc,u.sel);t&&!(Ln&&Yn&&e.composing&&t.empty&&(p.start!=p.endB||e.input.lastAndroidDeletet.content.size?null:Gr(e,t.resolve(n.anchor),t.resolve(n.head))}function Do(e,t,n){let r=e.depth,i=t?e.end():e.pos;for(;r>0&&(t||e.indexAfter(r)==e.node(r).childCount);)r--,i++,t=!1;if(n){let t=e.node(r).maybeChild(e.indexAfter(r));for(;t&&!t.isLeaf;)t=t.firstChild,i++}return i}function To(e){if(2!=e.length)return!1;let t=e.charCodeAt(0),n=e.charCodeAt(1);return t>=56320&&t<=57343&&n>=55296&&n<=56319}class Ao{constructor(e,t){this._root=null,this.focused=!1,this.trackWrites=null,this.mounted=!1,this.markCursor=null,this.cursorWrapper=null,this.lastSelectedViewDesc=void 0,this.input=new Ci,this.prevDirectPlugins=[],this.pluginViews=[],this.requiresGeckoHackNode=!1,this.dragging=null,this._props=t,this.state=t.state,this.directPlugins=t.plugins||[],this.directPlugins.forEach(Ro),this.dispatch=this.dispatch.bind(this),this.dom=e&&e.mount||document.createElement("div"),e&&(e.appendChild?e.appendChild(this.dom):"function"==typeof e?e(this.dom):e.mount&&(this.mounted=!0)),this.editable=Po(this),$o(this),this.nodeViews=Io(this),this.docView=Or(this.state.doc,Eo(this),mo(this),this.dom,this),this.domObserver=new wo(this,((e,t,n,r)=>Co(this,e,t,n,r))),this.domObserver.start(),function(e){for(let t in ki){let n=ki[t];e.dom.addEventListener(t,e.input.eventHandlers[t]=t=>{!Ai(e,t)||Ti(e,t)||!e.editable&&t.type in Mi||n(e,t)},Oi[t]?{passive:!0}:void 0)}Wn&&e.dom.addEventListener("input",(()=>null)),Di(e)}(this),this.updatePluginViews()}get composing(){return this.input.composing}get props(){if(this._props.state!=this.state){let e=this._props;this._props={};for(let t in e)this._props[t]=e[t];this._props.state=this.state}return this._props}update(e){e.handleDOMEvents!=this._props.handleDOMEvents&&Di(this);let t=this._props;this._props=e,e.plugins&&(e.plugins.forEach(Ro),this.directPlugins=e.plugins),this.updateStateInner(e.state,t)}setProps(e){let t={};for(let n in this._props)t[n]=this._props[n];t.state=this.state;for(let n in e)t[n]=e[n];this.update(t)}updateState(e){this.updateStateInner(e,this._props)}updateStateInner(e,t){var n;let r=this.state,i=!1,o=!1;e.storedMarks&&this.composing&&(qi(this),o=!0),this.state=e;let s=r.plugins!=e.plugins||this._props.plugins!=t.plugins;if(s||this._props.plugins!=t.plugins||this._props.nodeViews!=t.nodeViews){let e=Io(this);(function(e,t){let n=0,r=0;for(let i in e){if(e[i]!=t[i])return!0;n++}for(let i in t)r++;return n!=r})(e,this.nodeViews)&&(this.nodeViews=e,i=!0)}(s||t.handleDOMEvents!=this._props.handleDOMEvents)&&Di(this),this.editable=Po(this),$o(this);let l=mo(this),a=Eo(this),c=r.plugins==e.plugins||r.doc.eq(e.doc)?e.scrollToSelection>r.scrollToSelection?"to selection":"preserve":"reset",h=i||!this.docView.matchesNode(e.doc,a,l);!h&&e.selection.eq(r.selection)||(o=!0);let u="preserve"==c&&o&&null==this.dom.style.overflowAnchor&&function(e){let t,n,r=e.dom.getBoundingClientRect(),i=Math.max(0,r.top);for(let o=(r.left+r.right)/2,s=i+1;s=i-20){t=r,n=l.top;break}}return{refDOM:t,refTop:n,stack:tr(e.dom)}}(this);if(o){this.domObserver.stop();let t=h&&(Bn||Ln)&&!this.composing&&!r.selection.empty&&!e.selection.empty&&function(e,t){let n=Math.min(e.$anchor.sharedDepth(e.head),t.$anchor.sharedDepth(t.head));return e.$anchor.start(n)!=t.$anchor.start(n)}(r.selection,e.selection);if(h){let n=Ln?this.trackWrites=this.domSelectionRange().focusNode:null;this.composing&&(this.input.compositionNode=Wi(this)),!i&&this.docView.update(e.doc,a,l,this)||(this.docView.updateOuterDeco(a),this.docView.destroy(),this.docView=Or(e.doc,a,l,this.dom,this)),n&&!this.trackWrites&&(t=!0)}t||!(this.input.mouseDown&&this.domObserver.currentSelection.eq(this.domSelectionRange())&&function(e){let t=e.docView.domFromPos(e.state.selection.anchor,0),n=e.domSelectionRange();return On(t.node,t.offset,n.anchorNode,n.anchorOffset)}(this))?qr(this,t):(Yr(this,e.selection),this.domObserver.setCurSelection()),this.domObserver.start()}this.updatePluginViews(r),(null===(n=this.dragging)||void 0===n?void 0:n.node)&&!r.doc.eq(e.doc)&&this.updateDraggedNode(this.dragging,r),"reset"==c?this.dom.scrollTop=0:"to selection"==c?this.scrollToSelection():u&&function({refDOM:e,refTop:t,stack:n}){let r=e?e.getBoundingClientRect().top:0;nr(n,0==r?0:r-t)}(u)}scrollToSelection(){let e=this.domSelectionRange().focusNode;if(this.someProp("handleScrollToSelection",(e=>e(this))));else if(this.state.selection instanceof rn){let t=this.docView.domAfterPos(this.state.selection.from);1==t.nodeType&&er(this,t.getBoundingClientRect(),e)}else er(this,this.coordsAtPos(this.state.selection.head,1),e)}destroyPluginViews(){let e;for(;e=this.pluginViews.pop();)e.destroy&&e.destroy()}updatePluginViews(e){if(e&&e.plugins==this.state.plugins&&this.directPlugins==this.prevDirectPlugins)for(let t=0;t0&&this.state.doc.nodeAt(e))==n.node&&(r=e)}this.dragging=new Ui(e.slice,e.move,r<0?void 0:rn.create(this.state.doc,r))}someProp(e,t){let n,r=this._props&&this._props[e];if(null!=r&&(n=t?t(r):r))return n;for(let o=0;ot.ownerDocument.getSelection()),this._root=t;return e||document}updateRoot(){this._root=null}posAtCoords(e){return lr(this,e)}coordsAtPos(e,t=1){return ur(this,e,t)}domAtPos(e,t=0){return this.docView.domFromPos(e,t)}nodeDOM(e){let t=this.docView.descAt(e);return t?t.nodeDOM:null}posAtDOM(e,t,n=-1){let r=this.docView.posFromDOM(e,t,n);if(null==r)throw new RangeError("DOM position not inside the editor");return r}endOfTextblock(e,t){return wr(this,t||this.state,e)}pasteHTML(e,t){return Hi(this,"",e,!1,t||new ClipboardEvent("paste"))}pasteText(e,t){return Hi(this,e,null,!0,t||new ClipboardEvent("paste"))}destroy(){this.docView&&(!function(e){e.domObserver.stop();for(let t in e.input.eventHandlers)e.dom.removeEventListener(t,e.input.eventHandlers[t]);clearTimeout(e.input.composingTimeout),clearTimeout(e.input.lastIOSEnterFallbackTimeout)}(this),this.destroyPluginViews(),this.mounted?(this.docView.update(this.state.doc,[],mo(this),this),this.dom.textContent=""):this.dom.parentNode&&this.dom.parentNode.removeChild(this.dom),this.docView.destroy(),this.docView=null,kn=null)}get isDestroyed(){return null==this.docView}dispatchEvent(e){return function(e,t){Ti(e,t)||!ki[t.type]||!e.editable&&t.type in Mi||ki[t.type](e,t)}(this,e)}dispatch(e){let t=this._props.dispatchTransaction;t?t.call(this,e):this.updateState(this.state.apply(e))}domSelectionRange(){let e=this.domSelection();return Wn&&11===this.root.nodeType&&function(e){let t=e.activeElement;for(;t&&t.shadowRoot;)t=t.shadowRoot.activeElement;return t}(this.dom.ownerDocument)==this.dom&&function(e,t){if(t.getComposedRanges){let n=t.getComposedRanges(e.root)[0];if(n)return So(e,n)}let n;function r(e){e.preventDefault(),e.stopImmediatePropagation(),n=e.getTargetRanges()[0]}return e.dom.addEventListener("beforeinput",r,!0),document.execCommand("indent"),e.dom.removeEventListener("beforeinput",r,!0),n?So(e,n):null}(this,e)||e}domSelection(){return this.root.getSelection()}}function Eo(e){let t=Object.create(null);return t.class="ProseMirror",t.contenteditable=String(e.editable),e.someProp("attributes",(n=>{if("function"==typeof n&&(n=n(e.state)),n)for(let e in n)"class"==e?t.class+=" "+n[e]:"style"==e?t.style=(t.style?t.style+";":"")+n[e]:t[e]||"contenteditable"==e||"nodeName"==e||(t[e]=String(n[e]))})),t.translate||(t.translate="no"),[to.node(0,e.state.doc.content.size,t)]}function $o(e){if(e.markCursor){let t=document.createElement("img");t.className="ProseMirror-separator",t.setAttribute("mark-placeholder","true"),t.setAttribute("alt",""),e.cursorWrapper={dom:t,deco:to.widget(e.state.selection.head,t,{raw:!0,marks:e.markCursor})}}else e.cursorWrapper=null}function Po(e){return!e.someProp("editable",(t=>!1===t(e.state)))}function Io(e){let t=Object.create(null);function n(e){for(let n in e)Object.prototype.hasOwnProperty.call(t,n)||(t[n]=e[n])}return e.someProp("nodeViews",n),e.someProp("markViews",n),t}function Ro(e){if(e.spec.state||e.spec.filterTransaction||e.spec.appendTransaction)throw new RangeError("Plugins passed directly to the view must not have a state component")}for(var zo={8:"Backspace",9:"Tab",10:"Enter",12:"NumLock",13:"Enter",16:"Shift",17:"Control",18:"Alt",20:"CapsLock",27:"Escape",32:" ",33:"PageUp",34:"PageDown",35:"End",36:"Home",37:"ArrowLeft",38:"ArrowUp",39:"ArrowRight",40:"ArrowDown",44:"PrintScreen",45:"Insert",46:"Delete",59:";",61:"=",91:"Meta",92:"Meta",106:"*",107:"+",108:",",109:"-",110:".",111:"/",144:"NumLock",145:"ScrollLock",160:"Shift",161:"Shift",162:"Control",163:"Control",164:"Alt",165:"Alt",173:"-",186:";",187:"=",188:",",189:"-",190:".",191:"/",192:"`",219:"[",220:"\\",221:"]",222:"'"},_o={48:")",49:"!",50:"@",51:"#",52:"$",53:"%",54:"^",55:"&",56:"*",57:"(",59:":",61:"+",173:"_",186:":",187:"+",188:"<",189:"_",190:">",191:"?",192:"~",219:"{",220:"|",221:"}",222:'"'},Bo="undefined"!=typeof navigator&&/Chrome\/(\d+)/.exec(navigator.userAgent),Vo="undefined"!=typeof navigator&&/Mac/.test(navigator.platform),jo="undefined"!=typeof navigator&&/MSIE \d|Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(navigator.userAgent),Fo=Vo||Bo&&+Bo[1]<57,Lo=0;Lo<10;Lo++)zo[48+Lo]=zo[96+Lo]=String(Lo);for(Lo=1;Lo<=24;Lo++)zo[Lo+111]="F"+Lo;for(Lo=65;Lo<=90;Lo++)zo[Lo]=String.fromCharCode(Lo+32),_o[Lo]=String.fromCharCode(Lo);for(var qo in zo)_o.hasOwnProperty(qo)||(_o[qo]=zo[qo]);const Wo="undefined"!=typeof navigator&&/Mac|iP(hone|[oa]d)/.test(navigator.platform);function Jo(e){let t,n,r,i,o=e.split(/-(?!$)/),s=o[o.length-1];"Space"==s&&(s=" ");for(let l=0;l127)&&(r=zo[n.keyCode])&&r!=i){let i=t[Ko(r,n)];if(i&&i(e.state,e.dispatch,e))return!0}}return!1}}const Uo=(e,t)=>!e.selection.empty&&(t&&t(e.tr.deleteSelection().scrollIntoView()),!0);function Go(e,t,n=!1){for(let r=e;r;r="start"==t?r.firstChild:r.lastChild){if(r.isTextblock)return!0;if(n&&1!=r.childCount)return!1}return!1}function Zo(e){if(!e.parent.type.spec.isolating)for(let t=e.depth-1;t>=0;t--){if(e.index(t)>0)return e.doc.resolve(e.before(t+1));if(e.node(t).type.spec.isolating)break}return null}function Xo(e){if(!e.parent.type.spec.isolating)for(let t=e.depth-1;t>=0;t--){let n=e.node(t);if(e.index(t)+1{let{$from:n,$to:r}=e.selection,i=n.blockRange(r),o=i&&Et(i);return null!=o&&(t&&t(e.tr.lift(i,o).scrollIntoView()),!0)};function es(e){for(let t=0;t{let{$head:n,$anchor:r}=e.selection;if(!n.parent.type.spec.code||!n.sameParent(r))return!1;let i=n.node(-1),o=n.indexAfter(-1),s=es(i.contentMatchAt(o));if(!s||!i.canReplaceWith(o,o,s))return!1;if(t){let r=n.after(),i=e.tr.replaceWith(r,r,s.createAndFill());i.setSelection(Zt.near(i.doc.resolve(r),1)),t(i.scrollIntoView())}return!0};const ns=(e,t)=>{let{$from:n,$to:r}=e.selection;if(e.selection instanceof rn&&e.selection.node.isBlock)return!(!n.parentOffset||!It(e.doc,n.pos)||(t&&t(e.tr.split(n.pos).scrollIntoView()),0));if(!n.parent.isBlock)return!1;if(t){let i=r.parentOffset==r.parent.content.size,o=e.tr;(e.selection instanceof tn||e.selection instanceof sn)&&o.deleteSelection();let s=0==n.depth?null:es(n.node(-1).contentMatchAt(n.indexAfter(-1))),l=rs&&rs(r.parent,i),a=l?[l]:i&&s?[{type:s}]:void 0,c=It(o.doc,o.mapping.map(n.pos),1,a);if(a||c||!It(o.doc,o.mapping.map(n.pos),1,s?[{type:s}]:void 0)||(s&&(a=[{type:s}]),c=!0),c&&(o.split(o.mapping.map(n.pos),1,a),!i&&!n.parentOffset&&n.parent.type!=s)){let e=o.mapping.map(n.before()),t=o.doc.resolve(e);s&&n.node(-1).canReplaceWith(t.index(),t.index()+1,s)&&o.setNodeMarkup(o.mapping.map(n.before()),s)}t(o.scrollIntoView())}return!0};var rs;function is(e,t,n){let r,i,o=t.nodeBefore,s=t.nodeAfter;if(o.type.spec.isolating||s.type.spec.isolating)return!1;if(function(e,t,n){let r=t.nodeBefore,i=t.nodeAfter,o=t.index();return!(!(r&&i&&r.type.compatibleContent(i.type))||(!r.content.size&&t.parent.canReplace(o-1,o)?(n&&n(e.tr.delete(t.pos-r.nodeSize,t.pos).scrollIntoView()),0):!t.parent.canReplace(o,o+1)||!i.isTextblock&&!Rt(e.doc,t.pos)||(n&&n(e.tr.clearIncompatible(t.pos,r.type,r.contentMatchAt(r.childCount)).join(t.pos).scrollIntoView()),0)))}(e,t,n))return!0;let l=t.parent.canReplace(t.index(),t.index()+1);if(l&&(r=(i=o.contentMatchAt(o.childCount)).findWrapping(s.type))&&i.matchType(r[0]||s.type).validEnd){if(n){let i=t.pos+s.nodeSize,l=ue.empty;for(let e=r.length-1;e>=0;e--)l=ue.from(r[e].create(null,l));l=ue.from(o.copy(l));let a=e.tr.step(new Dt(t.pos-1,i,t.pos,i,new ye(l,1,0),r.length,!0)),c=i+2*r.length;Rt(a.doc,c)&&a.join(c),n(a.scrollIntoView())}return!0}let a=Zt.findFrom(t,1),c=a&&a.$from.blockRange(a.$to),h=c&&Et(c);if(null!=h&&h>=t.depth)return n&&n(e.tr.lift(c,h).scrollIntoView()),!0;if(l&&Go(s,"start",!0)&&Go(o,"end")){let r=o,i=[];for(;i.push(r),!r.isTextblock;)r=r.lastChild;let l=s,a=1;for(;!l.isTextblock;l=l.firstChild)a++;if(r.canReplace(r.childCount,r.childCount,l.content)){if(n){let r=ue.empty;for(let e=i.length-1;e>=0;e--)r=ue.from(i[e].copy(r));n(e.tr.step(new Dt(t.pos-i.length,t.pos+s.nodeSize,t.pos+a,t.pos+s.nodeSize-a,new ye(r,i.length,0),0,!0)).scrollIntoView())}return!0}}return!1}function ss(e){return function(t,n){let r=t.selection,i=e<0?r.$from:r.$to,o=i.depth;for(;i.node(o).isInline;){if(!o)return!1;o--}return!!i.node(o).isTextblock&&(n&&n(t.tr.setSelection(tn.create(t.doc,e<0?i.start(o):i.end(o)))),!0)}}const ls=ss(-1),as=ss(1);function cs(e,t=null){return function(n,r){let{$from:i,$to:o}=n.selection,s=i.blockRange(o),l=s&&$t(s,e,t);return!!l&&(r&&r(n.tr.wrap(s,l).scrollIntoView()),!0)}}function hs(e,t=null){return function(n,r){let i=!1;for(let o=0;o{if(i)return!1;if(r.isTextblock&&!r.hasMarkup(e,t))if(r.type==e)i=!0;else{let t=n.doc.resolve(o),r=t.index();i=t.parent.canReplaceWith(r,r+1,e)}}))}if(!i)return!1;if(r){let i=n.tr;for(let r=0;r{if(s)return!1;s=e.inlineContent&&e.type.allowsMarkType(n)})),s)return!0}return!1}(n.doc,s,e))return!1;if(r)if(o)e.isInSet(n.storedMarks||o.marks())?r(n.tr.removeStoredMark(e)):r(n.tr.addStoredMark(e.create(t)));else{let i=!1,o=n.tr;for(let t=0;!i&&t{let r=function(e,t){let{$cursor:n}=e.selection;return!n||(t?!t.endOfTextblock("backward",e):n.parentOffset>0)?null:n}(e,n);if(!r)return!1;let i=Zo(r);if(!i){let n=r.blockRange(),i=n&&Et(n);return null!=i&&(t&&t(e.tr.lift(n,i).scrollIntoView()),!0)}let o=i.nodeBefore;if(!o.type.spec.isolating&&is(e,i,t))return!0;if(0==r.parent.content.size&&(Go(o,"end")||rn.isSelectable(o))){let n=zt(e.doc,r.before(),r.after(),ye.empty);if(n&&n.slice.size{let{$head:r,empty:i}=e.selection,o=r;if(!i)return!1;if(r.parent.isTextblock){if(n?!n.endOfTextblock("backward",e):r.parentOffset>0)return!1;o=Zo(r)}let s=o&&o.nodeBefore;return!(!s||!rn.isSelectable(s))&&(t&&t(e.tr.setSelection(rn.create(e.doc,o.pos-s.nodeSize)).scrollIntoView()),!0)})),ps=ds(Uo,((e,t,n)=>{let r=function(e,t){let{$cursor:n}=e.selection;return!n||(t?!t.endOfTextblock("forward",e):n.parentOffset{let{$head:r,empty:i}=e.selection,o=r;if(!i)return!1;if(r.parent.isTextblock){if(n?!n.endOfTextblock("forward",e):r.parentOffset{let{$head:n,$anchor:r}=e.selection;return!(!n.parent.type.spec.code||!n.sameParent(r))&&(t&&t(e.tr.insertText("\n").scrollIntoView()),!0)}),((e,t)=>{let n=e.selection,{$from:r,$to:i}=n;if(n instanceof sn||r.parent.inlineContent||i.parent.inlineContent)return!1;let o=es(i.parent.contentMatchAt(i.indexAfter()));if(!o||!o.isTextblock)return!1;if(t){let n=(!r.parentOffset&&i.index(){let{$cursor:n}=e.selection;if(!n||n.parent.content.size)return!1;if(n.depth>1&&n.after()!=n.end(-1)){let r=n.before();if(It(e.doc,r))return t&&t(e.tr.split(r).scrollIntoView()),!0}let r=n.blockRange(),i=r&&Et(r);return null!=i&&(t&&t(e.tr.lift(r,i).scrollIntoView()),!0)}),ns),"Mod-Enter":ts,Backspace:fs,"Mod-Backspace":fs,"Shift-Backspace":fs,Delete:ps,"Mod-Delete":ps,"Mod-a":(e,t)=>(t&&t(e.tr.setSelection(new sn(e.doc))),!0)},gs={"Ctrl-h":ms.Backspace,"Alt-Backspace":ms["Mod-Backspace"],"Ctrl-d":ms.Delete,"Ctrl-Alt-Backspace":ms["Mod-Delete"],"Alt-Delete":ms["Mod-Delete"],"Alt-d":ms["Mod-Delete"],"Ctrl-a":ls,"Ctrl-e":as};for(let os in ms)gs[os]=ms[os];const ys=("undefined"!=typeof navigator?/Mac|iP(hone|[oa]d)/.test(navigator.platform):!("undefined"==typeof os||!os.platform)&&"darwin"==os.platform())?gs:ms;class vs{constructor(e,t,n={}){var r;this.match=e,this.match=e,this.handler="string"==typeof t?(r=t,function(e,t,n,i){let o=r;if(t[1]){let e=t[0].lastIndexOf(t[1]);o+=t[0].slice(e+t[1].length);let r=(n+=e)-i;r>0&&(o=t[0].slice(e-r,e)+o,n=i)}return e.tr.insertText(o,n,i)}):t,this.undoable=!1!==n.undoable,this.inCode=n.inCode||!1}}const ws=500;function bs({rules:e}){let t=new yn({state:{init:()=>null,apply(e,t){let n=e.getMeta(this);return n||(e.selectionSet||e.docChanged?null:t)}},props:{handleTextInput:(n,r,i,o)=>xs(n,r,i,o,e,t),handleDOMEvents:{compositionend:n=>{setTimeout((()=>{let{$cursor:r}=n.state.selection;r&&xs(n,r.pos,r.pos,"",e,t)}))}}},isInputRules:!0});return t}function xs(e,t,n,r,i,o){if(e.composing)return!1;let s=e.state,l=s.doc.resolve(t),a=l.parent.textBetween(Math.max(0,l.parentOffset-ws),l.parentOffset,null,"")+r;for(let c=0;c{let n=e.plugins;for(let r=0;r=0;e--)n.step(r.steps[e].invert(r.docs[e]));if(i.text){let t=n.doc.resolve(i.from).marks();n.replaceWith(i.from,i.to,e.schema.text(i.text,t))}else n.delete(i.from,i.to);t(n)}return!0}}return!1};function ks(e,t,n=null,r){return new vs(e,((e,i,o,s)=>{let l=n instanceof Function?n(i):n,a=e.tr.delete(o,s),c=a.doc.resolve(o).blockRange(),h=c&&$t(c,t,l);if(!h)return null;a.wrap(c,h);let u=a.doc.resolve(o-1).nodeBefore;return u&&u.type==t&&Rt(a.doc,o-1)&&(!r||r(i,u))&&a.join(o-1),a}))}function Ms(e,t,n=null){return new vs(e,((e,r,i,o)=>{let s=e.doc.resolve(i),l=n instanceof Function?n(r):n;return s.node(-1).canReplaceWith(s.index(-1),s.indexAfter(-1),t)?e.tr.delete(i,o).setBlockType(i,i,t,l):null}))}new vs(/--$/,"—"),new vs(/\.\.\.$/,"…"),new vs(/(?:^|[\s\{\[\(\<'"\u2018\u201C])(")$/,"“"),new vs(/"$/,"”"),new vs(/(?:^|[\s\{\[\(\<'"\u2018\u201C])(')$/,"‘"),new vs(/'$/,"’");const Os=["ol",0],Cs=["ul",0],Ns=["li",0],Ds={attrs:{order:{default:1}},parseDOM:[{tag:"ol",getAttrs:e=>({order:e.hasAttribute("start")?+e.getAttribute("start"):1})}],toDOM:e=>1==e.attrs.order?Os:["ol",{start:e.attrs.order},0]},Ts={parseDOM:[{tag:"ul"}],toDOM:()=>Cs},As={parseDOM:[{tag:"li"}],toDOM:()=>Ns,defining:!0};function Es(e,t){let n={};for(let r in e)n[r]=e[r];for(let r in t)n[r]=t[r];return n}function $s(e,t,n){return e.append({ordered_list:Es(Ds,{content:"list_item+",group:n}),bullet_list:Es(Ts,{content:"list_item+",group:n}),list_item:Es(As,{content:t})})}function Ps(e,t=null){return function(n,r){let{$from:i,$to:o}=n.selection,s=i.blockRange(o),l=!1,a=s;if(!s)return!1;if(s.depth>=2&&i.node(s.depth-1).type.compatibleContent(e)&&0==s.startIndex){if(0==i.index(s.depth-1))return!1;let e=n.doc.resolve(s.start-2);a=new Pe(e,e,s.depth),s.endIndex=0;h--)o=ue.from(n[h].type.create(n[h].attrs,o));e.step(new Dt(t.start-(r?2:0),t.end,t.start,t.end,new ye(o,0,0),n.length,!0));let s=0;for(let h=0;h=i.depth-3;e--)t=ue.from(i.node(e).copy(t));let s=i.indexAfter(-1){if(c>-1)return!1;e.isTextblock&&0==e.content.size&&(c=t+1)})),c>-1&&a.setSelection(Zt.near(a.doc.resolve(c))),r(a.scrollIntoView())}return!0}let a=o.pos==i.end()?l.contentMatchAt(0).defaultType:null,c=n.tr.delete(i.pos,o.pos),h=a?[t?{type:e,attrs:t}:null,{type:a}]:void 0;return!!It(c.doc,i.pos,2,h)&&(r&&r(c.split(i.pos,2,h).scrollIntoView()),!0)}}function Rs(e){return function(t,n){let{$from:r,$to:i}=t.selection,o=r.blockRange(i,(t=>t.childCount>0&&t.firstChild.type==e));return!!o&&(!n||(r.node(o.depth-1).type==e?function(e,t,n,r){let i=e.tr,o=r.end,s=r.$to.end(r.depth);om;p--)f-=i.child(p).nodeSize,r.delete(f-1,f+1);let o=r.doc.resolve(n.start),s=o.nodeAfter;if(r.mapping.map(n.end)!=n.start+o.nodeAfter.nodeSize)return!1;let l=0==n.startIndex,a=n.endIndex==i.childCount,c=o.node(-1),h=o.index(-1);if(!c.canReplace(h+(l?0:1),h+1,s.content.append(a?ue.empty:ue.from(i))))return!1;let u=o.pos,d=u+s.nodeSize;return r.step(new Dt(u-(l?1:0),d+(a?1:0),u+1,d-1,new ye((l?ue.empty:ue.from(i.copy(ue.empty))).append(a?ue.empty:ue.from(i.copy(ue.empty))),l?0:1,a?0:1),l?0:1)),t(r.scrollIntoView()),!0}(t,n,o)))}}function zs(e){return function(t,n){let{$from:r,$to:i}=t.selection,o=r.blockRange(i,(t=>t.childCount>0&&t.firstChild.type==e));if(!o)return!1;let s=o.startIndex;if(0==s)return!1;let l=o.parent,a=l.child(s-1);if(a.type!=e)return!1;if(n){let r=a.lastChild&&a.lastChild.type==l.type,i=ue.from(r?e.create():null),s=new ye(ue.from(e.create(null,ue.from(l.type.create(null,i)))),r?3:1,0),c=o.start,h=o.end;n(t.tr.step(new Dt(c-(r?3:1),h,c,h,s,1,!0)).scrollIntoView())}return!0}}var _s=200,Bs=function(){};Bs.prototype.append=function(e){return e.length?(e=Bs.from(e),!this.length&&e||e.length<_s&&this.leafAppend(e)||this.length<_s&&e.leafPrepend(this)||this.appendInner(e)):this},Bs.prototype.prepend=function(e){return e.length?Bs.from(e).append(this):this},Bs.prototype.appendInner=function(e){return new js(this,e)},Bs.prototype.slice=function(e,t){return void 0===e&&(e=0),void 0===t&&(t=this.length),e>=t?Bs.empty:this.sliceInner(Math.max(0,e),Math.min(this.length,t))},Bs.prototype.get=function(e){if(!(e<0||e>=this.length))return this.getInner(e)},Bs.prototype.forEach=function(e,t,n){void 0===t&&(t=0),void 0===n&&(n=this.length),t<=n?this.forEachInner(e,t,n,0):this.forEachInvertedInner(e,t,n,0)},Bs.prototype.map=function(e,t,n){void 0===t&&(t=0),void 0===n&&(n=this.length);var r=[];return this.forEach((function(t,n){return r.push(e(t,n))}),t,n),r},Bs.from=function(e){return e instanceof Bs?e:e&&e.length?new Vs(e):Bs.empty};var Vs=function(e){function t(t){e.call(this),this.values=t}e&&(t.__proto__=e),t.prototype=Object.create(e&&e.prototype),t.prototype.constructor=t;var n={length:{configurable:!0},depth:{configurable:!0}};return t.prototype.flatten=function(){return this.values},t.prototype.sliceInner=function(e,n){return 0==e&&n==this.length?this:new t(this.values.slice(e,n))},t.prototype.getInner=function(e){return this.values[e]},t.prototype.forEachInner=function(e,t,n,r){for(var i=t;i=n;i--)if(!1===e(this.values[i],r+i))return!1},t.prototype.leafAppend=function(e){if(this.length+e.length<=_s)return new t(this.values.concat(e.flatten()))},t.prototype.leafPrepend=function(e){if(this.length+e.length<=_s)return new t(e.flatten().concat(this.values))},n.length.get=function(){return this.values.length},n.depth.get=function(){return 0},Object.defineProperties(t.prototype,n),t}(Bs);Bs.empty=new Vs([]);var js=function(e){function t(t,n){e.call(this),this.left=t,this.right=n,this.length=t.length+n.length,this.depth=Math.max(t.depth,n.depth)+1}return e&&(t.__proto__=e),t.prototype=Object.create(e&&e.prototype),t.prototype.constructor=t,t.prototype.flatten=function(){return this.left.flatten().concat(this.right.flatten())},t.prototype.getInner=function(e){return ei&&!1===this.right.forEachInner(e,Math.max(t-i,0),Math.min(this.length,n)-i,r+i))&&void 0)},t.prototype.forEachInvertedInner=function(e,t,n,r){var i=this.left.length;return!(t>i&&!1===this.right.forEachInvertedInner(e,t-i,Math.max(n,i)-i,r+i))&&(!(n=n?this.right.slice(e-n,t-n):this.left.slice(e,n).append(this.right.slice(0,t-n))},t.prototype.leafAppend=function(e){var n=this.right.leafAppend(e);if(n)return new t(this.left,n)},t.prototype.leafPrepend=function(e){var n=this.left.leafPrepend(e);if(n)return new t(n,this.right)},t.prototype.appendInner=function(e){return this.left.depth>=Math.max(this.right.depth,e.depth)+1?new t(this.left,new t(this.right,e)):new t(this,e)},t}(Bs),Fs=Bs;class Ls{constructor(e,t){this.items=e,this.eventCount=t}popEvent(e,t){if(0==this.eventCount)return null;let n,r,i=this.items.length;for(;;i--){if(this.items.get(i-1).selection){--i;break}}t&&(n=this.remapping(i,this.items.length),r=n.maps.length);let o,s,l=e.tr,a=[],c=[];return this.items.forEach(((e,t)=>{if(!e.step)return n||(n=this.remapping(i,t+1),r=n.maps.length),r--,void c.push(e);if(n){c.push(new qs(e.map));let t,i=e.step.map(n.slice(r));i&&l.maybeStep(i).doc&&(t=l.mapping.maps[l.mapping.maps.length-1],a.push(new qs(t,void 0,void 0,a.length+c.length))),r--,t&&n.appendMap(t,r)}else l.maybeStep(e.step);return e.selection?(o=n?e.selection.map(n.slice(r)):e.selection,s=new Ls(this.items.slice(0,i).append(c.reverse().concat(a)),this.eventCount-1),!1):void 0}),this.items.length,0),{remaining:s,transform:l,selection:o}}addTransform(e,t,n,r){let i=[],o=this.eventCount,s=this.items,l=!r&&s.length?s.get(s.length-1):null;for(let c=0;cJs&&(s=function(e,t){let n;return e.forEach(((e,r)=>{if(e.selection&&0==t--)return n=r,!1})),e.slice(n)}(s,a),o-=a),new Ls(s.append(i),o)}remapping(e,t){let n=new vt;return this.items.forEach(((t,r)=>{let i=null!=t.mirrorOffset&&r-t.mirrorOffset>=e?n.maps.length-t.mirrorOffset:void 0;n.appendMap(t.map,i)}),e,t),n}addMaps(e){return 0==this.eventCount?this:new Ls(this.items.append(e.map((e=>new qs(e)))),this.eventCount)}rebased(e,t){if(!this.eventCount)return this;let n=[],r=Math.max(0,this.items.length-t),i=e.mapping,o=e.steps.length,s=this.eventCount;this.items.forEach((e=>{e.selection&&s--}),r);let l=t;this.items.forEach((t=>{let r=i.getMirror(--l);if(null==r)return;o=Math.min(o,r);let a=i.maps[r];if(t.step){let o=e.steps[r].invert(e.docs[r]),c=t.selection&&t.selection.map(i.slice(l+1,r));c&&s++,n.push(new qs(a,o,c))}else n.push(new qs(a))}),r);let a=[];for(let u=t;u500&&(h=h.compress(this.items.length-n.length)),h}emptyItemCount(){let e=0;return this.items.forEach((t=>{t.step||e++})),e}compress(e=this.items.length){let t=this.remapping(0,e),n=t.maps.length,r=[],i=0;return this.items.forEach(((o,s)=>{if(s>=e)r.push(o),o.selection&&i++;else if(o.step){let e=o.step.map(t.slice(n)),s=e&&e.getMap();if(n--,s&&t.appendMap(s,n),e){let l=o.selection&&o.selection.map(t.slice(n));l&&i++;let a,c=new qs(s.invert(),e,l),h=r.length-1;(a=r.length&&r[h].merge(c))?r[h]=a:r.push(c)}}else o.map&&n--}),this.items.length,0),new Ls(Fs.from(r.reverse()),i)}}Ls.empty=new Ls(Fs.empty,0);class qs{constructor(e,t,n,r){this.map=e,this.step=t,this.selection=n,this.mirrorOffset=r}merge(e){if(this.step&&e.step&&!e.selection){let t=e.step.merge(this.step);if(t)return new qs(t.getMap().invert(),t,this.selection)}}}class Ws{constructor(e,t,n,r,i){this.done=e,this.undone=t,this.prevRanges=n,this.prevTime=r,this.prevComposition=i}}const Js=20;function Ks(e){let t=[];return e.forEach(((e,n,r,i)=>t.push(r,i))),t}function Hs(e,t){if(!e)return null;let n=[];for(let r=0;rnew Ws(Ls.empty,Ls.empty,null,0,-1),apply:(t,n,r)=>function(e,t,n,r){let i,o=n.getMeta(Zs);if(o)return o.historyState;n.getMeta(Xs)&&(e=new Ws(e.done,e.undone,null,0,-1));let s=n.getMeta("appendedTransaction");if(0==n.steps.length)return e;if(s&&s.getMeta(Zs))return s.getMeta(Zs).redo?new Ws(e.done.addTransform(n,void 0,r,Gs(t)),e.undone,Ks(n.mapping.maps[n.steps.length-1]),e.prevTime,e.prevComposition):new Ws(e.done,e.undone.addTransform(n,void 0,r,Gs(t)),null,e.prevTime,e.prevComposition);if(!1===n.getMeta("addToHistory")||s&&!1===s.getMeta("addToHistory"))return(i=n.getMeta("rebased"))?new Ws(e.done.rebased(n,i),e.undone.rebased(n,i),Hs(e.prevRanges,n.mapping),e.prevTime,e.prevComposition):new Ws(e.done.addMaps(n.mapping.maps),e.undone.addMaps(n.mapping.maps),Hs(e.prevRanges,n.mapping),e.prevTime,e.prevComposition);{let i=n.getMeta("composition"),o=0==e.prevTime||!s&&e.prevComposition!=i&&(e.prevTime<(n.time||0)-r.newGroupDelay||!function(e,t){if(!t)return!1;if(!e.docChanged)return!0;let n=!1;return e.mapping.maps[0].forEach(((e,r)=>{for(let i=0;i=t[i]&&(n=!0)})),n}(n,e.prevRanges)),l=s?Hs(e.prevRanges,n.mapping):Ks(n.mapping.maps[n.steps.length-1]);return new Ws(e.done.addTransform(n,o?t.selection.getBookmark():void 0,r,Gs(t)),Ls.empty,l,n.time,null==i?e.prevComposition:i)}}(n,r,t,e)},config:e,props:{handleDOMEvents:{beforeinput(e,t){let n=t.inputType,r="historyUndo"==n?tl:"historyRedo"==n?nl:null;return!!r&&(t.preventDefault(),r(e.state,e.dispatch))}}}})}function el(e,t){return(n,r)=>{let i=Zs.getState(n);if(!i||0==(e?i.undone:i.done).eventCount)return!1;if(r){let o=function(e,t,n){let r=Gs(t),i=Zs.get(t).spec.config,o=(n?e.undone:e.done).popEvent(t,r);if(!o)return null;let s=o.selection.resolve(o.transform.doc),l=(n?e.done:e.undone).addTransform(o.transform,t.selection.getBookmark(),i,r),a=new Ws(n?l:o.remaining,n?o.remaining:l,null,0,-1);return o.transform.setSelection(s).setMeta(Zs,{redo:n,historyState:a})}(i,n,e);o&&r(t?o.scrollIntoView():o)}return!0}}const tl=el(!1,!0),nl=el(!0,!0);function rl(e){let t=Zs.getState(e);return t?t.done.eventCount:0}function il(e){let t=Zs.getState(e);return t?t.undone.eventCount:0} -/*! - * portal-vue © Thorsten Lünborg, 2019 - * - * Version: 2.1.7 - * - * LICENCE: MIT - * - * https://github.com/linusborg/portal-vue - * - */function ol(e){return(ol="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function sl(e){return function(e){if(Array.isArray(e)){for(var t=0,n=new Array(e.length);t1&&void 0!==arguments[1]&&arguments[1],n=e.to,r=e.from;if(n&&(r||!1!==t)&&this.transports[n])if(t)this.transports[n]=[];else{var i=this.$_getTransportIndex(e);if(i>=0){var o=this.transports[n].slice(0);o.splice(i,1),this.transports[n]=o}}},registerTarget:function(e,t,n){ll&&(this.trackInstances&&!n&&this.targets[e]&&console.warn("[portal-vue]: Target ".concat(e," already exists")),this.$set(this.targets,e,Object.freeze([t])))},unregisterTarget:function(e){this.$delete(this.targets,e)},registerSource:function(e,t,n){ll&&(this.trackInstances&&!n&&this.sources[e]&&console.warn("[portal-vue]: source ".concat(e," already exists")),this.$set(this.sources,e,Object.freeze([t])))},unregisterSource:function(e){this.$delete(this.sources,e)},hasTarget:function(e){return!(!this.targets[e]||!this.targets[e][0])},hasSource:function(e){return!(!this.sources[e]||!this.sources[e][0])},hasContentFor:function(e){return!!this.transports[e]&&!!this.transports[e].length},$_getTransportIndex:function(e){var t=e.to,n=e.from;for(var r in this.transports[t])if(this.transports[t][r].from===n)return+r;return-1}}}),fl=new dl(cl),pl=1,ml=Vue.extend({name:"portal",props:{disabled:{type:Boolean},name:{type:String,default:function(){return String(pl++)}},order:{type:Number,default:0},slim:{type:Boolean},slotProps:{type:Object,default:function(){return{}}},tag:{type:String,default:"DIV"},to:{type:String,default:function(){return String(Math.round(1e7*Math.random()))}}},created:function(){var e=this;this.$nextTick((function(){fl.registerSource(e.name,e)}))},mounted:function(){this.disabled||this.sendUpdate()},updated:function(){this.disabled?this.clear():this.sendUpdate()},beforeDestroy:function(){fl.unregisterSource(this.name),this.clear()},watch:{to:function(e,t){t&&t!==e&&this.clear(t),this.sendUpdate()}},methods:{clear:function(e){var t={from:this.name,to:e||this.to};fl.close(t)},normalizeSlots:function(){return this.$scopedSlots.default?[this.$scopedSlots.default]:this.$slots.default},normalizeOwnChildren:function(e){return"function"==typeof e?e(this.slotProps):e},sendUpdate:function(){var e=this.normalizeSlots();if(e){var t={from:this.name,to:this.to,passengers:sl(e),order:this.order};fl.open(t)}else this.clear()}},render:function(e){var t=this.$slots.default||this.$scopedSlots.default||[],n=this.tag;return t&&this.disabled?t.length<=1&&this.slim?this.normalizeOwnChildren(t)[0]:e(n,[this.normalizeOwnChildren(t)]):this.slim?e():e(n,{class:{"v-portal":!0},style:{display:"none"},key:"v-portal-placeholder"})}}),gl=Vue.extend({name:"portalTarget",props:{multiple:{type:Boolean,default:!1},name:{type:String,required:!0},slim:{type:Boolean,default:!1},slotProps:{type:Object,default:function(){return{}}},tag:{type:String,default:"div"},transition:{type:[String,Object,Function]}},data:function(){return{transports:fl.transports,firstRender:!0}},created:function(){var e=this;this.$nextTick((function(){fl.registerTarget(e.name,e)}))},watch:{ownTransports:function(){this.$emit("change",this.children().length>0)},name:function(e,t){fl.unregisterTarget(t),fl.registerTarget(e,this)}},mounted:function(){var e=this;this.transition&&this.$nextTick((function(){e.firstRender=!1}))},beforeDestroy:function(){fl.unregisterTarget(this.name)},computed:{ownTransports:function(){var e=this.transports[this.name]||[];return this.multiple?e:0===e.length?[]:[e[e.length-1]]},passengers:function(){return function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};return e.reduce((function(e,n){var r=n.passengers[0],i="function"==typeof r?r(t):n.passengers;return e.concat(i)}),[])}(this.ownTransports,this.slotProps)}},methods:{children:function(){return 0!==this.passengers.length?this.passengers:this.$scopedSlots.default?this.$scopedSlots.default(this.slotProps):this.$slots.default||[]},noWrapper:function(){var e=this.slim&&!this.transition;return e&&this.children().length>1&&console.warn("[portal-vue]: PortalTarget with `slim` option received more than one child element."),e}},render:function(e){var t=this.noWrapper(),n=this.children(),r=this.transition||this.tag;return t?n[0]:this.slim&&!r?e():e(r,{props:{tag:this.transition&&this.tag?this.tag:void 0},class:{"vue-portal-target":!0}},n)}}),yl=0,vl=["disabled","name","order","slim","slotProps","tag","to"],wl=["multiple","transition"],bl=Vue.extend({name:"MountingPortal",inheritAttrs:!1,props:{append:{type:[Boolean,String]},bail:{type:Boolean},mountTo:{type:String,required:!0},disabled:{type:Boolean},name:{type:String,default:function(){return"mounted_"+String(yl++)}},order:{type:Number,default:0},slim:{type:Boolean},slotProps:{type:Object,default:function(){return{}}},tag:{type:String,default:"DIV"},to:{type:String,default:function(){return String(Math.round(1e7*Math.random()))}},multiple:{type:Boolean,default:!1},targetSlim:{type:Boolean},targetSlotProps:{type:Object,default:function(){return{}}},targetTag:{type:String,default:"div"},transition:{type:[String,Object,Function]}},created:function(){if("undefined"!=typeof document){var e=document.querySelector(this.mountTo);if(e){var t=this.$props;if(fl.targets[t.name])t.bail?console.warn("[portal-vue]: Target ".concat(t.name," is already mounted.\n Aborting because 'bail: true' is set")):this.portalTarget=fl.targets[t.name];else{var n=t.append;if(n){var r="string"==typeof n?n:"DIV",i=document.createElement(r);e.appendChild(i),e=i}var o=al(this.$props,wl);o.slim=this.targetSlim,o.tag=this.targetTag,o.slotProps=this.targetSlotProps,o.name=this.to,this.portalTarget=new gl({el:e,parent:this.$parent||this,propsData:o})}}else console.error("[portal-vue]: Mount Point '".concat(this.mountTo,"' not found in document"))}},beforeDestroy:function(){var e=this.portalTarget;if(this.append){var t=e.$el;t.parentNode.removeChild(t)}e.$destroy()},render:function(e){if(!this.portalTarget)return console.warn("[portal-vue] Target wasn't mounted"),e();if(!this.$scopedSlots.manual){var t=al(this.$props,vl);return e(ml,{props:t,attrs:this.$attrs,on:this.$listeners,scopedSlots:this.$scopedSlots},this.$slots.default)}var n=this.$scopedSlots.manual({to:this.to});return Array.isArray(n)&&(n=n[0]),n||e()}});var xl={install:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};e.component(t.portalName||"Portal",ml),e.component(t.portalTargetName||"PortalTarget",gl),e.component(t.MountingPortalName||"MountingPortal",bl)}},Sl=new Map;function kl(e){var t=Sl.get(e);t&&t.destroy()}function Ml(e){var t=Sl.get(e);t&&t.update()}var Ol=null;"undefined"==typeof window?((Ol=function(e){return e}).destroy=function(e){return e},Ol.update=function(e){return e}):((Ol=function(e,t){return e&&Array.prototype.forEach.call(e.length?e:[e],(function(e){return function(e){if(e&&e.nodeName&&"TEXTAREA"===e.nodeName&&!Sl.has(e)){var t,n=null,r=window.getComputedStyle(e),i=(t=e.value,function(){s({testForHeightReduction:""===t||!e.value.startsWith(t),restoreTextAlign:null}),t=e.value}),o=function(t){e.removeEventListener("autosize:destroy",o),e.removeEventListener("autosize:update",l),e.removeEventListener("input",i),window.removeEventListener("resize",l),Object.keys(t).forEach((function(n){return e.style[n]=t[n]})),Sl.delete(e)}.bind(e,{height:e.style.height,resize:e.style.resize,textAlign:e.style.textAlign,overflowY:e.style.overflowY,overflowX:e.style.overflowX,wordWrap:e.style.wordWrap});e.addEventListener("autosize:destroy",o),e.addEventListener("autosize:update",l),e.addEventListener("input",i),window.addEventListener("resize",l),e.style.overflowX="hidden",e.style.wordWrap="break-word",Sl.set(e,{destroy:o,update:l}),l()}function s(t){var i,o,l=t.restoreTextAlign,a=void 0===l?null:l,c=t.testForHeightReduction,h=void 0===c||c,u=r.overflowY;if(0!==e.scrollHeight&&("vertical"===r.resize?e.style.resize="none":"both"===r.resize&&(e.style.resize="horizontal"),h&&(i=function(e){for(var t=[];e&&e.parentNode&&e.parentNode instanceof Element;)e.parentNode.scrollTop&&t.push([e.parentNode,e.parentNode.scrollTop]),e=e.parentNode;return function(){return t.forEach((function(e){var t=e[0],n=e[1];t.style.scrollBehavior="auto",t.scrollTop=n,t.style.scrollBehavior=null}))}}(e),e.style.height=""),o="content-box"===r.boxSizing?e.scrollHeight-(parseFloat(r.paddingTop)+parseFloat(r.paddingBottom)):e.scrollHeight+parseFloat(r.borderTopWidth)+parseFloat(r.borderBottomWidth),"none"!==r.maxHeight&&o>parseFloat(r.maxHeight)?("hidden"===r.overflowY&&(e.style.overflow="scroll"),o=parseFloat(r.maxHeight)):"hidden"!==r.overflowY&&(e.style.overflow="hidden"),e.style.height=o+"px",a&&(e.style.textAlign=a),i&&i(),n!==o&&(e.dispatchEvent(new Event("autosize:resized",{bubbles:!0})),n=o),u!==r.overflow&&!a)){var d=r.textAlign;"hidden"===r.overflow&&(e.style.textAlign="start"===d?"end":"start"),s({restoreTextAlign:d,testForHeightReduction:!0})}}function l(){s({testForHeightReduction:!0,restoreTextAlign:null})}}(e)})),e}).destroy=function(e){return e&&Array.prototype.forEach.call(e.length?e:[e],kl),e},Ol.update=function(e){return e&&Array.prototype.forEach.call(e.length?e:[e],Ml),e});var Cl=Ol,Nl={exports:{}};Nl.exports=function(){var e=1e3,t=6e4,n=36e5,r="millisecond",i="second",o="minute",s="hour",l="day",a="week",c="month",h="quarter",u="year",d="date",f="Invalid Date",p=/^(\d{4})[-/]?(\d{1,2})?[-/]?(\d{0,2})[Tt\s]*(\d{1,2})?:?(\d{1,2})?:?(\d{1,2})?[.:]?(\d+)?$/,m=/\[([^\]]+)]|Y{1,4}|M{1,4}|D{1,2}|d{1,4}|H{1,2}|h{1,2}|a|A|m{1,2}|s{1,2}|Z{1,2}|SSS/g,g={name:"en",weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),ordinal:function(e){var t=["th","st","nd","rd"],n=e%100;return"["+e+(t[(n-20)%10]||t[n]||t[0])+"]"}},y=function(e,t,n){var r=String(e);return!r||r.length>=t?e:""+Array(t+1-r.length).join(n)+e},v={s:y,z:function(e){var t=-e.utcOffset(),n=Math.abs(t),r=Math.floor(n/60),i=n%60;return(t<=0?"+":"-")+y(r,2,"0")+":"+y(i,2,"0")},m:function e(t,n){if(t.date()1)return e(s[0])}else{var l=t.name;b[l]=t,i=l}return!r&&i&&(w=i),i||!r&&w},M=function(e,t){if(S(e))return e.clone();var n="object"==typeof t?t:{};return n.date=e,n.args=arguments,new C(n)},O=v;O.l=k,O.i=S,O.w=function(e,t){return M(e,{locale:t.$L,utc:t.$u,x:t.$x,$offset:t.$offset})};var C=function(){function g(e){this.$L=k(e.locale,null,!0),this.parse(e),this.$x=this.$x||e.x||{},this[x]=!0}var y=g.prototype;return y.parse=function(e){this.$d=function(e){var t=e.date,n=e.utc;if(null===t)return new Date(NaN);if(O.u(t))return new Date;if(t instanceof Date)return new Date(t);if("string"==typeof t&&!/Z$/i.test(t)){var r=t.match(p);if(r){var i=r[2]-1||0,o=(r[7]||"0").substring(0,3);return n?new Date(Date.UTC(r[1],i,r[3]||1,r[4]||0,r[5]||0,r[6]||0,o)):new Date(r[1],i,r[3]||1,r[4]||0,r[5]||0,r[6]||0,o)}}return new Date(t)}(e),this.init()},y.init=function(){var e=this.$d;this.$y=e.getFullYear(),this.$M=e.getMonth(),this.$D=e.getDate(),this.$W=e.getDay(),this.$H=e.getHours(),this.$m=e.getMinutes(),this.$s=e.getSeconds(),this.$ms=e.getMilliseconds()},y.$utils=function(){return O},y.isValid=function(){return!(this.$d.toString()===f)},y.isSame=function(e,t){var n=M(e);return this.startOf(t)<=n&&n<=this.endOf(t)},y.isAfter=function(e,t){return M(e)68?1900:2e3)},l=function(e){return function(t){this[e]=+t}},a=[/[+-]\d\d:?(\d\d)?|Z/,function(e){(this.zone||(this.zone={})).offset=function(e){if(!e)return 0;if("Z"===e)return 0;var t=e.match(/([+-]|\d\d)/g),n=60*t[1]+(+t[2]||0);return 0===n?0:"+"===t[0]?-n:n}(e)}],c=function(e){var t=o[e];return t&&(t.indexOf?t:t.s.concat(t.f))},h=function(e,t){var n,r=o.meridiem;if(r){for(var i=1;i<=24;i+=1)if(e.indexOf(r(i,0,t))>-1){n=i>12;break}}else n=e===(t?"pm":"PM");return n},u={A:[i,function(e){this.afternoon=h(e,!1)}],a:[i,function(e){this.afternoon=h(e,!0)}],S:[/\d/,function(e){this.milliseconds=100*+e}],SS:[n,function(e){this.milliseconds=10*+e}],SSS:[/\d{3}/,function(e){this.milliseconds=+e}],s:[r,l("seconds")],ss:[r,l("seconds")],m:[r,l("minutes")],mm:[r,l("minutes")],H:[r,l("hours")],h:[r,l("hours")],HH:[r,l("hours")],hh:[r,l("hours")],D:[r,l("day")],DD:[n,l("day")],Do:[i,function(e){var t=o.ordinal,n=e.match(/\d+/);if(this.day=n[0],t)for(var r=1;r<=31;r+=1)t(r).replace(/\[|\]/g,"")===e&&(this.day=r)}],M:[r,l("month")],MM:[n,l("month")],MMM:[i,function(e){var t=c("months"),n=(c("monthsShort")||t.map((function(e){return e.slice(0,3)}))).indexOf(e)+1;if(n<1)throw new Error;this.month=n%12||n}],MMMM:[i,function(e){var t=c("months").indexOf(e)+1;if(t<1)throw new Error;this.month=t%12||t}],Y:[/[+-]?\d+/,l("year")],YY:[n,function(e){this.year=s(e)}],YYYY:[/\d{4}/,l("year")],Z:a,ZZ:a};function d(n){var r,i;r=n,i=o&&o.formats;for(var s=(n=r.replace(/(\[[^\]]+])|(LTS?|l{1,4}|L{1,4})/g,(function(t,n,r){var o=r&&r.toUpperCase();return n||i[r]||e[r]||i[o].replace(/(\[[^\]]+])|(MMMM|MM|DD|dddd)/g,(function(e,t,n){return t||n.slice(1)}))}))).match(t),l=s.length,a=0;a-1)return new Date(("X"===t?1e3:1)*e);var r=d(t)(e),i=r.year,o=r.month,s=r.day,l=r.hours,a=r.minutes,c=r.seconds,h=r.milliseconds,u=r.zone,f=new Date,p=s||(i||o?1:f.getDate()),m=i||f.getFullYear(),g=0;i&&!o||(g=o>0?o-1:f.getMonth());var y=l||0,v=a||0,w=c||0,b=h||0;return u?new Date(Date.UTC(m,g,p,y,v,w,b+60*u.offset*1e3)):n?new Date(Date.UTC(m,g,p,y,v,w,b)):new Date(m,g,p,y,v,w,b)}catch(x){return new Date("")}}(t,l,r),this.init(),u&&!0!==u&&(this.$L=this.locale(u).$L),h&&t!=this.format(l)&&(this.$d=new Date("")),o={}}else if(l instanceof Array)for(var f=l.length,p=1;p<=f;p+=1){s[1]=l[p-1];var m=n.apply(this,s);if(m.isValid()){this.$d=m.$d,this.$L=m.$L,this.init();break}p===f&&(this.$d=new Date(""))}else i.call(this,e)}}}();const Al=e(Tl.exports);function El(e){return{all:e=e||new Map,on:function(t,n){var r=e.get(t);r?r.push(n):e.set(t,[n])},off:function(t,n){var r=e.get(t);r&&(n?r.splice(r.indexOf(n)>>>0,1):e.set(t,[]))},emit:function(t,n){var r=e.get(t);r&&r.slice().map((function(e){e(n)})),(r=e.get("*"))&&r.slice().map((function(e){e(t,n)}))}}} -/*! - * vuex v3.6.2 - * (c) 2021 Evan You - * @license MIT - */var $l=("undefined"!=typeof window?window:"undefined"!=typeof global?global:{}).__VUE_DEVTOOLS_GLOBAL_HOOK__;function Pl(e,t){if(void 0===t&&(t=[]),null===e||"object"!=typeof e)return e;var n,r=(n=function(t){return t.original===e},t.filter(n)[0]);if(r)return r.copy;var i=Array.isArray(e)?[]:{};return t.push({original:e,copy:i}),Object.keys(e).forEach((function(n){i[n]=Pl(e[n],t)})),i}function Il(e,t){Object.keys(e).forEach((function(n){return t(e[n],n)}))}function Rl(e){return null!==e&&"object"==typeof e}var zl=function(e,t){this.runtime=t,this._children=Object.create(null),this._rawModule=e;var n=e.state;this.state=("function"==typeof n?n():n)||{}},_l={namespaced:{configurable:!0}};_l.namespaced.get=function(){return!!this._rawModule.namespaced},zl.prototype.addChild=function(e,t){this._children[e]=t},zl.prototype.removeChild=function(e){delete this._children[e]},zl.prototype.getChild=function(e){return this._children[e]},zl.prototype.hasChild=function(e){return e in this._children},zl.prototype.update=function(e){this._rawModule.namespaced=e.namespaced,e.actions&&(this._rawModule.actions=e.actions),e.mutations&&(this._rawModule.mutations=e.mutations),e.getters&&(this._rawModule.getters=e.getters)},zl.prototype.forEachChild=function(e){Il(this._children,e)},zl.prototype.forEachGetter=function(e){this._rawModule.getters&&Il(this._rawModule.getters,e)},zl.prototype.forEachAction=function(e){this._rawModule.actions&&Il(this._rawModule.actions,e)},zl.prototype.forEachMutation=function(e){this._rawModule.mutations&&Il(this._rawModule.mutations,e)},Object.defineProperties(zl.prototype,_l);var Bl,Vl=function(e){this.register([],e,!1)};function jl(e,t,n){if(t.update(n),n.modules)for(var r in n.modules){if(!t.getChild(r))return;jl(e.concat(r),t.getChild(r),n.modules[r])}}Vl.prototype.get=function(e){return e.reduce((function(e,t){return e.getChild(t)}),this.root)},Vl.prototype.getNamespace=function(e){var t=this.root;return e.reduce((function(e,n){return e+((t=t.getChild(n)).namespaced?n+"/":"")}),"")},Vl.prototype.update=function(e){jl([],this.root,e)},Vl.prototype.register=function(e,t,n){var r=this;void 0===n&&(n=!0);var i=new zl(t,n);0===e.length?this.root=i:this.get(e.slice(0,-1)).addChild(e[e.length-1],i);t.modules&&Il(t.modules,(function(t,i){r.register(e.concat(i),t,n)}))},Vl.prototype.unregister=function(e){var t=this.get(e.slice(0,-1)),n=e[e.length-1],r=t.getChild(n);r&&r.runtime&&t.removeChild(n)},Vl.prototype.isRegistered=function(e){var t=this.get(e.slice(0,-1)),n=e[e.length-1];return!!t&&t.hasChild(n)};var Fl=function(e){var t=this;void 0===e&&(e={}),!Bl&&"undefined"!=typeof window&&window.Vue&&Ul(window.Vue);var n=e.plugins;void 0===n&&(n=[]);var r=e.strict;void 0===r&&(r=!1),this._committing=!1,this._actions=Object.create(null),this._actionSubscribers=[],this._mutations=Object.create(null),this._wrappedGetters=Object.create(null),this._modules=new Vl(e),this._modulesNamespaceMap=Object.create(null),this._subscribers=[],this._watcherVM=new Bl,this._makeLocalGettersCache=Object.create(null);var i=this,o=this.dispatch,s=this.commit;this.dispatch=function(e,t){return o.call(i,e,t)},this.commit=function(e,t,n){return s.call(i,e,t,n)},this.strict=r;var l=this._modules.root.state;Kl(this,l,[],this._modules.root),Jl(this,l),n.forEach((function(e){return e(t)})),(void 0!==e.devtools?e.devtools:Bl.config.devtools)&&function(e){$l&&(e._devtoolHook=$l,$l.emit("vuex:init",e),$l.on("vuex:travel-to-state",(function(t){e.replaceState(t)})),e.subscribe((function(e,t){$l.emit("vuex:mutation",e,t)}),{prepend:!0}),e.subscribeAction((function(e,t){$l.emit("vuex:action",e,t)}),{prepend:!0}))}(this)},Ll={state:{configurable:!0}};function ql(e,t,n){return t.indexOf(e)<0&&(n&&n.prepend?t.unshift(e):t.push(e)),function(){var n=t.indexOf(e);n>-1&&t.splice(n,1)}}function Wl(e,t){e._actions=Object.create(null),e._mutations=Object.create(null),e._wrappedGetters=Object.create(null),e._modulesNamespaceMap=Object.create(null);var n=e.state;Kl(e,n,[],e._modules.root,!0),Jl(e,n,t)}function Jl(e,t,n){var r=e._vm;e.getters={},e._makeLocalGettersCache=Object.create(null);var i=e._wrappedGetters,o={};Il(i,(function(t,n){o[n]=function(e,t){return function(){return e(t)}}(t,e),Object.defineProperty(e.getters,n,{get:function(){return e._vm[n]},enumerable:!0})}));var s=Bl.config.silent;Bl.config.silent=!0,e._vm=new Bl({data:{$$state:t},computed:o}),Bl.config.silent=s,e.strict&&function(e){e._vm.$watch((function(){return this._data.$$state}),(function(){}),{deep:!0,sync:!0})}(e),r&&(n&&e._withCommit((function(){r._data.$$state=null})),Bl.nextTick((function(){return r.$destroy()})))}function Kl(e,t,n,r,i){var o=!n.length,s=e._modules.getNamespace(n);if(r.namespaced&&(e._modulesNamespaceMap[s],e._modulesNamespaceMap[s]=r),!o&&!i){var l=Hl(t,n.slice(0,-1)),a=n[n.length-1];e._withCommit((function(){Bl.set(l,a,r.state)}))}var c=r.context=function(e,t,n){var r=""===t,i={dispatch:r?e.dispatch:function(n,r,i){var o=Yl(n,r,i),s=o.payload,l=o.options,a=o.type;return l&&l.root||(a=t+a),e.dispatch(a,s)},commit:r?e.commit:function(n,r,i){var o=Yl(n,r,i),s=o.payload,l=o.options,a=o.type;l&&l.root||(a=t+a),e.commit(a,s,l)}};return Object.defineProperties(i,{getters:{get:r?function(){return e.getters}:function(){return function(e,t){if(!e._makeLocalGettersCache[t]){var n={},r=t.length;Object.keys(e.getters).forEach((function(i){if(i.slice(0,r)===t){var o=i.slice(r);Object.defineProperty(n,o,{get:function(){return e.getters[i]},enumerable:!0})}})),e._makeLocalGettersCache[t]=n}return e._makeLocalGettersCache[t]}(e,t)}},state:{get:function(){return Hl(e.state,n)}}}),i}(e,s,n);r.forEachMutation((function(t,n){!function(e,t,n,r){var i=e._mutations[t]||(e._mutations[t]=[]);i.push((function(t){n.call(e,r.state,t)}))}(e,s+n,t,c)})),r.forEachAction((function(t,n){var r=t.root?n:s+n,i=t.handler||t;!function(e,t,n,r){var i=e._actions[t]||(e._actions[t]=[]);i.push((function(t){var i,o=n.call(e,{dispatch:r.dispatch,commit:r.commit,getters:r.getters,state:r.state,rootGetters:e.getters,rootState:e.state},t);return(i=o)&&"function"==typeof i.then||(o=Promise.resolve(o)),e._devtoolHook?o.catch((function(t){throw e._devtoolHook.emit("vuex:error",t),t})):o}))}(e,r,i,c)})),r.forEachGetter((function(t,n){!function(e,t,n,r){if(e._wrappedGetters[t])return;e._wrappedGetters[t]=function(e){return n(r.state,r.getters,e.state,e.getters)}}(e,s+n,t,c)})),r.forEachChild((function(r,o){Kl(e,t,n.concat(o),r,i)}))}function Hl(e,t){return t.reduce((function(e,t){return e[t]}),e)}function Yl(e,t,n){return Rl(e)&&e.type&&(n=t,t=e,e=e.type),{type:e,payload:t,options:n}}function Ul(e){Bl&&e===Bl||function(e){if(Number(e.version.split(".")[0])>=2)e.mixin({beforeCreate:n});else{var t=e.prototype._init;e.prototype._init=function(e){void 0===e&&(e={}),e.init=e.init?[n].concat(e.init):n,t.call(this,e)}}function n(){var e=this.$options;e.store?this.$store="function"==typeof e.store?e.store():e.store:e.parent&&e.parent.$store&&(this.$store=e.parent.$store)}}(Bl=e)}Ll.state.get=function(){return this._vm._data.$$state},Ll.state.set=function(e){},Fl.prototype.commit=function(e,t,n){var r=this,i=Yl(e,t,n),o=i.type,s=i.payload,l={type:o,payload:s},a=this._mutations[o];a&&(this._withCommit((function(){a.forEach((function(e){e(s)}))})),this._subscribers.slice().forEach((function(e){return e(l,r.state)})))},Fl.prototype.dispatch=function(e,t){var n=this,r=Yl(e,t),i=r.type,o=r.payload,s={type:i,payload:o},l=this._actions[i];if(l){try{this._actionSubscribers.slice().filter((function(e){return e.before})).forEach((function(e){return e.before(s,n.state)}))}catch(c){}var a=l.length>1?Promise.all(l.map((function(e){return e(o)}))):l[0](o);return new Promise((function(e,t){a.then((function(t){try{n._actionSubscribers.filter((function(e){return e.after})).forEach((function(e){return e.after(s,n.state)}))}catch(c){}e(t)}),(function(e){try{n._actionSubscribers.filter((function(e){return e.error})).forEach((function(t){return t.error(s,n.state,e)}))}catch(c){}t(e)}))}))}},Fl.prototype.subscribe=function(e,t){return ql(e,this._subscribers,t)},Fl.prototype.subscribeAction=function(e,t){return ql("function"==typeof e?{before:e}:e,this._actionSubscribers,t)},Fl.prototype.watch=function(e,t,n){var r=this;return this._watcherVM.$watch((function(){return e(r.state,r.getters)}),t,n)},Fl.prototype.replaceState=function(e){var t=this;this._withCommit((function(){t._vm._data.$$state=e}))},Fl.prototype.registerModule=function(e,t,n){void 0===n&&(n={}),"string"==typeof e&&(e=[e]),this._modules.register(e,t),Kl(this,this.state,e,this._modules.get(e),n.preserveState),Jl(this,this.state)},Fl.prototype.unregisterModule=function(e){var t=this;"string"==typeof e&&(e=[e]),this._modules.unregister(e),this._withCommit((function(){var n=Hl(t.state,e.slice(0,-1));Bl.delete(n,e[e.length-1])})),Wl(this)},Fl.prototype.hasModule=function(e){return"string"==typeof e&&(e=[e]),this._modules.isRegistered(e)},Fl.prototype.hotUpdate=function(e){this._modules.update(e),Wl(this,!0)},Fl.prototype._withCommit=function(e){var t=this._committing;this._committing=!0,e(),this._committing=t},Object.defineProperties(Fl.prototype,Ll);var Gl=ta((function(e,t){var n={};return ea(t).forEach((function(t){var r=t.key,i=t.val;n[r]=function(){var t=this.$store.state,n=this.$store.getters;if(e){var r=na(this.$store,"mapState",e);if(!r)return;t=r.context.state,n=r.context.getters}return"function"==typeof i?i.call(this,t,n):t[i]},n[r].vuex=!0})),n})),Zl=ta((function(e,t){var n={};return ea(t).forEach((function(t){var r=t.key,i=t.val;n[r]=function(){for(var t=[],n=arguments.length;n--;)t[n]=arguments[n];var r=this.$store.commit;if(e){var o=na(this.$store,"mapMutations",e);if(!o)return;r=o.context.commit}return"function"==typeof i?i.apply(this,[r].concat(t)):r.apply(this.$store,[i].concat(t))}})),n})),Xl=ta((function(e,t){var n={};return ea(t).forEach((function(t){var r=t.key,i=t.val;i=e+i,n[r]=function(){if(!e||na(this.$store,"mapGetters",e))return this.$store.getters[i]},n[r].vuex=!0})),n})),Ql=ta((function(e,t){var n={};return ea(t).forEach((function(t){var r=t.key,i=t.val;n[r]=function(){for(var t=[],n=arguments.length;n--;)t[n]=arguments[n];var r=this.$store.dispatch;if(e){var o=na(this.$store,"mapActions",e);if(!o)return;r=o.context.dispatch}return"function"==typeof i?i.apply(this,[r].concat(t)):r.apply(this.$store,[i].concat(t))}})),n}));function ea(e){return function(e){return Array.isArray(e)||Rl(e)}(e)?Array.isArray(e)?e.map((function(e){return{key:e,val:e}})):Object.keys(e).map((function(t){return{key:t,val:e[t]}})):[]}function ta(e){return function(t,n){return"string"!=typeof t?(n=t,t=""):"/"!==t.charAt(t.length-1)&&(t+="/"),e(t,n)}}function na(e,t,n){return e._modulesNamespaceMap[n]}function ra(e,t,n){var r=n?e.groupCollapsed:e.group;try{r.call(e,t)}catch(i){e.log(t)}}function ia(e){try{e.groupEnd()}catch(t){e.log("—— log end ——")}}function oa(){var e=new Date;return" @ "+sa(e.getHours(),2)+":"+sa(e.getMinutes(),2)+":"+sa(e.getSeconds(),2)+"."+sa(e.getMilliseconds(),3)}function sa(e,t){return n="0",r=t-e.toString().length,new Array(r+1).join(n)+e;var n,r}const la={Store:Fl,install:Ul,version:"3.6.2",mapState:Gl,mapMutations:Zl,mapGetters:Xl,mapActions:Ql,createNamespacedHelpers:function(e){return{mapState:Gl.bind(null,e),mapGetters:Xl.bind(null,e),mapMutations:Zl.bind(null,e),mapActions:Ql.bind(null,e)}},createLogger:function(e){void 0===e&&(e={});var t=e.collapsed;void 0===t&&(t=!0);var n=e.filter;void 0===n&&(n=function(e,t,n){return!0});var r=e.transformer;void 0===r&&(r=function(e){return e});var i=e.mutationTransformer;void 0===i&&(i=function(e){return e});var o=e.actionFilter;void 0===o&&(o=function(e,t){return!0});var s=e.actionTransformer;void 0===s&&(s=function(e){return e});var l=e.logMutations;void 0===l&&(l=!0);var a=e.logActions;void 0===a&&(a=!0);var c=e.logger;return void 0===c&&(c=console),function(e){var h=Pl(e.state);void 0!==c&&(l&&e.subscribe((function(e,o){var s=Pl(o);if(n(e,h,s)){var l=oa(),a=i(e),u="mutation "+e.type+l;ra(c,u,t),c.log("%c prev state","color: #9E9E9E; font-weight: bold",r(h)),c.log("%c mutation","color: #03A9F4; font-weight: bold",a),c.log("%c next state","color: #4CAF50; font-weight: bold",r(s)),ia(c)}h=s})),a&&e.subscribeAction((function(e,n){if(o(e,n)){var r=oa(),i=s(e),l="action "+e.type+r;ra(c,l,t),c.log("%c action","color: #03A9F4; font-weight: bold",i),ia(c)}})))}}};var aa={},ca={};function ha(e){return null==e}function ua(e){return null!=e}function da(e,t){return t.tag===e.tag&&t.key===e.key}function fa(e){var t=e.tag;e.vm=new t({data:e.args})}function pa(e,t,n){var r,i,o={};for(r=t;r<=n;++r)ua(i=e[r].key)&&(o[i]=r);return o}function ma(e,t,n){for(;t<=n;++t)fa(e[t])}function ga(e,t,n){for(;t<=n;++t){var r=e[t];ua(r)&&(r.vm.$destroy(),r.vm=null)}}function ya(e,t){e!==t&&(t.vm=e.vm,function(e){for(var t=Object.keys(e.args),n=0;nl?ma(t,s,h):s>h&&ga(e,o,l)}(e,t):ua(t)?ma(t,0,t.length-1):ua(e)&&ga(e,0,e.length-1)},function(e){Object.defineProperty(e,"__esModule",{value:!0}),e.Vuelidate=C,e.validationMixin=e.default=void 0,Object.defineProperty(e,"withParams",{enumerable:!0,get:function(){return n.withParams}});var t=ca,n=o;function r(e){return function(e){if(Array.isArray(e))return i(e)}(e)||function(e){if("undefined"!=typeof Symbol&&null!=e[Symbol.iterator]||null!=e["@@iterator"])return Array.from(e)}(e)||function(e,t){if(!e)return;if("string"==typeof e)return i(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);"Object"===n&&e.constructor&&(n=e.constructor.name);if("Map"===n||"Set"===n)return Array.from(e);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return i(e,t)}(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function i(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n1?l:l.$sub[0]:null}}},computed:{run:function(){var e=this,t=this.lazyParentModel();if(Array.isArray(t)&&t.__ob__){var n=t.__ob__.dep;n.depend();var r=n.constructor.target;if(!this._indirectWatcher){var i=r.constructor;this._indirectWatcher=new i(this,(function(){return e.runRule(t)}),null,{lazy:!0})}var o=this.getModel();if(!this._indirectWatcher.dirty&&this._lastModel===o)return this._indirectWatcher.depend(),r.value;this._lastModel=o,this._indirectWatcher.evaluate(),this._indirectWatcher.depend()}else this._indirectWatcher&&(this._indirectWatcher.teardown(),this._indirectWatcher=null);return this._indirectWatcher?this._indirectWatcher.value:this.runRule(t)},$params:function(){return this.run.params},proxy:function(){var e=this.run.output;return e[m]?!!e.v:!!e},$pending:function(){var e=this.run.output;return!!e[m]&&e.p}},destroyed:function(){this._indirectWatcher&&(this._indirectWatcher.teardown(),this._indirectWatcher=null)}}),s=i.extend({data:function(){return{dirty:!1,validations:null,lazyModel:null,model:null,prop:null,lazyParentModel:null,rootModel:null}},methods:l(l({},v),{},{refProxy:function(e){return this.getRef(e).proxy},getRef:function(e){return this.refs[e]},isNested:function(e){return"function"!=typeof this.validations[e]}}),computed:l(l({},g),{},{nestedKeys:function(){return this.keys.filter(this.isNested)},ruleKeys:function(){var e=this;return this.keys.filter((function(t){return!e.isNested(t)}))},keys:function(){return Object.keys(this.validations).filter((function(e){return"$params"!==e}))},proxy:function(){var e=this,t=u(this.keys,(function(t){return{enumerable:!0,configurable:!0,get:function(){return e.refProxy(t)}}})),n=u(w,(function(t){return{enumerable:!0,configurable:!0,get:function(){return e[t]}}})),r=u(b,(function(t){return{enumerable:!1,configurable:!0,get:function(){return e[t]}}})),i=this.hasIter()?{$iter:{enumerable:!0,value:Object.defineProperties({},l({},t))}}:{};return Object.defineProperties({},l(l(l(l({},t),i),{},{$model:{enumerable:!0,get:function(){var t=e.lazyParentModel();return null!=t?t[e.prop]:null},set:function(t){var n=e.lazyParentModel();null!=n&&(n[e.prop]=t,e.$touch())}}},n),r))},children:function(){var e=this;return[].concat(r(this.nestedKeys.map((function(t){return y(e,t)}))),r(this.ruleKeys.map((function(t){return S(e,t)})))).filter(Boolean)}})}),a=s.extend({methods:{isNested:function(e){return void 0!==this.validations[e]()},getRef:function(e){var t=this;return{get proxy(){return t.validations[e]()||!1}}}}}),c=s.extend({computed:{keys:function(){var e=this.getModel();return f(e)?Object.keys(e):[]},tracker:function(){var e=this,t=this.validations.$trackBy;return t?function(n){return"".concat(p(e.rootModel,e.getModelKey(n),t))}:function(e){return"".concat(e)}},getModelLazy:function(){var e=this;return function(){return e.getModel()}},children:function(){var e=this,n=this.validations,r=this.getModel(),i=l({},n);delete i.$trackBy;var o={};return this.keys.map((function(n){var l=e.tracker(n);return o.hasOwnProperty(l)?null:(o[l]=!0,(0,t.h)(s,l,{validations:i,prop:n,lazyParentModel:e.getModelLazy,model:r[n],rootModel:e.rootModel}))})).filter(Boolean)}},methods:{isNested:function(){return!0},getRef:function(e){return this.refs[this.tracker(e)]},hasIter:function(){return!0}}}),y=function(e,n){if("$each"===n)return(0,t.h)(c,n,{validations:e.validations[n],lazyParentModel:e.lazyParentModel,prop:n,lazyModel:e.getModel,rootModel:e.rootModel});var r=e.validations[n];if(Array.isArray(r)){var i=e.rootModel,o=u(r,(function(e){return function(){return p(i,i.$v,e)}}),(function(e){return Array.isArray(e)?e.join("."):e}));return(0,t.h)(a,n,{validations:o,lazyParentModel:h,prop:n,lazyModel:h,rootModel:i})}return(0,t.h)(s,n,{validations:r,lazyParentModel:e.getModel,prop:n,lazyModel:e.getModelKey,rootModel:e.rootModel})},S=function(e,n){return(0,t.h)(o,n,{rule:e.validations[n],lazyParentModel:e.lazyParentModel,lazyModel:e.getModel,rootModel:e.rootModel})};return x={VBase:i,Validation:s}},k=null;var M=function(e,n){var r=function(e){if(k)return k;for(var t=e.constructor;t.super;)t=t.super;return k=t,t}(e),i=S(r),o=i.Validation;return new(0,i.VBase)({computed:{children:function(){var r="function"==typeof n?n.call(e):n;return[(0,t.h)(o,"$v",{validations:r,lazyParentModel:h,prop:"$v",model:e,rootModel:e})]}}})},O={data:function(){var e=this.$options.validations;return e&&(this._vuelidate=M(this,e)),{}},beforeCreate:function(){var e=this.$options;e.validations&&(e.computed||(e.computed={}),e.computed.$v||(e.computed.$v=function(){return this._vuelidate?this._vuelidate.refs.$v.proxy:null}))},beforeDestroy:function(){this._vuelidate&&(this._vuelidate.$destroy(),this._vuelidate=null)}};function C(e){e.mixin(O)}e.validationMixin=O;var N=C;e.default=N}(aa);const va=e(aa);export{xl as A,Dl as B,Al as C,tt as D,mn as E,ue as F,Cl as G,El as H,vs as I,va as J,rn as N,yn as P,ye as S,tn as T,la as V,Qo as a,cs as b,ds as c,ks as d,ts as e,Ms as f,$s as g,Is as h,zs as i,Qe as j,Ho as k,Rs as l,bs as m,Ao as n,ut as o,ys as p,tl as q,nl as r,hs as s,us as t,Ss as u,t as v,Ps as w,rl as x,il as y,Qs as z}; diff --git a/kirby/panel/dist/js/vue.min.js b/kirby/panel/dist/js/vue.min.js deleted file mode 100644 index 5b49427..0000000 --- a/kirby/panel/dist/js/vue.min.js +++ /dev/null @@ -1,11 +0,0 @@ -/*! - * Vue.js v2.7.16 - * (c) 2014-2023 Evan You - * Released under the MIT License. - */ -/*! - * Vue.js v2.7.16 - * (c) 2014-2023 Evan You - * Released under the MIT License. - */ -!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).Vue=e()}(this,(function(){"use strict";var t=Object.freeze({}),e=Array.isArray;function n(t){return null==t}function r(t){return null!=t}function o(t){return!0===t}function i(t){return"string"==typeof t||"number"==typeof t||"symbol"==typeof t||"boolean"==typeof t}function a(t){return"function"==typeof t}function s(t){return null!==t&&"object"==typeof t}var c=Object.prototype.toString;function u(t){return"[object Object]"===c.call(t)}function l(t){var e=parseFloat(String(t));return e>=0&&Math.floor(e)===e&&isFinite(t)}function f(t){return r(t)&&"function"==typeof t.then&&"function"==typeof t.catch}function d(t){return null==t?"":Array.isArray(t)||u(t)&&t.toString===c?JSON.stringify(t,p,2):String(t)}function p(t,e){return e&&e.__v_isRef?e.value:e}function v(t){var e=parseFloat(t);return isNaN(e)?t:e}function h(t,e){for(var n=Object.create(null),r=t.split(","),o=0;o-1)return t.splice(r,1)}}var _=Object.prototype.hasOwnProperty;function b(t,e){return _.call(t,e)}function $(t){var e=Object.create(null);return function(n){return e[n]||(e[n]=t(n))}}var w=/-(\w)/g,x=$((function(t){return t.replace(w,(function(t,e){return e?e.toUpperCase():""}))})),C=$((function(t){return t.charAt(0).toUpperCase()+t.slice(1)})),k=/\B([A-Z])/g,S=$((function(t){return t.replace(k,"-$1").toLowerCase()}));var O=Function.prototype.bind?function(t,e){return t.bind(e)}:function(t,e){function n(n){var r=arguments.length;return r?r>1?t.apply(e,arguments):t.call(e,n):t.call(e)}return n._length=t.length,n};function T(t,e){e=e||0;for(var n=t.length-e,r=new Array(n);n--;)r[n]=t[n+e];return r}function A(t,e){for(var n in e)t[n]=e[n];return t}function j(t){for(var e={},n=0;n0,X=W&&W.indexOf("edge/")>0;W&&W.indexOf("android");var Y=W&&/iphone|ipad|ipod|ios/.test(W);W&&/chrome\/\d+/.test(W),W&&/phantomjs/.test(W);var Q,tt=W&&W.match(/firefox\/(\d+)/),et={}.watch,nt=!1;if(q)try{var rt={};Object.defineProperty(rt,"passive",{get:function(){nt=!0}}),window.addEventListener("test-passive",null,rt)}catch(t){}var ot=function(){return void 0===Q&&(Q=!q&&"undefined"!=typeof global&&(global.process&&"server"===global.process.env.VUE_ENV)),Q},it=q&&window.__VUE_DEVTOOLS_GLOBAL_HOOK__;function at(t){return"function"==typeof t&&/native code/.test(t.toString())}var st,ct="undefined"!=typeof Symbol&&at(Symbol)&&"undefined"!=typeof Reflect&&at(Reflect.ownKeys);st="undefined"!=typeof Set&&at(Set)?Set:function(){function t(){this.set=Object.create(null)}return t.prototype.has=function(t){return!0===this.set[t]},t.prototype.add=function(t){this.set[t]=!0},t.prototype.clear=function(){this.set=Object.create(null)},t}();var ut=null;function lt(t){void 0===t&&(t=null),t||ut&&ut._scope.off(),ut=t,t&&t._scope.on()}var ft=function(){function t(t,e,n,r,o,i,a,s){this.tag=t,this.data=e,this.children=n,this.text=r,this.elm=o,this.ns=void 0,this.context=i,this.fnContext=void 0,this.fnOptions=void 0,this.fnScopeId=void 0,this.key=e&&e.key,this.componentOptions=a,this.componentInstance=void 0,this.parent=void 0,this.raw=!1,this.isStatic=!1,this.isRootInsert=!0,this.isComment=!1,this.isCloned=!1,this.isOnce=!1,this.asyncFactory=s,this.asyncMeta=void 0,this.isAsyncPlaceholder=!1}return Object.defineProperty(t.prototype,"child",{get:function(){return this.componentInstance},enumerable:!1,configurable:!0}),t}(),dt=function(t){void 0===t&&(t="");var e=new ft;return e.text=t,e.isComment=!0,e};function pt(t){return new ft(void 0,void 0,void 0,String(t))}function vt(t){var e=new ft(t.tag,t.data,t.children&&t.children.slice(),t.text,t.elm,t.context,t.componentOptions,t.asyncFactory);return e.ns=t.ns,e.isStatic=t.isStatic,e.key=t.key,e.isComment=t.isComment,e.fnContext=t.fnContext,e.fnOptions=t.fnOptions,e.fnScopeId=t.fnScopeId,e.asyncMeta=t.asyncMeta,e.isCloned=!0,e}"function"==typeof SuppressedError&&SuppressedError;var ht=0,mt=[],gt=function(){for(var t=0;t0&&(ne((c=re(c,"".concat(a||"","_").concat(s)))[0])&&ne(l)&&(f[u]=pt(l.text+c[0].text),c.shift()),f.push.apply(f,c)):i(c)?ne(l)?f[u]=pt(l.text+c):""!==c&&f.push(pt(c)):ne(c)&&ne(l)?f[u]=pt(l.text+c.text):(o(t._isVList)&&r(c.tag)&&n(c.key)&&r(a)&&(c.key="__vlist".concat(a,"_").concat(s,"__")),f.push(c)));return f}var oe=1,ie=2;function ae(t,n,c,u,l,f){return(e(c)||i(c))&&(l=u,u=c,c=void 0),o(f)&&(l=ie),function(t,n,o,i,c){if(r(o)&&r(o.__ob__))return dt();r(o)&&r(o.is)&&(n=o.is);if(!n)return dt();e(i)&&a(i[0])&&((o=o||{}).scopedSlots={default:i[0]},i.length=0);c===ie?i=ee(i):c===oe&&(i=function(t){for(var n=0;n0,s=n?!!n.$stable:!a,c=n&&n.$key;if(n){if(n._normalized)return n._normalized;if(s&&o&&o!==t&&c===o.$key&&!a&&!o.$hasNormal)return o;for(var u in i={},n)n[u]&&"$"!==u[0]&&(i[u]=Oe(e,r,u,n[u]))}else i={};for(var l in r)l in i||(i[l]=Te(r,l));return n&&Object.isExtensible(n)&&(n._normalized=i),V(i,"$stable",s),V(i,"$key",c),V(i,"$hasNormal",a),i}function Oe(t,n,r,o){var i=function(){var n=ut;lt(t);var r=arguments.length?o.apply(null,arguments):o({}),i=(r=r&&"object"==typeof r&&!e(r)?[r]:ee(r))&&r[0];return lt(n),r&&(!i||1===r.length&&i.isComment&&!ke(i))?void 0:r};return o.proxy&&Object.defineProperty(n,r,{get:i,enumerable:!0,configurable:!0}),i}function Te(t,e){return function(){return t[e]}}function Ae(e){return{get attrs(){if(!e._attrsProxy){var n=e._attrsProxy={};V(n,"_v_attr_proxy",!0),je(n,e.$attrs,t,e,"$attrs")}return e._attrsProxy},get listeners(){e._listenersProxy||je(e._listenersProxy={},e.$listeners,t,e,"$listeners");return e._listenersProxy},get slots(){return function(t){t._slotsProxy||Ne(t._slotsProxy={},t.$scopedSlots);return t._slotsProxy}(e)},emit:O(e.$emit,e),expose:function(t){t&&Object.keys(t).forEach((function(n){return zt(e,t,n)}))}}}function je(t,e,n,r,o){var i=!1;for(var a in e)a in t?e[a]!==n[a]&&(i=!0):(i=!0,Ee(t,a,r,o));for(var a in t)a in e||(i=!0,delete t[a]);return i}function Ee(t,e,n,r){Object.defineProperty(t,e,{enumerable:!0,configurable:!0,get:function(){return n[r][e]}})}function Ne(t,e){for(var n in e)t[n]=e[n];for(var n in t)n in e||delete t[n]}function Pe(){var t=ut;return t._setupContext||(t._setupContext=Ae(t))}var De,Me,Ie=null;function Le(t,e){return(t.__esModule||ct&&"Module"===t[Symbol.toStringTag])&&(t=t.default),s(t)?e.extend(t):t}function Re(t){if(e(t))for(var n=0;ndocument.createEvent("Event").timeStamp&&(on=function(){return an.now()})}var sn=function(t,e){if(t.post){if(!e.post)return 1}else if(e.post)return-1;return t.id-e.id};function cn(){var t,e;for(rn=on(),en=!0,Xe.sort(sn),nn=0;nnnn&&Xe[n].id>t.id;)n--;Xe.splice(n+1,0,t)}else Xe.push(t);tn||(tn=!0,En(cn))}}var ln="watcher",fn="".concat(ln," callback"),dn="".concat(ln," getter"),pn="".concat(ln," cleanup");function vn(t,e){return mn(t,null,{flush:"post"})}var hn={};function mn(n,r,o){var i=void 0===o?t:o,s=i.immediate,c=i.deep,u=i.flush,l=void 0===u?"pre":u;i.onTrack,i.onTrigger;var f,d,p=ut,v=function(t,e,n){void 0===n&&(n=null);var r=_n(t,null,n,p,e);return c&&r&&r.__ob__&&r.__ob__.dep.depend(),r},h=!1,m=!1;if(Bt(n)?(f=function(){return n.value},h=Rt(n)):Lt(n)?(f=function(){return n.__ob__.dep.depend(),n},c=!0):e(n)?(m=!0,h=n.some((function(t){return Lt(t)||Rt(t)})),f=function(){return n.map((function(t){return Bt(t)?t.value:Lt(t)?(t.__ob__.dep.depend(),Wn(t)):a(t)?v(t,dn):void 0}))}):f=a(n)?r?function(){return v(n,dn)}:function(){if(!p||!p._isDestroyed)return d&&d(),v(n,ln,[y])}:E,r&&c){var g=f;f=function(){return Wn(g())}}var y=function(t){d=_.onStop=function(){v(t,pn)}};if(ot())return y=E,r?s&&v(r,fn,[f(),m?[]:void 0,y]):f(),E;var _=new Xn(ut,f,E,{lazy:!0});_.noRecurse=!r;var b=m?[]:hn;return _.run=function(){if(_.active)if(r){var t=_.get();(c||h||(m?t.some((function(t,e){return L(t,b[e])})):L(t,b)))&&(d&&d(),v(r,fn,[t,b===hn?void 0:b,y]),b=t)}else _.get()},"sync"===l?_.update=_.run:"post"===l?(_.post=!0,_.update=function(){return un(_)}):_.update=function(){if(p&&p===ut&&!p._isMounted){var t=p._preWatchers||(p._preWatchers=[]);t.indexOf(_)<0&&t.push(_)}else un(_)},r?s?_.run():b=_.get():"post"===l&&p?p.$once("hook:mounted",(function(){return _.get()})):_.get(),function(){_.teardown()}}function gn(t){var e=t._provided,n=t.$parent&&t.$parent._provided;return n===e?t._provided=Object.create(n):e}function yn(t,e,n){bt();try{if(e)for(var r=e;r=r.$parent;){var o=r.$options.errorCaptured;if(o)for(var i=0;i1)return n&&a(e)?e.call(r):e}},h:function(t,e,n){return ae(ut,t,e,n,2,!0)},getCurrentInstance:function(){return ut&&{proxy:ut}},useSlots:function(){return Pe().slots},useAttrs:function(){return Pe().attrs},useListeners:function(){return Pe().listeners},mergeDefaults:function(t,n){var r=e(t)?t.reduce((function(t,e){return t[e]={},t}),{}):t;for(var o in n){var i=r[o];i?e(i)||a(i)?r[o]={type:i,default:n[o]}:i.default=n[o]:null===i&&(r[o]={default:n[o]})}return r},nextTick:En,set:Nt,del:Pt,useCssModule:function(e){return t},useCssVars:function(t){if(q){var e=ut;e&&vn((function(){var n=e.$el,r=t(e,e._setupProxy);if(n&&1===n.nodeType){var o=n.style;for(var i in r)o.setProperty("--".concat(i),r[i])}}))}},defineAsyncComponent:function(t){a(t)&&(t={loader:t});var e=t.loader,n=t.loadingComponent,r=t.errorComponent,o=t.delay,i=void 0===o?200:o,s=t.timeout;t.suspensible;var c=t.onError,u=null,l=0,f=function(){var t;return u||(t=u=e().catch((function(t){if(t=t instanceof Error?t:new Error(String(t)),c)return new Promise((function(e,n){c(t,(function(){return e((l++,u=null,f()))}),(function(){return n(t)}),l+1)}));throw t})).then((function(e){return t!==u&&u?u:(e&&(e.__esModule||"Module"===e[Symbol.toStringTag])&&(e=e.default),e)})))};return function(){return{component:f(),delay:i,timeout:s,error:r,loading:n}}},onBeforeMount:Pn,onMounted:Dn,onBeforeUpdate:Mn,onUpdated:In,onBeforeUnmount:Ln,onUnmounted:Rn,onActivated:Fn,onDeactivated:Hn,onServerPrefetch:Bn,onRenderTracked:Un,onRenderTriggered:zn,onErrorCaptured:function(t,e){void 0===e&&(e=ut),Vn(t,e)}}),qn=new st;function Wn(t){return Zn(t,qn),qn.clear(),t}function Zn(t,n){var r,o,i=e(t);if(!(!i&&!s(t)||t.__v_skip||Object.isFrozen(t)||t instanceof ft)){if(t.__ob__){var a=t.__ob__.dep.id;if(n.has(a))return;n.add(a)}if(i)for(r=t.length;r--;)Zn(t[r],n);else if(Bt(t))Zn(t.value,n);else for(r=(o=Object.keys(t)).length;r--;)Zn(t[o[r]],n)}}var Gn=0,Xn=function(){function t(t,e,n,r,o){!function(t,e){void 0===e&&(e=Me),e&&e.active&&e.effects.push(t)}(this,Me&&!Me._vm?Me:t?t._scope:void 0),(this.vm=t)&&o&&(t._watcher=this),r?(this.deep=!!r.deep,this.user=!!r.user,this.lazy=!!r.lazy,this.sync=!!r.sync,this.before=r.before):this.deep=this.user=this.lazy=this.sync=!1,this.cb=n,this.id=++Gn,this.active=!0,this.post=!1,this.dirty=this.lazy,this.deps=[],this.newDeps=[],this.depIds=new st,this.newDepIds=new st,this.expression="",a(e)?this.getter=e:(this.getter=function(t){if(!K.test(t)){var e=t.split(".");return function(t){for(var n=0;n-1)if(i&&!b(o,"default"))s=!1;else if(""===s||s===S(t)){var u=jr(String,o.type);(u<0||c-1:"string"==typeof t?t.split(",").indexOf(n)>-1:(r=t,"[object RegExp]"===c.call(r)&&t.test(n));var r}function Mr(t,e){var n=t.cache,r=t.keys,o=t._vnode,i=t.$vnode;for(var a in n){var s=n[a];if(s){var c=s.name;c&&!e(c)&&Ir(n,a,r,o)}}i.componentOptions.children=void 0}function Ir(t,e,n,r){var o=t[e];!o||r&&o.tag===r.tag||o.componentInstance.$destroy(),t[e]=null,y(n,e)}!function(e){e.prototype._init=function(e){var n=this;n._uid=sr++,n._isVue=!0,n.__v_skip=!0,n._scope=new ze(!0),n._scope.parent=void 0,n._scope._vm=!0,e&&e._isComponent?function(t,e){var n=t.$options=Object.create(t.constructor.options),r=e._parentVnode;n.parent=e.parent,n._parentVnode=r;var o=r.componentOptions;n.propsData=o.propsData,n._parentListeners=o.listeners,n._renderChildren=o.children,n._componentTag=o.tag,e.render&&(n.render=e.render,n.staticRenderFns=e.staticRenderFns)}(n,e):n.$options=Cr(cr(n.constructor),e||{},n),n._renderProxy=n,n._self=n,function(t){var e=t.$options,n=e.parent;if(n&&!e.abstract){for(;n.$options.abstract&&n.$parent;)n=n.$parent;n.$children.push(t)}t.$parent=n,t.$root=n?n.$root:t,t.$children=[],t.$refs={},t._provided=n?n._provided:Object.create(null),t._watcher=null,t._inactive=null,t._directInactive=!1,t._isMounted=!1,t._isDestroyed=!1,t._isBeingDestroyed=!1}(n),function(t){t._events=Object.create(null),t._hasHookEvent=!1;var e=t.$options._parentListeners;e&&Ue(t,e)}(n),function(e){e._vnode=null,e._staticTrees=null;var n=e.$options,r=e.$vnode=n._parentVnode,o=r&&r.context;e.$slots=xe(n._renderChildren,o),e.$scopedSlots=r?Se(e.$parent,r.data.scopedSlots,e.$slots):t,e._c=function(t,n,r,o){return ae(e,t,n,r,o,!1)},e.$createElement=function(t,n,r,o){return ae(e,t,n,r,o,!0)};var i=r&&r.data;Et(e,"$attrs",i&&i.attrs||t,null,!0),Et(e,"$listeners",n._parentListeners||t,null,!0)}(n),Ge(n,"beforeCreate",void 0,!1),function(t){var e=ar(t.$options.inject,t);e&&(Ot(!1),Object.keys(e).forEach((function(n){Et(t,n,e[n])})),Ot(!0))}(n),tr(n),function(t){var e=t.$options.provide;if(e){var n=a(e)?e.call(t):e;if(!s(n))return;for(var r=gn(t),o=ct?Reflect.ownKeys(n):Object.keys(n),i=0;i1?T(n):n;for(var r=T(arguments,1),o='event handler for "'.concat(t,'"'),i=0,a=n.length;iparseInt(this.max)&&Ir(e,n[0],n,this._vnode),this.vnodeToCache=null}}},created:function(){this.cache=Object.create(null),this.keys=[]},destroyed:function(){for(var t in this.cache)Ir(this.cache,t,this.keys)},mounted:function(){var t=this;this.cacheVNode(),this.$watch("include",(function(e){Mr(t,(function(t){return Dr(e,t)}))})),this.$watch("exclude",(function(e){Mr(t,(function(t){return!Dr(e,t)}))}))},updated:function(){this.cacheVNode()},render:function(){var t=this.$slots.default,e=Re(t),n=e&&e.componentOptions;if(n){var r=Pr(n),o=this.include,i=this.exclude;if(o&&(!r||!Dr(o,r))||i&&r&&Dr(i,r))return e;var a=this.cache,s=this.keys,c=null==e.key?n.Ctor.cid+(n.tag?"::".concat(n.tag):""):e.key;a[c]?(e.componentInstance=a[c].componentInstance,y(s,c),s.push(c)):(this.vnodeToCache=e,this.keyToCache=c),e.data.keepAlive=!0}return e||t&&t[0]}},Fr={KeepAlive:Rr};!function(t){var e={get:function(){return B}};Object.defineProperty(t,"config",e),t.util={warn:gr,extend:A,mergeOptions:Cr,defineReactive:Et},t.set=Nt,t.delete=Pt,t.nextTick=En,t.observable=function(t){return jt(t),t},t.options=Object.create(null),F.forEach((function(e){t.options[e+"s"]=Object.create(null)})),t.options._base=t,A(t.options.components,Fr),function(t){t.use=function(t){var e=this._installedPlugins||(this._installedPlugins=[]);if(e.indexOf(t)>-1)return this;var n=T(arguments,1);return n.unshift(this),a(t.install)?t.install.apply(t,n):a(t)&&t.apply(null,n),e.push(t),this}}(t),function(t){t.mixin=function(t){return this.options=Cr(this.options,t),this}}(t),Nr(t),function(t){F.forEach((function(e){t[e]=function(t,n){return n?("component"===e&&u(n)&&(n.name=n.name||t,n=this.options._base.extend(n)),"directive"===e&&a(n)&&(n={bind:n,update:n}),this.options[e+"s"][t]=n,n):this.options[e+"s"][t]}}))}(t)}(Er),Object.defineProperty(Er.prototype,"$isServer",{get:ot}),Object.defineProperty(Er.prototype,"$ssrContext",{get:function(){return this.$vnode&&this.$vnode.ssrContext}}),Object.defineProperty(Er,"FunctionalRenderContext",{value:ur}),Er.version=Kn;var Hr=h("style,class"),Br=h("input,textarea,option,select,progress"),Ur=function(t,e,n){return"value"===n&&Br(t)&&"button"!==e||"selected"===n&&"option"===t||"checked"===n&&"input"===t||"muted"===n&&"video"===t},zr=h("contenteditable,draggable,spellcheck"),Vr=h("events,caret,typing,plaintext-only"),Kr=function(t,e){return Gr(e)||"false"===e?"false":"contenteditable"===t&&Vr(e)?e:"true"},Jr=h("allowfullscreen,async,autofocus,autoplay,checked,compact,controls,declare,default,defaultchecked,defaultmuted,defaultselected,defer,disabled,enabled,formnovalidate,hidden,indeterminate,inert,ismap,itemscope,loop,multiple,muted,nohref,noresize,noshade,novalidate,nowrap,open,pauseonexit,readonly,required,reversed,scoped,seamless,selected,sortable,truespeed,typemustmatch,visible"),qr="http://www.w3.org/1999/xlink",Wr=function(t){return":"===t.charAt(5)&&"xlink"===t.slice(0,5)},Zr=function(t){return Wr(t)?t.slice(6,t.length):""},Gr=function(t){return null==t||!1===t};function Xr(t){for(var e=t.data,n=t,o=t;r(o.componentInstance);)(o=o.componentInstance._vnode)&&o.data&&(e=Yr(o.data,e));for(;r(n=n.parent);)n&&n.data&&(e=Yr(e,n.data));return function(t,e){if(r(t)||r(e))return Qr(t,to(e));return""}(e.staticClass,e.class)}function Yr(t,e){return{staticClass:Qr(t.staticClass,e.staticClass),class:r(t.class)?[t.class,e.class]:e.class}}function Qr(t,e){return t?e?t+" "+e:t:e||""}function to(t){return Array.isArray(t)?function(t){for(var e,n="",o=0,i=t.length;o-1?Oo(t,e,n):Jr(e)?Gr(n)?t.removeAttribute(e):(n="allowfullscreen"===e&&"EMBED"===t.tagName?"true":e,t.setAttribute(e,n)):zr(e)?t.setAttribute(e,Kr(e,n)):Wr(e)?Gr(n)?t.removeAttributeNS(qr,Zr(e)):t.setAttributeNS(qr,e,n):Oo(t,e,n)}function Oo(t,e,n){if(Gr(n))t.removeAttribute(e);else{if(Z&&!G&&"TEXTAREA"===t.tagName&&"placeholder"===e&&""!==n&&!t.__ieph){var r=function(e){e.stopImmediatePropagation(),t.removeEventListener("input",r)};t.addEventListener("input",r),t.__ieph=!0}t.setAttribute(e,n)}}var To={create:ko,update:ko};function Ao(t,e){var o=e.elm,i=e.data,a=t.data;if(!(n(i.staticClass)&&n(i.class)&&(n(a)||n(a.staticClass)&&n(a.class)))){var s=Xr(e),c=o._transitionClasses;r(c)&&(s=Qr(s,to(c))),s!==o._prevClass&&(o.setAttribute("class",s),o._prevClass=s)}}var jo,Eo,No,Po,Do,Mo,Io={create:Ao,update:Ao},Lo=/[\w).+\-_$\]]/;function Ro(t){var e,n,r,o,i,a=!1,s=!1,c=!1,u=!1,l=0,f=0,d=0,p=0;for(r=0;r=0&&" "===(h=t.charAt(v));v--);h&&Lo.test(h)||(u=!0)}}else void 0===o?(p=r+1,o=t.slice(0,r).trim()):m();function m(){(i||(i=[])).push(t.slice(p,r).trim()),p=r+1}if(void 0===o?o=t.slice(0,r).trim():0!==p&&m(),i)for(r=0;r-1?{exp:t.slice(0,Po),key:'"'+t.slice(Po+1)+'"'}:{exp:t,key:null};Eo=t,Po=Do=Mo=0;for(;!ei();)ni(No=ti())?oi(No):91===No&&ri(No);return{exp:t.slice(0,Do),key:t.slice(Do+1,Mo)}}(t);return null===n.key?"".concat(t,"=").concat(e):"$set(".concat(n.exp,", ").concat(n.key,", ").concat(e,")")}function ti(){return Eo.charCodeAt(++Po)}function ei(){return Po>=jo}function ni(t){return 34===t||39===t}function ri(t){var e=1;for(Do=Po;!ei();)if(ni(t=ti()))oi(t);else if(91===t&&e++,93===t&&e--,0===e){Mo=Po;break}}function oi(t){for(var e=t;!ei()&&(t=ti())!==e;);}var ii,ai="__r",si="__c";function ci(t,e,n){var r=ii;return function o(){null!==e.apply(null,arguments)&&fi(t,o,n,r)}}var ui=xn&&!(tt&&Number(tt[1])<=53);function li(t,e,n,r){if(ui){var o=rn,i=e;e=i._wrapper=function(t){if(t.target===t.currentTarget||t.timeStamp>=o||t.timeStamp<=0||t.target.ownerDocument!==document)return i.apply(this,arguments)}}ii.addEventListener(t,e,nt?{capture:n,passive:r}:n)}function fi(t,e,n,r){(r||ii).removeEventListener(t,e._wrapper||e,n)}function di(t,e){if(!n(t.data.on)||!n(e.data.on)){var o=e.data.on||{},i=t.data.on||{};ii=e.elm||t.elm,function(t){if(r(t[ai])){var e=Z?"change":"input";t[e]=[].concat(t[ai],t[e]||[]),delete t[ai]}r(t[si])&&(t.change=[].concat(t[si],t.change||[]),delete t[si])}(o),Yt(o,i,li,fi,ci,e.context),ii=void 0}}var pi,vi={create:di,update:di,destroy:function(t){return di(t,vo)}};function hi(t,e){if(!n(t.data.domProps)||!n(e.data.domProps)){var i,a,s=e.elm,c=t.data.domProps||{},u=e.data.domProps||{};for(i in(r(u.__ob__)||o(u._v_attr_proxy))&&(u=e.data.domProps=A({},u)),c)i in u||(s[i]="");for(i in u){if(a=u[i],"textContent"===i||"innerHTML"===i){if(e.children&&(e.children.length=0),a===c[i])continue;1===s.childNodes.length&&s.removeChild(s.childNodes[0])}if("value"===i&&"PROGRESS"!==s.tagName){s._value=a;var l=n(a)?"":String(a);mi(s,l)&&(s.value=l)}else if("innerHTML"===i&&ro(s.tagName)&&n(s.innerHTML)){(pi=pi||document.createElement("div")).innerHTML="".concat(a,"");for(var f=pi.firstChild;s.firstChild;)s.removeChild(s.firstChild);for(;f.firstChild;)s.appendChild(f.firstChild)}else if(a!==c[i])try{s[i]=a}catch(t){}}}}function mi(t,e){return!t.composing&&("OPTION"===t.tagName||function(t,e){var n=!0;try{n=document.activeElement!==t}catch(t){}return n&&t.value!==e}(t,e)||function(t,e){var n=t.value,o=t._vModifiers;if(r(o)){if(o.number)return v(n)!==v(e);if(o.trim)return n.trim()!==e.trim()}return n!==e}(t,e))}var gi={create:hi,update:hi},yi=$((function(t){var e={},n=/:(.+)/;return t.split(/;(?![^(]*\))/g).forEach((function(t){if(t){var r=t.split(n);r.length>1&&(e[r[0].trim()]=r[1].trim())}})),e}));function _i(t){var e=bi(t.style);return t.staticStyle?A(t.staticStyle,e):e}function bi(t){return Array.isArray(t)?j(t):"string"==typeof t?yi(t):t}var $i,wi=/^--/,xi=/\s*!important$/,Ci=function(t,e,n){if(wi.test(e))t.style.setProperty(e,n);else if(xi.test(n))t.style.setProperty(S(e),n.replace(xi,""),"important");else{var r=Si(e);if(Array.isArray(n))for(var o=0,i=n.length;o-1?e.split(Ai).forEach((function(e){return t.classList.add(e)})):t.classList.add(e);else{var n=" ".concat(t.getAttribute("class")||""," ");n.indexOf(" "+e+" ")<0&&t.setAttribute("class",(n+e).trim())}}function Ei(t,e){if(e&&(e=e.trim()))if(t.classList)e.indexOf(" ")>-1?e.split(Ai).forEach((function(e){return t.classList.remove(e)})):t.classList.remove(e),t.classList.length||t.removeAttribute("class");else{for(var n=" ".concat(t.getAttribute("class")||""," "),r=" "+e+" ";n.indexOf(r)>=0;)n=n.replace(r," ");(n=n.trim())?t.setAttribute("class",n):t.removeAttribute("class")}}function Ni(t){if(t){if("object"==typeof t){var e={};return!1!==t.css&&A(e,Pi(t.name||"v")),A(e,t),e}return"string"==typeof t?Pi(t):void 0}}var Pi=$((function(t){return{enterClass:"".concat(t,"-enter"),enterToClass:"".concat(t,"-enter-to"),enterActiveClass:"".concat(t,"-enter-active"),leaveClass:"".concat(t,"-leave"),leaveToClass:"".concat(t,"-leave-to"),leaveActiveClass:"".concat(t,"-leave-active")}})),Di=q&&!G,Mi="transition",Ii="animation",Li="transition",Ri="transitionend",Fi="animation",Hi="animationend";Di&&(void 0===window.ontransitionend&&void 0!==window.onwebkittransitionend&&(Li="WebkitTransition",Ri="webkitTransitionEnd"),void 0===window.onanimationend&&void 0!==window.onwebkitanimationend&&(Fi="WebkitAnimation",Hi="webkitAnimationEnd"));var Bi=q?window.requestAnimationFrame?window.requestAnimationFrame.bind(window):setTimeout:function(t){return t()};function Ui(t){Bi((function(){Bi(t)}))}function zi(t,e){var n=t._transitionClasses||(t._transitionClasses=[]);n.indexOf(e)<0&&(n.push(e),ji(t,e))}function Vi(t,e){t._transitionClasses&&y(t._transitionClasses,e),Ei(t,e)}function Ki(t,e,n){var r=qi(t,e),o=r.type,i=r.timeout,a=r.propCount;if(!o)return n();var s=o===Mi?Ri:Hi,c=0,u=function(){t.removeEventListener(s,l),n()},l=function(e){e.target===t&&++c>=a&&u()};setTimeout((function(){c0&&(n=Mi,l=a,f=i.length):e===Ii?u>0&&(n=Ii,l=u,f=c.length):f=(n=(l=Math.max(a,u))>0?a>u?Mi:Ii:null)?n===Mi?i.length:c.length:0,{type:n,timeout:l,propCount:f,hasTransform:n===Mi&&Ji.test(r[Li+"Property"])}}function Wi(t,e){for(;t.length1}function ta(t,e){!0!==e.data.show&&Gi(e)}var ea=function(t){var a,s,c={},u=t.modules,l=t.nodeOps;for(a=0;av?b(t,n(o[g+1])?null:o[g+1].elm,o,p,g,i):p>g&&w(e,f,v)}(f,h,m,i,u):r(m)?(r(t.text)&&l.setTextContent(f,""),b(f,null,m,0,m.length-1,i)):r(h)?w(h,0,h.length-1):r(t.text)&&l.setTextContent(f,""):t.text!==e.text&&l.setTextContent(f,e.text),r(v)&&r(p=v.hook)&&r(p=p.postpatch)&&p(t,e)}}}function S(t,e,n){if(o(n)&&r(t.parent))t.parent.data.pendingInsert=e;else for(var i=0;i-1,a.selected!==i&&(a.selected=i);else if(D(aa(a),r))return void(t.selectedIndex!==s&&(t.selectedIndex=s));o||(t.selectedIndex=-1)}}function ia(t,e){return e.every((function(e){return!D(e,t)}))}function aa(t){return"_value"in t?t._value:t.value}function sa(t){t.target.composing=!0}function ca(t){t.target.composing&&(t.target.composing=!1,ua(t.target,"input"))}function ua(t,e){var n=document.createEvent("HTMLEvents");n.initEvent(e,!0,!0),t.dispatchEvent(n)}function la(t){return!t.componentInstance||t.data&&t.data.transition?t:la(t.componentInstance._vnode)}var fa={bind:function(t,e,n){var r=e.value,o=(n=la(n)).data&&n.data.transition,i=t.__vOriginalDisplay="none"===t.style.display?"":t.style.display;r&&o?(n.data.show=!0,Gi(n,(function(){t.style.display=i}))):t.style.display=r?i:"none"},update:function(t,e,n){var r=e.value;!r!=!e.oldValue&&((n=la(n)).data&&n.data.transition?(n.data.show=!0,r?Gi(n,(function(){t.style.display=t.__vOriginalDisplay})):Xi(n,(function(){t.style.display="none"}))):t.style.display=r?t.__vOriginalDisplay:"none")},unbind:function(t,e,n,r,o){o||(t.style.display=t.__vOriginalDisplay)}},da={model:na,show:fa},pa={name:String,appear:Boolean,css:Boolean,mode:String,type:String,enterClass:String,leaveClass:String,enterToClass:String,leaveToClass:String,enterActiveClass:String,leaveActiveClass:String,appearClass:String,appearActiveClass:String,appearToClass:String,duration:[Number,String,Object]};function va(t){var e=t&&t.componentOptions;return e&&e.Ctor.options.abstract?va(Re(e.children)):t}function ha(t){var e={},n=t.$options;for(var r in n.propsData)e[r]=t[r];var o=n._parentListeners;for(var r in o)e[x(r)]=o[r];return e}function ma(t,e){if(/\d-keep-alive$/.test(e.tag))return t("keep-alive",{props:e.componentOptions.propsData})}var ga=function(t){return t.tag||ke(t)},ya=function(t){return"show"===t.name},_a={name:"transition",props:pa,abstract:!0,render:function(t){var e=this,n=this.$slots.default;if(n&&(n=n.filter(ga)).length){var r=this.mode,o=n[0];if(function(t){for(;t=t.parent;)if(t.data.transition)return!0}(this.$vnode))return o;var a=va(o);if(!a)return o;if(this._leaving)return ma(t,o);var s="__transition-".concat(this._uid,"-");a.key=null==a.key?a.isComment?s+"comment":s+a.tag:i(a.key)?0===String(a.key).indexOf(s)?a.key:s+a.key:a.key;var c=(a.data||(a.data={})).transition=ha(this),u=this._vnode,l=va(u);if(a.data.directives&&a.data.directives.some(ya)&&(a.data.show=!0),l&&l.data&&!function(t,e){return e.key===t.key&&e.tag===t.tag}(a,l)&&!ke(l)&&(!l.componentInstance||!l.componentInstance._vnode.isComment)){var f=l.data.transition=A({},c);if("out-in"===r)return this._leaving=!0,Qt(f,"afterLeave",(function(){e._leaving=!1,e.$forceUpdate()})),ma(t,o);if("in-out"===r){if(ke(a))return u;var d,p=function(){d()};Qt(c,"afterEnter",p),Qt(c,"enterCancelled",p),Qt(f,"delayLeave",(function(t){d=t}))}}return o}}},ba=A({tag:String,moveClass:String},pa);delete ba.mode;var $a={props:ba,beforeMount:function(){var t=this,e=this._update;this._update=function(n,r){var o=Je(t);t.__patch__(t._vnode,t.kept,!1,!0),t._vnode=t.kept,o(),e.call(t,n,r)}},render:function(t){for(var e=this.tag||this.$vnode.data.tag||"span",n=Object.create(null),r=this.prevChildren=this.children,o=this.$slots.default||[],i=this.children=[],a=ha(this),s=0;s-1?ao[t]=e.constructor===window.HTMLUnknownElement||e.constructor===window.HTMLElement:ao[t]=/HTMLUnknownElement/.test(e.toString())},A(Er.options.directives,da),A(Er.options.components,ka),Er.prototype.__patch__=q?ea:E,Er.prototype.$mount=function(t,e){return function(t,e,n){var r;t.$el=e,t.$options.render||(t.$options.render=dt),Ge(t,"beforeMount"),r=function(){t._update(t._render(),n)},new Xn(t,r,E,{before:function(){t._isMounted&&!t._isDestroyed&&Ge(t,"beforeUpdate")}},!0),n=!1;var o=t._preWatchers;if(o)for(var i=0;i\/=]+)(?:\s*(=)\s*(?:"([^"]*)"+|'([^']*)'+|([^\s"'=<>`]+)))?/,La=/^\s*((?:v-[\w-]+:|@|:|#)\[[^=]+?\][^\s"'<>\/=]*)(?:\s*(=)\s*(?:"([^"]*)"+|'([^']*)'+|([^\s"'=<>`]+)))?/,Ra="[a-zA-Z_][\\-\\.0-9_a-zA-Z".concat(U.source,"]*"),Fa="((?:".concat(Ra,"\\:)?").concat(Ra,")"),Ha=new RegExp("^<".concat(Fa)),Ba=/^\s*(\/?)>/,Ua=new RegExp("^<\\/".concat(Fa,"[^>]*>")),za=/^]+>/i,Va=/^",""":'"',"&":"&"," ":"\n"," ":"\t","'":"'"},Za=/&(?:lt|gt|quot|amp|#39);/g,Ga=/&(?:lt|gt|quot|amp|#39|#10|#9);/g,Xa=h("pre,textarea",!0),Ya=function(t,e){return t&&Xa(t)&&"\n"===e[0]};function Qa(t,e){var n=e?Ga:Za;return t.replace(n,(function(t){return Wa[t]}))}function ts(t,e){for(var n,r,o=[],i=e.expectHTML,a=e.isUnaryTag||N,s=e.canBeLeftOpenTag||N,c=0,u=function(){if(n=t,r&&Ja(r)){var u=0,d=r.toLowerCase(),p=qa[d]||(qa[d]=new RegExp("([\\s\\S]*?)(]*>)","i"));w=t.replace(p,(function(t,n,r){return u=r.length,Ja(d)||"noscript"===d||(n=n.replace(//g,"$1").replace(//g,"$1")),Ya(d,n)&&(n=n.slice(1)),e.chars&&e.chars(n),""}));c+=t.length-w.length,t=w,f(d,c-u,c)}else{var v=t.indexOf("<");if(0===v){if(Va.test(t)){var h=t.indexOf("--\x3e");if(h>=0)return e.shouldKeepComment&&e.comment&&e.comment(t.substring(4,h),c,c+h+3),l(h+3),"continue"}if(Ka.test(t)){var m=t.indexOf("]>");if(m>=0)return l(m+2),"continue"}var g=t.match(za);if(g)return l(g[0].length),"continue";var y=t.match(Ua);if(y){var _=c;return l(y[0].length),f(y[1],_,c),"continue"}var b=function(){var e=t.match(Ha);if(e){var n={tagName:e[1],attrs:[],start:c};l(e[0].length);for(var r=void 0,o=void 0;!(r=t.match(Ba))&&(o=t.match(La)||t.match(Ia));)o.start=c,l(o[0].length),o.end=c,n.attrs.push(o);if(r)return n.unarySlash=r[1],l(r[0].length),n.end=c,n}}();if(b)return function(t){var n=t.tagName,c=t.unarySlash;i&&("p"===r&&Ma(n)&&f(r),s(n)&&r===n&&f(n));for(var u=a(n)||!!c,l=t.attrs.length,d=new Array(l),p=0;p=0){for(w=t.slice(v);!(Ua.test(w)||Ha.test(w)||Va.test(w)||Ka.test(w)||(x=w.indexOf("<",1))<0);)v+=x,w=t.slice(v);$=t.substring(0,v)}v<0&&($=t),$&&l($.length),e.chars&&$&&e.chars($,c-$.length,c)}if(t===n)return e.chars&&e.chars(t),"break"};t;){if("break"===u())break}function l(e){c+=e,t=t.substring(e)}function f(t,n,i){var a,s;if(null==n&&(n=c),null==i&&(i=c),t)for(s=t.toLowerCase(),a=o.length-1;a>=0&&o[a].lowerCasedTag!==s;a--);else a=0;if(a>=0){for(var u=o.length-1;u>=a;u--)e.end&&e.end(o[u].tag,n,i);o.length=a,r=a&&o[a-1].tag}else"br"===s?e.start&&e.start(t,[],!0,n,i):"p"===s&&(e.start&&e.start(t,[],!1,n,i),e.end&&e.end(t,n,i))}f()}var es,ns,rs,os,is,as,ss,cs,us=/^@|^v-on:/,ls=/^v-|^@|^:|^#/,fs=/([\s\S]*?)\s+(?:in|of)\s+([\s\S]*)/,ds=/,([^,\}\]]*)(?:,([^,\}\]]*))?$/,ps=/^\(|\)$/g,vs=/^\[.*\]$/,hs=/:(.*)$/,ms=/^:|^\.|^v-bind:/,gs=/\.[^.\]]+(?=[^\]]*$)/g,ys=/^v-slot(:|$)|^#/,_s=/[\r\n]/,bs=/[ \f\t\r\n]+/g,$s=$(Na),ws="_empty_";function xs(t,e,n){return{type:1,tag:t,attrsList:e,attrsMap:js(e),rawAttrsMap:{},parent:n,children:[]}}function Cs(t,e){es=e.warn||Ho,as=e.isPreTag||N,ss=e.mustUseProp||N,cs=e.getTagNamespace||N,e.isReservedTag,rs=Bo(e.modules,"transformNode"),os=Bo(e.modules,"preTransformNode"),is=Bo(e.modules,"postTransformNode"),ns=e.delimiters;var n,r,o=[],i=!1!==e.preserveWhitespace,a=e.whitespace,s=!1,c=!1;function u(t){if(l(t),s||t.processed||(t=ks(t,e)),o.length||t===n||n.if&&(t.elseif||t.else)&&Os(n,{exp:t.elseif,block:t}),r&&!t.forbidden)if(t.elseif||t.else)a=t,u=function(t){for(var e=t.length;e--;){if(1===t[e].type)return t[e];t.pop()}}(r.children),u&&u.if&&Os(u,{exp:a.elseif,block:a});else{if(t.slotScope){var i=t.slotTarget||'"default"';(r.scopedSlots||(r.scopedSlots={}))[i]=t}r.children.push(t),t.parent=r}var a,u;t.children=t.children.filter((function(t){return!t.slotScope})),l(t),t.pre&&(s=!1),as(t.tag)&&(c=!1);for(var f=0;fc&&(s.push(i=t.slice(c,o)),a.push(JSON.stringify(i)));var u=Ro(r[1].trim());a.push("_s(".concat(u,")")),s.push({"@binding":u}),c=o+r[0].length}return c-1")+("true"===i?":(".concat(e,")"):":_q(".concat(e,",").concat(i,")"))),qo(t,"change","var $$a=".concat(e,",")+"$$el=$event.target,"+"$$c=$$el.checked?(".concat(i,"):(").concat(a,");")+"if(Array.isArray($$a)){"+"var $$v=".concat(r?"_n("+o+")":o,",")+"$$i=_i($$a,$$v);"+"if($$el.checked){$$i<0&&(".concat(Qo(e,"$$a.concat([$$v])"),")}")+"else{$$i>-1&&(".concat(Qo(e,"$$a.slice(0,$$i).concat($$a.slice($$i+1))"),")}")+"}else{".concat(Qo(e,"$$c"),"}"),null,!0)}(t,r,o);else if("input"===i&&"radio"===a)!function(t,e,n){var r=n&&n.number,o=Wo(t,"value")||"null";o=r?"_n(".concat(o,")"):o,Uo(t,"checked","_q(".concat(e,",").concat(o,")")),qo(t,"change",Qo(e,o),null,!0)}(t,r,o);else if("input"===i||"textarea"===i)!function(t,e,n){var r=t.attrsMap.type,o=n||{},i=o.lazy,a=o.number,s=o.trim,c=!i&&"range"!==r,u=i?"change":"range"===r?ai:"input",l="$event.target.value";s&&(l="$event.target.value.trim()");a&&(l="_n(".concat(l,")"));var f=Qo(e,l);c&&(f="if($event.target.composing)return;".concat(f));Uo(t,"value","(".concat(e,")")),qo(t,u,f,null,!0),(s||a)&&qo(t,"blur","$forceUpdate()")}(t,r,o);else if(!B.isReservedTag(i))return Yo(t,r,o),!1;return!0},text:function(t,e){e.value&&Uo(t,"textContent","_s(".concat(e.value,")"),e)},html:function(t,e){e.value&&Uo(t,"innerHTML","_s(".concat(e.value,")"),e)}},Rs={expectHTML:!0,modules:Ds,directives:Ls,isPreTag:function(t){return"pre"===t},isUnaryTag:Pa,mustUseProp:Ur,canBeLeftOpenTag:Da,isReservedTag:oo,getTagNamespace:io,staticKeys:function(t){return t.reduce((function(t,e){return t.concat(e.staticKeys||[])}),[]).join(",")}(Ds)},Fs=$((function(t){return h("type,tag,attrsList,attrsMap,plain,parent,children,attrs,start,end,rawAttrsMap"+(t?","+t:""))}));function Hs(t,e){t&&(Ms=Fs(e.staticKeys||""),Is=e.isReservedTag||N,Bs(t),Us(t,!1))}function Bs(t){if(t.static=function(t){if(2===t.type)return!1;if(3===t.type)return!0;return!(!t.pre&&(t.hasBindings||t.if||t.for||m(t.tag)||!Is(t.tag)||function(t){for(;t.parent;){if("template"!==(t=t.parent).tag)return!1;if(t.for)return!0}return!1}(t)||!Object.keys(t).every(Ms)))}(t),1===t.type){if(!Is(t.tag)&&"slot"!==t.tag&&null==t.attrsMap["inline-template"])return;for(var e=0,n=t.children.length;e|^function(?:\s+[\w$]+)?\s*\(/,Vs=/\([^)]*?\);*$/,Ks=/^[A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*|\['[^']*?']|\["[^"]*?"]|\[\d+]|\[[A-Za-z_$][\w$]*])*$/,Js={esc:27,tab:9,enter:13,space:32,up:38,left:37,right:39,down:40,delete:[8,46]},qs={esc:["Esc","Escape"],tab:"Tab",enter:"Enter",space:[" ","Spacebar"],up:["Up","ArrowUp"],left:["Left","ArrowLeft"],right:["Right","ArrowRight"],down:["Down","ArrowDown"],delete:["Backspace","Delete","Del"]},Ws=function(t){return"if(".concat(t,")return null;")},Zs={stop:"$event.stopPropagation();",prevent:"$event.preventDefault();",self:Ws("$event.target !== $event.currentTarget"),ctrl:Ws("!$event.ctrlKey"),shift:Ws("!$event.shiftKey"),alt:Ws("!$event.altKey"),meta:Ws("!$event.metaKey"),left:Ws("'button' in $event && $event.button !== 0"),middle:Ws("'button' in $event && $event.button !== 1"),right:Ws("'button' in $event && $event.button !== 2")};function Gs(t,e){var n=e?"nativeOn:":"on:",r="",o="";for(var i in t){var a=Xs(t[i]);t[i]&&t[i].dynamic?o+="".concat(i,",").concat(a,","):r+='"'.concat(i,'":').concat(a,",")}return r="{".concat(r.slice(0,-1),"}"),o?n+"_d(".concat(r,",[").concat(o.slice(0,-1),"])"):n+r}function Xs(t){if(!t)return"function(){}";if(Array.isArray(t))return"[".concat(t.map((function(t){return Xs(t)})).join(","),"]");var e=Ks.test(t.value),n=zs.test(t.value),r=Ks.test(t.value.replace(Vs,""));if(t.modifiers){var o="",i="",a=[],s=function(e){if(Zs[e])i+=Zs[e],Js[e]&&a.push(e);else if("exact"===e){var n=t.modifiers;i+=Ws(["ctrl","shift","alt","meta"].filter((function(t){return!n[t]})).map((function(t){return"$event.".concat(t,"Key")})).join("||"))}else a.push(e)};for(var c in t.modifiers)s(c);a.length&&(o+=function(t){return"if(!$event.type.indexOf('key')&&"+"".concat(t.map(Ys).join("&&"),")return null;")}(a)),i&&(o+=i);var u=e?"return ".concat(t.value,".apply(null, arguments)"):n?"return (".concat(t.value,").apply(null, arguments)"):r?"return ".concat(t.value):t.value;return"function($event){".concat(o).concat(u,"}")}return e||n?t.value:"function($event){".concat(r?"return ".concat(t.value):t.value,"}")}function Ys(t){var e=parseInt(t,10);if(e)return"$event.keyCode!==".concat(e);var n=Js[t],r=qs[t];return"_k($event.keyCode,"+"".concat(JSON.stringify(t),",")+"".concat(JSON.stringify(n),",")+"$event.key,"+"".concat(JSON.stringify(r))+")"}var Qs={on:function(t,e){t.wrapListeners=function(t){return"_g(".concat(t,",").concat(e.value,")")}},bind:function(t,e){t.wrapData=function(n){return"_b(".concat(n,",'").concat(t.tag,"',").concat(e.value,",").concat(e.modifiers&&e.modifiers.prop?"true":"false").concat(e.modifiers&&e.modifiers.sync?",true":"",")")}},cloak:E},tc=function(t){this.options=t,this.warn=t.warn||Ho,this.transforms=Bo(t.modules,"transformCode"),this.dataGenFns=Bo(t.modules,"genData"),this.directives=A(A({},Qs),t.directives);var e=t.isReservedTag||N;this.maybeComponent=function(t){return!!t.component||!e(t.tag)},this.onceId=0,this.staticRenderFns=[],this.pre=!1};function ec(t,e){var n=new tc(e),r=t?"script"===t.tag?"null":nc(t,n):'_c("div")';return{render:"with(this){return ".concat(r,"}"),staticRenderFns:n.staticRenderFns}}function nc(t,e){if(t.parent&&(t.pre=t.pre||t.parent.pre),t.staticRoot&&!t.staticProcessed)return rc(t,e);if(t.once&&!t.onceProcessed)return oc(t,e);if(t.for&&!t.forProcessed)return sc(t,e);if(t.if&&!t.ifProcessed)return ic(t,e);if("template"!==t.tag||t.slotTarget||e.pre){if("slot"===t.tag)return function(t,e){var n=t.slotName||'"default"',r=fc(t,e),o="_t(".concat(n).concat(r?",function(){return ".concat(r,"}"):""),i=t.attrs||t.dynamicAttrs?vc((t.attrs||[]).concat(t.dynamicAttrs||[]).map((function(t){return{name:x(t.name),value:t.value,dynamic:t.dynamic}}))):null,a=t.attrsMap["v-bind"];!i&&!a||r||(o+=",null");i&&(o+=",".concat(i));a&&(o+="".concat(i?"":",null",",").concat(a));return o+")"}(t,e);var n=void 0;if(t.component)n=function(t,e,n){var r=e.inlineTemplate?null:fc(e,n,!0);return"_c(".concat(t,",").concat(cc(e,n)).concat(r?",".concat(r):"",")")}(t.component,t,e);else{var r=void 0,o=e.maybeComponent(t);(!t.plain||t.pre&&o)&&(r=cc(t,e));var i=void 0,a=e.options.bindings;o&&a&&!1!==a.__isScriptSetup&&(i=function(t,e){var n=x(e),r=C(n),o=function(o){return t[e]===o?e:t[n]===o?n:t[r]===o?r:void 0},i=o("setup-const")||o("setup-reactive-const");if(i)return i;var a=o("setup-let")||o("setup-ref")||o("setup-maybe-ref");if(a)return a}(a,t.tag)),i||(i="'".concat(t.tag,"'"));var s=t.inlineTemplate?null:fc(t,e,!0);n="_c(".concat(i).concat(r?",".concat(r):"").concat(s?",".concat(s):"",")")}for(var c=0;c>>0}(a)):"",")")}(t,t.scopedSlots,e),",")),t.model&&(n+="model:{value:".concat(t.model.value,",callback:").concat(t.model.callback,",expression:").concat(t.model.expression,"},")),t.inlineTemplate){var i=function(t,e){var n=t.children[0];if(n&&1===n.type){var r=ec(n,e.options);return"inlineTemplate:{render:function(){".concat(r.render,"},staticRenderFns:[").concat(r.staticRenderFns.map((function(t){return"function(){".concat(t,"}")})).join(","),"]}")}}(t,e);i&&(n+="".concat(i,","))}return n=n.replace(/,$/,"")+"}",t.dynamicAttrs&&(n="_b(".concat(n,',"').concat(t.tag,'",').concat(vc(t.dynamicAttrs),")")),t.wrapData&&(n=t.wrapData(n)),t.wrapListeners&&(n=t.wrapListeners(n)),n}function uc(t){return 1===t.type&&("slot"===t.tag||t.children.some(uc))}function lc(t,e){var n=t.attrsMap["slot-scope"];if(t.if&&!t.ifProcessed&&!n)return ic(t,e,lc,"null");if(t.for&&!t.forProcessed)return sc(t,e,lc);var r=t.slotScope===ws?"":String(t.slotScope),o="function(".concat(r,"){")+"return ".concat("template"===t.tag?t.if&&n?"(".concat(t.if,")?").concat(fc(t,e)||"undefined",":undefined"):fc(t,e)||"undefined":nc(t,e),"}"),i=r?"":",proxy:true";return"{key:".concat(t.slotTarget||'"default"',",fn:").concat(o).concat(i,"}")}function fc(t,e,n,r,o){var i=t.children;if(i.length){var a=i[0];if(1===i.length&&a.for&&"template"!==a.tag&&"slot"!==a.tag){var s=n?e.maybeComponent(a)?",1":",0":"";return"".concat((r||nc)(a,e)).concat(s)}var c=n?function(t,e){for(var n=0,r=0;r':'
      ',_c.innerHTML.indexOf(" ")>0}var xc=!!q&&wc(!1),Cc=!!q&&wc(!0),kc=$((function(t){var e=co(t);return e&&e.innerHTML})),Sc=Er.prototype.$mount;return Er.prototype.$mount=function(t,e){if((t=t&&co(t))===document.body||t===document.documentElement)return this;var n=this.$options;if(!n.render){var r=n.template;if(r)if("string"==typeof r)"#"===r.charAt(0)&&(r=kc(r));else{if(!r.nodeType)return this;r=r.innerHTML}else t&&(r=function(t){if(t.outerHTML)return t.outerHTML;var e=document.createElement("div");return e.appendChild(t.cloneNode(!0)),e.innerHTML}(t));if(r){var o=$c(r,{outputSourceRange:!1,shouldDecodeNewlines:xc,shouldDecodeNewlinesForHref:Cc,delimiters:n.delimiters,comments:n.comments},this),i=o.render,a=o.staticRenderFns;n.render=i,n.staticRenderFns=a}}return Sc.call(this,t,e)},Er.compile=$c,A(Er,Jn),Er.effect=function(t,e){var n=new Xn(ut,t,E,{sync:!0});e&&(n.update=function(){e((function(){return n.run()}))})},Er})); \ No newline at end of file diff --git a/kirby/panel/dist/js/vuedraggable.js b/kirby/panel/dist/js/vuedraggable.js new file mode 100644 index 0000000..2b85509 --- /dev/null +++ b/kirby/panel/dist/js/vuedraggable.js @@ -0,0 +1,7 @@ +/**! + * Sortable 1.10.2 + * @author RubaXa + * @author owenm + * @license MIT + */ +function t(e){return(t="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(e)}function e(t,e,n){return e in t?Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):t[e]=n,t}function n(){return n=Object.assign||function(t){for(var e=1;e=0||(i[n]=t[n]);return i}(t,e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(t);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(t,n)&&(i[n]=t[n])}return i}function r(t){if("undefined"!=typeof window&&window.navigator)return!!navigator.userAgent.match(t)}var a=r(/(?:Trident.*rv[ :]?11\.|msie|iemobile|Windows Phone)/i),l=r(/Edge/i),s=r(/firefox/i),c=r(/safari/i)&&!r(/chrome/i)&&!r(/android/i),d=r(/iP(ad|od|hone)/i),u=r(/chrome/i)&&r(/android/i),h={capture:!1,passive:!1};function f(t,e,n){t.addEventListener(e,n,!a&&h)}function p(t,e,n){t.removeEventListener(e,n,!a&&h)}function g(t,e){if(e){if(">"===e[0]&&(e=e.substring(1)),t)try{if(t.matches)return t.matches(e);if(t.msMatchesSelector)return t.msMatchesSelector(e);if(t.webkitMatchesSelector)return t.webkitMatchesSelector(e)}catch(n){return!1}return!1}}function m(t){return t.host&&t!==document&&t.host.nodeType?t.host:t.parentNode}function v(t,e,n,o){if(t){n=n||document;do{if(null!=e&&(">"===e[0]?t.parentNode===n&&g(t,e):g(t,e))||o&&t===n)return t;if(t===n)break}while(t=m(t))}return null}var b,y=/\s+/g;function w(t,e,n){if(t&&e)if(t.classList)t.classList[n?"add":"remove"](e);else{var o=(" "+t.className+" ").replace(y," ").replace(" "+e+" "," ");t.className=(o+(n?" "+e:"")).replace(y," ")}}function E(t,e,n){var o=t&&t.style;if(o){if(void 0===n)return document.defaultView&&document.defaultView.getComputedStyle?n=document.defaultView.getComputedStyle(t,""):t.currentStyle&&(n=t.currentStyle),void 0===e?n:n[e];e in o||-1!==e.indexOf("webkit")||(e="-webkit-"+e),o[e]=n+("string"==typeof n?"":"px")}}function D(t,e){var n="";if("string"==typeof t)n=t;else do{var o=E(t,"transform");o&&"none"!==o&&(n=o+" "+n)}while(!e&&(t=t.parentNode));var i=window.DOMMatrix||window.WebKitCSSMatrix||window.CSSMatrix||window.MSCSSMatrix;return i&&new i(n)}function _(t,e,n){if(t){var o=t.getElementsByTagName(e),i=0,r=o.length;if(n)for(;i=r:i<=r))return o;if(o===S())break;o=N(o,!1)}return!1}function T(t,e,n){for(var o=0,i=0,r=t.children;i2&&void 0!==arguments[2]?arguments[2]:{},r=n.evt,a=i(n,["evt"]);$.pluginEvent.bind(At)(t,e,o({dragEl:H,parentEl:W,ghostEl:V,rootEl:U,nextEl:z,lastDownEl:G,cloneEl:q,cloneHidden:J,dragStarted:ct,putSortable:nt,activeSortable:At.active,originalEvent:r,oldIndex:Z,oldDraggableIndex:Q,newIndex:K,newDraggableIndex:tt,hideGhostForTarget:It,unhideGhostForTarget:Mt,cloneNowHidden:function(){J=!0},cloneNowShown:function(){J=!1},dispatchSortableEvent:function(t){j({sortable:e,name:t,originalEvent:r})}},a))};function j(t){!function(t){var e=t.sortable,n=t.rootEl,i=t.name,r=t.targetEl,s=t.cloneEl,c=t.toEl,d=t.fromEl,u=t.oldIndex,h=t.newIndex,f=t.oldDraggableIndex,p=t.newDraggableIndex,g=t.originalEvent,m=t.putSortable,v=t.extraEventProperties;if(e=e||n&&n[R]){var b,y=e.options,w="on"+i.charAt(0).toUpperCase()+i.substr(1);!window.CustomEvent||a||l?(b=document.createEvent("Event")).initEvent(i,!0,!0):b=new CustomEvent(i,{bubbles:!0,cancelable:!0}),b.to=c||n,b.from=d||n,b.item=r||n,b.clone=s,b.oldIndex=u,b.newIndex=h,b.oldDraggableIndex=f,b.newDraggableIndex=p,b.originalEvent=g,b.pullMode=m?m.lastPutMode:void 0;var E=o({},v,$.getEventProperties(i,e));for(var D in E)b[D]=E[D];n&&n.dispatchEvent(b),y[w]&&y[w].call(e,b)}}(o({putSortable:nt,cloneEl:q,targetEl:H,rootEl:U,oldIndex:Z,oldDraggableIndex:Q,newIndex:K,newDraggableIndex:tt},t))}var H,W,V,U,z,G,q,J,Z,K,Q,tt,et,nt,ot,it,rt,at,lt,st,ct,dt,ut,ht,ft,pt=!1,gt=!1,mt=[],vt=!1,bt=!1,yt=[],wt=!1,Et=[],Dt="undefined"!=typeof document,_t=d,St=l||a?"cssFloat":"float",Ct=Dt&&!u&&!d&&"draggable"in document.createElement("div"),xt=function(){if(Dt){if(a)return!1;var t=document.createElement("x");return t.style.cssText="pointer-events:auto","auto"===t.style.pointerEvents}}(),Tt=function(t,e){var n=E(t),o=parseInt(n.width)-parseInt(n.paddingLeft)-parseInt(n.paddingRight)-parseInt(n.borderLeftWidth)-parseInt(n.borderRightWidth),i=T(t,0,e),r=T(t,1,e),a=i&&E(i),l=r&&E(r),s=a&&parseInt(a.marginLeft)+parseInt(a.marginRight)+C(i).width,c=l&&parseInt(l.marginLeft)+parseInt(l.marginRight)+C(r).width;if("flex"===n.display)return"column"===n.flexDirection||"column-reverse"===n.flexDirection?"vertical":"horizontal";if("grid"===n.display)return n.gridTemplateColumns.split(" ").length<=1?"vertical":"horizontal";if(i&&a.float&&"none"!==a.float){var d="left"===a.float?"left":"right";return!r||"both"!==l.clear&&l.clear!==d?"horizontal":"vertical"}return i&&("block"===a.display||"flex"===a.display||"table"===a.display||"grid"===a.display||s>=o&&"none"===n[St]||r&&"none"===n[St]&&s+c>o)?"vertical":"horizontal"},Ot=function(e){function n(t,e){return function(o,i,r,a){var l=o.options.group.name&&i.options.group.name&&o.options.group.name===i.options.group.name;if(null==t&&(e||l))return!0;if(null==t||!1===t)return!1;if(e&&"clone"===t)return t;if("function"==typeof t)return n(t(o,i,r,a),e)(o,i,r,a);var s=(e?o:i).options.group.name;return!0===t||"string"==typeof t&&t===s||t.join&&t.indexOf(s)>-1}}var o={},i=e.group;i&&"object"==t(i)||(i={name:i}),o.name=i.name,o.checkPull=n(i.pull,!0),o.checkPut=n(i.put),o.revertClone=i.revertClone,e.group=o},It=function(){!xt&&V&&E(V,"display","none")},Mt=function(){!xt&&V&&E(V,"display","")};Dt&&document.addEventListener("click",(function(t){if(gt)return t.preventDefault(),t.stopPropagation&&t.stopPropagation(),t.stopImmediatePropagation&&t.stopImmediatePropagation(),gt=!1,!1}),!0);var Nt=function(t){if(H){t=t.touches?t.touches[0]:t;var e=(i=t.clientX,r=t.clientY,mt.some((function(t){if(!O(t)){var e=C(t),n=t[R].options.emptyInsertThreshold,o=i>=e.left-n&&i<=e.right+n,l=r>=e.top-n&&r<=e.bottom+n;return n&&o&&l?a=t:void 0}})),a);if(e){var n={};for(var o in t)t.hasOwnProperty(o)&&(n[o]=t[o]);n.target=n.rootEl=e,n.preventDefault=void 0,n.stopPropagation=void 0,e[R]._onDragOver(n)}}var i,r,a},Pt=function(t){H&&H.parentNode[R]._isOutsideThisEl(t.target)};function At(t,e){if(!t||!t.nodeType||1!==t.nodeType)throw"Sortable: `el` must be an HTMLElement, not ".concat({}.toString.call(t));this.el=t,this.options=e=n({},e),t[R]=this;var o={group:null,sort:!0,disabled:!1,store:null,handle:null,draggable:/^[uo]l$/i.test(t.nodeName)?">li":">*",swapThreshold:1,invertSwap:!1,invertedSwapThreshold:null,removeCloneOnHide:!0,direction:function(){return Tt(t,this.options)},ghostClass:"sortable-ghost",chosenClass:"sortable-chosen",dragClass:"sortable-drag",ignore:"a, img",filter:null,preventOnFilter:!0,animation:0,easing:null,setData:function(t,e){t.setData("Text",e.textContent)},dropBubble:!1,dragoverBubble:!1,dataIdAttr:"data-id",delay:0,delayOnTouchOnly:!1,touchStartThreshold:(Number.parseInt?Number:window).parseInt(window.devicePixelRatio,10)||1,forceFallback:!1,fallbackClass:"sortable-fallback",fallbackOnBody:!1,fallbackTolerance:0,fallbackOffset:{x:0,y:0},supportPointer:!1!==At.supportPointer&&"PointerEvent"in window,emptyInsertThreshold:5};for(var i in $.initializePlugins(this,t,o),o)!(i in e)&&(e[i]=o[i]);for(var r in Ot(e),this)"_"===r.charAt(0)&&"function"==typeof this[r]&&(this[r]=this[r].bind(this));this.nativeDraggable=!e.forceFallback&&Ct,this.nativeDraggable&&(this.options.touchStartThreshold=1),e.supportPointer?f(t,"pointerdown",this._onTapStart):(f(t,"mousedown",this._onTapStart),f(t,"touchstart",this._onTapStart)),this.nativeDraggable&&(f(t,"dragover",this),f(t,"dragenter",this)),mt.push(this.el),e.store&&e.store.get&&this.sort(e.store.get(this)||[]),n(this,X())}function kt(t,e,n,o,i,r,s,c){var d,u,h=t[R],f=h.options.onMove;return!window.CustomEvent||a||l?(d=document.createEvent("Event")).initEvent("move",!0,!0):d=new CustomEvent("move",{bubbles:!0,cancelable:!0}),d.to=e,d.from=t,d.dragged=n,d.draggedRect=o,d.related=i||e,d.relatedRect=r||C(e),d.willInsertAfter=c,d.originalEvent=s,t.dispatchEvent(d),f&&(u=f.call(h,d,s)),u}function Ft(t){t.draggable=!1}function Rt(){wt=!1}function Xt(t){for(var e=t.tagName+t.className+t.src+t.href+t.textContent,n=e.length,o=0;n--;)o+=e.charCodeAt(n);return o.toString(36)}function Lt(t){return setTimeout(t,0)}function Yt(t){return clearTimeout(t)}At.prototype={constructor:At,_isOutsideThisEl:function(t){this.el.contains(t)||t===this.el||(dt=null)},_getDirection:function(t,e){return"function"==typeof this.options.direction?this.options.direction.call(this,t,e,H):this.options.direction},_onTapStart:function(t){if(t.cancelable){var e=this,n=this.el,o=this.options,i=o.preventOnFilter,r=t.type,a=t.touches&&t.touches[0]||t.pointerType&&"touch"===t.pointerType&&t,l=(a||t).target,s=t.target.shadowRoot&&(t.path&&t.path[0]||t.composedPath&&t.composedPath()[0])||l,c=o.filter;if(function(t){Et.length=0;var e=t.getElementsByTagName("input"),n=e.length;for(;n--;){var o=e[n];o.checked&&Et.push(o)}}(n),!H&&!(/mousedown|pointerdown/.test(r)&&0!==t.button||o.disabled||s.isContentEditable||(l=v(l,o.draggable,n,!1))&&l.animated||G===l)){if(Z=I(l),Q=I(l,o.draggable),"function"==typeof c){if(c.call(this,t,l,this))return j({sortable:e,rootEl:s,name:"filter",targetEl:l,toEl:n,fromEl:n}),B("filter",e,{evt:t}),void(i&&t.cancelable&&t.preventDefault())}else if(c&&(c=c.split(",").some((function(o){if(o=v(s,o.trim(),n,!1))return j({sortable:e,rootEl:o,name:"filter",targetEl:l,fromEl:n,toEl:n}),B("filter",e,{evt:t}),!0}))))return void(i&&t.cancelable&&t.preventDefault());o.handle&&!v(s,o.handle,n,!1)||this._prepareDragStart(t,a,l)}}},_prepareDragStart:function(t,e,n){var o,i=this,r=i.el,c=i.options,d=r.ownerDocument;if(n&&!H&&n.parentNode===r){var u=C(n);if(U=r,W=(H=n).parentNode,z=H.nextSibling,G=n,et=c.group,At.dragged=H,ot={target:H,clientX:(e||t).clientX,clientY:(e||t).clientY},lt=ot.clientX-u.left,st=ot.clientY-u.top,this._lastX=(e||t).clientX,this._lastY=(e||t).clientY,H.style["will-change"]="all",o=function(){B("delayEnded",i,{evt:t}),At.eventCanceled?i._onDrop():(i._disableDelayedDragEvents(),!s&&i.nativeDraggable&&(H.draggable=!0),i._triggerDragStart(t,e),j({sortable:i,name:"choose",originalEvent:t}),w(H,c.chosenClass,!0))},c.ignore.split(",").forEach((function(t){_(H,t.trim(),Ft)})),f(d,"dragover",Nt),f(d,"mousemove",Nt),f(d,"touchmove",Nt),f(d,"mouseup",i._onDrop),f(d,"touchend",i._onDrop),f(d,"touchcancel",i._onDrop),s&&this.nativeDraggable&&(this.options.touchStartThreshold=4,H.draggable=!0),B("delayStart",this,{evt:t}),!c.delay||c.delayOnTouchOnly&&!e||this.nativeDraggable&&(l||a))o();else{if(At.eventCanceled)return void this._onDrop();f(d,"mouseup",i._disableDelayedDrag),f(d,"touchend",i._disableDelayedDrag),f(d,"touchcancel",i._disableDelayedDrag),f(d,"mousemove",i._delayedDragTouchMoveHandler),f(d,"touchmove",i._delayedDragTouchMoveHandler),c.supportPointer&&f(d,"pointermove",i._delayedDragTouchMoveHandler),i._dragStartTimer=setTimeout(o,c.delay)}}},_delayedDragTouchMoveHandler:function(t){var e=t.touches?t.touches[0]:t;Math.max(Math.abs(e.clientX-this._lastX),Math.abs(e.clientY-this._lastY))>=Math.floor(this.options.touchStartThreshold/(this.nativeDraggable&&window.devicePixelRatio||1))&&this._disableDelayedDrag()},_disableDelayedDrag:function(){H&&Ft(H),clearTimeout(this._dragStartTimer),this._disableDelayedDragEvents()},_disableDelayedDragEvents:function(){var t=this.el.ownerDocument;p(t,"mouseup",this._disableDelayedDrag),p(t,"touchend",this._disableDelayedDrag),p(t,"touchcancel",this._disableDelayedDrag),p(t,"mousemove",this._delayedDragTouchMoveHandler),p(t,"touchmove",this._delayedDragTouchMoveHandler),p(t,"pointermove",this._delayedDragTouchMoveHandler)},_triggerDragStart:function(t,e){e=e||"touch"==t.pointerType&&t,!this.nativeDraggable||e?this.options.supportPointer?f(document,"pointermove",this._onTouchMove):f(document,e?"touchmove":"mousemove",this._onTouchMove):(f(H,"dragend",this),f(U,"dragstart",this._onDragStart));try{document.selection?Lt((function(){document.selection.empty()})):window.getSelection().removeAllRanges()}catch(n){}},_dragStarted:function(t,e){if(pt=!1,U&&H){B("dragStarted",this,{evt:e}),this.nativeDraggable&&f(document,"dragover",Pt);var n=this.options;!t&&w(H,n.dragClass,!1),w(H,n.ghostClass,!0),At.active=this,t&&this._appendGhost(),j({sortable:this,name:"start",originalEvent:e})}else this._nulling()},_emulateDragOver:function(){if(it){this._lastX=it.clientX,this._lastY=it.clientY,It();for(var t=document.elementFromPoint(it.clientX,it.clientY),e=t;t&&t.shadowRoot&&(t=t.shadowRoot.elementFromPoint(it.clientX,it.clientY))!==e;)e=t;if(H.parentNode[R]._isOutsideThisEl(t),e)do{if(e[R]){if(e[R]._onDragOver({clientX:it.clientX,clientY:it.clientY,target:t,rootEl:e})&&!this.options.dragoverBubble)break}t=e}while(e=e.parentNode);Mt()}},_onTouchMove:function(t){if(ot){var e=this.options,n=e.fallbackTolerance,o=e.fallbackOffset,i=t.touches?t.touches[0]:t,r=V&&D(V,!0),a=V&&r&&r.a,l=V&&r&&r.d,s=_t&&ft&&M(ft),c=(i.clientX-ot.clientX+o.x)/(a||1)+(s?s[0]-yt[0]:0)/(a||1),d=(i.clientY-ot.clientY+o.y)/(l||1)+(s?s[1]-yt[1]:0)/(l||1);if(!At.active&&!pt){if(n&&Math.max(Math.abs(i.clientX-this._lastX),Math.abs(i.clientY-this._lastY))o.right+i||t.clientX<=o.right&&t.clientY>o.bottom&&t.clientX>=o.left:t.clientX>o.right&&t.clientY>o.top||t.clientX<=o.right&&t.clientY>o.bottom+i}(t,r,this)&&!m.animated){if(m===H)return $(!1);if(m&&a===t.target&&(l=m),l&&(n=C(l)),!1!==kt(U,a,H,e,l,n,t,!!l))return Y(),a.appendChild(H),W=a,G(),$(!0)}else if(l.parentNode===a){n=C(l);var b,y,D,_=H.parentNode!==a,S=!function(t,e,n){var o=n?t.left:t.top,i=n?t.right:t.bottom,r=n?t.width:t.height,a=n?e.left:e.top,l=n?e.right:e.bottom,s=n?e.width:e.height;return o===a||i===l||o+r/2===a+s/2}(H.animated&&H.toRect||e,l.animated&&l.toRect||n,r),T=r?"top":"left",M=x(l,"top","top")||x(H,"top","top"),N=M?M.scrollTop:void 0;if(dt!==l&&(y=n[T],vt=!1,bt=!S&&s.invertSwap||_),b=function(t,e,n,o,i,r,a,l){var s=o?t.clientY:t.clientX,c=o?n.height:n.width,d=o?n.top:n.left,u=o?n.bottom:n.right,h=!1;if(!a)if(l&&htd+c*r/2:su-ht)return-ut}else if(s>d+c*(1-i)/2&&su-c*r/2))return s>d+c/2?1:-1;return 0}(t,l,n,r,S?1:s.swapThreshold,null==s.invertedSwapThreshold?s.swapThreshold:s.invertedSwapThreshold,bt,dt===l),0!==b){var P=I(H);do{P-=b,D=W.children[P]}while(D&&("none"===E(D,"display")||D===V))}if(0===b||D===l)return $(!1);dt=l,ut=b;var A=l.nextElementSibling,F=!1,X=kt(U,a,H,e,l,n,t,F=1===b);if(!1!==X)return 1!==X&&-1!==X||(F=1===X),wt=!0,setTimeout(Rt,30),Y(),F&&!A?a.appendChild(H):l.parentNode.insertBefore(H,F?A:l),M&&k(M,0,N-M.scrollTop),W=H.parentNode,void 0===y||bt||(ht=Math.abs(y-C(l)[T])),G(),$(!0)}if(a.contains(H))return $(!1)}return!1}function L(s,c){B(s,p,o({evt:t,isOwner:u,axis:r?"vertical":"horizontal",revert:i,dragRect:e,targetRect:n,canSort:h,fromSortable:f,target:l,completed:$,onMove:function(n,o){return kt(U,a,H,e,n,C(n),t,o)},changed:G},c))}function Y(){L("dragOverAnimationCapture"),p.captureAnimationState(),p!==f&&f.captureAnimationState()}function $(e){return L("dragOverCompleted",{insertion:e}),e&&(u?d._hideClone():d._showClone(p),p!==f&&(w(H,nt?nt.options.ghostClass:d.options.ghostClass,!1),w(H,s.ghostClass,!0)),nt!==p&&p!==At.active?nt=p:p===At.active&&nt&&(nt=null),f===p&&(p._ignoreWhileAnimating=l),p.animateAll((function(){L("dragOverAnimationComplete"),p._ignoreWhileAnimating=null})),p!==f&&(f.animateAll(),f._ignoreWhileAnimating=null)),(l===H&&!H.animated||l===a&&!l.animated)&&(dt=null),s.dragoverBubble||t.rootEl||l===document||(H.parentNode[R]._isOutsideThisEl(t.target),!e&&Nt(t)),!s.dragoverBubble&&t.stopPropagation&&t.stopPropagation(),g=!0}function G(){K=I(H),tt=I(H,s.draggable),j({sortable:p,name:"change",toEl:a,newIndex:K,newDraggableIndex:tt,originalEvent:t})}},_ignoreWhileAnimating:null,_offMoveEvents:function(){p(document,"mousemove",this._onTouchMove),p(document,"touchmove",this._onTouchMove),p(document,"pointermove",this._onTouchMove),p(document,"dragover",Nt),p(document,"mousemove",Nt),p(document,"touchmove",Nt)},_offUpEvents:function(){var t=this.el.ownerDocument;p(t,"mouseup",this._onDrop),p(t,"touchend",this._onDrop),p(t,"pointerup",this._onDrop),p(t,"touchcancel",this._onDrop),p(document,"selectstart",this)},_onDrop:function(t){var e=this.el,n=this.options;K=I(H),tt=I(H,n.draggable),B("drop",this,{evt:t}),W=H&&H.parentNode,K=I(H),tt=I(H,n.draggable),At.eventCanceled||(pt=!1,bt=!1,vt=!1,clearInterval(this._loopId),clearTimeout(this._dragStartTimer),Yt(this.cloneId),Yt(this._dragStartId),this.nativeDraggable&&(p(document,"drop",this),p(e,"dragstart",this._onDragStart)),this._offMoveEvents(),this._offUpEvents(),c&&E(document.body,"user-select",""),E(H,"transform",""),t&&(ct&&(t.cancelable&&t.preventDefault(),!n.dropBubble&&t.stopPropagation()),V&&V.parentNode&&V.parentNode.removeChild(V),(U===W||nt&&"clone"!==nt.lastPutMode)&&q&&q.parentNode&&q.parentNode.removeChild(q),H&&(this.nativeDraggable&&p(H,"dragend",this),Ft(H),H.style["will-change"]="",ct&&!pt&&w(H,nt?nt.options.ghostClass:this.options.ghostClass,!1),w(H,this.options.chosenClass,!1),j({sortable:this,name:"unchoose",toEl:W,newIndex:null,newDraggableIndex:null,originalEvent:t}),U!==W?(K>=0&&(j({rootEl:W,name:"add",toEl:W,fromEl:U,originalEvent:t}),j({sortable:this,name:"remove",toEl:W,originalEvent:t}),j({rootEl:W,name:"sort",toEl:W,fromEl:U,originalEvent:t}),j({sortable:this,name:"sort",toEl:W,originalEvent:t})),nt&&nt.save()):K!==Z&&K>=0&&(j({sortable:this,name:"update",toEl:W,originalEvent:t}),j({sortable:this,name:"sort",toEl:W,originalEvent:t})),At.active&&(null!=K&&-1!==K||(K=Z,tt=Q),j({sortable:this,name:"end",toEl:W,originalEvent:t}),this.save())))),this._nulling()},_nulling:function(){B("nulling",this),U=H=W=V=z=q=G=J=ot=it=ct=K=tt=Z=Q=dt=ut=nt=et=At.dragged=At.ghost=At.clone=At.active=null,Et.forEach((function(t){t.checked=!0})),Et.length=rt=at=0},handleEvent:function(t){switch(t.type){case"drop":case"dragend":this._onDrop(t);break;case"dragenter":case"dragover":H&&(this._onDragOver(t),function(t){t.dataTransfer&&(t.dataTransfer.dropEffect="move");t.cancelable&&t.preventDefault()}(t));break;case"selectstart":t.preventDefault()}},toArray:function(){for(var t,e=[],n=this.el.children,o=0,i=n.length,r=this.options;ot.replace(ee,((t,e)=>e?e.toUpperCase():""))));function oe(t){null!==t.parentElement&&t.parentElement.removeChild(t)}function ie(t,e,n){const o=0===n?t.children[0]:t.children[n-1].nextSibling;t.insertBefore(e,o)}function re(t,e){this.$nextTick((()=>this.$emit(t.toLowerCase(),e)))}function ae(t){return e=>{null!==this.realList&&this["onDrag"+t](e),re.call(this,t,e)}}function le(t){return["transition-group","TransitionGroup"].includes(t)}function se(t,e,n){return t[n]||(e[n]?e[n]():void 0)}const ce=["Start","Add","Remove","Update","End"],de=["Choose","Unchoose","Sort","Filter","Clone"],ue=["Move",...ce,...de].map((t=>"on"+t));var he=null;const fe={name:"draggable",inheritAttrs:!1,props:{options:Object,list:{type:Array,required:!1,default:null},value:{type:Array,required:!1,default:null},noTransitionOnDrag:{type:Boolean,default:!1},clone:{type:Function,default:t=>t},element:{type:String,default:"div"},tag:{type:String,default:null},move:{type:Function,default:null},componentData:{type:Object,required:!1,default:null}},data:()=>({transitionMode:!1,noneFunctionalComponentMode:!1}),render(t){const e=this.$slots.default;this.transitionMode=function(t){if(!t||1!==t.length)return!1;const[{componentOptions:e}]=t;return!!e&&le(e.tag)}(e);const{children:n,headerOffset:o,footerOffset:i}=function(t,e,n){let o=0,i=0;const r=se(e,n,"header");r&&(o=r.length,t=t?[...r,...t]:[...r]);const a=se(e,n,"footer");return a&&(i=a.length,t=t?[...t,...a]:[...a]),{children:t,headerOffset:o,footerOffset:i}}(e,this.$slots,this.$scopedSlots);this.headerOffset=o,this.footerOffset=i;const r=function(t,e){let n=null;const o=(t,e)=>{n=function(t,e,n){return void 0===n||((t=t||{})[e]=n),t}(n,t,e)};if(o("attrs",Object.keys(t).filter((t=>"id"===t||t.startsWith("data-"))).reduce(((e,n)=>(e[n]=t[n],e)),{})),!e)return n;const{on:i,props:r,attrs:a}=e;return o("on",i),o("props",r),Object.assign(n.attrs,a),n}(this.$attrs,this.componentData);return t(this.getTag(),r,n)},created(){null!==this.list&&null!==this.value&&te.error("Value and list props are mutually exclusive! Please set one or another."),"div"!==this.element&&te.warn("Element props is deprecated please use tag props instead. See https://github.com/SortableJS/Vue.Draggable/blob/master/documentation/migrate.md#element-props"),void 0!==this.options&&te.warn("Options props is deprecated, add sortable options directly as vue.draggable item, or use v-bind. See https://github.com/SortableJS/Vue.Draggable/blob/master/documentation/migrate.md#options-props")},mounted(){if(this.noneFunctionalComponentMode=this.getTag().toLowerCase()!==this.$el.nodeName.toLowerCase()&&!this.getIsFunctional(),this.noneFunctionalComponentMode&&this.transitionMode)throw new Error(`Transition-group inside component is not supported. Please alter tag value or remove transition-group. Current tag value: ${this.getTag()}`);const t={};ce.forEach((e=>{t["on"+e]=ae.call(this,e)})),de.forEach((e=>{t["on"+e]=re.bind(this,e)}));const e=Object.keys(this.$attrs).reduce(((t,e)=>(t[ne(e)]=this.$attrs[e],t)),{}),n=Object.assign({},this.options,e,t,{onMove:(t,e)=>this.onDragMove(t,e)});!("draggable"in n)&&(n.draggable=">*"),this._sortable=new At(this.rootContainer,n),this.computeIndexes()},beforeDestroy(){void 0!==this._sortable&&this._sortable.destroy()},computed:{rootContainer(){return this.transitionMode?this.$el.children[0]:this.$el},realList(){return this.list?this.list:this.value}},watch:{options:{handler(t){this.updateOptions(t)},deep:!0},$attrs:{handler(t){this.updateOptions(t)},deep:!0},realList(){this.computeIndexes()}},methods:{getIsFunctional(){const{fnOptions:t}=this._vnode;return t&&t.functional},getTag(){return this.tag||this.element},updateOptions(t){for(var e in t){const n=ne(e);-1===ue.indexOf(n)&&this._sortable.option(n,t[e])}},getChildrenNodes(){if(this.noneFunctionalComponentMode)return this.$children[0].$slots.default;const t=this.$slots.default;return this.transitionMode?t[0].child.$slots.default:t},computeIndexes(){this.$nextTick((()=>{this.visibleIndexes=function(t,e,n,o){if(!t)return[];const i=t.map((t=>t.elm)),r=e.length-o,a=[...e].map(((t,e)=>e>=r?i.length:i.indexOf(t)));return n?a.filter((t=>-1!==t)):a}(this.getChildrenNodes(),this.rootContainer.children,this.transitionMode,this.footerOffset)}))},getUnderlyingVm(t){const e=function(t,e){return t.map((t=>t.elm)).indexOf(e)}(this.getChildrenNodes()||[],t);if(-1===e)return null;return{index:e,element:this.realList[e]}},getUnderlyingPotencialDraggableComponent:({__vue__:t})=>t&&t.$options&&le(t.$options._componentTag)?t.$parent:!("realList"in t)&&1===t.$children.length&&"realList"in t.$children[0]?t.$children[0]:t,emitChanges(t){this.$nextTick((()=>{this.$emit("change",t)}))},alterList(t){if(this.list)return void t(this.list);const e=[...this.value];t(e),this.$emit("input",e)},spliceList(){this.alterList((t=>t.splice(...arguments)))},updatePosition(t,e){this.alterList((n=>n.splice(e,0,n.splice(t,1)[0])))},getRelatedContextFromMoveEvent({to:t,related:e}){const n=this.getUnderlyingPotencialDraggableComponent(t);if(!n)return{component:n};const o=n.realList,i={list:o,component:n};if(t!==e&&o&&n.getUnderlyingVm){const t=n.getUnderlyingVm(e);if(t)return Object.assign(t,i)}return i},getVmIndex(t){const e=this.visibleIndexes,n=e.length;return t>n-1?n:e[t]},getComponent(){return this.$slots.default[0].componentInstance},resetTransitionData(t){if(!this.noTransitionOnDrag||!this.transitionMode)return;this.getChildrenNodes()[t].data=null;const e=this.getComponent();e.children=[],e.kept=void 0},onDragStart(t){this.context=this.getUnderlyingVm(t.item),t.item._underlying_vm_=this.clone(this.context.element),he=t.item},onDragAdd(t){const e=t.item._underlying_vm_;if(void 0===e)return;oe(t.item);const n=this.getVmIndex(t.newIndex);this.spliceList(n,0,e),this.computeIndexes();const o={element:e,newIndex:n};this.emitChanges({added:o})},onDragRemove(t){if(ie(this.rootContainer,t.item,t.oldIndex),"clone"===t.pullMode)return void oe(t.clone);const e=this.context.index;this.spliceList(e,1);const n={element:this.context.element,oldIndex:e};this.resetTransitionData(e),this.emitChanges({removed:n})},onDragUpdate(t){oe(t.item),ie(t.from,t.item,t.oldIndex);const e=this.context.index,n=this.getVmIndex(t.newIndex);this.updatePosition(e,n);const o={element:this.context.element,oldIndex:e,newIndex:n};this.emitChanges({moved:o})},updateProperty(t,e){t.hasOwnProperty(e)&&(t[e]+=this.headerOffset)},computeFutureIndex(t,e){if(!t.element)return 0;const n=[...e.to.children].filter((t=>"none"!==t.style.display)),o=n.indexOf(e.related),i=t.component.getVmIndex(o);return-1!==n.indexOf(he)||!e.willInsertAfter?i:i+1},onDragMove(t,e){const n=this.move;if(!n||!this.realList)return!0;const o=this.getRelatedContextFromMoveEvent(t),i=this.context,r=this.computeFutureIndex(o,t);Object.assign(i,{futureIndex:r});return n(Object.assign({},t,{relatedContext:o,draggedContext:i}),e)},onDragEnd(){this.computeIndexes(),he=null}}};"undefined"!=typeof window&&"Vue"in window&&window.Vue.component("draggable",fe);export{fe as default}; diff --git a/kirby/panel/dist/js/vuedraggable.min.js b/kirby/panel/dist/js/vuedraggable.min.js deleted file mode 100644 index 05b004f..0000000 --- a/kirby/panel/dist/js/vuedraggable.min.js +++ /dev/null @@ -1,7 +0,0 @@ -/**! - * Sortable 1.10.2 - * @author RubaXa - * @author owenm - * @license MIT - */ -function t(e){return(t="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(e)}function e(t,e,n){return e in t?Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):t[e]=n,t}function n(){return n=Object.assign||function(t){for(var e=1;e=0||(i[n]=t[n]);return i}(t,e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(t);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(t,n)&&(i[n]=t[n])}return i}function r(t){if("undefined"!=typeof window&&window.navigator)return!!navigator.userAgent.match(t)}var a=r(/(?:Trident.*rv[ :]?11\.|msie|iemobile|Windows Phone)/i),l=r(/Edge/i),s=r(/firefox/i),c=r(/safari/i)&&!r(/chrome/i)&&!r(/android/i),d=r(/iP(ad|od|hone)/i),u=r(/chrome/i)&&r(/android/i),h={capture:!1,passive:!1};function f(t,e,n){t.addEventListener(e,n,!a&&h)}function p(t,e,n){t.removeEventListener(e,n,!a&&h)}function g(t,e){if(e){if(">"===e[0]&&(e=e.substring(1)),t)try{if(t.matches)return t.matches(e);if(t.msMatchesSelector)return t.msMatchesSelector(e);if(t.webkitMatchesSelector)return t.webkitMatchesSelector(e)}catch(n){return!1}return!1}}function m(t){return t.host&&t!==document&&t.host.nodeType?t.host:t.parentNode}function v(t,e,n,o){if(t){n=n||document;do{if(null!=e&&(">"===e[0]?t.parentNode===n&&g(t,e):g(t,e))||o&&t===n)return t;if(t===n)break}while(t=m(t))}return null}var b,y=/\s+/g;function w(t,e,n){if(t&&e)if(t.classList)t.classList[n?"add":"remove"](e);else{var o=(" "+t.className+" ").replace(y," ").replace(" "+e+" "," ");t.className=(o+(n?" "+e:"")).replace(y," ")}}function E(t,e,n){var o=t&&t.style;if(o){if(void 0===n)return document.defaultView&&document.defaultView.getComputedStyle?n=document.defaultView.getComputedStyle(t,""):t.currentStyle&&(n=t.currentStyle),void 0===e?n:n[e];e in o||-1!==e.indexOf("webkit")||(e="-webkit-"+e),o[e]=n+("string"==typeof n?"":"px")}}function D(t,e){var n="";if("string"==typeof t)n=t;else do{var o=E(t,"transform");o&&"none"!==o&&(n=o+" "+n)}while(!e&&(t=t.parentNode));var i=window.DOMMatrix||window.WebKitCSSMatrix||window.CSSMatrix||window.MSCSSMatrix;return i&&new i(n)}function _(t,e,n){if(t){var o=t.getElementsByTagName(e),i=0,r=o.length;if(n)for(;i=r:i<=r))return o;if(o===S())break;o=N(o,!1)}return!1}function T(t,e,n){for(var o=0,i=0,r=t.children;i2&&void 0!==arguments[2]?arguments[2]:{},r=n.evt,a=i(n,["evt"]);$.pluginEvent.bind(At)(t,e,o({dragEl:H,parentEl:W,ghostEl:V,rootEl:U,nextEl:z,lastDownEl:G,cloneEl:q,cloneHidden:J,dragStarted:ct,putSortable:nt,activeSortable:At.active,originalEvent:r,oldIndex:Z,oldDraggableIndex:Q,newIndex:K,newDraggableIndex:tt,hideGhostForTarget:It,unhideGhostForTarget:Mt,cloneNowHidden:function(){J=!0},cloneNowShown:function(){J=!1},dispatchSortableEvent:function(t){j({sortable:e,name:t,originalEvent:r})}},a))};function j(t){!function(t){var e=t.sortable,n=t.rootEl,i=t.name,r=t.targetEl,s=t.cloneEl,c=t.toEl,d=t.fromEl,u=t.oldIndex,h=t.newIndex,f=t.oldDraggableIndex,p=t.newDraggableIndex,g=t.originalEvent,m=t.putSortable,v=t.extraEventProperties;if(e=e||n&&n[R]){var b,y=e.options,w="on"+i.charAt(0).toUpperCase()+i.substr(1);!window.CustomEvent||a||l?(b=document.createEvent("Event")).initEvent(i,!0,!0):b=new CustomEvent(i,{bubbles:!0,cancelable:!0}),b.to=c||n,b.from=d||n,b.item=r||n,b.clone=s,b.oldIndex=u,b.newIndex=h,b.oldDraggableIndex=f,b.newDraggableIndex=p,b.originalEvent=g,b.pullMode=m?m.lastPutMode:void 0;var E=o({},v,$.getEventProperties(i,e));for(var D in E)b[D]=E[D];n&&n.dispatchEvent(b),y[w]&&y[w].call(e,b)}}(o({putSortable:nt,cloneEl:q,targetEl:H,rootEl:U,oldIndex:Z,oldDraggableIndex:Q,newIndex:K,newDraggableIndex:tt},t))}var H,W,V,U,z,G,q,J,Z,K,Q,tt,et,nt,ot,it,rt,at,lt,st,ct,dt,ut,ht,ft,pt=!1,gt=!1,mt=[],vt=!1,bt=!1,yt=[],wt=!1,Et=[],Dt="undefined"!=typeof document,_t=d,St=l||a?"cssFloat":"float",Ct=Dt&&!u&&!d&&"draggable"in document.createElement("div"),xt=function(){if(Dt){if(a)return!1;var t=document.createElement("x");return t.style.cssText="pointer-events:auto","auto"===t.style.pointerEvents}}(),Tt=function(t,e){var n=E(t),o=parseInt(n.width)-parseInt(n.paddingLeft)-parseInt(n.paddingRight)-parseInt(n.borderLeftWidth)-parseInt(n.borderRightWidth),i=T(t,0,e),r=T(t,1,e),a=i&&E(i),l=r&&E(r),s=a&&parseInt(a.marginLeft)+parseInt(a.marginRight)+C(i).width,c=l&&parseInt(l.marginLeft)+parseInt(l.marginRight)+C(r).width;if("flex"===n.display)return"column"===n.flexDirection||"column-reverse"===n.flexDirection?"vertical":"horizontal";if("grid"===n.display)return n.gridTemplateColumns.split(" ").length<=1?"vertical":"horizontal";if(i&&a.float&&"none"!==a.float){var d="left"===a.float?"left":"right";return!r||"both"!==l.clear&&l.clear!==d?"horizontal":"vertical"}return i&&("block"===a.display||"flex"===a.display||"table"===a.display||"grid"===a.display||s>=o&&"none"===n[St]||r&&"none"===n[St]&&s+c>o)?"vertical":"horizontal"},Ot=function(e){function n(t,e){return function(o,i,r,a){var l=o.options.group.name&&i.options.group.name&&o.options.group.name===i.options.group.name;if(null==t&&(e||l))return!0;if(null==t||!1===t)return!1;if(e&&"clone"===t)return t;if("function"==typeof t)return n(t(o,i,r,a),e)(o,i,r,a);var s=(e?o:i).options.group.name;return!0===t||"string"==typeof t&&t===s||t.join&&t.indexOf(s)>-1}}var o={},i=e.group;i&&"object"==t(i)||(i={name:i}),o.name=i.name,o.checkPull=n(i.pull,!0),o.checkPut=n(i.put),o.revertClone=i.revertClone,e.group=o},It=function(){!xt&&V&&E(V,"display","none")},Mt=function(){!xt&&V&&E(V,"display","")};Dt&&document.addEventListener("click",(function(t){if(gt)return t.preventDefault(),t.stopPropagation&&t.stopPropagation(),t.stopImmediatePropagation&&t.stopImmediatePropagation(),gt=!1,!1}),!0);var Nt=function(t){if(H){t=t.touches?t.touches[0]:t;var e=(i=t.clientX,r=t.clientY,mt.some((function(t){if(!O(t)){var e=C(t),n=t[R].options.emptyInsertThreshold,o=i>=e.left-n&&i<=e.right+n,l=r>=e.top-n&&r<=e.bottom+n;return n&&o&&l?a=t:void 0}})),a);if(e){var n={};for(var o in t)t.hasOwnProperty(o)&&(n[o]=t[o]);n.target=n.rootEl=e,n.preventDefault=void 0,n.stopPropagation=void 0,e[R]._onDragOver(n)}}var i,r,a},Pt=function(t){H&&H.parentNode[R]._isOutsideThisEl(t.target)};function At(t,e){if(!t||!t.nodeType||1!==t.nodeType)throw"Sortable: `el` must be an HTMLElement, not ".concat({}.toString.call(t));this.el=t,this.options=e=n({},e),t[R]=this;var o={group:null,sort:!0,disabled:!1,store:null,handle:null,draggable:/^[uo]l$/i.test(t.nodeName)?">li":">*",swapThreshold:1,invertSwap:!1,invertedSwapThreshold:null,removeCloneOnHide:!0,direction:function(){return Tt(t,this.options)},ghostClass:"sortable-ghost",chosenClass:"sortable-chosen",dragClass:"sortable-drag",ignore:"a, img",filter:null,preventOnFilter:!0,animation:0,easing:null,setData:function(t,e){t.setData("Text",e.textContent)},dropBubble:!1,dragoverBubble:!1,dataIdAttr:"data-id",delay:0,delayOnTouchOnly:!1,touchStartThreshold:(Number.parseInt?Number:window).parseInt(window.devicePixelRatio,10)||1,forceFallback:!1,fallbackClass:"sortable-fallback",fallbackOnBody:!1,fallbackTolerance:0,fallbackOffset:{x:0,y:0},supportPointer:!1!==At.supportPointer&&"PointerEvent"in window,emptyInsertThreshold:5};for(var i in $.initializePlugins(this,t,o),o)!(i in e)&&(e[i]=o[i]);for(var r in Ot(e),this)"_"===r.charAt(0)&&"function"==typeof this[r]&&(this[r]=this[r].bind(this));this.nativeDraggable=!e.forceFallback&&Ct,this.nativeDraggable&&(this.options.touchStartThreshold=1),e.supportPointer?f(t,"pointerdown",this._onTapStart):(f(t,"mousedown",this._onTapStart),f(t,"touchstart",this._onTapStart)),this.nativeDraggable&&(f(t,"dragover",this),f(t,"dragenter",this)),mt.push(this.el),e.store&&e.store.get&&this.sort(e.store.get(this)||[]),n(this,X())}function kt(t,e,n,o,i,r,s,c){var d,u,h=t[R],f=h.options.onMove;return!window.CustomEvent||a||l?(d=document.createEvent("Event")).initEvent("move",!0,!0):d=new CustomEvent("move",{bubbles:!0,cancelable:!0}),d.to=e,d.from=t,d.dragged=n,d.draggedRect=o,d.related=i||e,d.relatedRect=r||C(e),d.willInsertAfter=c,d.originalEvent=s,t.dispatchEvent(d),f&&(u=f.call(h,d,s)),u}function Ft(t){t.draggable=!1}function Rt(){wt=!1}function Xt(t){for(var e=t.tagName+t.className+t.src+t.href+t.textContent,n=e.length,o=0;n--;)o+=e.charCodeAt(n);return o.toString(36)}function Lt(t){return setTimeout(t,0)}function Yt(t){return clearTimeout(t)}At.prototype={constructor:At,_isOutsideThisEl:function(t){this.el.contains(t)||t===this.el||(dt=null)},_getDirection:function(t,e){return"function"==typeof this.options.direction?this.options.direction.call(this,t,e,H):this.options.direction},_onTapStart:function(t){if(t.cancelable){var e=this,n=this.el,o=this.options,i=o.preventOnFilter,r=t.type,a=t.touches&&t.touches[0]||t.pointerType&&"touch"===t.pointerType&&t,l=(a||t).target,s=t.target.shadowRoot&&(t.path&&t.path[0]||t.composedPath&&t.composedPath()[0])||l,c=o.filter;if(function(t){Et.length=0;var e=t.getElementsByTagName("input"),n=e.length;for(;n--;){var o=e[n];o.checked&&Et.push(o)}}(n),!H&&!(/mousedown|pointerdown/.test(r)&&0!==t.button||o.disabled||s.isContentEditable||(l=v(l,o.draggable,n,!1))&&l.animated||G===l)){if(Z=I(l),Q=I(l,o.draggable),"function"==typeof c){if(c.call(this,t,l,this))return j({sortable:e,rootEl:s,name:"filter",targetEl:l,toEl:n,fromEl:n}),B("filter",e,{evt:t}),void(i&&t.cancelable&&t.preventDefault())}else if(c&&(c=c.split(",").some((function(o){if(o=v(s,o.trim(),n,!1))return j({sortable:e,rootEl:o,name:"filter",targetEl:l,fromEl:n,toEl:n}),B("filter",e,{evt:t}),!0}))))return void(i&&t.cancelable&&t.preventDefault());o.handle&&!v(s,o.handle,n,!1)||this._prepareDragStart(t,a,l)}}},_prepareDragStart:function(t,e,n){var o,i=this,r=i.el,c=i.options,d=r.ownerDocument;if(n&&!H&&n.parentNode===r){var u=C(n);if(U=r,W=(H=n).parentNode,z=H.nextSibling,G=n,et=c.group,At.dragged=H,ot={target:H,clientX:(e||t).clientX,clientY:(e||t).clientY},lt=ot.clientX-u.left,st=ot.clientY-u.top,this._lastX=(e||t).clientX,this._lastY=(e||t).clientY,H.style["will-change"]="all",o=function(){B("delayEnded",i,{evt:t}),At.eventCanceled?i._onDrop():(i._disableDelayedDragEvents(),!s&&i.nativeDraggable&&(H.draggable=!0),i._triggerDragStart(t,e),j({sortable:i,name:"choose",originalEvent:t}),w(H,c.chosenClass,!0))},c.ignore.split(",").forEach((function(t){_(H,t.trim(),Ft)})),f(d,"dragover",Nt),f(d,"mousemove",Nt),f(d,"touchmove",Nt),f(d,"mouseup",i._onDrop),f(d,"touchend",i._onDrop),f(d,"touchcancel",i._onDrop),s&&this.nativeDraggable&&(this.options.touchStartThreshold=4,H.draggable=!0),B("delayStart",this,{evt:t}),!c.delay||c.delayOnTouchOnly&&!e||this.nativeDraggable&&(l||a))o();else{if(At.eventCanceled)return void this._onDrop();f(d,"mouseup",i._disableDelayedDrag),f(d,"touchend",i._disableDelayedDrag),f(d,"touchcancel",i._disableDelayedDrag),f(d,"mousemove",i._delayedDragTouchMoveHandler),f(d,"touchmove",i._delayedDragTouchMoveHandler),c.supportPointer&&f(d,"pointermove",i._delayedDragTouchMoveHandler),i._dragStartTimer=setTimeout(o,c.delay)}}},_delayedDragTouchMoveHandler:function(t){var e=t.touches?t.touches[0]:t;Math.max(Math.abs(e.clientX-this._lastX),Math.abs(e.clientY-this._lastY))>=Math.floor(this.options.touchStartThreshold/(this.nativeDraggable&&window.devicePixelRatio||1))&&this._disableDelayedDrag()},_disableDelayedDrag:function(){H&&Ft(H),clearTimeout(this._dragStartTimer),this._disableDelayedDragEvents()},_disableDelayedDragEvents:function(){var t=this.el.ownerDocument;p(t,"mouseup",this._disableDelayedDrag),p(t,"touchend",this._disableDelayedDrag),p(t,"touchcancel",this._disableDelayedDrag),p(t,"mousemove",this._delayedDragTouchMoveHandler),p(t,"touchmove",this._delayedDragTouchMoveHandler),p(t,"pointermove",this._delayedDragTouchMoveHandler)},_triggerDragStart:function(t,e){e=e||"touch"==t.pointerType&&t,!this.nativeDraggable||e?this.options.supportPointer?f(document,"pointermove",this._onTouchMove):f(document,e?"touchmove":"mousemove",this._onTouchMove):(f(H,"dragend",this),f(U,"dragstart",this._onDragStart));try{document.selection?Lt((function(){document.selection.empty()})):window.getSelection().removeAllRanges()}catch(n){}},_dragStarted:function(t,e){if(pt=!1,U&&H){B("dragStarted",this,{evt:e}),this.nativeDraggable&&f(document,"dragover",Pt);var n=this.options;!t&&w(H,n.dragClass,!1),w(H,n.ghostClass,!0),At.active=this,t&&this._appendGhost(),j({sortable:this,name:"start",originalEvent:e})}else this._nulling()},_emulateDragOver:function(){if(it){this._lastX=it.clientX,this._lastY=it.clientY,It();for(var t=document.elementFromPoint(it.clientX,it.clientY),e=t;t&&t.shadowRoot&&(t=t.shadowRoot.elementFromPoint(it.clientX,it.clientY))!==e;)e=t;if(H.parentNode[R]._isOutsideThisEl(t),e)do{if(e[R]){if(e[R]._onDragOver({clientX:it.clientX,clientY:it.clientY,target:t,rootEl:e})&&!this.options.dragoverBubble)break}t=e}while(e=e.parentNode);Mt()}},_onTouchMove:function(t){if(ot){var e=this.options,n=e.fallbackTolerance,o=e.fallbackOffset,i=t.touches?t.touches[0]:t,r=V&&D(V,!0),a=V&&r&&r.a,l=V&&r&&r.d,s=_t&&ft&&M(ft),c=(i.clientX-ot.clientX+o.x)/(a||1)+(s?s[0]-yt[0]:0)/(a||1),d=(i.clientY-ot.clientY+o.y)/(l||1)+(s?s[1]-yt[1]:0)/(l||1);if(!At.active&&!pt){if(n&&Math.max(Math.abs(i.clientX-this._lastX),Math.abs(i.clientY-this._lastY))o.right+i||t.clientX<=o.right&&t.clientY>o.bottom&&t.clientX>=o.left:t.clientX>o.right&&t.clientY>o.top||t.clientX<=o.right&&t.clientY>o.bottom+i}(t,r,this)&&!m.animated){if(m===H)return $(!1);if(m&&a===t.target&&(l=m),l&&(n=C(l)),!1!==kt(U,a,H,e,l,n,t,!!l))return Y(),a.appendChild(H),W=a,G(),$(!0)}else if(l.parentNode===a){n=C(l);var b,y,D,_=H.parentNode!==a,S=!function(t,e,n){var o=n?t.left:t.top,i=n?t.right:t.bottom,r=n?t.width:t.height,a=n?e.left:e.top,l=n?e.right:e.bottom,s=n?e.width:e.height;return o===a||i===l||o+r/2===a+s/2}(H.animated&&H.toRect||e,l.animated&&l.toRect||n,r),T=r?"top":"left",M=x(l,"top","top")||x(H,"top","top"),N=M?M.scrollTop:void 0;if(dt!==l&&(y=n[T],vt=!1,bt=!S&&s.invertSwap||_),b=function(t,e,n,o,i,r,a,l){var s=o?t.clientY:t.clientX,c=o?n.height:n.width,d=o?n.top:n.left,u=o?n.bottom:n.right,h=!1;if(!a)if(l&&htd+c*r/2:su-ht)return-ut}else if(s>d+c*(1-i)/2&&su-c*r/2))return s>d+c/2?1:-1;return 0}(t,l,n,r,S?1:s.swapThreshold,null==s.invertedSwapThreshold?s.swapThreshold:s.invertedSwapThreshold,bt,dt===l),0!==b){var P=I(H);do{P-=b,D=W.children[P]}while(D&&("none"===E(D,"display")||D===V))}if(0===b||D===l)return $(!1);dt=l,ut=b;var A=l.nextElementSibling,F=!1,X=kt(U,a,H,e,l,n,t,F=1===b);if(!1!==X)return 1!==X&&-1!==X||(F=1===X),wt=!0,setTimeout(Rt,30),Y(),F&&!A?a.appendChild(H):l.parentNode.insertBefore(H,F?A:l),M&&k(M,0,N-M.scrollTop),W=H.parentNode,void 0===y||bt||(ht=Math.abs(y-C(l)[T])),G(),$(!0)}if(a.contains(H))return $(!1)}return!1}function L(s,c){B(s,p,o({evt:t,isOwner:u,axis:r?"vertical":"horizontal",revert:i,dragRect:e,targetRect:n,canSort:h,fromSortable:f,target:l,completed:$,onMove:function(n,o){return kt(U,a,H,e,n,C(n),t,o)},changed:G},c))}function Y(){L("dragOverAnimationCapture"),p.captureAnimationState(),p!==f&&f.captureAnimationState()}function $(e){return L("dragOverCompleted",{insertion:e}),e&&(u?d._hideClone():d._showClone(p),p!==f&&(w(H,nt?nt.options.ghostClass:d.options.ghostClass,!1),w(H,s.ghostClass,!0)),nt!==p&&p!==At.active?nt=p:p===At.active&&nt&&(nt=null),f===p&&(p._ignoreWhileAnimating=l),p.animateAll((function(){L("dragOverAnimationComplete"),p._ignoreWhileAnimating=null})),p!==f&&(f.animateAll(),f._ignoreWhileAnimating=null)),(l===H&&!H.animated||l===a&&!l.animated)&&(dt=null),s.dragoverBubble||t.rootEl||l===document||(H.parentNode[R]._isOutsideThisEl(t.target),!e&&Nt(t)),!s.dragoverBubble&&t.stopPropagation&&t.stopPropagation(),g=!0}function G(){K=I(H),tt=I(H,s.draggable),j({sortable:p,name:"change",toEl:a,newIndex:K,newDraggableIndex:tt,originalEvent:t})}},_ignoreWhileAnimating:null,_offMoveEvents:function(){p(document,"mousemove",this._onTouchMove),p(document,"touchmove",this._onTouchMove),p(document,"pointermove",this._onTouchMove),p(document,"dragover",Nt),p(document,"mousemove",Nt),p(document,"touchmove",Nt)},_offUpEvents:function(){var t=this.el.ownerDocument;p(t,"mouseup",this._onDrop),p(t,"touchend",this._onDrop),p(t,"pointerup",this._onDrop),p(t,"touchcancel",this._onDrop),p(document,"selectstart",this)},_onDrop:function(t){var e=this.el,n=this.options;K=I(H),tt=I(H,n.draggable),B("drop",this,{evt:t}),W=H&&H.parentNode,K=I(H),tt=I(H,n.draggable),At.eventCanceled||(pt=!1,bt=!1,vt=!1,clearInterval(this._loopId),clearTimeout(this._dragStartTimer),Yt(this.cloneId),Yt(this._dragStartId),this.nativeDraggable&&(p(document,"drop",this),p(e,"dragstart",this._onDragStart)),this._offMoveEvents(),this._offUpEvents(),c&&E(document.body,"user-select",""),E(H,"transform",""),t&&(ct&&(t.cancelable&&t.preventDefault(),!n.dropBubble&&t.stopPropagation()),V&&V.parentNode&&V.parentNode.removeChild(V),(U===W||nt&&"clone"!==nt.lastPutMode)&&q&&q.parentNode&&q.parentNode.removeChild(q),H&&(this.nativeDraggable&&p(H,"dragend",this),Ft(H),H.style["will-change"]="",ct&&!pt&&w(H,nt?nt.options.ghostClass:this.options.ghostClass,!1),w(H,this.options.chosenClass,!1),j({sortable:this,name:"unchoose",toEl:W,newIndex:null,newDraggableIndex:null,originalEvent:t}),U!==W?(K>=0&&(j({rootEl:W,name:"add",toEl:W,fromEl:U,originalEvent:t}),j({sortable:this,name:"remove",toEl:W,originalEvent:t}),j({rootEl:W,name:"sort",toEl:W,fromEl:U,originalEvent:t}),j({sortable:this,name:"sort",toEl:W,originalEvent:t})),nt&&nt.save()):K!==Z&&K>=0&&(j({sortable:this,name:"update",toEl:W,originalEvent:t}),j({sortable:this,name:"sort",toEl:W,originalEvent:t})),At.active&&(null!=K&&-1!==K||(K=Z,tt=Q),j({sortable:this,name:"end",toEl:W,originalEvent:t}),this.save())))),this._nulling()},_nulling:function(){B("nulling",this),U=H=W=V=z=q=G=J=ot=it=ct=K=tt=Z=Q=dt=ut=nt=et=At.dragged=At.ghost=At.clone=At.active=null,Et.forEach((function(t){t.checked=!0})),Et.length=rt=at=0},handleEvent:function(t){switch(t.type){case"drop":case"dragend":this._onDrop(t);break;case"dragenter":case"dragover":H&&(this._onDragOver(t),function(t){t.dataTransfer&&(t.dataTransfer.dropEffect="move");t.cancelable&&t.preventDefault()}(t));break;case"selectstart":t.preventDefault()}},toArray:function(){for(var t,e=[],n=this.el.children,o=0,i=n.length,r=this.options;ot.replace(ee,((t,e)=>e?e.toUpperCase():""))));function oe(t){null!==t.parentElement&&t.parentElement.removeChild(t)}function ie(t,e,n){const o=0===n?t.children[0]:t.children[n-1].nextSibling;t.insertBefore(e,o)}function re(t,e){this.$nextTick((()=>this.$emit(t.toLowerCase(),e)))}function ae(t){return e=>{null!==this.realList&&this["onDrag"+t](e),re.call(this,t,e)}}function le(t){return["transition-group","TransitionGroup"].includes(t)}function se(t,e,n){return t[n]||(e[n]?e[n]():void 0)}const ce=["Start","Add","Remove","Update","End"],de=["Choose","Unchoose","Sort","Filter","Clone"],ue=["Move",...ce,...de].map((t=>"on"+t));var he=null;const fe={name:"draggable",inheritAttrs:!1,props:{options:Object,list:{type:Array,required:!1,default:null},value:{type:Array,required:!1,default:null},noTransitionOnDrag:{type:Boolean,default:!1},clone:{type:Function,default:t=>t},element:{type:String,default:"div"},tag:{type:String,default:null},move:{type:Function,default:null},componentData:{type:Object,required:!1,default:null}},data:()=>({transitionMode:!1,noneFunctionalComponentMode:!1}),render(t){const e=this.$slots.default;this.transitionMode=function(t){if(!t||1!==t.length)return!1;const[{componentOptions:e}]=t;return!!e&&le(e.tag)}(e);const{children:n,headerOffset:o,footerOffset:i}=function(t,e,n){let o=0,i=0;const r=se(e,n,"header");r&&(o=r.length,t=t?[...r,...t]:[...r]);const a=se(e,n,"footer");return a&&(i=a.length,t=t?[...t,...a]:[...a]),{children:t,headerOffset:o,footerOffset:i}}(e,this.$slots,this.$scopedSlots);this.headerOffset=o,this.footerOffset=i;const r=function(t,e){let n=null;const o=(t,e)=>{n=function(t,e,n){return void 0===n||((t=t||{})[e]=n),t}(n,t,e)};if(o("attrs",Object.keys(t).filter((t=>"id"===t||t.startsWith("data-"))).reduce(((e,n)=>(e[n]=t[n],e)),{})),!e)return n;const{on:i,props:r,attrs:a}=e;return o("on",i),o("props",r),Object.assign(n.attrs,a),n}(this.$attrs,this.componentData);return t(this.getTag(),r,n)},created(){null!==this.list&&null!==this.value&&te.error("Value and list props are mutually exclusive! Please set one or another."),"div"!==this.element&&te.warn("Element props is deprecated please use tag props instead. See https://github.com/SortableJS/Vue.Draggable/blob/master/documentation/migrate.md#element-props"),void 0!==this.options&&te.warn("Options props is deprecated, add sortable options directly as vue.draggable item, or use v-bind. See https://github.com/SortableJS/Vue.Draggable/blob/master/documentation/migrate.md#options-props")},mounted(){if(this.noneFunctionalComponentMode=this.getTag().toLowerCase()!==this.$el.nodeName.toLowerCase()&&!this.getIsFunctional(),this.noneFunctionalComponentMode&&this.transitionMode)throw new Error(`Transition-group inside component is not supported. Please alter tag value or remove transition-group. Current tag value: ${this.getTag()}`);const t={};ce.forEach((e=>{t["on"+e]=ae.call(this,e)})),de.forEach((e=>{t["on"+e]=re.bind(this,e)}));const e=Object.keys(this.$attrs).reduce(((t,e)=>(t[ne(e)]=this.$attrs[e],t)),{}),n=Object.assign({},this.options,e,t,{onMove:(t,e)=>this.onDragMove(t,e)});!("draggable"in n)&&(n.draggable=">*"),this._sortable=new At(this.rootContainer,n),this.computeIndexes()},beforeDestroy(){void 0!==this._sortable&&this._sortable.destroy()},computed:{rootContainer(){return this.transitionMode?this.$el.children[0]:this.$el},realList(){return this.list?this.list:this.value}},watch:{options:{handler(t){this.updateOptions(t)},deep:!0},$attrs:{handler(t){this.updateOptions(t)},deep:!0},realList(){this.computeIndexes()}},methods:{getIsFunctional(){const{fnOptions:t}=this._vnode;return t&&t.functional},getTag(){return this.tag||this.element},updateOptions(t){for(var e in t){const n=ne(e);-1===ue.indexOf(n)&&this._sortable.option(n,t[e])}},getChildrenNodes(){if(this.noneFunctionalComponentMode)return this.$children[0].$slots.default;const t=this.$slots.default;return this.transitionMode?t[0].child.$slots.default:t},computeIndexes(){this.$nextTick((()=>{this.visibleIndexes=function(t,e,n,o){if(!t)return[];const i=t.map((t=>t.elm)),r=e.length-o,a=[...e].map(((t,e)=>e>=r?i.length:i.indexOf(t)));return n?a.filter((t=>-1!==t)):a}(this.getChildrenNodes(),this.rootContainer.children,this.transitionMode,this.footerOffset)}))},getUnderlyingVm(t){const e=function(t,e){return t.map((t=>t.elm)).indexOf(e)}(this.getChildrenNodes()||[],t);if(-1===e)return null;return{index:e,element:this.realList[e]}},getUnderlyingPotencialDraggableComponent:({__vue__:t})=>t&&t.$options&&le(t.$options._componentTag)?t.$parent:!("realList"in t)&&1===t.$children.length&&"realList"in t.$children[0]?t.$children[0]:t,emitChanges(t){this.$nextTick((()=>{this.$emit("change",t)}))},alterList(t){if(this.list)return void t(this.list);const e=[...this.value];t(e),this.$emit("input",e)},spliceList(){this.alterList((t=>t.splice(...arguments)))},updatePosition(t,e){this.alterList((n=>n.splice(e,0,n.splice(t,1)[0])))},getRelatedContextFromMoveEvent({to:t,related:e}){const n=this.getUnderlyingPotencialDraggableComponent(t);if(!n)return{component:n};const o=n.realList,i={list:o,component:n};if(t!==e&&o&&n.getUnderlyingVm){const t=n.getUnderlyingVm(e);if(t)return Object.assign(t,i)}return i},getVmIndex(t){const e=this.visibleIndexes,n=e.length;return t>n-1?n:e[t]},getComponent(){return this.$slots.default[0].componentInstance},resetTransitionData(t){if(!this.noTransitionOnDrag||!this.transitionMode)return;this.getChildrenNodes()[t].data=null;const e=this.getComponent();e.children=[],e.kept=void 0},onDragStart(t){this.context=this.getUnderlyingVm(t.item),t.item._underlying_vm_=this.clone(this.context.element),he=t.item},onDragAdd(t){const e=t.item._underlying_vm_;if(void 0===e)return;oe(t.item);const n=this.getVmIndex(t.newIndex);this.spliceList(n,0,e),this.computeIndexes();const o={element:e,newIndex:n};this.emitChanges({added:o})},onDragRemove(t){if(ie(this.rootContainer,t.item,t.oldIndex),"clone"===t.pullMode)return void oe(t.clone);const e=this.context.index;this.spliceList(e,1);const n={element:this.context.element,oldIndex:e};this.resetTransitionData(e),this.emitChanges({removed:n})},onDragUpdate(t){oe(t.item),ie(t.from,t.item,t.oldIndex);const e=this.context.index,n=this.getVmIndex(t.newIndex);this.updatePosition(e,n);const o={element:this.context.element,oldIndex:e,newIndex:n};this.emitChanges({moved:o})},updateProperty(t,e){t.hasOwnProperty(e)&&(t[e]+=this.headerOffset)},computeFutureIndex(t,e){if(!t.element)return 0;const n=[...e.to.children].filter((t=>"none"!==t.style.display)),o=n.indexOf(e.related),i=t.component.getVmIndex(o);return-1!==n.indexOf(he)||!e.willInsertAfter?i:i+1},onDragMove(t,e){const n=this.move;if(!n||!this.realList)return!0;const o=this.getRelatedContextFromMoveEvent(t),i=this.context,r=this.computeFutureIndex(o,t);Object.assign(i,{futureIndex:r});return n(Object.assign({},t,{relatedContext:o,draggedContext:i}),e)},onDragEnd(){this.computeIndexes(),he=null}}};"undefined"!=typeof window&&"Vue"in window&&window.Vue.component("draggable",fe);export{fe as default}; diff --git a/kirby/panel/eslint.config.mjs b/kirby/panel/eslint.config.mjs deleted file mode 100644 index cfe049e..0000000 --- a/kirby/panel/eslint.config.mjs +++ /dev/null @@ -1,28 +0,0 @@ -import js from "@eslint/js"; -import prettier from "eslint-config-prettier"; -import vue from "eslint-plugin-vue"; - -export default [ - js.configs.recommended, - ...vue.configs["flat/vue2-recommended"], - prettier, - { - rules: { - "vue/attributes-order": "error", - "vue/component-definition-name-casing": "off", - "vue/html-closing-bracket-newline": [ - "error", - { - singleline: "never", - multiline: "always" - } - ], - "vue/multi-word-component-names": "off", - "vue/require-default-prop": "off", - "vue/require-prop-types": "error" - }, - languageOptions: { - ecmaVersion: 2022 - } - } -]; diff --git a/kirby/router.php b/kirby/router.php index ea8cc86..10386c7 100644 --- a/kirby/router.php +++ b/kirby/router.php @@ -1,12 +1,11 @@ authentication = $props['authentication'] ?? null; - $this->data = $props['data'] ?? []; - $this->routes = $props['routes'] ?? []; - $this->debug = $props['debug'] ?? false; - - if ($collections = $props['collections'] ?? null) { - $this->collections = array_change_key_case($collections); - } - - if ($models = $props['models'] ?? null) { - $this->models = array_change_key_case($models); - } - - $this->setRequestData($props['requestData'] ?? null); - $this->setRequestMethod($props['requestMethod'] ?? null); - } + protected $requestMethod; /** * Magic accessor for any given data * + * @param string $method + * @param array $args + * @return mixed * @throws \Kirby\Exception\NotFoundException */ public function __call(string $method, array $args = []) @@ -115,19 +115,37 @@ class Api return $this->data($method, ...$args); } + /** + * Creates a new API instance + * + * @param array $props + */ + public function __construct(array $props) + { + $this->setProperties($props); + } + /** * Runs the authentication method * if set + * + * @return mixed */ public function authenticate() { - return $this->authentication()?->call($this) ?? true; + if ($auth = $this->authentication()) { + return $auth->call($this); + } + + return true; } /** * Returns the authentication callback + * + * @return \Closure|null */ - public function authentication(): Closure|null + public function authentication() { return $this->authentication; } @@ -136,14 +154,15 @@ class Api * Execute an API call for the given path, * request method and optional request data * + * @param string|null $path + * @param string $method + * @param array $requestData + * @return mixed * @throws \Kirby\Exception\NotFoundException * @throws \Exception */ - public function call( - string|null $path = null, - string $method = 'GET', - array $requestData = [] - ): mixed { + public function call(string $path = null, string $method = 'GET', array $requestData = []) + { $path = rtrim($path ?? '', '/'); $this->setRequestMethod($method); @@ -151,18 +170,19 @@ class Api $this->router = new Router($this->routes()); $this->route = $this->router->find($path, $method); - $auth = $this->route?->attributes()['auth'] ?? true; + $auth = $this->route->attributes()['auth'] ?? true; if ($auth !== false) { $user = $this->authenticate(); // set PHP locales based on *user* language // so that e.g. strftime() gets formatted correctly - if ($user instanceof User) { + if (is_a($user, 'Kirby\Cms\User') === true) { $language = $user->language(); // get the locale from the translation - $locale = $user->kirby()->translation($language)->locale(); + $translation = $user->kirby()->translation($language); + $locale = ($translation !== null) ? $translation->locale() : $language; // provide some variants as fallbacks to be // compatible with as many systems as possible @@ -188,17 +208,14 @@ class Api $validate = Pagination::$validate; Pagination::$validate = false; - $output = $this->route?->action()->call( - $this, - ...$this->route->arguments() - ); + $output = $this->route->action()->call($this, ...$this->route->arguments()); // restore old pagination validation mode Pagination::$validate = $validate; if ( is_object($output) === true && - $output instanceof Response === false + is_a($output, 'Kirby\\Http\\Response') !== true ) { return $this->resolve($output)->toResponse(); } @@ -206,34 +223,17 @@ class Api return $output; } - /** - * Creates a new instance while - * merging initial and new properties - */ - public function clone(array $props = []): static - { - return new static(array_merge([ - 'autentication' => $this->authentication, - 'data' => $this->data, - 'routes' => $this->routes, - 'debug' => $this->debug, - 'collections' => $this->collections, - 'models' => $this->models, - 'requestData' => $this->requestData, - 'requestMethod' => $this->requestMethod - ], $props)); - } - /** * Setter and getter for an API collection * + * @param string $name + * @param array|null $collection + * @return \Kirby\Api\Collection * @throws \Kirby\Exception\NotFoundException If no collection for `$name` exists * @throws \Exception */ - public function collection( - string $name, - array|BaseCollection|null $collection = null - ): Collection { + public function collection(string $name, $collection = null) + { if (isset($this->collections[$name]) === false) { throw new NotFoundException(sprintf('The collection "%s" does not exist', $name)); } @@ -243,6 +243,8 @@ class Api /** * Returns the collections definition + * + * @return array */ public function collections(): array { @@ -253,9 +255,13 @@ class Api * Returns the injected data array * or certain parts of it by key * + * @param string|null $key + * @param mixed ...$args + * @return mixed + * * @throws \Kirby\Exception\NotFoundException If no data for `$key` exists */ - public function data(string|null $key = null, ...$args): mixed + public function data($key = null, ...$args) { if ($key === null) { return $this->data; @@ -266,7 +272,7 @@ class Api } // lazy-load data wrapped in Closures - if ($this->data[$key] instanceof Closure) { + if (is_a($this->data[$key], 'Closure') === true) { return $this->data[$key]->call($this, ...$args); } @@ -275,6 +281,8 @@ class Api /** * Returns the debugging flag + * + * @return bool */ public function debug(): bool { @@ -283,6 +291,9 @@ class Api /** * Checks if injected data exists for the given key + * + * @param string $key + * @return bool */ public function hasData(string $key): bool { @@ -294,35 +305,39 @@ class Api * based on the `type` field * * @param array models or collections - * @return string|null key of match + * @param mixed $object + * + * @return string key of match */ - protected function match( - array $array, - $object = null - ): string|null { + protected function match(array $array, $object = null) + { foreach ($array as $definition => $model) { - if ($object instanceof $model['type']) { + if (is_a($object, $model['type']) === true) { return $definition; } } - - return null; } /** * Returns an API model instance by name * + * @param string|null $name + * @param mixed $object + * @return \Kirby\Api\Model + * * @throws \Kirby\Exception\NotFoundException If no model for `$name` exists */ - public function model( - string|null $name = null, - $object = null - ): Model { + public function model(string $name = null, $object = null) + { // Try to auto-match object with API models - $name ??= $this->match($this->models, $object); + if ($name === null) { + if ($model = $this->match($this->models, $object)) { + $name = $model; + } + } if (isset($this->models[$name]) === false) { - throw new NotFoundException(sprintf('The model "%s" does not exist', $name ?? 'NULL')); + throw new NotFoundException(sprintf('The model "%s" does not exist', $name)); } return new Model($this, $object, $this->models[$name]); @@ -330,6 +345,8 @@ class Api /** * Returns all model definitions + * + * @return array */ public function models(): array { @@ -340,12 +357,14 @@ class Api * Getter for request data * Can either get all the data * or certain parts of it. + * + * @param string|null $type + * @param string|null $key + * @param mixed $default + * @return mixed */ - public function requestData( - string|null $type = null, - string|null $key = null, - mixed $default = null - ): mixed { + public function requestData(string $type = null, string $key = null, $default = null) + { if ($type === null) { return $this->requestData; } @@ -362,49 +381,59 @@ class Api /** * Returns the request body if available + * + * @param string|null $key + * @param mixed $default + * @return mixed */ - public function requestBody( - string|null $key = null, - mixed $default = null - ): mixed { + public function requestBody(string $key = null, $default = null) + { return $this->requestData('body', $key, $default); } /** * Returns the files from the request if available + * + * @param string|null $key + * @param mixed $default + * @return mixed */ - public function requestFiles( - string|null $key = null, - mixed $default = null - ): mixed { + public function requestFiles(string $key = null, $default = null) + { return $this->requestData('files', $key, $default); } /** * Returns all headers from the request if available + * + * @param string|null $key + * @param mixed $default + * @return mixed */ - public function requestHeaders( - string|null $key = null, - mixed $default = null - ): mixed { + public function requestHeaders(string $key = null, $default = null) + { return $this->requestData('headers', $key, $default); } /** * Returns the request method + * + * @return string */ - public function requestMethod(): string|null + public function requestMethod(): string { return $this->requestMethod; } /** * Returns the request query if available + * + * @param string|null $key + * @param mixed $default + * @return mixed */ - public function requestQuery( - string|null $key = null, - mixed $default = null - ): mixed { + public function requestQuery(string $key = null, $default = null) + { return $this->requestData('query', $key, $default); } @@ -412,14 +441,14 @@ class Api * Turns a Kirby object into an * API model or collection representation * + * @param mixed $object + * @return \Kirby\Api\Model|\Kirby\Api\Collection + * * @throws \Kirby\Exception\NotFoundException If `$object` cannot be resolved */ - public function resolve($object): Model|Collection + public function resolve($object) { - if ( - $object instanceof Model || - $object instanceof Collection - ) { + if (is_a($object, 'Kirby\Api\Model') === true || is_a($object, 'Kirby\Api\Collection') === true) { return $object; } @@ -436,6 +465,8 @@ class Api /** * Returns all defined routes + * + * @return array */ public function routes(): array { @@ -443,25 +474,135 @@ class Api } /** - * Renders the API call + * Setter for the authentication callback + * + * @param \Closure|null $authentication + * @return $this */ - public function render( - string $path, - string $method = 'GET', - array $requestData = [] - ): mixed { + protected function setAuthentication(Closure $authentication = null) + { + $this->authentication = $authentication; + return $this; + } + + /** + * Setter for the collections definition + * + * @param array|null $collections + * @return $this + */ + protected function setCollections(array $collections = null) + { + if ($collections !== null) { + $this->collections = array_change_key_case($collections); + } + return $this; + } + + /** + * Setter for the injected data + * + * @param array|null $data + * @return $this + */ + protected function setData(array $data = null) + { + $this->data = $data ?? []; + return $this; + } + + /** + * Setter for the debug flag + * + * @param bool $debug + * @return $this + */ + protected function setDebug(bool $debug = false) + { + $this->debug = $debug; + return $this; + } + + /** + * Setter for the model definitions + * + * @param array|null $models + * @return $this + */ + protected function setModels(array $models = null) + { + if ($models !== null) { + $this->models = array_change_key_case($models); + } + + return $this; + } + + /** + * Setter for the request data + * + * @param array|null $requestData + * @return $this + */ + protected function setRequestData(array $requestData = null) + { + $defaults = [ + 'query' => [], + 'body' => [], + 'files' => [] + ]; + + $this->requestData = array_merge($defaults, (array)$requestData); + return $this; + } + + /** + * Setter for the request method + * + * @param string|null $requestMethod + * @return $this + */ + protected function setRequestMethod(string $requestMethod = null) + { + $this->requestMethod = $requestMethod ?? 'GET'; + return $this; + } + + /** + * Setter for the route definitions + * + * @param array|null $routes + * @return $this + */ + protected function setRoutes(array $routes = null) + { + $this->routes = $routes ?? []; + return $this; + } + + /** + * Renders the API call + * + * @param string $path + * @param string $method + * @param array $requestData + * @return mixed + */ + public function render(string $path, $method = 'GET', array $requestData = []) + { try { $result = $this->call($path, $method, $requestData); } catch (Throwable $e) { $result = $this->responseForException($e); } - $result = match ($result) { - null => $this->responseFor404(), - false => $this->responseFor400(), - true => $this->responseFor200(), - default => $result - }; + if ($result === null) { + $result = $this->responseFor404(); + } elseif ($result === false) { + $result = $this->responseFor400(); + } elseif ($result === true) { + $result = $this->responseFor200(); + } if (is_array($result) === false) { return $result; @@ -487,6 +628,8 @@ class Api /** * Returns a 200 - ok * response array. + * + * @return array */ public function responseFor200(): array { @@ -500,6 +643,8 @@ class Api /** * Returns a 400 - bad request * response array. + * + * @return array */ public function responseFor400(): array { @@ -513,6 +658,8 @@ class Api /** * Returns a 404 - not found * response array. + * + * @return array */ public function responseFor404(): array { @@ -527,6 +674,9 @@ class Api * Creates the response array for * an exception. Kirby exceptions will * have more information + * + * @param \Throwable $e + * @return array */ public function responseForException(Throwable $e): array { @@ -546,11 +696,11 @@ class Api 'file' => F::relativepath($e->getFile(), $docRoot), 'line' => $e->getLine(), 'details' => [], - 'route' => $this->route?->pattern() + 'route' => $this->route ? $this->route->pattern() : null ]; // extend the information for Kirby Exceptions - if ($e instanceof ExceptionException) { + if (is_a($e, 'Kirby\Exception\Exception') === true) { $result['key'] = $e->getKey(); $result['details'] = $e->getDetails(); $result['code'] = $e->getHttpCode(); @@ -570,47 +720,21 @@ class Api return $result; } - /** - * Setter for the request data - * @return $this - */ - protected function setRequestData( - array|null $requestData = [] - ): static { - $defaults = [ - 'query' => [], - 'body' => [], - 'files' => [] - ]; - - $this->requestData = array_merge($defaults, (array)$requestData); - return $this; - } - - /** - * Setter for the request method - * @return $this - */ - protected function setRequestMethod( - string $requestMethod = null - ): static { - $this->requestMethod = $requestMethod ?? 'GET'; - return $this; - } - /** * Upload helper method * * move_uploaded_file() not working with unit test * Added debug parameter for testing purposes as we did in the Email class * + * @param \Closure $callback + * @param bool $single + * @param bool $debug + * @return array + * * @throws \Exception If request has no files or there was an error with the upload */ - public function upload( - Closure $callback, - bool $single = false, - bool $debug = false - ): array { + public function upload(Closure $callback, $single = false, $debug = false): array + { $trials = 0; $uploads = []; $errors = []; @@ -632,27 +756,14 @@ class Api $uploadMaxFileSize = Str::toBytes(ini_get('upload_max_filesize')); if ($postMaxSize < $uploadMaxFileSize) { - throw new Exception( - I18n::translate( - 'upload.error.iniPostSize', - 'The uploaded file exceeds the post_max_size directive in php.ini' - ) - ); + throw new Exception(I18n::translate('upload.error.iniPostSize')); + } else { + throw new Exception(I18n::translate('upload.error.noFiles')); } - - throw new Exception( - I18n::translate( - 'upload.error.noFiles', - 'No files were uploaded' - ) - ); } foreach ($files as $upload) { - if ( - isset($upload['tmp_name']) === false && - is_array($upload) === true - ) { + if (isset($upload['tmp_name']) === false && is_array($upload)) { continue; } @@ -660,10 +771,8 @@ class Api try { if ($upload['error'] !== 0) { - throw new Exception( - $errorMessages[$upload['error']] ?? - I18n::translate('upload.error.default', 'The file could not be uploaded') - ); + $errorMessage = $errorMessages[$upload['error']] ?? I18n::translate('upload.error.default'); + throw new Exception($errorMessage); } // get the extension of the uploaded file @@ -671,10 +780,7 @@ class Api // try to detect the correct mime and add the extension // accordingly. This will avoid .tmp filenames - if ( - empty($extension) === true || - in_array($extension, ['tmp', 'temp']) === true - ) { + if (empty($extension) === true || in_array($extension, ['tmp', 'temp'])) { $mime = F::mime($upload['tmp_name']); $extension = F::mimeToExtension($mime); $filename = F::name($upload['name']) . '.' . $extension; @@ -686,13 +792,8 @@ class Api // move the file to a location including the extension, // for better mime detection - if ( - $debug === false && - move_uploaded_file($upload['tmp_name'], $source) === false - ) { - throw new Exception( - I18n::translate('upload.error.cantMove') - ); + if ($debug === false && move_uploaded_file($upload['tmp_name'], $source) === false) { + throw new Exception(I18n::translate('upload.error.cantMove')); } $data = $callback($source, $filename); diff --git a/kirby/src/Api/Collection.php b/kirby/src/Api/Collection.php index af66235..48ddca2 100644 --- a/kirby/src/Api/Collection.php +++ b/kirby/src/Api/Collection.php @@ -2,9 +2,7 @@ namespace Kirby\Api; -use Closure; use Exception; -use Kirby\Toolkit\Collection as BaseCollection; use Kirby\Toolkit\Str; /** @@ -21,25 +19,48 @@ use Kirby\Toolkit\Str; */ class Collection { - protected string|null $model; - protected array|null $select = null; - protected string|null $view; + /** + * @var \Kirby\Api\Api + */ + protected $api; + + /** + * @var mixed|null + */ + protected $data; + + /** + * @var mixed|null + */ + protected $model; + + /** + * @var mixed|null + */ + protected $select; + + /** + * @var mixed|null + */ + protected $view; /** * Collection constructor * + * @param \Kirby\Api\Api $api + * @param mixed|null $data + * @param array $schema * @throws \Exception */ - public function __construct( - protected Api $api, - protected BaseCollection|array|null $data, - array $schema - ) { + public function __construct(Api $api, $data, array $schema) + { + $this->api = $api; + $this->data = $data; $this->model = $schema['model'] ?? null; $this->view = $schema['view'] ?? null; if ($data === null) { - if (($schema['default'] ?? null) instanceof Closure === false) { + if (is_a($schema['default'] ?? null, 'Closure') === false) { throw new Exception('Missing collection data'); } @@ -48,17 +69,18 @@ class Collection if ( isset($schema['type']) === true && - $this->data instanceof $schema['type'] === false + is_a($this->data, $schema['type']) === false ) { throw new Exception('Invalid collection type'); } } /** + * @param string|array|null $keys * @return $this * @throws \Exception */ - public function select($keys = null): static + public function select($keys = null) { if ($keys === false) { return $this; @@ -77,6 +99,7 @@ class Collection } /** + * @return array * @throws \Kirby\Exception\NotFoundException * @throws \Exception */ @@ -102,6 +125,7 @@ class Collection } /** + * @return array * @throws \Kirby\Exception\NotFoundException * @throws \Exception */ @@ -143,9 +167,10 @@ class Collection } /** + * @param string $view * @return $this */ - public function view(string $view): static + public function view(string $view) { $this->view = $view; return $this; diff --git a/kirby/src/Api/Model.php b/kirby/src/Api/Model.php index 24af00b..f0189c0 100644 --- a/kirby/src/Api/Model.php +++ b/kirby/src/Api/Model.php @@ -2,7 +2,6 @@ namespace Kirby\Api; -use Closure; use Exception; use Kirby\Toolkit\Str; @@ -22,33 +21,53 @@ use Kirby\Toolkit\Str; */ class Model { - protected array $fields; - protected array|null $select; - protected array $views; + /** + * @var \Kirby\Api\Api + */ + protected $api; + + /** + * @var mixed|null + */ + protected $data; + + /** + * @var array|mixed + */ + protected $fields; + + /** + * @var mixed|null + */ + protected $select; + + /** + * @var array|mixed + */ + protected $views; /** * Model constructor * + * @param \Kirby\Api\Api $api + * @param mixed $data + * @param array $schema * @throws \Exception */ - public function __construct( - protected Api $api, - protected object|array|string|null $data, - array $schema - ) { + public function __construct(Api $api, $data, array $schema) + { + $this->api = $api; + $this->data = $data; $this->fields = $schema['fields'] ?? []; $this->select = $schema['select'] ?? null; $this->views = $schema['views'] ?? []; - if ( - $this->select === null && - array_key_exists('default', $this->views) - ) { + if ($this->select === null && array_key_exists('default', $this->views)) { $this->view('default'); } if ($data === null) { - if (($schema['default'] ?? null) instanceof Closure === false) { + if (is_a($schema['default'] ?? null, 'Closure') === false) { throw new Exception('Missing model data'); } @@ -57,21 +76,18 @@ class Model if ( isset($schema['type']) === true && - $this->data instanceof $schema['type'] === false + is_a($this->data, $schema['type']) === false ) { - $class = match ($this->data) { - null => 'null', - default => get_class($this->data), - }; - throw new Exception(sprintf('Invalid model type "%s" expected: "%s"', $class, $schema['type'])); + throw new Exception(sprintf('Invalid model type "%s" expected: "%s"', get_class($this->data), $schema['type'])); } } /** + * @param null $keys * @return $this * @throws \Exception */ - public function select($keys = null): static + public function select($keys = null) { if ($keys === false) { return $this; @@ -90,12 +106,17 @@ class Model } /** + * @return array * @throws \Exception */ public function selection(): array { - $select = $this->select; - $select ??= array_keys($this->fields); + $select = $this->select; + + if ($select === null) { + $select = array_keys($this->fields); + } + $selection = []; foreach ($select as $key => $value) { @@ -132,6 +153,7 @@ class Model } /** + * @return array * @throws \Kirby\Exception\NotFoundException * @throws \Exception */ @@ -141,10 +163,7 @@ class Model $result = []; foreach ($this->fields as $key => $resolver) { - if ( - array_key_exists($key, $select) === false || - $resolver instanceof Closure === false - ) { + if (array_key_exists($key, $select) === false || is_a($resolver, 'Closure') === false) { continue; } @@ -155,8 +174,8 @@ class Model } if ( - $value instanceof Collection || - $value instanceof self + is_a($value, 'Kirby\Api\Collection') === true || + is_a($value, 'Kirby\Api\Model') === true ) { $selection = $select[$key]; @@ -180,6 +199,7 @@ class Model } /** + * @return array * @throws \Kirby\Exception\NotFoundException * @throws \Exception */ @@ -204,10 +224,11 @@ class Model } /** + * @param string $name * @return $this * @throws \Exception */ - public function view(string $name): static + public function view(string $name) { if ($name === 'any') { return $this->select(null); diff --git a/kirby/src/Blueprint/Collection.php b/kirby/src/Blueprint/Collection.php deleted file mode 100644 index a8dc604..0000000 --- a/kirby/src/Blueprint/Collection.php +++ /dev/null @@ -1,97 +0,0 @@ - - * @link https://getkirby.com - * @copyright Bastian Allgeier - * @license https://opensource.org/licenses/MIT - * - * // TODO: include in test coverage once blueprint refactoring is done - * @codeCoverageIgnore - */ -class Collection extends BaseCollection -{ - /** - * The expected object type - */ - public const TYPE = Node::class; - - public function __construct(array $objects = []) - { - foreach ($objects as $object) { - $this->__set($object->id, $object); - } - } - - /** - * The Kirby Collection class only shows the key to - * avoid huge tress with dump, but for the blueprint - * collections this is really not useful - * - * @codeCoverageIgnore - */ - public function __debugInfo(): array - { - return A::map($this->data, fn ($item) => (array)$item); - } - - /** - * Validate the type of every item that is being - * added to the collection. They need to have - * the class defined by static::TYPE. - */ - public function __set(string $key, $value): void - { - if (is_a($value, static::TYPE) === false) { - throw new TypeError('Each value in the collection must be an instance of ' . static::TYPE); - } - - parent::__set($key, $value); - } - - /** - * Creates a collection from a nested array structure - */ - public static function factory(array $items): static - { - $collection = new static(); - $className = static::TYPE; - - foreach ($items as $id => $item) { - if (is_array($item) === true) { - $item['id'] ??= $id; - $item = $className::factory($item); - $collection->__set($item->id, $item); - } else { - $collection->__set($id, $className::factory($item)); - } - } - - return $collection; - } - - /** - * Renders each item with a model and returns - * an array of all rendered results - */ - public function render(ModelWithContent $model): array - { - $props = []; - - foreach ($this->data as $key => $item) { - $props[$key] = $item->render($model); - } - - return $props; - } -} diff --git a/kirby/src/Blueprint/Config.php b/kirby/src/Blueprint/Config.php deleted file mode 100644 index c7edb23..0000000 --- a/kirby/src/Blueprint/Config.php +++ /dev/null @@ -1,75 +0,0 @@ - - * @link https://getkirby.com - * @copyright Bastian Allgeier - * @license https://opensource.org/licenses/MIT - * - * // TODO: include in test coverage once blueprint refactoring is done - * @codeCoverageIgnore - */ -class Config -{ - public string $file; - public string $id; - public string|array|Closure|null $plugin; - public string $root; - - public function __construct( - public string $path - ) { - $kirby = App::instance(); - - $this->id = basename($this->path); - $this->root = $kirby->root('blueprints'); - $this->file = $this->root . '/' . $this->path . '.yml'; - $this->plugin = $kirby->extension('blueprints', $this->path); - } - - public function read(): array - { - if (F::exists($this->file, $this->root) === true) { - return $this->unpack($this->file); - } - - return $this->unpack($this->plugin); - } - - public function write(array $props): bool - { - return Yaml::write($this->file, $props); - } - - public function unpack(string|array|Closure|null $extension): array - { - return match (true) { - // extension does not exist - is_null($extension) - => throw new NotFoundException('"' . $this->path . '" could not be found'), - - // extension is stored as a file path - is_string($extension) - => Yaml::read($extension), - - // extension is a callback to be resolved - is_callable($extension) - => $extension(App::instance()), - - // extension is already defined as array - default - => $extension - }; - } -} diff --git a/kirby/src/Blueprint/Extension.php b/kirby/src/Blueprint/Extension.php deleted file mode 100644 index 9d3d25f..0000000 --- a/kirby/src/Blueprint/Extension.php +++ /dev/null @@ -1,65 +0,0 @@ - - * @link https://getkirby.com - * @copyright Bastian Allgeier - * @license https://opensource.org/licenses/MIT - * - * // TODO: include in test coverage once blueprint refactoring is done - * @codeCoverageIgnore - */ -class Extension -{ - public function __construct( - public string $path - ) { - } - - public static function apply(array $props): array - { - if (isset($props['extends']) === false) { - return $props; - } - - // already extended - if (is_a($props['extends'], Extension::class) === true) { - return $props; - } - - $extension = new static($props['extends']); - return $extension->extend($props); - } - - public function extend(array $props): array - { - $props = array_replace_recursive( - $this->read(), - $props - ); - - $props['extends'] = $this; - - return $props; - } - - public static function factory(string|array $path): static - { - if (is_string($path) === true) { - return new static(path: $path); - } - - return new static(...$path); - } - - public function read(): array - { - $config = new Config($this->path); - return $config->read(); - } -} diff --git a/kirby/src/Blueprint/Factory.php b/kirby/src/Blueprint/Factory.php deleted file mode 100644 index 756611c..0000000 --- a/kirby/src/Blueprint/Factory.php +++ /dev/null @@ -1,119 +0,0 @@ - - * @link https://getkirby.com - * @copyright Bastian Allgeier - * @license https://opensource.org/licenses/MIT - * - * // TODO: include in test coverage once blueprint refactoring is done - * @codeCoverageIgnore - */ -class Factory -{ - /** - * Resolves the properties by - * applying a map of factories (propName => class) - */ - public static function apply(array $properties, array $factories): array - { - foreach ($factories as $property => $class) { - // skip non-existing properties, empty properties - // or properties that are matching objects - if ( - isset($properties[$property]) === false || - $properties[$property] === null || - is_a($properties[$property], $class) === true - ) { - continue; - } - - $properties[$property] = $class::factory($properties[$property]); - } - - return $properties; - } - - public static function forNamedType(ReflectionNamedType|null $type, $value) - { - // get the class name for the single type - $className = $type->getName(); - - // check if there's a factory for the value - if (method_exists($className, 'factory') === true) { - return $className::factory($value); - } - - // try to assign the value directly and trust - // in PHP's type system. - return $value; - } - - public static function forProperties(string $class, array $properties): array - { - foreach ($properties as $property => $value) { - try { - $properties[$property] = static::forProperty($class, $property, $value); - } catch (ReflectionException $e) { - // the property does not exist - unset($properties[$property]); - } - } - - return $properties; - } - - public static function forProperty(string $class, string $property, $value) - { - if (is_null($value) === true) { - return $value; - } - - // instantly assign objects - // PHP's type system will find issues automatically - if (is_object($value) === true) { - return $value; - } - - // get the type for the property - $reflection = new ReflectionProperty($class, $property); - $propType = $reflection->getType(); - - // no type given - if ($propType === null) { - return $value; - } - - // union types - if ($propType instanceof ReflectionUnionType) { - return static::forUnionType($propType, $value); - } - - return static::forNamedType($propType, $value); - } - - /** - * For properties with union types, - * the first named type is used to create - * the factory or pass a built-in value - */ - public static function forUnionType(ReflectionUnionType $type, $value) - { - return static::forNamedType($type->getTypes()[0], $value); - } - - public static function make(string $class, array $properties): object - { - return new $class(...static::forProperties($class, $properties)); - } -} diff --git a/kirby/src/Blueprint/Node.php b/kirby/src/Blueprint/Node.php deleted file mode 100644 index 96d4dca..0000000 --- a/kirby/src/Blueprint/Node.php +++ /dev/null @@ -1,117 +0,0 @@ - - * @link https://getkirby.com - * @copyright Bastian Allgeier - * @license https://opensource.org/licenses/MIT - * - * // TODO: include in test coverage once blueprint refactoring is done - * @codeCoverageIgnore - */ -class Node -{ - public const TYPE = 'node'; - - public function __construct( - public string $id, - public Extension|null $extends = null, - ) { - } - - /** - * Dynamic getter for properties - */ - public function __call(string $name, array $args) - { - $this->defaults(); - return $this->$name; - } - - /** - * Apply default values - */ - public function defaults(): static - { - return $this; - } - - /** - * Creates an instance by a set of array properties. - */ - public static function factory(array $props): static - { - $props = Extension::apply($props); - $props = static::polyfill($props); - return Factory::make(static::class, $props); - } - - public static function load(string|array $props): static - { - // load by path - if (is_string($props) === true) { - $props = static::loadProps($props); - } - - return static::factory($props); - } - - public static function loadProps(string $path): array - { - $config = new Config($path); - $props = $config->read(); - - // add the id if it's not set yet - $props['id'] ??= basename($path); - - return $props; - } - - /** - * Optional method that runs before static::factory sends - * its properties to the instance. This is perfect to clean - * up props or keep deprecated props compatible. - */ - public static function polyfill(array $props): array - { - return $props; - } - - public function render(ModelWithContent $model) - { - // apply default values - $this->defaults(); - - $array = []; - - // go through all public properties - foreach (get_object_vars($this) as $key => $value) { - if (is_object($value) === false && is_resource($value) === false) { - $array[$key] = $value; - continue; - } - - if (method_exists($value, 'render') === true) { - $array[$key] = $value->render($model); - } - } - - return $array; - } - - /** - * Universal setter for properties - */ - public function set(string $property, $value): static - { - $this->$property = Factory::forProperty(static::class, $property, $value); - return $this; - } -} diff --git a/kirby/src/Blueprint/NodeI18n.php b/kirby/src/Blueprint/NodeI18n.php deleted file mode 100644 index 6dc06aa..0000000 --- a/kirby/src/Blueprint/NodeI18n.php +++ /dev/null @@ -1,44 +0,0 @@ - - * @link https://getkirby.com - * @copyright Bastian Allgeier - * @license https://opensource.org/licenses/MIT - * - * // TODO: include in test coverage once blueprint refactoring is done - * @codeCoverageIgnore - */ -class NodeI18n extends NodeProperty -{ - public function __construct( - public array $translations, - ) { - } - - public static function factory($value = null): static|null - { - if ($value === false || $value === null) { - return null; - } - - if (is_array($value) === false) { - $value = ['en' => $value]; - } - - return new static($value); - } - - public function render(ModelWithContent $model): string|null - { - return I18n::translate($this->translations, $this->translations); - } -} diff --git a/kirby/src/Blueprint/NodeIcon.php b/kirby/src/Blueprint/NodeIcon.php deleted file mode 100644 index 3fa672d..0000000 --- a/kirby/src/Blueprint/NodeIcon.php +++ /dev/null @@ -1,27 +0,0 @@ - - * @link https://getkirby.com - * @copyright Bastian Allgeier - * @license https://opensource.org/licenses/MIT - * - * // TODO: include in test coverage once blueprint refactoring is done - * @codeCoverageIgnore - */ -class NodeIcon extends NodeString -{ - public static function field() - { - $field = parent::field(); - $field->id = 'icon'; - $field->label->translations = ['en' => 'Icon']; - - return $field; - } -} diff --git a/kirby/src/Blueprint/NodeProperty.php b/kirby/src/Blueprint/NodeProperty.php deleted file mode 100644 index 6aef2db..0000000 --- a/kirby/src/Blueprint/NodeProperty.php +++ /dev/null @@ -1,27 +0,0 @@ - - * @link https://getkirby.com - * @copyright Bastian Allgeier - * @license https://opensource.org/licenses/MIT - * - * // TODO: include in test coverage once blueprint refactoring is done - * @codeCoverageIgnore - */ -abstract class NodeProperty -{ - abstract public static function factory($value = null): static|null; - - public function render(ModelWithContent $model) - { - return null; - } -} diff --git a/kirby/src/Blueprint/NodeString.php b/kirby/src/Blueprint/NodeString.php deleted file mode 100644 index 1093e1f..0000000 --- a/kirby/src/Blueprint/NodeString.php +++ /dev/null @@ -1,39 +0,0 @@ - - * @link https://getkirby.com - * @copyright Bastian Allgeier - * @license https://opensource.org/licenses/MIT - * - * // TODO: include in test coverage once blueprint refactoring is done - * @codeCoverageIgnore - */ -class NodeString extends NodeProperty -{ - public function __construct( - public string $value, - ) { - } - - public static function factory($value = null): static|null - { - if ($value === null) { - return null; - } - - return new static($value); - } - - public function render(ModelWithContent $model): string|null - { - return $this->value; - } -} diff --git a/kirby/src/Blueprint/NodeText.php b/kirby/src/Blueprint/NodeText.php deleted file mode 100644 index bbc4cd7..0000000 --- a/kirby/src/Blueprint/NodeText.php +++ /dev/null @@ -1,30 +0,0 @@ - - * @link https://getkirby.com - * @copyright Bastian Allgeier - * @license https://opensource.org/licenses/MIT - * - * // TODO: include in test coverage once blueprint refactoring is done - * @codeCoverageIgnore - */ -class NodeText extends NodeI18n -{ - public function render(ModelWithContent $model): string|null - { - if ($text = parent::render($model)) { - return $model->toSafeString($text); - } - - return $text; - } -} diff --git a/kirby/src/Cache/ApcuCache.php b/kirby/src/Cache/ApcuCache.php index ee13215..fb11eda 100644 --- a/kirby/src/Cache/ApcuCache.php +++ b/kirby/src/Cache/ApcuCache.php @@ -15,17 +15,11 @@ use APCUIterator; */ class ApcuCache extends Cache { - /** - * Returns whether the cache is ready to - * store values - */ - public function enabled(): bool - { - return apcu_enabled(); - } - /** * Determines if an item exists in the cache + * + * @param string $key + * @return bool */ public function exists(string $key): bool { @@ -35,19 +29,24 @@ class ApcuCache extends Cache /** * Flushes the entire cache and returns * whether the operation was successful + * + * @return bool */ public function flush(): bool { if (empty($this->options['prefix']) === false) { return apcu_delete(new APCUIterator('!^' . preg_quote($this->options['prefix']) . '!')); + } else { + return apcu_clear_cache(); } - - return apcu_clear_cache(); } /** * Removes an item from the cache and returns * whether the operation was successful + * + * @param string $key + * @return bool */ public function remove(string $key): bool { @@ -57,11 +56,13 @@ class ApcuCache extends Cache /** * Internal method to retrieve the raw cache value; * needs to return a Value object or null if not found + * + * @param string $key + * @return \Kirby\Cache\Value|null */ - public function retrieve(string $key): Value|null + public function retrieve(string $key) { - $value = apcu_fetch($this->key($key)); - return Value::fromJson($value); + return Value::fromJson(apcu_fetch($this->key($key))); } /** @@ -72,12 +73,14 @@ class ApcuCache extends Cache * // put an item in the cache for 15 minutes * $cache->set('value', 'my value', 15); * + * + * @param string $key + * @param mixed $value + * @param int $minutes + * @return bool */ public function set(string $key, $value, int $minutes = 0): bool { - $key = $this->key($key); - $value = (new Value($value, $minutes))->toJson(); - $expires = $this->expiration($minutes); - return apcu_store($key, $value, $expires); + return apcu_store($this->key($key), (new Value($value, $minutes))->toJson(), $this->expiration($minutes)); } } diff --git a/kirby/src/Cache/Cache.php b/kirby/src/Cache/Cache.php index 5b2a05b..5eeaec8 100644 --- a/kirby/src/Cache/Cache.php +++ b/kirby/src/Cache/Cache.php @@ -2,8 +2,6 @@ namespace Kirby\Cache; -use Closure; - /** * Cache foundation * This abstract class is used as @@ -20,11 +18,14 @@ abstract class Cache { /** * Stores all options for the driver + * @var array */ - protected array $options = []; + protected $options = []; /** * Sets all parameters which are needed to connect to the cache storage + * + * @param array $options */ public function __construct(array $options = []) { @@ -32,47 +33,87 @@ abstract class Cache } /** - * Checks when the cache has been created; - * returns the creation timestamp on success - * and false if the item does not exist + * Writes an item to the cache for a given number of minutes and + * returns whether the operation was successful; + * this needs to be defined by the driver + * + * + * // put an item in the cache for 15 minutes + * $cache->set('value', 'my value', 15); + * + * + * @param string $key + * @param mixed $value + * @param int $minutes + * @return bool */ - public function created(string $key): int|false - { - // get the Value object - $value = $this->retrieve($key); + abstract public function set(string $key, $value, int $minutes = 0): bool; - // check for a valid Value object - if ($value instanceof Value === false) { - return false; + /** + * Adds the prefix to the key if given + * + * @param string $key + * @return string + */ + protected function key(string $key): string + { + if (empty($this->options['prefix']) === false) { + $key = $this->options['prefix'] . '/' . $key; } - // return the expires timestamp - return $value->created(); + return $key; } /** - * Returns whether the cache is ready to - * store values + * Internal method to retrieve the raw cache value; + * needs to return a Value object or null if not found; + * this needs to be defined by the driver + * + * @param string $key + * @return \Kirby\Cache\Value|null */ - public function enabled(): bool - { - // TODO: Make this method abstract in a future - // release to ensure that cache drivers override it; - // until then, we assume that the cache is enabled - return true; - } + abstract public function retrieve(string $key); /** - * Determines if an item exists in the cache + * Gets an item from the cache + * + * + * // get an item from the cache driver + * $value = $cache->get('value'); + * + * // return a default value if the requested item isn't cached + * $value = $cache->get('value', 'default value'); + * + * + * @param string $key + * @param mixed $default + * @return mixed */ - public function exists(string $key): bool + public function get(string $key, $default = null) { - return $this->expired($key) === false; - } + // get the Value + $value = $this->retrieve($key); + // check for a valid cache value + if (!is_a($value, 'Kirby\Cache\Value')) { + return $default; + } + + // remove the item if it is expired + if ($value->expires() > 0 && time() >= $value->expires()) { + $this->remove($key); + return $default; + } + + // return the pure value + return $value->value(); + } /** * Calculates the expiration timestamp + * + * @param int $minutes + * @return int */ protected function expiration(int $minutes = 0): int { @@ -89,14 +130,17 @@ abstract class Cache * Checks when an item in the cache expires; * returns the expiry timestamp on success, null if the * item never expires and false if the item does not exist + * + * @param string $key + * @return int|null|false */ - public function expires(string $key): int|false|null + public function expires(string $key) { // get the Value object $value = $this->retrieve($key); // check for a valid Value object - if ($value instanceof Value === false) { + if (!is_a($value, 'Kirby\Cache\Value')) { return false; } @@ -106,6 +150,9 @@ abstract class Cache /** * Checks if an item in the cache is expired + * + * @param string $key + * @return bool */ public function expired(string $key): bool { @@ -113,126 +160,83 @@ abstract class Cache if ($expires === null) { return false; - } - - if (is_int($expires) === false) { + } elseif (!is_int($expires)) { return true; + } else { + return time() >= $expires; } - - return time() >= $expires; } /** - * Flushes the entire cache and returns - * whether the operation was successful; - * this needs to be defined by the driver - */ - abstract public function flush(): bool; - - /** - * Gets an item from the cache + * Checks when the cache has been created; + * returns the creation timestamp on success + * and false if the item does not exist * - * - * // get an item from the cache driver - * $value = $cache->get('value'); - * - * // return a default value if the requested item isn't cached - * $value = $cache->get('value', 'default value'); - * + * @param string $key + * @return int|false */ - public function get(string $key, $default = null) + public function created(string $key) { - // get the Value + // get the Value object $value = $this->retrieve($key); - // check for a valid cache value - if ($value instanceof Value === false) { - return $default; + // check for a valid Value object + if (!is_a($value, 'Kirby\Cache\Value')) { + return false; } - // remove the item if it is expired - if ($value->expires() > 0 && time() >= $value->expires()) { - $this->remove($key); - return $default; - } - - // return the pure value - return $value->value(); - } - - /** - * Returns a value by either getting it from the cache - * or via the callback function which then is stored in - * the cache for future retrieval. This method cannot be - * used for `null` as value to be cached. - * @since 3.8.0 - */ - public function getOrSet( - string $key, - Closure $result, - int $minutes = 0 - ) { - $value = $this->get($key); - $result = $value ?? $result(); - - if ($value === null) { - $this->set($key, $result, $minutes); - } - - return $result; - } - - /** - * Adds the prefix to the key if given - */ - protected function key(string $key): string - { - if (empty($this->options['prefix']) === false) { - $key = $this->options['prefix'] . '/' . $key; - } - - return $key; + // return the expires timestamp + return $value->created(); } /** * Alternate version for Cache::created($key) + * + * @param string $key + * @return int|false */ - public function modified(string $key): int|false + public function modified(string $key) { return static::created($key); } /** - * Returns all passed cache options + * Determines if an item exists in the cache + * + * @param string $key + * @return bool */ - public function options(): array + public function exists(string $key): bool { - return $this->options; + return $this->expired($key) === false; } /** * Removes an item from the cache and returns * whether the operation was successful; * this needs to be defined by the driver + * + * @param string $key + * @return bool */ abstract public function remove(string $key): bool; /** - * Internal method to retrieve the raw cache value; - * needs to return a Value object or null if not found; - * this needs to be defined by the driver - */ - abstract public function retrieve(string $key): Value|null; - - /** - * Writes an item to the cache for a given number of minutes and - * returns whether the operation was successful; + * Flushes the entire cache and returns + * whether the operation was successful; * this needs to be defined by the driver * - * - * // put an item in the cache for 15 minutes - * $cache->set('value', 'my value', 15); - * + * @return bool */ - abstract public function set(string $key, $value, int $minutes = 0): bool; + abstract public function flush(): bool; + + /** + * Returns all passed cache options + * + * @return array + */ + public function options(): array + { + return $this->options; + } } diff --git a/kirby/src/Cache/FileCache.php b/kirby/src/Cache/FileCache.php index 4916dc5..4063263 100644 --- a/kirby/src/Cache/FileCache.php +++ b/kirby/src/Cache/FileCache.php @@ -20,8 +20,10 @@ class FileCache extends Cache { /** * Full root including prefix + * + * @var string */ - protected string $root; + protected $root; /** * Sets all parameters which are needed for the file cache @@ -42,7 +44,6 @@ class FileCache extends Cache // build the full root including prefix $this->root = $this->options['root']; - if (empty($this->options['prefix']) === false) { $this->root .= '/' . $this->options['prefix']; } @@ -51,17 +52,10 @@ class FileCache extends Cache Dir::make($this->root, true); } - /** - * Returns whether the cache is ready to - * store values - */ - public function enabled(): bool - { - return is_writable($this->root) === true; - } - /** * Returns the full root including prefix + * + * @return string */ public function root(): string { @@ -70,6 +64,9 @@ class FileCache extends Cache /** * Returns the full path to a file for a given key + * + * @param string $key + * @return string */ protected function file(string $key): string { @@ -111,9 +108,9 @@ class FileCache extends Cache if (isset($this->options['extension'])) { return $file . '.' . $this->options['extension']; + } else { + return $file; } - - return $file; } /** @@ -124,6 +121,11 @@ class FileCache extends Cache * // put an item in the cache for 15 minutes * $cache->set('value', 'my value', 15); * + * + * @param string $key + * @param mixed $value + * @param int $minutes + * @return bool */ public function set(string $key, $value, int $minutes = 0): bool { @@ -135,8 +137,11 @@ class FileCache extends Cache /** * Internal method to retrieve the raw cache value; * needs to return a Value object or null if not found + * + * @param string $key + * @return \Kirby\Cache\Value|null */ - public function retrieve(string $key): Value|null + public function retrieve(string $key) { $file = $this->file($key); $value = F::read($file); @@ -148,8 +153,11 @@ class FileCache extends Cache * Checks when the cache has been created; * returns the creation timestamp on success * and false if the item does not exist + * + * @param string $key + * @return mixed */ - public function created(string $key): int|false + public function created(string $key) { // use the modification timestamp // as indicator when the cache has been created/overwritten @@ -157,12 +165,15 @@ class FileCache extends Cache // get the file for this cache key $file = $this->file($key); - return file_exists($file) ? filemtime($file) : false; + return file_exists($file) ? filemtime($this->file($key)) : false; } /** * Removes an item from the cache and returns * whether the operation was successful + * + * @param string $key + * @return bool */ public function remove(string $key): bool { @@ -179,6 +190,9 @@ class FileCache extends Cache /** * Removes empty directories safely by checking each directory * up to the root directory + * + * @param string $dir + * @return void */ protected function removeEmptyDirectories(string $dir): void { @@ -188,13 +202,7 @@ class FileCache extends Cache // checks all directory segments until reaching the root directory while (Str::startsWith($dir, $this->root()) === true && $dir !== $this->root()) { - $files = scandir($dir); - - if ($files === false) { - $files = []; // @codeCoverageIgnore - } - - $files = array_diff($files, ['.', '..']); + $files = array_diff(scandir($dir) ?? [], ['.', '..']); if (empty($files) === true && Dir::remove($dir) === true) { // continue with the next level up @@ -204,7 +212,7 @@ class FileCache extends Cache break; } } - } catch (Exception) { // @codeCoverageIgnore + } catch (Exception $e) { // @codeCoverageIgnore // silently stops the process } } @@ -212,13 +220,12 @@ class FileCache extends Cache /** * Flushes the entire cache and returns * whether the operation was successful + * + * @return bool */ public function flush(): bool { - if ( - Dir::remove($this->root) === true && - Dir::make($this->root) === true - ) { + if (Dir::remove($this->root) === true && Dir::make($this->root) === true) { return true; } diff --git a/kirby/src/Cache/MemCached.php b/kirby/src/Cache/MemCached.php index d6b1f89..591919f 100644 --- a/kirby/src/Cache/MemCached.php +++ b/kirby/src/Cache/MemCached.php @@ -16,14 +16,10 @@ use Memcached as MemcachedExt; class MemCached extends Cache { /** - * Store for the memcache connection + * store for the memcache connection + * @var \Memcached */ - protected MemcachedExt $connection; - - /** - * Stores whether the connection was successful - */ - protected bool $enabled; + protected $connection; /** * Sets all parameters which are needed to connect to Memcached @@ -43,19 +39,7 @@ class MemCached extends Cache parent::__construct(array_merge($defaults, $options)); $this->connection = new MemcachedExt(); - $this->enabled = $this->connection->addServer( - $this->options['host'], - $this->options['port'] - ); - } - - /** - * Returns whether the cache is ready to - * store values - */ - public function enabled(): bool - { - return $this->enabled; + $this->connection->addServer($this->options['host'], $this->options['port']); } /** @@ -66,28 +50,35 @@ class MemCached extends Cache * // put an item in the cache for 15 minutes * $cache->set('value', 'my value', 15); * + * + * @param string $key + * @param mixed $value + * @param int $minutes + * @return bool */ public function set(string $key, $value, int $minutes = 0): bool { - $key = $this->key($key); - $value = (new Value($value, $minutes))->toJson(); - $expires = $this->expiration($minutes); - return $this->connection->set($key, $value, $expires); + return $this->connection->set($this->key($key), (new Value($value, $minutes))->toJson(), $this->expiration($minutes)); } /** * Internal method to retrieve the raw cache value; * needs to return a Value object or null if not found + * + * @param string $key + * @return \Kirby\Cache\Value|null */ - public function retrieve(string $key): Value|null + public function retrieve(string $key) { - $value = $this->connection->get($this->key($key)); - return Value::fromJson($value); + return Value::fromJson($this->connection->get($this->key($key))); } /** * Removes an item from the cache and returns * whether the operation was successful + * + * @param string $key + * @return bool */ public function remove(string $key): bool { @@ -98,6 +89,8 @@ class MemCached extends Cache * Flushes the entire cache and returns * whether the operation was successful; * WARNING: Memcached only supports flushing the whole cache at once! + * + * @return bool */ public function flush(): bool { diff --git a/kirby/src/Cache/MemoryCache.php b/kirby/src/Cache/MemoryCache.php index 55fdbc1..3ee6636 100644 --- a/kirby/src/Cache/MemoryCache.php +++ b/kirby/src/Cache/MemoryCache.php @@ -15,17 +15,9 @@ class MemoryCache extends Cache { /** * Cache data + * @var array */ - protected array $store = []; - - /** - * Returns whether the cache is ready to - * store values - */ - public function enabled(): bool - { - return true; - } + protected $store = []; /** * Writes an item to the cache for a given number of minutes and @@ -35,6 +27,11 @@ class MemoryCache extends Cache * // put an item in the cache for 15 minutes * $cache->set('value', 'my value', 15); * + * + * @param string $key + * @param mixed $value + * @param int $minutes + * @return bool */ public function set(string $key, $value, int $minutes = 0): bool { @@ -45,8 +42,11 @@ class MemoryCache extends Cache /** * Internal method to retrieve the raw cache value; * needs to return a Value object or null if not found + * + * @param string $key + * @return \Kirby\Cache\Value|null */ - public function retrieve(string $key): Value|null + public function retrieve(string $key) { return $this->store[$key] ?? null; } @@ -54,20 +54,25 @@ class MemoryCache extends Cache /** * Removes an item from the cache and returns * whether the operation was successful + * + * @param string $key + * @return bool */ public function remove(string $key): bool { if (isset($this->store[$key])) { unset($this->store[$key]); return true; + } else { + return false; } - - return false; } /** * Flushes the entire cache and returns * whether the operation was successful + * + * @return bool */ public function flush(): bool { diff --git a/kirby/src/Cache/NullCache.php b/kirby/src/Cache/NullCache.php index 7c2211d..36b419e 100644 --- a/kirby/src/Cache/NullCache.php +++ b/kirby/src/Cache/NullCache.php @@ -13,15 +13,6 @@ namespace Kirby\Cache; */ class NullCache extends Cache { - /** - * Returns whether the cache is ready to - * store values - */ - public function enabled(): bool - { - return false; - } - /** * Writes an item to the cache for a given number of minutes and * returns whether the operation was successful @@ -30,6 +21,11 @@ class NullCache extends Cache * // put an item in the cache for 15 minutes * $cache->set('value', 'my value', 15); * + * + * @param string $key + * @param mixed $value + * @param int $minutes + * @return bool */ public function set(string $key, $value, int $minutes = 0): bool { @@ -39,8 +35,11 @@ class NullCache extends Cache /** * Internal method to retrieve the raw cache value; * needs to return a Value object or null if not found + * + * @param string $key + * @return \Kirby\Cache\Value|null */ - public function retrieve(string $key): Value|null + public function retrieve(string $key) { return null; } @@ -48,6 +47,9 @@ class NullCache extends Cache /** * Removes an item from the cache and returns * whether the operation was successful + * + * @param string $key + * @return bool */ public function remove(string $key): bool { @@ -57,6 +59,8 @@ class NullCache extends Cache /** * Flushes the entire cache and returns * whether the operation was successful + * + * @return bool */ public function flush(): bool { diff --git a/kirby/src/Cache/Value.php b/kirby/src/Cache/Value.php index 693d95d..3a1105e 100644 --- a/kirby/src/Cache/Value.php +++ b/kirby/src/Cache/Value.php @@ -19,6 +19,7 @@ class Value { /** * Cached value + * @var mixed */ protected $value; @@ -26,31 +27,35 @@ class Value * the number of minutes until the value expires * @todo Rename this property to $expiry to reflect * both minutes and absolute timestamps + * @var int */ - protected int $minutes; + protected $minutes; /** * Creation timestamp + * @var int */ - protected int $created; + protected $created; /** * Constructor * + * @param mixed $value * @param int $minutes the number of minutes until the value expires * or an absolute UNIX timestamp - * @param int|null $created the UNIX timestamp when the value has been created - * (defaults to the current time) + * @param int $created the UNIX timestamp when the value has been created */ - public function __construct($value, int $minutes = 0, int|null $created = null) + public function __construct($value, int $minutes = 0, int $created = null) { $this->value = $value; - $this->minutes = $minutes; + $this->minutes = $minutes ?? 0; $this->created = $created ?? time(); } /** * Returns the creation date as UNIX timestamp + * + * @return int */ public function created(): int { @@ -60,8 +65,10 @@ class Value /** * Returns the expiration date as UNIX timestamp or * null if the value never expires + * + * @return int|null */ - public function expires(): int|null + public function expires(): ?int { // 0 = keep forever if ($this->minutes === 0) { @@ -78,37 +85,41 @@ class Value /** * Creates a value object from an array + * + * @param array $array + * @return static */ - public static function fromArray(array $array): static + public static function fromArray(array $array) { - return new static( - $array['value'] ?? null, - $array['minutes'] ?? 0, - $array['created'] ?? null - ); + return new static($array['value'] ?? null, $array['minutes'] ?? 0, $array['created'] ?? null); } /** * Creates a value object from a JSON string; * returns null on error + * + * @param string $json + * @return static|null */ - public static function fromJson(string $json): static|null + public static function fromJson(string $json) { try { $array = json_decode($json, true); - if (is_array($array) === true) { + if (is_array($array)) { return static::fromArray($array); + } else { + return null; } - - return null; - } catch (Throwable) { + } catch (Throwable $e) { return null; } } /** * Converts the object to a JSON string + * + * @return string */ public function toJson(): string { @@ -117,6 +128,8 @@ class Value /** * Converts the object to an array + * + * @return array */ public function toArray(): array { @@ -129,6 +142,8 @@ class Value /** * Returns the pure value + * + * @return mixed */ public function value() { diff --git a/kirby/src/Cms/Api.php b/kirby/src/Cms/Api.php index 49dcac9..30aa140 100644 --- a/kirby/src/Cms/Api.php +++ b/kirby/src/Cms/Api.php @@ -5,7 +5,6 @@ namespace Kirby\Cms; use Kirby\Api\Api as BaseApi; use Kirby\Exception\NotFoundException; use Kirby\Form\Form; -use Kirby\Session\Session; /** * Api @@ -18,132 +17,114 @@ use Kirby\Session\Session; */ class Api extends BaseApi { - protected App $kirby; - - public function __construct(array $props) - { - $this->kirby = $props['kirby']; - parent::__construct($props); - } + /** + * @var App + */ + protected $kirby; /** * Execute an API call for the given path, * request method and optional request data + * + * @param string|null $path + * @param string $method + * @param array $requestData + * @return mixed */ - public function call( - string|null $path = null, - string $method = 'GET', - array $requestData = [] - ): mixed { + public function call(string $path = null, string $method = 'GET', array $requestData = []) + { $this->setRequestMethod($method); $this->setRequestData($requestData); $this->kirby->setCurrentLanguage($this->language()); $allowImpersonation = $this->kirby()->option('api.allowImpersonation', false); - - $translation = $this->kirby->user(null, $allowImpersonation)?->language(); - $translation ??= $this->kirby->panelLanguage(); + if ($user = $this->kirby->user(null, $allowImpersonation)) { + $translation = $user->language(); + } else { + $translation = $this->kirby->panelLanguage(); + } $this->kirby->setCurrentTranslation($translation); return parent::call($path, $method, $requestData); } /** - * Creates a new instance while - * merging initial and new properties - */ - public function clone(array $props = []): static - { - return parent::clone(array_merge([ - 'kirby' => $this->kirby - ], $props)); - } - - /** + * @param mixed $model + * @param string $name + * @param string|null $path + * @return mixed * @throws \Kirby\Exception\NotFoundException if the field type cannot be found or the field cannot be loaded */ - public function fieldApi( - ModelWithContent $model, - string $name, - string|null $path = null - ): mixed { + public function fieldApi($model, string $name, string $path = null) + { $field = Form::for($model)->field($name); - $fieldApi = $this->clone([ - 'data' => [...$this->data(), 'field' => $field], - 'routes' => $field->api(), - ]); - - return $fieldApi->call( - $path, - $this->requestMethod(), - $this->requestData() + $fieldApi = new static( + array_merge($this->propertyData, [ + 'data' => array_merge($this->data(), ['field' => $field]), + 'routes' => $field->api(), + ]), ); + + return $fieldApi->call($path, $this->requestMethod(), $this->requestData()); } /** * Returns the file object for the given * parent path and filename * - * @param string $path Path to file's parent model + * @param string|null $path Path to file's parent model + * @param string $filename Filename + * @return \Kirby\Cms\File|null * @throws \Kirby\Exception\NotFoundException if the file cannot be found */ - public function file( - string $path, - string $filename - ): File|null { - return Find::file($path, $filename); - } - - /** - * Returns the all readable files for the parent - * - * @param string $path Path to file's parent model - * @throws \Kirby\Exception\NotFoundException if the file cannot be found - */ - public function files(string $path): Files + public function file(string $path = null, string $filename) { - return $this->parent($path)->files()->filter('isAccessible', true); + return Find::file($path, $filename); } /** * Returns the model's object for the given path * * @param string $path Path to parent model + * @return \Kirby\Cms\Model|null * @throws \Kirby\Exception\InvalidArgumentException if the model type is invalid * @throws \Kirby\Exception\NotFoundException if the model cannot be found */ - public function parent(string $path): ModelWithContent|null + public function parent(string $path) { return Find::parent($path); } /** * Returns the Kirby instance + * + * @return \Kirby\Cms\App */ - public function kirby(): App + public function kirby() { return $this->kirby; } /** * Returns the language request header + * + * @return string|null */ - public function language(): string|null + public function language(): ?string { - return - $this->requestQuery('language') ?? - $this->requestHeaders('x-language'); + return $this->requestQuery('language') ?? $this->requestHeaders('x-language'); } /** * Returns the page object for the given id * * @param string $id Page's id + * @return \Kirby\Cms\Page|null * @throws \Kirby\Exception\NotFoundException if the page cannot be found */ - public function page(string $id): Page|null + public function page(string $id) { return Find::page($id); } @@ -152,29 +133,39 @@ class Api extends BaseApi * Returns the subpages for the given * parent. The subpages can be filtered * by status (draft, listed, unlisted, published, all) + * + * @param string|null $parentId + * @param string|null $status + * @return \Kirby\Cms\Pages */ - public function pages( - string|null $parentId = null, - string|null $status = null - ): Pages { + public function pages(string $parentId = null, string $status = null) + { $parent = $parentId === null ? $this->site() : $this->page($parentId); - $pages = match ($status) { - 'all' => $parent->childrenAndDrafts(), - 'draft', 'drafts' => $parent->drafts(), - 'listed' => $parent->children()->listed(), - 'unlisted' => $parent->children()->unlisted(), - 'published' => $parent->children(), - default => $parent->children() - }; - return $pages->filter('isAccessible', true); + switch ($status) { + case 'all': + return $parent->childrenAndDrafts(); + case 'draft': + case 'drafts': + return $parent->drafts(); + case 'listed': + return $parent->children()->listed(); + case 'unlisted': + return $parent->children()->unlisted(); + case 'published': + default: + return $parent->children(); + } } /** * Search for direct subpages of the * given parent + * + * @param string|null $parent + * @return \Kirby\Cms\Pages */ - public function searchPages(string|null $parent = null): Pages + public function searchPages(string $parent = null) { $pages = $this->pages($parent, $this->requestQuery('status')); @@ -185,36 +176,13 @@ class Api extends BaseApi return $pages->query($this->requestBody()); } - /** - * @throws \Kirby\Exception\NotFoundException if the section type cannot be found or the section cannot be loaded - */ - public function sectionApi( - ModelWithContent $model, - string $name, - string|null $path = null - ): mixed { - if (!$section = $model->blueprint()?->section($name)) { - throw new NotFoundException('The section "' . $name . '" could not be found'); - } - - $sectionApi = $this->clone([ - 'data' => [...$this->data(), 'section' => $section], - 'routes' => $section->api(), - ]); - - return $sectionApi->call( - $path, - $this->requestMethod(), - $this->requestData() - ); - } - /** * Returns the current Session instance * * @param array $options Additional options, see the session component + * @return \Kirby\Session\Session */ - public function session(array $options = []): Session + public function session(array $options = []) { return $this->kirby->session(array_merge([ 'detect' => true @@ -222,9 +190,23 @@ class Api extends BaseApi } /** - * Returns the site object + * Setter for the parent Kirby instance + * + * @param \Kirby\Cms\App $kirby + * @return $this */ - public function site(): Site + protected function setKirby(App $kirby) + { + $this->kirby = $kirby; + return $this; + } + + /** + * Returns the site object + * + * @return \Kirby\Cms\Site + */ + public function site() { return $this->kirby->site(); } @@ -235,9 +217,10 @@ class Api extends BaseApi * id is passed * * @param string|null $id User's id + * @return \Kirby\Cms\User|null * @throws \Kirby\Exception\NotFoundException if the user for the given id cannot be found */ - public function user(string|null $id = null): User|null + public function user(string $id = null) { try { return Find::user($id); @@ -252,8 +235,10 @@ class Api extends BaseApi /** * Returns the users collection + * + * @return \Kirby\Cms\Users */ - public function users(): Users + public function users() { return $this->kirby->users(); } diff --git a/kirby/src/Cms/App.php b/kirby/src/Cms/App.php index a29aa14..04cb4be 100644 --- a/kirby/src/Cms/App.php +++ b/kirby/src/Cms/App.php @@ -2,12 +2,8 @@ namespace Kirby\Cms; -use Closure; -use Generator; use Kirby\Data\Data; -use Kirby\Email\Email as BaseEmail; use Kirby\Exception\ErrorPageException; -use Kirby\Exception\Exception; use Kirby\Exception\InvalidArgumentException; use Kirby\Exception\LogicException; use Kirby\Exception\NotFoundException; @@ -16,23 +12,17 @@ use Kirby\Filesystem\F; use Kirby\Http\Environment; use Kirby\Http\Request; use Kirby\Http\Response; -use Kirby\Http\Route; use Kirby\Http\Router; use Kirby\Http\Uri; use Kirby\Http\Visitor; use Kirby\Session\AutoSession; -use Kirby\Session\Session; -use Kirby\Template\Snippet; -use Kirby\Template\Template; use Kirby\Text\KirbyTag; use Kirby\Text\KirbyTags; use Kirby\Toolkit\A; use Kirby\Toolkit\Config; use Kirby\Toolkit\Controller; -use Kirby\Toolkit\LazyValue; -use Kirby\Toolkit\Locale; +use Kirby\Toolkit\Properties; use Kirby\Toolkit\Str; -use Kirby\Uuid\Uuid; use Throwable; /** @@ -55,43 +45,45 @@ class App use AppPlugins; use AppTranslations; use AppUsers; + use Properties; public const CLASS_ALIAS = 'kirby'; - protected static App|null $instance = null; - protected static string|null $version = null; + protected static $instance; + protected static $version; - public array $data = []; + public $data = []; - protected Api|null $api = null; - protected Collections|null $collections = null; - protected Core $core; - protected Language|null $defaultLanguage = null; - protected Environment|null $environment = null; - protected Language|null $language = null; - protected Languages|null $languages = null; - protected ContentLocks|null $locks = null; - protected bool|null $multilang = null; - protected string|null $nonce = null; - protected array $options; - protected string|null $path = null; - protected Request|null $request = null; - protected Responder|null $response = null; - protected Roles|null $roles = null; - protected Ingredients $roots; - protected array|null $routes = null; - protected Router|null $router = null; - protected AutoSession|null $sessionHandler = null; - protected Site|null $site = null; - protected System|null $system = null; - protected Ingredients $urls; - protected Visitor|null $visitor = null; - - protected array $propertyData; + protected $api; + protected $collections; + protected $core; + protected $defaultLanguage; + protected $environment; + protected $language; + protected $languages; + protected $locks; + protected $multilang; + protected $nonce; + protected $options; + protected $path; + protected $request; + protected $response; + protected $roles; + protected $roots; + protected $routes; + protected $router; + protected $sessionHandler; + protected $site; + protected $system; + protected $urls; + protected $user; + protected $users; + protected $visitor; /** * Creates a new App instance * + * @param array $props * @param bool $setInstance If false, the instance won't be set globally */ public function __construct(array $props = [], bool $setInstance = true) @@ -113,8 +105,6 @@ class App $this->handleErrors(); } - $this->propertyData = $props; - // a custom request setup must come before defining the path $this->setRequest($props['request'] ?? null); @@ -126,15 +116,17 @@ class App $this->bakeUrls($props['urls'] ?? []); // configurable properties - $this->setLanguages($props['languages'] ?? null); - $this->setRoles($props['roles'] ?? null); - $this->setSite($props['site'] ?? null); - $this->setUser($props['user'] ?? null); - $this->setUsers($props['users'] ?? null); + $this->setOptionalProperties($props, [ + 'languages', + 'roles', + 'site', + 'user', + 'users' + ]); // set the singleton if (static::$instance === null || $setInstance === true) { - static::$instance = ModelWithContent::$kirby = Model::$kirby = $this; + Model::$kirby = static::$instance = $this; } // setup the I18n class with the translation loader @@ -160,7 +152,7 @@ class App /** * Improved `var_dump` output * - * @codeCoverageIgnore + * @return array */ public function __debugInfo(): array { @@ -171,7 +163,7 @@ class App 'roots' => $this->roots(), 'site' => $this->site(), 'urls' => $this->urls(), - 'version' => static::version(), + 'version' => $this->version(), ]; } @@ -179,8 +171,9 @@ class App * Returns the Api instance * * @internal + * @return \Kirby\Cms\Api */ - public function api(): Api + public function api() { if ($this->api !== null) { return $this->api; @@ -206,18 +199,15 @@ class App /** * Applies a hook to the given value * + * @internal * @param string $name Full event name * @param array $args Associative array of named event arguments * @param string $modify Key in $args that is modified by the hooks * @param \Kirby\Cms\Event|null $originalEvent Event object (internal use) * @return mixed Resulting value as modified by the hooks */ - public function apply( - string $name, - array $args, - string $modify, - Event|null $originalEvent = null - ): mixed { + public function apply(string $name, array $args, string $modify, ?Event $originalEvent = null) + { $event = $originalEvent ?? new Event($name, $args); if ($functions = $this->extension('hooks', $name)) { @@ -250,13 +240,13 @@ class App * * @return $this */ - protected function bakeOptions(): static + protected function bakeOptions() { // convert the old plugin option syntax to the new one foreach ($this->options as $key => $value) { // detect option keys with the `vendor.plugin.option` format if (preg_match('/^([a-z0-9-]+\.[a-z0-9-]+)\.(.*)$/i', $key, $matches) === 1) { - [, $plugin, $option] = $matches; + list(, $plugin, $option) = $matches; // verify that it's really a plugin option if (isset(static::$plugins[str_replace('.', '/', $plugin)]) !== true) { @@ -283,9 +273,10 @@ class App /** * Sets the directory structure * + * @param array|null $roots * @return $this */ - protected function bakeRoots(array $roots = null): static + protected function bakeRoots(array $roots = null) { $roots = array_merge($this->core->roots(), (array)$roots); $this->roots = Ingredients::bake($roots); @@ -295,9 +286,10 @@ class App /** * Sets the Url structure * + * @param array|null $urls * @return $this */ - protected function bakeUrls(array $urls = null): static + protected function bakeUrls(array $urls = null) { $urls = array_merge($this->core->urls(), (array)$urls); $this->urls = Ingredients::bake($urls); @@ -306,6 +298,9 @@ class App /** * Returns all available blueprints for this installation + * + * @param string $type + * @return array */ public function blueprints(string $type = 'pages'): array { @@ -330,8 +325,12 @@ class App /** * Calls any Kirby route + * + * @param string|null $path + * @param string|null $method + * @return mixed */ - public function call(string $path = null, string $method = null): mixed + public function call(string $path = null, string $method = null) { $path ??= $this->path(); $method ??= $this->request()->method(); @@ -342,9 +341,11 @@ class App * Creates an instance with the same * initial properties * + * @param array $props * @param bool $setInstance If false, the instance won't be set globally + * @return static */ - public function clone(array $props = [], bool $setInstance = true): static + public function clone(array $props = [], bool $setInstance = true) { $props = array_replace_recursive($this->propertyData, $props); @@ -359,34 +360,37 @@ class App * by name. All relevant dependencies are * automatically injected * - * @return \Kirby\Toolkit\Collection|null - * @todo 5.0 Add return type declaration + * @param string $name + * @return \Kirby\Cms\Collection|null */ - public function collection(string $name, array $options = []) + public function collection(string $name) { - return $this->collections()->get($name, array_merge($options, [ + return $this->collections()->get($name, [ 'kirby' => $this, - 'site' => $site = $this->site(), - 'pages' => new LazyValue(fn () => $site->children()), - 'users' => new LazyValue(fn () => $this->users()) - - ])); + 'site' => $this->site(), + 'pages' => $this->site()->children(), + 'users' => $this->users() + ]); } /** * Returns all user-defined collections + * + * @return \Kirby\Cms\Collections */ - public function collections(): Collections + public function collections() { - return $this->collections ??= new Collections(); + return $this->collections = $this->collections ?? new Collections(); } /** * Returns a core component * * @internal + * @param string $name + * @return mixed */ - public function component(string $name): mixed + public function component($name) { return $this->extensions['components'][$name] ?? null; } @@ -395,6 +399,7 @@ class App * Returns the content extension * * @internal + * @return string */ public function contentExtension(): string { @@ -405,6 +410,7 @@ class App * Returns files that should be ignored when scanning folders * * @internal + * @return array */ public function contentIgnore(): array { @@ -417,8 +423,9 @@ class App * * @param mixed $model Object to pass to the salt callback if configured * @param string $value Model data to include in the generated token + * @return string */ - public function contentToken(mixed $model, string $value): string + public function contentToken($model, string $value): string { if (method_exists($model, 'root') === true) { $default = $model->root(); @@ -428,7 +435,7 @@ class App $salt = $this->option('content.salt', $default); - if ($salt instanceof Closure) { + if (is_a($salt, 'Closure') === true) { $salt = $salt($model); } @@ -438,12 +445,15 @@ class App /** * Calls a page controller by name * and with the given arguments + * + * @internal + * @param string $name + * @param array $arguments + * @param string $contentType + * @return array */ - public function controller( - string $name, - array $arguments = [], - string $contentType = 'html' - ): array { + public function controller(string $name, array $arguments = [], string $contentType = 'html'): array + { $name = basename(strtolower($name)); if ($controller = $this->controllerLookup($name, $contentType)) { @@ -468,26 +478,25 @@ class App /** * Try to find a controller by name + * + * @param string $name + * @param string $contentType + * @return \Kirby\Toolkit\Controller|null */ - protected function controllerLookup( - string $name, - string $contentType = 'html' - ): Controller|null { + protected function controllerLookup(string $name, string $contentType = 'html') + { if ($contentType !== null && $contentType !== 'html') { $name .= '.' . $contentType; } - // controller from site root - $controller = Controller::load($this->root('controllers') . '/' . $name . '.php'); - // controller from extension - $controller ??= $this->extension('controllers', $name); - - if ($controller instanceof Controller) { + // controller on disk + if ($controller = Controller::load($this->root('controllers') . '/' . $name . '.php')) { return $controller; } - if ($controller !== null) { - return new Controller($controller); + // registry controller + if ($controller = $this->extension('controllers', $name)) { + return is_a($controller, 'Kirby\Toolkit\Controller') ? $controller : new Controller($controller); } return null; @@ -496,8 +505,10 @@ class App /** * Get access to object that lists * all parts of Kirby core + * + * @return \Kirby\Cms\Core */ - public function core(): Core + public function core() { return $this->core; } @@ -509,7 +520,7 @@ class App * @param string|null $check Pass a token here to compare it to the one in the session * @return string|bool Either the token or a boolean check result */ - public function csrf(string|null $check = null): string|bool + public function csrf(?string $check = null) { $session = $this->session(); @@ -539,20 +550,14 @@ class App return false; } - /** - * Returns the current language, if set by `static::setCurrentLanguage` - */ - public function currentLanguage(): Language|null - { - return $this->language ??= $this->defaultLanguage(); - } - /** * Returns the default language object + * + * @return \Kirby\Cms\Language|null */ - public function defaultLanguage(): Language|null + public function defaultLanguage() { - return $this->defaultLanguage ??= $this->languages()->default(); + return $this->defaultLanguage = $this->defaultLanguage ?? $this->languages()->default(); } /** @@ -569,28 +574,22 @@ class App /** * Detect the preferred language from the visitor object + * + * @return \Kirby\Cms\Language */ - public function detectedLanguage(): Language|null + public function detectedLanguage() { $languages = $this->languages(); $visitor = $this->visitor(); - foreach ($visitor->acceptedLanguages() as $acceptedLang) { - $closure = function ($language) use ($acceptedLang) { - $languageLocale = $language->locale(LC_ALL); - $acceptedLocale = $acceptedLang->locale(); - - return $languageLocale === $acceptedLocale || - $acceptedLocale === Str::substr($languageLocale, 0, 2); - }; - - if ($language = $languages->filter($closure)?->first()) { + foreach ($visitor->acceptedLanguages() as $lang) { + if ($language = $languages->findBy('locale', $lang->locale(LC_ALL))) { return $language; } } - foreach ($visitor->acceptedLanguages() as $acceptedLang) { - if ($language = $languages->findBy('code', $acceptedLang->code())) { + foreach ($visitor->acceptedLanguages() as $lang) { + if ($language = $languages->findBy('code', $lang->code())) { return $language; } } @@ -600,8 +599,12 @@ class App /** * Returns the Email singleton + * + * @param mixed $preset + * @param array $props + * @return \Kirby\Email\Email */ - public function email(mixed $preset = [], array $props = []): BaseEmail + public function email($preset = [], array $props = []) { $debug = $props['debug'] ?? false; $props = (new Email($preset, $props))->toArray(); @@ -612,40 +615,46 @@ class App /** * Returns the environment object with access * to the detected host, base url and dedicated options + * + * @return \Kirby\Http\Environment */ - public function environment(): Environment + public function environment() { - return $this->environment ??= new Environment(); + return $this->environment ?? new Environment(); } /** * Finds any file in the content directory + * + * @param string $path + * @param mixed $parent + * @param bool $drafts + * @return \Kirby\Cms\File|null */ - public function file( - string $path, - mixed $parent = null, - bool $drafts = true - ): File|null { - // find by global UUID - if (Uuid::is($path, 'file') === true) { - // prefer files of parent, when parent given - return Uuid::for($path, $parent?->files())->model(); - } - - $parent ??= $this->site(); + public function file(string $path, $parent = null, bool $drafts = true) + { + $parent = $parent ?? $this->site(); $id = dirname($path); $filename = basename($path); - if ($parent instanceof User) { + if (is_a($parent, 'Kirby\Cms\User') === true) { return $parent->file($filename); } - if ($parent instanceof File) { + if (is_a($parent, 'Kirby\Cms\File') === true) { $parent = $parent->parent(); } if ($id === '.') { - return $parent->file($filename) ?? $this->site()->file($filename); + if ($file = $parent->file($filename)) { + return $file; + } + + if ($file = $this->site()->file($filename)) { + return $file; + } + + return null; } if ($page = $this->page($id, $parent, $drafts)) { @@ -664,11 +673,14 @@ class App * specified by the path * * Example: - * image('some/page/myimage.jpg') ?> + * + * + * @param string|null $path + * @return \Kirby\Cms\File|null * * @todo merge with App::file() */ - public function image(string|null $path = null): File|null + public function image(?string $path = null) { if ($path === null) { return $this->site()->page()->image(); @@ -681,34 +693,43 @@ class App $uri = null; } - $parent = match ($uri) { - '/' => $this->site(), - null => $this->site()->page(), - default => $this->site()->page($uri) - }; + switch ($uri) { + case '/': + $parent = $this->site(); + break; + case null: + $parent = $this->site()->page(); + break; + default: + $parent = $this->site()->page($uri); + break; + } - return $parent?->image($filename); + if ($parent) { + return $parent->image($filename); + } + + return null; } /** * Returns the current App instance * + * @param \Kirby\Cms\App|null $instance * @param bool $lazy If `true`, the instance is only returned if already existing - * @psalm-return ($lazy is false ? static : static|null) + * @return static|null */ - public static function instance( - self $instance = null, - bool $lazy = false - ): static|null { - if ($instance !== null) { - return static::$instance = $instance; + public static function instance(self $instance = null, bool $lazy = false) + { + if ($instance === null) { + if ($lazy === true) { + return static::$instance; + } else { + return static::$instance ?? new static(); + } } - if ($lazy === true) { - return static::$instance; - } - - return static::$instance ?? new static(); + return static::$instance = $instance; } /** @@ -716,15 +737,17 @@ class App * tries to convert it into a valid response * * @internal + * @param mixed $input + * @return \Kirby\Http\Response */ - public function io(mixed $input): Response + public function io($input) { // use the current response configuration $response = $this->response(); // any direct exception will be turned into an error page - if ($input instanceof Throwable) { - if ($input instanceof Exception) { + if (is_a($input, 'Throwable') === true) { + if (is_a($input, 'Kirby\Exception\Exception') === true) { $code = $input->getHttpCode(); } else { $code = $input->getCode(); @@ -755,7 +778,7 @@ class App } // (Modified) global response configuration, e.g. in routes - if ($input instanceof Responder) { + if (is_a($input, 'Kirby\Cms\Responder') === true) { // return the passed object unmodified (without injecting headers // from the global object) to allow a complete response override // https://github.com/getkirby/kirby/pull/4144#issuecomment-1034766726 @@ -763,41 +786,37 @@ class App } // Responses - if ($input instanceof Response) { + if (is_a($input, 'Kirby\Http\Response') === true) { $data = $input->toArray(); // inject headers from the global response configuration // lazily (only if they are not already set); // the case-insensitive nature of headers will be // handled by PHP's `header()` function - $data['headers'] = array_merge( - $response->headers(), - $data['headers'] - ); + $data['headers'] = array_merge($response->headers(), $data['headers']); return new Response($data); } // Pages - if ($input instanceof Page) { + if (is_a($input, 'Kirby\Cms\Page')) { try { $html = $input->render(); } catch (ErrorPageException $e) { return $this->io($e); } - if ( - $input->isErrorPage() === true && - $response->code() === null - ) { - $response->code(404); + if ($input->isErrorPage() === true) { + if ($response->code() === null) { + $response->code(404); + } } return $response->send($html); } // Files - if ($input instanceof File) { + if (is_a($input, 'Kirby\Cms\File')) { return $response->redirect($input->mediaUrl(), 307)->send(); } @@ -820,13 +839,13 @@ class App * @internal * @param string|array $type Tag type or array with all tag arguments * (the key of the first element becomes the type) + * @param string|null $value + * @param array $attr + * @param array $data + * @return string */ - public function kirbytag( - string|array $type, - string|null $value = null, - array $attr = [], - array $data = [] - ): string { + public function kirbytag($type, ?string $value = null, array $attr = [], array $data = []): string + { if (is_array($type) === true) { $kirbytag = $type; $type = key($kirbytag); @@ -840,9 +859,9 @@ class App } } - $data['kirby'] ??= $this; - $data['site'] ??= $data['kirby']->site(); - $data['parent'] ??= $data['site']->page(); + $data['kirby'] = $data['kirby'] ?? $this; + $data['site'] = $data['site'] ?? $data['kirby']->site(); + $data['parent'] = $data['parent'] ?? $data['site']->page(); return (new KirbyTag($type, $value, $attr, $data, $this->options))->render(); } @@ -851,6 +870,9 @@ class App * KirbyTags Parser * * @internal + * @param string|null $text + * @param array $data + * @return string */ public function kirbytags(string $text = null, array $data = []): string { @@ -871,12 +893,26 @@ class App * Parses KirbyTags first and Markdown afterwards * * @internal + * @param string|null $text + * @param array $options + * @param bool $inline (deprecated: use $options['markdown']['inline'] instead) + * @return string + * @todo remove $inline parameter in in 3.8.0 */ - public function kirbytext(string $text = null, array $options = []): string + public function kirbytext(string $text = null, array $options = [], bool $inline = false): string { + // warning for deprecated fourth parameter + // @codeCoverageIgnoreStart + if (func_num_args() === 3) { + Helpers::deprecated('Cms\App::kirbytext(): the $inline parameter is deprecated and will be removed in Kirby 3.8.0. Use $options[\'markdown\'][\'inline\'] instead.'); + } + // @codeCoverageIgnoreEnd + + $options['markdown']['inline'] ??= $inline; + $text = $this->apply('kirbytext:before', compact('text'), 'text'); $text = $this->kirbytags($text, $options); - $text = $this->markdown($text, $options['markdown'] ?? []); + $text = $this->markdown($text, $options['markdown']); if ($this->option('smartypants', false) !== false) { $text = $this->smartypants($text); @@ -888,42 +924,52 @@ class App } /** - * Returns the language by code or shortcut (`default`, `current`). - * Passing `null` is an alias for passing `current` + * Returns the current language + * + * @param string|null $code + * @return \Kirby\Cms\Language|null */ - public function language(string $code = null): Language|null + public function language(string $code = null) { if ($this->multilang() === false) { return null; } - return match ($code ?? 'current') { - 'default' => $this->defaultLanguage(), - 'current' => $this->currentLanguage(), - default => $this->languages()->find($code) - }; + if ($code === 'default') { + return $this->languages()->default(); + } + + if ($code !== null) { + return $this->languages()->find($code); + } + + return $this->language = $this->language ?? $this->languages()->default(); } /** * Returns the current language code * * @internal + * @param string|null $languageCode + * @return string|null */ - public function languageCode(string $languageCode = null): string|null + public function languageCode(string $languageCode = null): ?string { - return $this->language($languageCode)?->code(); + if ($language = $this->language($languageCode)) { + return $language->code(); + } + + return null; } /** * Returns all available site languages + * + * @param bool + * @return \Kirby\Cms\Languages */ - public function languages(bool $clone = true): Languages + public function languages(bool $clone = true) { - if ($clone === false) { - $this->multilang = null; - $this->defaultLanguage = null; - } - if ($this->languages !== null) { return $clone === true ? clone $this->languages : $this->languages; } @@ -933,88 +979,105 @@ class App /** * Access Kirby's part loader + * + * @return \Kirby\Cms\Loader */ - public function load(): Loader + public function load() { return new Loader($this); } /** * Returns the app's locks object + * + * @return \Kirby\Cms\ContentLocks */ public function locks(): ContentLocks { - return $this->locks ??= new ContentLocks(); + if ($this->locks !== null) { + return $this->locks; + } + + return $this->locks = new ContentLocks(); } /** * Parses Markdown * * @internal + * @param string|null $text + * @param bool|array $options Boolean inline value is deprecated, use `['inline' => true]` instead + * @return string + * @todo remove boolean $options in in 3.8.0 */ - public function markdown(string $text = null, array $options = null): string + public function markdown(string $text = null, $options = null): string { + // support for the old syntax to enable inline mode as second argument + // @codeCoverageIgnoreStart + if (is_bool($options) === true) { + Helpers::deprecated('Cms\App::markdown(): Passing a boolean as second parameter has been deprecated and won\'t be supported anymore in Kirby 3.8.0. Instead pass array with the key "inline" set to true or false.'); + + $options = [ + 'inline' => $options + ]; + } + // @codeCoverageIgnoreEnd + // merge global options with local options $options = array_merge( $this->options['markdown'] ?? [], (array)$options ); - return ($this->component('markdown'))($this, $text, $options); - } - - /** - * Yields all models (site, pages, files and users) of this site - * @since 4.0.0 - * - * @return \Generator|\Kirby\Cms\ModelWithContent[] - */ - public function models(): Generator - { - $site = $this->site(); - - yield from $site->files(); - yield $site; - - foreach ($site->index(true) as $page) { - yield from $page->files(); - yield $page; - } - - foreach ($this->users() as $user) { - yield from $user->files(); - yield $user; - } + // TODO: remove passing the $inline parameter in 3.8.0 + // $options['inline'] is set to `false` to avoid the deprecation + // warning in the component; this can also be removed in 3.8.0 + $inline = $options['inline'] ??= false; + return ($this->component('markdown'))($this, $text, $options, $inline); } /** * Check for a multilang setup + * + * @return bool */ public function multilang(): bool { - return $this->multilang ??= $this->languages()->count() !== 0; + if ($this->multilang !== null) { + return $this->multilang; + } + + return $this->multilang = $this->languages()->count() !== 0; } /** * Returns the nonce, which is used * in the panel for inline scripts * @since 3.3.0 + * + * @return string */ public function nonce(): string { - return $this->nonce ??= base64_encode(random_bytes(20)); + return $this->nonce = $this->nonce ?? base64_encode(random_bytes(20)); } /** * Load a specific configuration option + * + * @param string $key + * @param mixed $default + * @return mixed */ - public function option(string $key, mixed $default = null): mixed + public function option(string $key, $default = null) { return A::get($this->options, $key, $default); } /** * Returns all configuration options + * + * @return array */ public function options(): array { @@ -1023,6 +1086,8 @@ class App /** * Load all options from files in site/config + * + * @return array */ protected function optionsFromConfig(): array { @@ -1031,7 +1096,7 @@ class App // load the main config options $root = $this->root('config'); - $options = F::load($root . '/config.php', [], allowOutput: false); + $options = F::load($root . '/config.php', []); // merge into one clean options array return $this->options = array_replace_recursive(Config::$data, $options); @@ -1040,30 +1105,25 @@ class App /** * Load all options for the current * server environment + * + * @param array $props + * @return array */ protected function optionsFromEnvironment(array $props = []): array { - $root = $this->root('config'); + $globalUrl = $this->options['url'] ?? null; - // first load `config/env.php` to access its `url` option - $envOptions = F::load($root . '/env.php', [], allowOutput: false); - - // use the option from the main `config.php`, - // but allow the `env.php` to override it - $globalUrl = $envOptions['url'] ?? $this->options['url'] ?? null; - - // create the URL setup based on hostname and server IP address + // create the environment based on the URL setup $this->environment = new Environment([ 'allowed' => $globalUrl, 'cli' => $props['cli'] ?? null, ], $props['server'] ?? null); - // merge into one clean options array; - // the `env.php` options always override everything else - $hostAddrOptions = $this->environment()->options($root); - $this->options = array_replace_recursive($this->options, $hostAddrOptions, $envOptions); + // merge into one clean options array + $options = $this->environment()->options($this->root('config')); + $this->options = array_replace_recursive($this->options, $options); - // reload the environment if the host/address config has overridden + // reload the environment if the environment config has overridden // the `url` option; this ensures that the base URL is correct $envUrl = $this->options['url'] ?? null; if ($envUrl !== $globalUrl) { @@ -1078,6 +1138,9 @@ class App /** * Inject options from Kirby instance props + * + * @param array $options + * @return array */ protected function optionsFromProps(array $options = []): array { @@ -1089,13 +1152,12 @@ class App /** * Merge last-minute options from ready callback + * + * @return array */ protected function optionsFromReadyCallback(): array { - if ( - isset($this->options['ready']) === true && - is_callable($this->options['ready']) === true - ) { + if (isset($this->options['ready']) === true && is_callable($this->options['ready']) === true) { // fetch last-minute options from the callback $options = (array)$this->options['ready']($this); @@ -1133,17 +1195,19 @@ class App /** * Returns any page from the content folder + * + * @param string|null $id + * @param \Kirby\Cms\Page|\Kirby\Cms\Site|null $parent + * @param bool $drafts + * @return \Kirby\Cms\Page|null */ - public function page( - string|null $id = null, - Page|Site|null $parent = null, - bool $drafts = true - ): Page|null { + public function page(?string $id = null, $parent = null, bool $drafts = true) + { if ($id === null) { return null; } - $parent ??= $this->site(); + $parent = $parent ?? $this->site(); if ($page = $parent->find($id)) { /** @@ -1162,6 +1226,8 @@ class App /** * Returns the request path + * + * @return string */ public function path(): string { @@ -1179,22 +1245,22 @@ class App /** * Returns the Response object for the * current request + * + * @param string|null $path + * @param string|null $method + * @return \Kirby\Http\Response */ - public function render( - string $path = null, - string $method = null - ): Response|null { - if (($_ENV['KIRBY_RENDER'] ?? true) === false) { - return null; - } - + public function render(string $path = null, string $method = null) + { return $this->io($this->call($path, $method)); } /** * Returns the Request singleton + * + * @return \Kirby\Http\Request */ - public function request(): Request + public function request() { if ($this->request !== null) { return $this->request; @@ -1212,9 +1278,12 @@ class App * Path resolver for the router * * @internal + * @param string|null $path + * @param string|null $language + * @return mixed * @throws \Kirby\Exception\NotFoundException if the home page cannot be found */ - public function resolve(string|null $path = null, string|null $language = null): mixed + public function resolve(string $path = null, string $language = null) { // set the current translation $this->setCurrentTranslation($language); @@ -1222,11 +1291,6 @@ class App // set the current locale $this->setCurrentLanguage($language); - // directly prevent path with incomplete content representation - if (Str::endsWith($path, '.') === true) { - return null; - } - // the site is needed a couple times here $site = $this->site(); @@ -1244,10 +1308,7 @@ class App // search for a draft if the page cannot be found if (!$page && $draft = $site->draft($path)) { - if ( - $this->user() || - $draft->isVerified($this->request()->get('token')) - ) { + if ($this->user() || $draft->isVerified($this->request()->get('token'))) { $page = $draft; } } @@ -1274,7 +1335,7 @@ class App } return $response->body($output); - } catch (NotFoundException) { + } catch (NotFoundException $e) { return null; } } @@ -1293,40 +1354,51 @@ class App /** * Response configuration + * + * @return \Kirby\Cms\Responder */ - public function response(): Responder + public function response() { - return $this->response ??= new Responder(); + return $this->response = $this->response ?? new Responder(); } /** * Returns all user roles + * + * @return \Kirby\Cms\Roles */ - public function roles(): Roles + public function roles() { - return $this->roles ??= Roles::load($this->root('roles')); + return $this->roles = $this->roles ?? Roles::load($this->root('roles')); } /** * Returns a system root + * + * @param string $type + * @return string|null */ - public function root(string $type = 'index'): string|null + public function root(string $type = 'index'): ?string { return $this->roots->__get($type); } /** * Returns the directory structure + * + * @return \Kirby\Cms\Ingredients */ - public function roots(): Ingredients + public function roots() { return $this->roots; } /** * Returns the currently active route + * + * @return \Kirby\Http\Route|null */ - public function route(): Route|null + public function route() { return $this->router()->route(); } @@ -1335,13 +1407,10 @@ class App * Returns the Router singleton * * @internal + * @return \Kirby\Http\Router */ - public function router(): Router + public function router() { - if ($this->router !== null) { - return $this->router; - } - $routes = $this->routes(); if ($this->multilang() === true) { @@ -1361,13 +1430,14 @@ class App } ]; - return $this->router = new Router($routes, $hooks); + return $this->router ??= new Router($routes, $hooks); } /** * Returns all defined routes * * @internal + * @return array */ public function routes(): array { @@ -1386,8 +1456,9 @@ class App * Returns the current session object * * @param array $options Additional options, see the session component + * @return \Kirby\Session\Session */ - public function session(array $options = []): Session + public function session(array $options = []) { $session = $this->sessionHandler()->get($options); @@ -1403,45 +1474,22 @@ class App /** * Returns the session handler - */ - public function sessionHandler(): AutoSession - { - return $this->sessionHandler ??= new AutoSession( - $this->root('sessions'), - $this->option('session', []) - ); - } - - /** - * Load and set the current language if it exists - * Otherwise fall back to the default language * - * @internal + * @return \Kirby\Session\AutoSession */ - public function setCurrentLanguage( - string|null $languageCode = null - ): Language|null { - if ($this->multilang() === false) { - Locale::set($this->option('locale', 'en_US.utf-8')); - return $this->language = null; - } - - $this->language = $this->language($languageCode) ?? $this->defaultLanguage(); - - Locale::set($this->language->locale()); - - // add language slug rules to Str class - Str::$language = $this->language->rules(); - - return $this->language; + public function sessionHandler() + { + $this->sessionHandler = $this->sessionHandler ?? new AutoSession($this->root('sessions'), $this->option('session', [])); + return $this->sessionHandler; } /** * Create your own set of languages * + * @param array|null $languages * @return $this */ - protected function setLanguages(array $languages = null): static + protected function setLanguages(array $languages = null) { if ($languages !== null) { $objects = []; @@ -1460,9 +1508,10 @@ class App * Sets the request path that is * used for the router * + * @param string|null $path * @return $this */ - protected function setPath(string $path = null): static + protected function setPath(string $path = null) { $this->path = $path !== null ? trim($path, '/') : null; return $this; @@ -1471,9 +1520,10 @@ class App /** * Sets the request * + * @param array|null $request * @return $this */ - protected function setRequest(array $request = null): static + protected function setRequest(array $request = null) { if ($request !== null) { $this->request = new Request($request); @@ -1485,12 +1535,15 @@ class App /** * Create your own set of roles * + * @param array|null $roles * @return $this */ - protected function setRoles(array $roles = null): static + protected function setRoles(array $roles = null) { if ($roles !== null) { - $this->roles = Roles::factory($roles); + $this->roles = Roles::factory($roles, [ + 'kirby' => $this + ]); } return $this; @@ -1499,12 +1552,15 @@ class App /** * Sets a custom Site object * + * @param \Kirby\Cms\Site|array|null $site * @return $this */ - protected function setSite(Site|array $site = null): static + protected function setSite($site = null) { if (is_array($site) === true) { - $site = new Site($site); + $site = new Site($site + [ + 'kirby' => $this + ]); } $this->site = $site; @@ -1512,13 +1568,30 @@ class App } /** - * Initializes and returns the Site object + * Returns the Environment object + * @deprecated 3.7.0 Use `$kirby->environment()` instead + * + * @return \Kirby\Http\Environment + * @todo Start throwing deprecation warnings in 3.8.0 + * @todo Remove in 3.9.0 + * @codeCoverageIgnore */ - public function site(): Site + public function server() { - return $this->site ??= new Site([ + return $this->environment(); + } + + /** + * Initializes and returns the Site object + * + * @return \Kirby\Cms\Site + */ + public function site() + { + return $this->site = $this->site ?? new Site([ 'errorPageId' => $this->options['error'] ?? 'error', 'homePageId' => $this->options['home'] ?? 'home', + 'kirby' => $this, 'url' => $this->url('index'), ]); } @@ -1527,6 +1600,8 @@ class App * Applies the smartypants rule on the text * * @internal + * @param string|null $text + * @return string */ public function smartypants(string $text = null): string { @@ -1534,9 +1609,7 @@ class App if ($options === false) { return $text; - } - - if (is_array($options) === false) { + } elseif (is_array($options) === false) { $options = []; } @@ -1555,28 +1628,21 @@ class App * Uses the snippet component to create * and return a template snippet * + * @internal + * @param mixed $name * @param array|object $data Variables or an object that becomes `$item` * @param bool $return On `false`, directly echo the snippet - * @psalm-return ($return is true ? string : null) + * @return string|null */ - public function snippet( - string|array|null $name, - array|object $data = [], - bool $return = true, - bool $slots = false - ): Snippet|string|null { + public function snippet($name, $data = [], bool $return = true): ?string + { if (is_object($data) === true) { $data = ['item' => $data]; } - $snippet = ($this->component('snippet'))( - $this, - $name, - array_merge($this->data, $data), - $slots - ); + $snippet = ($this->component('snippet'))($this, $name, array_merge($this->data, $data)); - if ($return === true || $slots === true) { + if ($return === true) { return $snippet; } @@ -1586,10 +1652,12 @@ class App /** * System check class + * + * @return \Kirby\Cms\System */ - public function system(): System + public function system() { - return $this->system ??= new System($this); + return $this->system = $this->system ?? new System($this); } /** @@ -1597,17 +1665,23 @@ class App * and return the Template object * * @internal + * @return \Kirby\Cms\Template + * @param string $name + * @param string $type + * @param string $defaultType */ - public function template( - string $name, - string $type = 'html', - string $defaultType = 'html' - ): Template { + public function template(string $name, string $type = 'html', string $defaultType = 'html') + { return ($this->component('template'))($this, $name, $type, $defaultType); } /** * Thumbnail creator + * + * @param string $src + * @param string $dst + * @param array $options + * @return string */ public function thumb(string $src, string $dst, array $options = []): string { @@ -1617,15 +1691,14 @@ class App /** * Trigger a hook by name * + * @internal * @param string $name Full event name * @param array $args Associative array of named event arguments * @param \Kirby\Cms\Event|null $originalEvent Event object (internal use) + * @return void */ - public function trigger( - string $name, - array $args = [], - Event|null $originalEvent = null - ): void { + public function trigger(string $name, array $args = [], ?Event $originalEvent = null) + { $event = $originalEvent ?? new Event($name, $args); if ($functions = $this->extension('hooks', $name)) { @@ -1664,13 +1737,12 @@ class App /** * Returns a system url * + * @param string $type * @param bool $object If set to `true`, the URL is converted to an object - * @psalm-return ($object is false ? string|null : \Kirby\Http\Uri) + * @return string|\Kirby\Http\Uri|null */ - public function url( - string $type = 'index', - bool $object = false - ): string|Uri|null { + public function url(string $type = 'index', bool $object = false) + { $url = $this->urls->__get($type); if ($object === true) { @@ -1690,8 +1762,10 @@ class App /** * Returns the url structure + * + * @return \Kirby\Cms\Ingredients */ - public function urls(): Ingredients + public function urls() { return $this->urls; } @@ -1700,19 +1774,22 @@ class App * Returns the current version number from * the composer.json (Keep that up to date! :)) * + * @return string|null * @throws \Kirby\Exception\LogicException if the Kirby version cannot be detected */ - public static function version(): string|null + public static function version(): ?string { try { - return static::$version ??= Data::read(dirname(__DIR__, 2) . '/composer.json')['version'] ?? null; - } catch (Throwable) { + return static::$version = static::$version ?? Data::read(dirname(__DIR__, 2) . '/composer.json')['version'] ?? null; + } catch (Throwable $e) { throw new LogicException('The Kirby version cannot be detected. The composer.json is probably missing or not readable.'); } } /** * Creates a hash of the version number + * + * @return string */ public static function versionHash(): string { @@ -1721,9 +1798,11 @@ class App /** * Returns the visitor object + * + * @return \Kirby\Http\Visitor */ - public function visitor(): Visitor + public function visitor() { - return $this->visitor ??= new Visitor(); + return $this->visitor = $this->visitor ?? new Visitor(); } } diff --git a/kirby/src/Cms/AppCaches.php b/kirby/src/Cms/AppCaches.php index 6c1595c..2bea1ed 100644 --- a/kirby/src/Cms/AppCaches.php +++ b/kirby/src/Cms/AppCaches.php @@ -2,7 +2,6 @@ namespace Kirby\Cms; -use Kirby\Cache\Cache; use Kirby\Cache\NullCache; use Kirby\Exception\InvalidArgumentException; @@ -17,12 +16,15 @@ use Kirby\Exception\InvalidArgumentException; */ trait AppCaches { - protected array $caches = []; + protected $caches = []; /** * Returns a cache instance by key + * + * @param string $key + * @return \Kirby\Cache\Cache */ - public function cache(string $key): Cache + public function cache(string $key) { if (isset($this->caches[$key]) === true) { return $this->caches[$key]; @@ -41,7 +43,7 @@ trait AppCaches if (array_key_exists($type, $types) === false) { throw new InvalidArgumentException([ - 'key' => 'cache.type.invalid', + 'key' => 'app.invalid.cacheType', 'data' => ['type' => $type] ]); } @@ -52,9 +54,9 @@ trait AppCaches $cache = new $className($options); // check if it is a usable cache object - if ($cache instanceof Cache === false) { + if (is_a($cache, 'Kirby\Cache\Cache') !== true) { throw new InvalidArgumentException([ - 'key' => 'cache.type.invalid', + 'key' => 'app.invalid.cacheType', 'data' => ['type' => $type] ]); } @@ -64,11 +66,13 @@ trait AppCaches /** * Returns the cache options by key + * + * @param string $key + * @return array */ protected function cacheOptions(string $key): array { - $options = $this->option($this->cacheOptionsKey($key), null); - $options ??= $this->core()->caches()[$key] ?? false; + $options = $this->option($this->cacheOptionsKey($key), false); if ($options === false) { return [ @@ -76,10 +80,9 @@ trait AppCaches ]; } - $prefix = - str_replace(['/', ':'], '_', $this->system()->indexUrl()) . - '/' . - str_replace('.', '/', $key); + $prefix = str_replace(['/', ':'], '_', $this->system()->indexUrl()) . + '/' . + str_replace('.', '/', $key); $defaults = [ 'active' => true, @@ -91,15 +94,18 @@ trait AppCaches if ($options === true) { return $defaults; + } else { + return array_merge($defaults, $options); } - - return array_merge($defaults, $options); } /** * Takes care of converting prefixed plugin cache setups * to the right cache key, while leaving regular cache * setups untouched. + * + * @param string $key + * @return string */ protected function cacheOptionsKey(string $key): string { diff --git a/kirby/src/Cms/AppErrors.php b/kirby/src/Cms/AppErrors.php index 43dba9c..a1013a5 100644 --- a/kirby/src/Cms/AppErrors.php +++ b/kirby/src/Cms/AppErrors.php @@ -2,15 +2,11 @@ namespace Kirby\Cms; -use Closure; -use Kirby\Exception\Exception; use Kirby\Filesystem\F; use Kirby\Http\Response; use Kirby\Toolkit\I18n; -use Throwable; use Whoops\Handler\CallbackHandler; use Whoops\Handler\Handler; -use Whoops\Handler\HandlerInterface; use Whoops\Handler\PlainTextHandler; use Whoops\Handler\PrettyPageHandler; use Whoops\Run as Whoops; @@ -26,22 +22,17 @@ use Whoops\Run as Whoops; */ trait AppErrors { - /** - * Allows to disable Whoops globally in CI; - * can be overridden by explicitly setting - * the `whoops` option to `true` or `false` - * - * @internal - */ - public static bool $enableWhoops = true; - /** * Whoops instance cache + * + * @var \Whoops\Run */ - protected Whoops $whoops; + protected $whoops; /** * Registers the PHP error handler for CLI usage + * + * @return void */ protected function handleCliErrors(): void { @@ -51,20 +42,11 @@ trait AppErrors /** * Registers the PHP error handler * based on the environment + * + * @return void */ protected function handleErrors(): void { - // no matter the environment, exit early if - // Whoops was disabled globally - // (but continue if the option was explicitly - // set to `true` in the config) - if ( - static::$enableWhoops === false && - $this->option('whoops') !== true - ) { - return; - } - if ($this->environment()->cli() === true) { $this->handleCliErrors(); return; @@ -80,35 +62,29 @@ trait AppErrors /** * Registers the PHP error handler for HTML output + * + * @return void */ protected function handleHtmlErrors(): void { $handler = null; if ($this->option('debug') === true) { - if ($this->option('whoops', true) !== false) { + if ($this->option('whoops', true) === true) { $handler = new PrettyPageHandler(); $handler->setPageTitle('Kirby CMS Debugger'); - $handler->addResourcePath(dirname(__DIR__, 2) . '/assets'); + $handler->setResourcesPath(dirname(__DIR__, 2) . '/assets'); $handler->addCustomCss('whoops.css'); if ($editor = $this->option('editor')) { $handler->setEditor($editor); } - - if ($blocklist = $this->option('whoops.blocklist')) { - foreach ($blocklist as $superglobal => $vars) { - foreach ($vars as $var) { - $handler->blacklist($superglobal, $var); - } - } - } } } else { $handler = new CallbackHandler(function ($exception, $inspector, $run) { $fatal = $this->option('fatal'); - if ($fatal instanceof Closure) { + if (is_a($fatal, 'Closure') === true) { echo $fatal($this, $exception); } else { include $this->root('kirby') . '/views/fatal.php'; @@ -127,15 +103,17 @@ trait AppErrors /** * Registers the PHP error handler for JSON output + * + * @return void */ protected function handleJsonErrors(): void { $handler = new CallbackHandler(function ($exception, $inspector, $run) { - if ($exception instanceof Exception) { + if (is_a($exception, 'Kirby\Exception\Exception') === true) { $httpCode = $exception->getHttpCode(); $code = $exception->getCode(); $details = $exception->getDetails(); - } elseif ($exception instanceof Throwable) { + } elseif (is_a($exception, '\Throwable') === true) { $httpCode = 500; $code = $exception->getCode(); $details = null; @@ -173,31 +151,36 @@ trait AppErrors /** * Enables Whoops with the specified handler + * + * @param Callable|\Whoops\Handler\HandlerInterface $handler + * @return void */ - protected function setWhoopsHandler(callable|HandlerInterface $handler): void + protected function setWhoopsHandler($handler): void { $whoops = $this->whoops(); $whoops->clearHandlers(); $whoops->pushHandler($handler); - $whoops->pushHandler($this->getAdditionalWhoopsHandler()); + $whoops->pushHandler($this->getExceptionHookWhoopsHandler()); $whoops->register(); // will only do something if not already registered } /** - * Whoops callback handler for additional error handling - * (`system.exception` hook and output to error log) + * Initializes a callback handler for triggering the `system.exception` hook + * + * @return \Whoops\Handler\CallbackHandler */ - protected function getAdditionalWhoopsHandler(): CallbackHandler + protected function getExceptionHookWhoopsHandler(): CallbackHandler { return new CallbackHandler(function ($exception, $inspector, $run) { $this->trigger('system.exception', compact('exception')); - error_log($exception); return Handler::DONE; }); } /** * Clears the Whoops handlers and disables Whoops + * + * @return void */ protected function unsetWhoopsHandler(): void { @@ -208,9 +191,15 @@ trait AppErrors /** * Returns the Whoops error handler instance + * + * @return \Whoops\Run */ - protected function whoops(): Whoops + protected function whoops() { - return $this->whoops ??= new Whoops(); + if ($this->whoops !== null) { + return $this->whoops; + } + + return $this->whoops = new Whoops(); } } diff --git a/kirby/src/Cms/AppPlugins.php b/kirby/src/Cms/AppPlugins.php index 8cfeae3..161fb2b 100644 --- a/kirby/src/Cms/AppPlugins.php +++ b/kirby/src/Cms/AppPlugins.php @@ -3,14 +3,13 @@ namespace Kirby\Cms; use Closure; -use Kirby\Content\Field; use Kirby\Exception\DuplicateException; -use Kirby\Filesystem\Asset; use Kirby\Filesystem\Dir; use Kirby\Filesystem\F; use Kirby\Filesystem\Mime; use Kirby\Form\Field as FormField; use Kirby\Image\Image; +use Kirby\Panel\Panel; use Kirby\Text\KirbyTag; use Kirby\Toolkit\A; use Kirby\Toolkit\Collection as ToolkitCollection; @@ -29,20 +28,23 @@ trait AppPlugins { /** * A list of all registered plugins + * + * @var array */ - protected static array $plugins = []; + protected static $plugins = []; /** * The extension registry + * + * @var array */ - protected array $extensions = [ + protected $extensions = [ // load options first to make them available for the rest 'options' => [], // other plugin types 'api' => [], 'areas' => [], - 'assetMethods' => [], 'authChallenges' => [], 'blockMethods' => [], 'blockModels' => [], @@ -50,7 +52,6 @@ trait AppPlugins 'blueprints' => [], 'cacheTypes' => [], 'collections' => [], - 'commands' => [], 'components' => [], 'controllers' => [], 'collectionFilters' => [], @@ -73,8 +74,6 @@ trait AppPlugins 'sections' => [], 'siteMethods' => [], 'snippets' => [], - 'structureMethods' => [], - 'structureObjectMethods' => [], 'tags' => [], 'templates' => [], 'thirdParty' => [], @@ -88,19 +87,21 @@ trait AppPlugins /** * Flag when plugins have been loaded * to not load them again + * + * @var bool */ - protected bool $pluginsAreLoaded = false; + protected $pluginsAreLoaded = false; /** * Register all given extensions * * @internal + * @param array $extensions * @param \Kirby\Cms\Plugin $plugin|null The plugin which defined those extensions + * @return array */ - public function extend( - array $extensions, - Plugin $plugin = null - ): array { + public function extend(array $extensions, Plugin $plugin = null): array + { foreach ($this->extensions as $type => $registered) { if (isset($extensions[$type]) === true) { $this->{'extend' . $type}($extensions[$type], $plugin); @@ -112,43 +113,47 @@ trait AppPlugins /** * Registers API extensions + * + * @param array|bool $api + * @return array */ - protected function extendApi(array|bool $api): array + protected function extendApi($api): array { if (is_array($api) === true) { - if (($api['routes'] ?? []) instanceof Closure) { + if (is_a($api['routes'] ?? [], 'Closure') === true) { $api['routes'] = $api['routes']($this); } return $this->extensions['api'] = A::merge($this->extensions['api'], $api, A::MERGE_APPEND); + } else { + return $this->extensions['api']; } - - return $this->extensions['api']; } /** * Registers additional custom Panel areas + * + * @param array $areas + * @return array */ protected function extendAreas(array $areas): array { foreach ($areas as $id => $area) { - $this->extensions['areas'][$id] ??= []; + if (isset($this->extensions['areas'][$id]) === false) { + $this->extensions['areas'][$id] = []; + } + $this->extensions['areas'][$id][] = $area; } return $this->extensions['areas']; } - /** - * Registers additional asset methods - */ - protected function extendAssetMethods(array $methods): array - { - return $this->extensions['assetMethods'] = Asset::$methods = array_merge(Asset::$methods, $methods); - } - /** * Registers additional authentication challenges + * + * @param array $challenges + * @return array */ protected function extendAuthChallenges(array $challenges): array { @@ -157,6 +162,9 @@ trait AppPlugins /** * Registers additional block methods + * + * @param array $methods + * @return array */ protected function extendBlockMethods(array $methods): array { @@ -165,6 +173,9 @@ trait AppPlugins /** * Registers additional block models + * + * @param array $models + * @return array */ protected function extendBlockModels(array $models): array { @@ -173,6 +184,9 @@ trait AppPlugins /** * Registers additional blocks methods + * + * @param array $methods + * @return array */ protected function extendBlocksMethods(array $methods): array { @@ -181,6 +195,9 @@ trait AppPlugins /** * Registers additional blueprints + * + * @param array $blueprints + * @return array */ protected function extendBlueprints(array $blueprints): array { @@ -189,22 +206,20 @@ trait AppPlugins /** * Registers additional cache types + * + * @param array $cacheTypes + * @return array */ protected function extendCacheTypes(array $cacheTypes): array { return $this->extensions['cacheTypes'] = array_merge($this->extensions['cacheTypes'], $cacheTypes); } - /** - * Registers additional CLI commands - */ - protected function extendCommands(array $commands): array - { - return $this->extensions['commands'] = array_merge($this->extensions['commands'], $commands); - } - /** * Registers additional collection filters + * + * @param array $filters + * @return array */ protected function extendCollectionFilters(array $filters): array { @@ -213,6 +228,9 @@ trait AppPlugins /** * Registers additional collection methods + * + * @param array $methods + * @return array */ protected function extendCollectionMethods(array $methods): array { @@ -221,6 +239,9 @@ trait AppPlugins /** * Registers additional collections + * + * @param array $collections + * @return array */ protected function extendCollections(array $collections): array { @@ -229,6 +250,9 @@ trait AppPlugins /** * Registers core components + * + * @param array $components + * @return array */ protected function extendComponents(array $components): array { @@ -237,6 +261,9 @@ trait AppPlugins /** * Registers additional controllers + * + * @param array $controllers + * @return array */ protected function extendControllers(array $controllers): array { @@ -245,6 +272,9 @@ trait AppPlugins /** * Registers additional file methods + * + * @param array $methods + * @return array */ protected function extendFileMethods(array $methods): array { @@ -253,6 +283,9 @@ trait AppPlugins /** * Registers additional custom file types and mimes + * + * @param array $fileTypes + * @return array */ protected function extendFileTypes(array $fileTypes): array { @@ -303,6 +336,9 @@ trait AppPlugins /** * Registers additional files methods + * + * @param array $methods + * @return array */ protected function extendFilesMethods(array $methods): array { @@ -311,6 +347,9 @@ trait AppPlugins /** * Registers additional field methods + * + * @param array $methods + * @return array */ protected function extendFieldMethods(array $methods): array { @@ -319,6 +358,9 @@ trait AppPlugins /** * Registers Panel fields + * + * @param array $fields + * @return array */ protected function extendFields(array $fields): array { @@ -327,11 +369,16 @@ trait AppPlugins /** * Registers hooks + * + * @param array $hooks + * @return array */ protected function extendHooks(array $hooks): array { foreach ($hooks as $name => $callbacks) { - $this->extensions['hooks'][$name] ??= []; + if (isset($this->extensions['hooks'][$name]) === false) { + $this->extensions['hooks'][$name] = []; + } if (is_array($callbacks) === false) { $callbacks = [$callbacks]; @@ -347,14 +394,20 @@ trait AppPlugins /** * Registers markdown component + * + * @param Closure $markdown + * @return Closure */ - protected function extendMarkdown(Closure $markdown): Closure + protected function extendMarkdown(Closure $markdown) { return $this->extensions['markdown'] = $markdown; } /** * Registers additional layout methods + * + * @param array $methods + * @return array */ protected function extendLayoutMethods(array $methods): array { @@ -363,6 +416,9 @@ trait AppPlugins /** * Registers additional layout column methods + * + * @param array $methods + * @return array */ protected function extendLayoutColumnMethods(array $methods): array { @@ -371,6 +427,9 @@ trait AppPlugins /** * Registers additional layouts methods + * + * @param array $methods + * @return array */ protected function extendLayoutsMethods(array $methods): array { @@ -379,11 +438,13 @@ trait AppPlugins /** * Registers additional options + * + * @param array $options + * @param \Kirby\Cms\Plugin|null $plugin + * @return array */ - protected function extendOptions( - array $options, - Plugin $plugin = null - ): array { + protected function extendOptions(array $options, Plugin $plugin = null): array + { if ($plugin !== null) { $options = [$plugin->prefix() => $options]; } @@ -393,6 +454,9 @@ trait AppPlugins /** * Registers additional page methods + * + * @param array $methods + * @return array */ protected function extendPageMethods(array $methods): array { @@ -401,6 +465,9 @@ trait AppPlugins /** * Registers additional pages methods + * + * @param array $methods + * @return array */ protected function extendPagesMethods(array $methods): array { @@ -409,6 +476,9 @@ trait AppPlugins /** * Registers additional page models + * + * @param array $models + * @return array */ protected function extendPageModels(array $models): array { @@ -417,6 +487,9 @@ trait AppPlugins /** * Registers pages + * + * @param array $pages + * @return array */ protected function extendPages(array $pages): array { @@ -425,11 +498,13 @@ trait AppPlugins /** * Registers additional permissions + * + * @param array $permissions + * @param \Kirby\Cms\Plugin|null $plugin + * @return array */ - protected function extendPermissions( - array $permissions, - Plugin $plugin = null - ): array { + protected function extendPermissions(array $permissions, Plugin $plugin = null): array + { if ($plugin !== null) { $permissions = [$plugin->prefix() => $permissions]; } @@ -439,10 +514,13 @@ trait AppPlugins /** * Registers additional routes + * + * @param array|\Closure $routes + * @return array */ - protected function extendRoutes(array|Closure $routes): array + protected function extendRoutes($routes): array { - if ($routes instanceof Closure) { + if (is_a($routes, 'Closure') === true) { $routes = $routes($this); } @@ -451,6 +529,9 @@ trait AppPlugins /** * Registers Panel sections + * + * @param array $sections + * @return array */ protected function extendSections(array $sections): array { @@ -459,6 +540,9 @@ trait AppPlugins /** * Registers additional site methods + * + * @param array $methods + * @return array */ protected function extendSiteMethods(array $methods): array { @@ -467,38 +551,31 @@ trait AppPlugins /** * Registers SmartyPants component + * + * @param \Closure $smartypants + * @return \Closure */ - protected function extendSmartypants(Closure $smartypants): Closure + protected function extendSmartypants(Closure $smartypants) { return $this->extensions['smartypants'] = $smartypants; } /** * Registers additional snippets + * + * @param array $snippets + * @return array */ protected function extendSnippets(array $snippets): array { return $this->extensions['snippets'] = array_merge($this->extensions['snippets'], $snippets); } - /** - * Registers additional structure methods - */ - protected function extendStructureMethods(array $methods): array - { - return $this->extensions['structureMethods'] = Structure::$methods = array_merge(Structure::$methods, $methods); - } - - /** - * Registers additional structure object methods - */ - protected function extendStructureObjectMethods(array $methods): array - { - return $this->extensions['structureObjectMethods'] = StructureObject::$methods = array_merge(StructureObject::$methods, $methods); - } - /** * Registers additional KirbyTags + * + * @param array $tags + * @return array */ protected function extendTags(array $tags): array { @@ -507,6 +584,9 @@ trait AppPlugins /** * Registers additional templates + * + * @param array $templates + * @return array */ protected function extendTemplates(array $templates): array { @@ -515,6 +595,9 @@ trait AppPlugins /** * Registers translations + * + * @param array $translations + * @return array */ protected function extendTranslations(array $translations): array { @@ -525,6 +608,9 @@ trait AppPlugins * Add third party extensions to the registry * so they can be used as plugins for plugins * for example. + * + * @param array $extensions + * @return array */ protected function extendThirdParty(array $extensions): array { @@ -533,6 +619,9 @@ trait AppPlugins /** * Registers additional user methods + * + * @param array $methods + * @return array */ protected function extendUserMethods(array $methods): array { @@ -541,6 +630,9 @@ trait AppPlugins /** * Registers additional user models + * + * @param array $models + * @return array */ protected function extendUserModels(array $models): array { @@ -549,6 +641,9 @@ trait AppPlugins /** * Registers additional users methods + * + * @param array $methods + * @return array */ protected function extendUsersMethods(array $methods): array { @@ -557,6 +652,9 @@ trait AppPlugins /** * Registers additional custom validators + * + * @param array $validators + * @return array */ protected function extendValidators(array $validators): array { @@ -569,12 +667,11 @@ trait AppPlugins * @internal * @param string $type i.e. `'hooks'` * @param string $name i.e. `'page.delete:before'` + * @param mixed $fallback + * @return mixed */ - public function extension( - string $type, - string $name, - mixed $fallback = null - ): mixed { + public function extension(string $type, string $name, $fallback = null) + { return $this->extensions($type)[$name] ?? $fallback; } @@ -582,8 +679,10 @@ trait AppPlugins * Returns the extensions registry * * @internal + * @param string|null $type + * @return array */ - public function extensions(string $type = null): array + public function extensions(string $type = null) { if ($type === null) { return $this->extensions; @@ -597,7 +696,7 @@ trait AppPlugins * This is only used for models for now, but * could be extended later */ - protected function extensionsFromFolders(): void + protected function extensionsFromFolders() { $models = []; @@ -606,7 +705,7 @@ trait AppPlugins $class = str_replace(['.', '-', '_'], '', $name) . 'Page'; // load the model class - F::loadOnce($model, allowOutput: false); + F::loadOnce($model); if (class_exists($class) === true) { $models[$name] = $class; @@ -620,8 +719,10 @@ trait AppPlugins * Register extensions that could be located in * the options array. I.e. hooks and routes can be * setup from the config. + * + * @return void */ - protected function extensionsFromOptions(): void + protected function extensionsFromOptions() { // register routes and hooks from options $this->extend([ @@ -633,8 +734,10 @@ trait AppPlugins /** * Apply all plugin extensions + * + * @return void */ - protected function extensionsFromPlugins(): void + protected function extensionsFromPlugins() { // register all their extensions foreach ($this->plugins() as $plugin) { @@ -648,22 +751,22 @@ trait AppPlugins /** * Apply all passed extensions + * + * @param array $props + * @return void */ - protected function extensionsFromProps(array $props): void + protected function extensionsFromProps(array $props) { $this->extend($props); } /** * Apply all default extensions + * + * @return void */ - protected function extensionsFromSystem(): void + protected function extensionsFromSystem() { - // Always start with fresh fields and sections - // from the core and add plugins on top of that - FormField::$types = []; - Section::$types = []; - // mixins FormField::$mixins = $this->core->fieldMixins(); Section::$mixins = $this->core->sectionMixins(); @@ -679,8 +782,8 @@ trait AppPlugins $this->extendCacheTypes($this->core->cacheTypes()); $this->extendComponents($this->core->components()); $this->extendBlueprints($this->core->blueprints()); - $this->extendFieldMethods($this->core->fieldMethods()); $this->extendFields($this->core->fields()); + $this->extendFieldMethods($this->core->fieldMethods()); $this->extendSections($this->core->sections()); $this->extendSnippets($this->core->snippets()); $this->extendTags($this->core->kirbyTags()); @@ -690,6 +793,9 @@ trait AppPlugins /** * Checks if a native component was extended * @since 3.7.0 + * + * @param string $component + * @return bool */ public function isNativeComponent(string $component): bool { @@ -699,8 +805,11 @@ trait AppPlugins /** * Returns the native implementation * of a core component + * + * @param string $component + * @return \Closure|false */ - public function nativeComponent(string $component): Closure|false + public function nativeComponent(string $component) { return $this->core->components()[$component] ?? false; } @@ -708,30 +817,22 @@ trait AppPlugins /** * Kirby plugin factory and getter * + * @param string $name * @param array|null $extends If null is passed it will be used as getter. Otherwise as factory. + * @return \Kirby\Cms\Plugin|null * @throws \Kirby\Exception\DuplicateException */ - public static function plugin( - string $name, - array $extends = null, - array $info = [], - string|null $root = null, - string|null $version = null - ): Plugin|null { + public static function plugin(string $name, array $extends = null) + { if ($extends === null) { return static::$plugins[$name] ?? null; } - $plugin = new Plugin( - name: $name, - extends: $extends, - info: $info, - // TODO: Remove fallback to $extends in v7 - root: $root ?? $extends['root'] ?? dirname(debug_backtrace()[0]['file']), - version: $version - ); + // get the correct root for the plugin + $extends['root'] = $extends['root'] ?? dirname(debug_backtrace()[0]['file']); - $name = $plugin->name(); + $plugin = new Plugin($name, $extends); + $name = $plugin->name(); if (isset(static::$plugins[$name]) === true) { throw new DuplicateException('The plugin "' . $name . '" has already been registered'); @@ -746,6 +847,7 @@ trait AppPlugins * * @internal * @param array|null $plugins Can be used to overwrite the plugins registry + * @return array */ public function plugins(array $plugins = null): array { @@ -794,17 +896,13 @@ trait AppPlugins $styles = $dir . '/index.css'; if (is_file($entry) === true) { - F::loadOnce($entry, allowOutput: false); + F::loadOnce($entry); } elseif (is_file($script) === true || is_file($styles) === true) { // if no PHP file is present but an index.js or index.css, // register as anonymous plugin (without actual extensions) // to be picked up by the Panel\Document class when // rendering the Panel view - static::plugin( - name: 'plugins/' . $dirname, - extends: [], - root: $dir - ); + static::plugin('plugins/' . $dirname, ['root' => $dir]); } else { continue; } diff --git a/kirby/src/Cms/AppTranslations.php b/kirby/src/Cms/AppTranslations.php index 1efae28..86d09c2 100644 --- a/kirby/src/Cms/AppTranslations.php +++ b/kirby/src/Cms/AppTranslations.php @@ -3,6 +3,7 @@ namespace Kirby\Cms; use Kirby\Toolkit\I18n; +use Kirby\Toolkit\Locale; use Kirby\Toolkit\Str; /** @@ -16,15 +17,21 @@ use Kirby\Toolkit\Str; */ trait AppTranslations { - protected Translations|null $translations = null; + protected $translations; /** * Setup internationalization + * + * @return void */ protected function i18n(): void { I18n::$load = function ($locale): array { - $data = $this->translation($locale)?->data() ?? []; + $data = []; + + if ($translation = $this->translation($locale)) { + $data = $translation->data(); + } // inject translations from the current language if ( @@ -42,9 +49,9 @@ trait AppTranslations I18n::$locale = function (): string { if ($this->multilang() === true) { return $this->defaultLanguage()->code(); + } else { + return 'en'; } - - return 'en'; }; I18n::$fallback = function (): array { @@ -64,9 +71,9 @@ trait AppTranslations $fallback[] = 'en'; return $fallback; + } else { + return ['en']; } - - return ['en']; }; I18n::$translations = []; @@ -85,6 +92,8 @@ trait AppTranslations * Returns the language code that will be used * for the Panel if no user is logged in or if * no language is configured for the user + * + * @return string */ public function panelLanguage(): string { @@ -103,10 +112,43 @@ trait AppTranslations return $this->option('panel.language', $defaultCode); } + /** + * Load and set the current language if it exists + * Otherwise fall back to the default language + * + * @internal + * @param string|null $languageCode + * @return \Kirby\Cms\Language|null + */ + public function setCurrentLanguage(string $languageCode = null) + { + if ($this->multilang() === false) { + Locale::set($this->option('locale', 'en_US.utf-8')); + return $this->language = null; + } + + if ($language = $this->language($languageCode)) { + $this->language = $language; + } else { + $this->language = $this->defaultLanguage(); + } + + if ($this->language) { + Locale::set($this->language->locale()); + } + + // add language slug rules to Str class + Str::$language = $this->language->rules(); + + return $this->language; + } + /** * Set the current translation * * @internal + * @param string|null $translationCode + * @return void */ public function setCurrentTranslation(string $translationCode = null): void { @@ -117,14 +159,15 @@ trait AppTranslations * Load a specific translation by locale * * @param string|null $locale Locale name or `null` for the current locale + * @return \Kirby\Cms\Translation */ - public function translation(string|null $locale = null): Translation + public function translation(?string $locale = null) { - $locale ??= I18n::locale(); + $locale = $locale ?? I18n::locale(); $locale = basename($locale); // prefer loading them from the translations collection - if ($this->translations instanceof Translations) { + if (is_a($this->translations, 'Kirby\Cms\Translations') === true) { if ($translation = $this->translations()->find($locale)) { return $translation; } @@ -144,10 +187,12 @@ trait AppTranslations /** * Returns all available translations + * + * @return \Kirby\Cms\Translations */ - public function translations(): Translations + public function translations() { - if ($this->translations instanceof Translations) { + if (is_a($this->translations, 'Kirby\Cms\Translations') === true) { return $this->translations; } @@ -169,6 +214,8 @@ trait AppTranslations } } - return $this->translations = Translations::load($this->root('i18n:translations'), $translations); + $this->translations = Translations::load($this->root('i18n:translations'), $translations); + + return $this->translations; } } diff --git a/kirby/src/Cms/AppUsers.php b/kirby/src/Cms/AppUsers.php index 82a61f0..8eedcce 100644 --- a/kirby/src/Cms/AppUsers.php +++ b/kirby/src/Cms/AppUsers.php @@ -16,17 +16,22 @@ use Throwable; */ trait AppUsers { - protected Auth|null $auth = null; - protected User|string|null $user = null; - protected Users|null $users = null; + /** + * Cache for the auth auth layer + * + * @var Auth + */ + protected $auth; /** * Returns the Authentication layer class + * * @internal + * @return \Kirby\Cms\Auth */ - public function auth(): Auth + public function auth() { - return $this->auth ??= new Auth($this); + return $this->auth = $this->auth ?? new Auth($this); } /** @@ -43,10 +48,8 @@ trait AppUsers * if called with callback: Return value from the callback * @throws \Throwable */ - public function impersonate( - string|null $who = null, - Closure|null $callback = null - ): mixed { + public function impersonate(?string $who = null, ?Closure $callback = null) + { $auth = $this->auth(); $userBefore = $auth->currentUserFromImpersonation(); @@ -57,22 +60,24 @@ trait AppUsers } try { - return $callback($userAfter); + // bind the App object to the callback + return $callback->call($this, $userAfter); } catch (Throwable $e) { throw $e; } finally { // ensure that the impersonation is *always* reset // to the original value, even if an error occurred - $auth->impersonate($userBefore?->id()); + $auth->impersonate($userBefore !== null ? $userBefore->id() : null); } } /** * Set the currently active user id * - * @return $this + * @param \Kirby\Cms\User|string $user + * @return \Kirby\Cms\App */ - protected function setUser(User|string $user = null): static + protected function setUser($user = null) { $this->user = $user; return $this; @@ -81,12 +86,15 @@ trait AppUsers /** * Create your own set of app users * - * @return $this + * @param array|null $users + * @return \Kirby\Cms\App */ - protected function setUsers(array $users = null): static + protected function setUsers(array $users = null) { if ($users !== null) { - $this->users = Users::factory($users); + $this->users = Users::factory($users, [ + 'kirby' => $this + ]); } return $this; @@ -96,36 +104,40 @@ trait AppUsers * Returns a specific user by id * or the current user if no id is given * + * @param string|null $id * @param bool $allowImpersonation If set to false, only the actually * logged in user will be returned * (when `$id` is passed as `null`) + * @return \Kirby\Cms\User|null */ - public function user( - string|null $id = null, - bool $allowImpersonation = true - ): User|null { + public function user(?string $id = null, bool $allowImpersonation = true) + { if ($id !== null) { return $this->users()->find($id); } if ($allowImpersonation === true && is_string($this->user) === true) { return $this->auth()->impersonate($this->user); - } - - try { - return $this->auth()->user(null, $allowImpersonation); - } catch (Throwable) { - return null; + } else { + try { + return $this->auth()->user(null, $allowImpersonation); + } catch (Throwable $e) { + return null; + } } } /** * Returns all users + * + * @return \Kirby\Cms\Users */ - public function users(): Users + public function users() { - return $this->users ??= Users::load( - $this->root('accounts'), - ); + if (is_a($this->users, 'Kirby\Cms\Users') === true) { + return $this->users; + } + + return $this->users = Users::load($this->root('accounts'), ['kirby' => $this]); } } diff --git a/kirby/src/Cms/Auth.php b/kirby/src/Cms/Auth.php index d02b01e..161ebad 100644 --- a/kirby/src/Cms/Auth.php +++ b/kirby/src/Cms/Auth.php @@ -2,10 +2,8 @@ namespace Kirby\Cms; -use Kirby\Cms\Auth\Challenge; use Kirby\Cms\Auth\Status; use Kirby\Data\Data; -use Kirby\Exception\Exception; use Kirby\Exception\InvalidArgumentException; use Kirby\Exception\LogicException; use Kirby\Exception\NotFoundException; @@ -13,9 +11,7 @@ use Kirby\Exception\PermissionException; use Kirby\Filesystem\F; use Kirby\Http\Idn; use Kirby\Http\Request\Auth\BasicAuth; -use Kirby\Session\Session; use Kirby\Toolkit\A; -use SensitiveParameter; use Throwable; /** @@ -32,37 +28,55 @@ class Auth /** * Available auth challenge classes * from the core and plugins + * + * @var array */ - public static array $challenges = []; + public static $challenges = []; /** * Currently impersonated user + * + * @var \Kirby\Cms\User|null */ - protected User|null $impersonate = null; + protected $impersonate; + + /** + * Kirby instance + * + * @var \Kirby\Cms\App + */ + protected $kirby; /** * Cache of the auth status object + * + * @var \Kirby\Cms\Auth\Status */ - protected Status|null $status = null; + protected $status; /** * Instance of the currently logged in user or * `false` if the user was not yet determined + * + * @var \Kirby\Cms\User|null|false */ - protected User|false|null $user = false; + protected $user = false; /** * Exception that was thrown while * determining the current user + * + * @var \Throwable */ - protected Throwable|null $userException = null; + protected $userException; /** + * @param \Kirby\Cms\App $kirby * @codeCoverageIgnore */ - public function __construct( - protected App $kirby - ) { + public function __construct(App $kirby) + { + $this->kirby = $kirby; } /** @@ -70,18 +84,17 @@ class Auth * (one-time auth code) * @since 3.5.0 * + * @param string $email * @param bool $long If `true`, a long session will be created - * @param 'login'|'password-reset'|'2fa' $mode Purpose of the code + * @param string $mode Either 'login' or 'password-reset' + * @return \Kirby\Cms\Auth\Status * * @throws \Kirby\Exception\LogicException If there is no suitable authentication challenge (only in debug mode) * @throws \Kirby\Exception\NotFoundException If the user does not exist (only in debug mode) * @throws \Kirby\Exception\PermissionException If the rate limit is exceeded */ - public function createChallenge( - string $email, - bool $long = false, - string $mode = 'login' - ): Status { + public function createChallenge(string $email, bool $long = false, string $mode = 'login') + { $email = Idn::decodeEmail($email); $session = $this->kirby->session([ @@ -89,8 +102,6 @@ class Auth 'long' => $long === true ]); - $timeout = $this->kirby->option('auth.challenge.timeout', 10 * 60); - // catch every exception to hide them from attackers // unless auth debugging is enabled try { @@ -99,6 +110,8 @@ class Auth // rate-limit the number of challenges for DoS/DDoS protection $this->track($email, false); + $timeout = $this->kirby->option('auth.challenge.timeout', 10 * 60); + // try to find the provided user $user = $this->kirby->users()->find($email); if ($user === null) { @@ -119,7 +132,7 @@ class Auth if ( $class && class_exists($class) === true && - is_subclass_of($class, Challenge::class) === true && + is_subclass_of($class, 'Kirby\Cms\Auth\Challenge') === true && $class::isAvailable($user, $mode) === true ) { $challenge = $name; @@ -128,10 +141,8 @@ class Auth $session->set('kirby.challenge.type', $challenge); if ($code !== null) { - $session->set( - 'kirby.challenge.code', - password_hash($code, PASSWORD_DEFAULT) - ); + $session->set('kirby.challenge.code', password_hash($code, PASSWORD_DEFAULT)); + $session->set('kirby.challenge.timeout', time() + $timeout); } break; @@ -147,10 +158,9 @@ class Auth $this->fail($e); } - // always set the email and timeout, even if the challenge - // won't be created; this avoids leaking whether the user exists + // always set the email, even if the challenge won't be + // created to avoid leaking whether the user exists $session->set('kirby.challenge.email', $email); - $session->set('kirby.challenge.timeout', time() + $timeout); // sleep for a random amount of milliseconds // to make automated attacks harder and to @@ -165,8 +175,10 @@ class Auth /** * Returns the csrf token if it exists and if it is valid + * + * @return string|false */ - public function csrf(): string|false + public function csrf() { // get the csrf from the header $fromHeader = $this->kirby->request()->csrf(); @@ -185,6 +197,8 @@ class Auth /** * Returns either predefined csrf or the one from session * @since 3.6.0 + * + * @return string */ public function csrfFromSession(): string { @@ -199,10 +213,11 @@ class Auth * valid credentials * * @param \Kirby\Http\Request\Auth\BasicAuth|null $auth + * @return \Kirby\Cms\User|null * @throws \Kirby\Exception\InvalidArgumentException if the authorization header is invalid * @throws \Kirby\Exception\PermissionException if basic authentication is not allowed */ - public function currentUserFromBasicAuth(BasicAuth $auth = null): User|null + public function currentUserFromBasicAuth(BasicAuth $auth = null) { if ($this->kirby->option('api.basicAuth', false) !== true) { throw new PermissionException('Basic authentication is not activated'); @@ -221,8 +236,8 @@ class Auth } } - $request = $this->kirby->request(); - $auth ??= $request->auth(); + $request = $this->kirby->request(); + $auth = $auth ?? $request->auth(); if (!$auth || $auth->type() !== 'basic') { throw new InvalidArgumentException('Invalid authorization header'); @@ -238,8 +253,10 @@ class Auth /** * Returns the currently impersonated user + * + * @return \Kirby\Cms\User|null */ - public function currentUserFromImpersonation(): User|null + public function currentUserFromImpersonation() { return $this->impersonate; } @@ -248,10 +265,12 @@ class Auth * Returns the logged in user by checking * the current session and finding a valid * valid user id in there + * + * @param \Kirby\Session\Session|array|null $session + * @return \Kirby\Cms\User|null */ - public function currentUserFromSession( - Session|array $session = null - ): User|null { + public function currentUserFromSession($session = null) + { $session = $this->session($session); $id = $session->data()->get('kirby.userId'); @@ -295,12 +314,12 @@ class Auth * Returns the list of enabled challenges in the * configured order * @since 3.5.1 + * + * @return array */ public function enabledChallenges(): array { - return A::wrap( - $this->kirby->option('auth.challenges', ['totp', 'email']) - ); + return A::wrap($this->kirby->option('auth.challenges', ['email'])); } /** @@ -310,32 +329,43 @@ class Auth * `null` to use the actual user again, * `'kirby'` for a virtual admin user or * `'nobody'` to disable the actual user + * @return \Kirby\Cms\User|null * @throws \Kirby\Exception\NotFoundException if the given user cannot be found */ - public function impersonate(string|null $who = null): User|null + public function impersonate(?string $who = null) { // clear the status cache $this->status = null; - return $this->impersonate = match ($who) { - null => null, - 'kirby' => new User([ - 'email' => 'kirby@getkirby.com', - 'id' => 'kirby', - 'role' => 'admin', - ]), - 'nobody' => new User([ - 'email' => 'nobody@getkirby.com', - 'id' => 'nobody', - 'role' => 'nobody', - ]), - default => ($this->kirby->users()->find($who) ?? throw new NotFoundException('The user "' . $who . '" cannot be found')) - }; + switch ($who) { + case null: + return $this->impersonate = null; + case 'kirby': + return $this->impersonate = new User([ + 'email' => 'kirby@getkirby.com', + 'id' => 'kirby', + 'role' => 'admin', + ]); + case 'nobody': + return $this->impersonate = new User([ + 'email' => 'nobody@getkirby.com', + 'id' => 'nobody', + 'role' => 'nobody', + ]); + default: + if ($user = $this->kirby->users()->find($who)) { + return $this->impersonate = $user; + } + + throw new NotFoundException('The user "' . $who . '" cannot be found'); + } } /** * Returns the hashed ip of the visitor * which is used to track invalid logins + * + * @return string */ public function ipHash(): string { @@ -347,6 +377,9 @@ class Auth /** * Check if logins are blocked for the current ip or email + * + * @param string $email + * @return bool */ public function isBlocked(string $email): bool { @@ -374,16 +407,17 @@ class Auth /** * Login a user by email and password * + * @param string $email + * @param string $password + * @param bool $long + * @return \Kirby\Cms\User + * * @throws \Kirby\Exception\PermissionException If the rate limit was exceeded or if any other error occurred with debug mode off * @throws \Kirby\Exception\NotFoundException If the email was invalid * @throws \Kirby\Exception\InvalidArgumentException If the password is not valid (via `$user->login()`) */ - public function login( - string $email, - #[SensitiveParameter] - string $password, - bool $long = false - ): User { + public function login(string $email, string $password, bool $long = false) + { // session options $options = [ 'createMode' => 'cookie', @@ -404,16 +438,17 @@ class Auth * Login a user by email, password and auth challenge * @since 3.5.0 * + * @param string $email + * @param string $password + * @param bool $long + * @return \Kirby\Cms\Auth\Status + * * @throws \Kirby\Exception\PermissionException If the rate limit was exceeded or if any other error occurred with debug mode off * @throws \Kirby\Exception\NotFoundException If the email was invalid * @throws \Kirby\Exception\InvalidArgumentException If the password is not valid (via `$user->login()`) */ - public function login2fa( - string $email, - #[SensitiveParameter] - string $password, - bool $long = false - ): Status { + public function login2fa(string $email, string $password, bool $long = false) + { $this->validatePassword($email, $password); return $this->createChallenge($email, $long, '2fa'); } @@ -421,12 +456,16 @@ class Auth /** * Sets a user object as the current user in the cache * @internal + * + * @param \Kirby\Cms\User $user + * @return void */ public function setUser(User $user): void { // stop impersonating $this->impersonate = null; - $this->user = $user; + + $this->user = $user; // clear the status cache $this->status = null; @@ -436,13 +475,13 @@ class Auth * Returns the authentication status object * @since 3.5.1 * + * @param \Kirby\Session\Session|array|null $session * @param bool $allowImpersonation If set to false, only the actually * logged in user will be returned + * @return \Kirby\Cms\Auth\Status */ - public function status( - Session|array $session = null, - bool $allowImpersonation = true - ): Status { + public function status($session = null, bool $allowImpersonation = true) + { // try to return from cache if ($this->status && $session === null && $allowImpersonation === true) { return $this->status; @@ -503,15 +542,16 @@ class Auth * Validates the user credentials and returns the user object on success; * otherwise logs the failed attempt * + * @param string $email + * @param string $password + * @return \Kirby\Cms\User + * * @throws \Kirby\Exception\PermissionException If the rate limit was exceeded or if any other error occurred with debug mode off * @throws \Kirby\Exception\NotFoundException If the email was invalid * @throws \Kirby\Exception\InvalidArgumentException If the password is not valid (via `$user->login()`) */ - public function validatePassword( - string $email, - #[SensitiveParameter] - string $password - ): User { + public function validatePassword(string $email, string $password) + { $email = Idn::decodeEmail($email); try { @@ -531,7 +571,7 @@ class Auth ] ]); } catch (Throwable $e) { - $details = $e instanceof Exception ? $e->getDetails() : []; + $details = is_a($e, 'Kirby\Exception\Exception') === true ? $e->getDetails() : []; // log invalid login trial unless the rate limit is already active if (($details['reason'] ?? null) !== 'rate-limited') { @@ -555,6 +595,8 @@ class Auth /** * Returns the absolute path to the logins log + * + * @return string */ public function logfile(): string { @@ -563,20 +605,22 @@ class Auth /** * Read all tracked logins + * + * @return array */ public function log(): array { try { $log = Data::read($this->logfile(), 'json'); $read = true; - } catch (Throwable) { + } catch (Throwable $e) { $log = []; $read = false; } // ensure that the category arrays are defined - $log['by-ip'] ??= []; - $log['by-email'] ??= []; + $log['by-ip'] = $log['by-ip'] ?? []; + $log['by-email'] = $log['by-email'] ?? []; // remove all elements on the top level with different keys (old structure) $log = array_intersect_key($log, array_flip(['by-ip', 'by-email'])); @@ -605,6 +649,8 @@ class Auth /** * Logout the current user + * + * @return void */ public function logout(): void { @@ -613,7 +659,9 @@ class Auth $this->impersonate = null; // logout the current user if it exists - $this->user()?->logout(); + if ($user = $this->user()) { + $user->logout(); + } // clear the pending challenge $session = $this->kirby->session(); @@ -629,6 +677,8 @@ class Auth /** * Clears the cached user data after logout * @internal + * + * @return void */ public function flush(): void { @@ -640,12 +690,12 @@ class Auth /** * Tracks a login * + * @param string|null $email * @param bool $triggerHook If `false`, no user.login:failed hook is triggered + * @return bool */ - public function track( - string|null $email, - bool $triggerHook = true - ): bool { + public function track(?string $email, bool $triggerHook = true): bool + { if ($triggerHook === true) { $this->kirby->trigger('user.login:failed', compact('email')); } @@ -689,43 +739,34 @@ class Auth * @param bool $allowImpersonation If set to false, 'impersonate' won't * be returned as authentication type * even if an impersonation is active + * @return string */ public function type(bool $allowImpersonation = true): string { $basicAuth = $this->kirby->option('api.basicAuth', false); - $request = $this->kirby->request(); + $auth = $this->kirby->request()->auth(); - if ( - $basicAuth === true && - - // only get the auth object if the option is enabled - // to avoid triggering `$responder->usesAuth()` if - // the option is disabled - $request->auth() && - $request->auth()->type() === 'basic' - ) { + if ($basicAuth === true && $auth && $auth->type() === 'basic') { return 'basic'; - } - - if ($allowImpersonation === true && $this->impersonate !== null) { + } elseif ($allowImpersonation === true && $this->impersonate !== null) { return 'impersonate'; + } else { + return 'session'; } - - return 'session'; } /** * Validates the currently logged in user * + * @param \Kirby\Session\Session|array|null $session * @param bool $allowImpersonation If set to false, only the actually * logged in user will be returned + * @return \Kirby\Cms\User|null * * @throws \Throwable If an authentication error occurred */ - public function user( - Session|array $session = null, - bool $allowImpersonation = true - ): User|null { + public function user($session = null, bool $allowImpersonation = true) + { if ($allowImpersonation === true && $this->impersonate !== null) { return $this->impersonate; } @@ -738,18 +779,16 @@ class Auth } return null; - } - - if ($this->user !== false) { + } elseif ($this->user !== false) { return $this->user; } try { if ($this->type() === 'basic') { return $this->user = $this->currentUserFromBasicAuth(); + } else { + return $this->user = $this->currentUserFromSession($session); } - - return $this->user = $this->currentUserFromSession($session); } catch (Throwable $e) { $this->user = null; @@ -775,42 +814,16 @@ class Auth * @throws \Kirby\Exception\InvalidArgumentException If no authentication challenge is active * @throws \Kirby\Exception\LogicException If the authentication challenge is invalid */ - public function verifyChallenge( - #[SensitiveParameter] - string $code - ): User { + public function verifyChallenge(string $code) + { try { $session = $this->kirby->session(); - // time-limiting; check this early so that we can destroy the session no - // matter if the user exists (avoids leaking user information to attackers) - $timeout = $session->get('kirby.challenge.timeout'); - if ($timeout !== null && time() > $timeout) { - // this challenge can never be completed, - // so delete it immediately - $this->logout(); - - throw new PermissionException([ - 'details' => ['challengeDestroyed' => true], - 'fallback' => 'Authentication challenge timeout' - ]); - } - - // check if we have an active challenge + // first check if we have an active challenge at all $email = $session->get('kirby.challenge.email'); $challenge = $session->get('kirby.challenge.type'); if (is_string($email) !== true || is_string($challenge) !== true) { - // if the challenge timed out on the previous request, the - // challenge data was already deleted from the session, so we can - // set `challengeDestroyed` to `true` in this response as well; - // however we must only base this on the email, not the type - // (otherwise "faked" challenges would be leaked) - $challengeDestroyed = is_string($email) !== true; - - throw new InvalidArgumentException([ - 'details' => compact('challengeDestroyed'), - 'fallback' => 'No authentication challenge is active' - ]); + throw new InvalidArgumentException('No authentication challenge is active'); } $user = $this->kirby->users()->find($email); @@ -826,10 +839,16 @@ class Auth // rate-limiting $this->checkRateLimit($email); + // time-limiting + $timeout = $session->get('kirby.challenge.timeout'); + if ($timeout !== null && time() > $timeout) { + throw new PermissionException('Authentication challenge timeout'); + } + if ( isset(static::$challenges[$challenge]) === true && class_exists(static::$challenges[$challenge]) === true && - is_subclass_of(static::$challenges[$challenge], Challenge::class) === true + is_subclass_of(static::$challenges[$challenge], 'Kirby\Cms\Auth\Challenge') === true ) { $class = static::$challenges[$challenge]; if ($class::verify($user, $code) === true) { @@ -840,16 +859,14 @@ class Auth $this->status = null; return $user; + } else { + throw new PermissionException(['key' => 'access.code']); } - - throw new PermissionException(['key' => 'access.code']); } - throw new LogicException( - 'Invalid authentication challenge: ' . $challenge - ); + throw new LogicException('Invalid authentication challenge: ' . $challenge); } catch (Throwable $e) { - $details = $e instanceof Exception ? $e->getDetails() : []; + $details = is_a($e, 'Kirby\Exception\Exception') === true ? $e->getDetails() : []; if ( empty($email) === false && @@ -863,14 +880,7 @@ class Auth // avoid leaking whether the user exists usleep(random_int(10000, 2000000)); - // specifically copy over the marker for a destroyed challenge - // even in production (used by the Panel to reset to the login form) - $challengeDestroyed = $details['challengeDestroyed'] ?? false; - - $fallback = new PermissionException([ - 'details' => compact('challengeDestroyed'), - 'key' => 'access.code' - ]); + $fallback = new PermissionException(['key' => 'access.code']); // keep throwing the original error in debug mode, // otherwise hide it to avoid leaking security-relevant information @@ -885,10 +895,8 @@ class Auth * @throws \Throwable Either the passed `$exception` or the `$fallback` * (no exception if debugging is disabled and no fallback was passed) */ - protected function fail( - Throwable $exception, - Throwable $fallback = null - ): void { + protected function fail(Throwable $exception, Throwable $fallback = null): void + { $debug = $this->kirby->option('auth.debug', 'log'); // throw the original exception only in debug mode @@ -910,8 +918,11 @@ class Auth /** * Creates a session object from the passed options + * + * @param \Kirby\Session\Session|array|null $session + * @return \Kirby\Session\Session */ - protected function session(Session|array $session = null): Session + protected function session($session = null) { // use passed session options or session object if set if (is_array($session) === true) { @@ -919,7 +930,7 @@ class Auth } // try session in header or cookie - if ($session instanceof Session === false) { + if (is_a($session, 'Kirby\Session\Session') === false) { return $this->kirby->session(['detect' => true]); } diff --git a/kirby/src/Cms/Auth/Challenge.php b/kirby/src/Cms/Auth/Challenge.php index cee81b9..69a7574 100644 --- a/kirby/src/Cms/Auth/Challenge.php +++ b/kirby/src/Cms/Auth/Challenge.php @@ -3,7 +3,6 @@ namespace Kirby\Cms\Auth; use Kirby\Cms\User; -use SensitiveParameter; /** * Template class for authentication challenges @@ -22,7 +21,8 @@ abstract class Challenge * for the passed user and purpose * * @param \Kirby\Cms\User $user User the code will be generated for - * @param 'login'|'password-reset'|'2fa' $mode Purpose of the code + * @param string $mode Purpose of the code ('login', 'reset' or '2fa') + * @return bool */ abstract public static function isAvailable(User $user, string $mode): bool; @@ -32,12 +32,12 @@ abstract class Challenge * * @param \Kirby\Cms\User $user User to generate the code for * @param array $options Details of the challenge request: - * - 'mode': Purpose of the code ('login', 'password-reset' or '2fa') + * - 'mode': Purpose of the code ('login', 'reset' or '2fa') * - 'timeout': Number of seconds the code will be valid for * @return string|null The generated and sent code or `null` in case * there was no code to generate by this algorithm */ - abstract public static function create(User $user, array $options): string|null; + abstract public static function create(User $user, array $options): ?string; /** * Verifies the provided code against the created one; @@ -46,12 +46,10 @@ abstract class Challenge * * @param \Kirby\Cms\User $user User to check the code for * @param string $code Code to verify + * @return bool */ - public static function verify( - User $user, - #[SensitiveParameter] - string $code - ): bool { + public static function verify(User $user, string $code): bool + { $hash = $user->kirby()->session()->get('kirby.challenge.code'); if (is_string($hash) !== true) { return false; diff --git a/kirby/src/Cms/Auth/EmailChallenge.php b/kirby/src/Cms/Auth/EmailChallenge.php index e2bef6f..e0bcfbe 100644 --- a/kirby/src/Cms/Auth/EmailChallenge.php +++ b/kirby/src/Cms/Auth/EmailChallenge.php @@ -23,7 +23,8 @@ class EmailChallenge extends Challenge * for the passed user and purpose * * @param \Kirby\Cms\User $user User the code will be generated for - * @param 'login'|'password-reset'|'2fa' $mode Purpose of the code + * @param string $mode Purpose of the code ('login', 'reset' or '2fa') + * @return bool */ public static function isAvailable(User $user, string $mode): bool { @@ -36,7 +37,7 @@ class EmailChallenge extends Challenge * * @param \Kirby\Cms\User $user User to generate the code for * @param array $options Details of the challenge request: - * - 'mode': Purpose of the code ('login', 'password-reset' or '2fa') + * - 'mode': Purpose of the code ('login', 'reset' or '2fa') * - 'timeout': Number of seconds the code will be valid for * @return string The generated and sent code */ diff --git a/kirby/src/Cms/Auth/Status.php b/kirby/src/Cms/Auth/Status.php index ec43107..43031c7 100644 --- a/kirby/src/Cms/Auth/Status.php +++ b/kirby/src/Cms/Auth/Status.php @@ -3,7 +3,6 @@ namespace Kirby\Cms\Auth; use Kirby\Cms\App; -use Kirby\Cms\User; use Kirby\Exception\InvalidArgumentException; use Kirby\Toolkit\Properties; @@ -20,32 +19,44 @@ use Kirby\Toolkit\Properties; */ class Status { + use Properties; + /** * Type of the active challenge + * + * @var string|null */ - protected string|null $challenge = null; + protected $challenge = null; /** * Challenge type to use as a fallback * when $challenge is `null` + * + * @var string|null */ - protected string|null $challengeFallback = null; + protected $challengeFallback = null; /** * Email address of the current/pending user + * + * @var string|null */ - protected string|null $email; + protected $email = null; /** * Kirby instance for user lookup + * + * @var \Kirby\Cms\App */ - protected App $kirby; + protected $kirby; /** * Authentication status: * `active|impersonated|pending|inactive` + * + * @var string */ - protected string $status; + protected $status; /** * Class constructor @@ -54,24 +65,13 @@ class Status */ public function __construct(array $props) { - if (in_array($props['status'], ['active', 'impersonated', 'pending', 'inactive']) !== true) { - throw new InvalidArgumentException([ - 'data' => [ - 'argument' => '$props[\'status\']', - 'method' => 'Status::__construct' - ] - ]); - } - - $this->kirby = $props['kirby']; - $this->challenge = $props['challenge'] ?? null; - $this->challengeFallback = $props['challengeFallback'] ?? null; - $this->email = $props['email'] ?? null; - $this->status = $props['status']; + $this->setProperties($props); } /** * Returns the authentication status + * + * @return string */ public function __toString(): string { @@ -84,8 +84,9 @@ class Status * @param bool $automaticFallback If set to `false`, no faked challenge is returned; * WARNING: never send the resulting `null` value to the * user to avoid leaking whether the pending user exists + * @return string|null */ - public function challenge(bool $automaticFallback = true): string|null + public function challenge(bool $automaticFallback = true): ?string { // never return a challenge type if the status doesn't match if ($this->status() !== 'pending') { @@ -94,30 +95,17 @@ class Status if ($automaticFallback === false) { return $this->challenge; + } else { + return $this->challenge ?? $this->challengeFallback; } - - return $this->challenge ?? $this->challengeFallback; - } - - /** - * Creates a new instance while - * merging initial and new properties - */ - public function clone(array $props = []): static - { - return new static(array_replace_recursive([ - 'kirby' => $this->kirby, - 'challenge' => $this->challenge, - 'challengeFallback' => $this->challengeFallback, - 'email' => $this->email, - 'status' => $this->status, - ], $props)); } /** * Returns the email address of the current/pending user + * + * @return string|null */ - public function email(): string|null + public function email(): ?string { return $this->email; } @@ -134,6 +122,8 @@ class Status /** * Returns an array with all public status data + * + * @return array */ public function toArray(): array { @@ -146,8 +136,10 @@ class Status /** * Returns the currently logged in user + * + * @return \Kirby\Cms\User */ - public function user(): User|null + public function user() { // for security, only return the user if they are // already logged in @@ -157,4 +149,71 @@ class Status return $this->kirby->user($this->email()); } + + /** + * Sets the type of the active challenge + * + * @param string|null $challenge + * @return $this + */ + protected function setChallenge(?string $challenge = null) + { + $this->challenge = $challenge; + return $this; + } + + /** + * Sets the challenge type to use as + * a fallback when $challenge is `null` + * + * @param string|null $challengeFallback + * @return $this + */ + protected function setChallengeFallback(?string $challengeFallback = null) + { + $this->challengeFallback = $challengeFallback; + return $this; + } + + /** + * Sets the email address of the current/pending user + * + * @param string|null $email + * @return $this + */ + protected function setEmail(?string $email = null) + { + $this->email = $email; + return $this; + } + + /** + * Sets the Kirby instance for user lookup + * + * @param \Kirby\Cms\App $kirby + * @return $this + */ + protected function setKirby(App $kirby) + { + $this->kirby = $kirby; + return $this; + } + + /** + * Sets the authentication status + * + * @param string $status `active|impersonated|pending|inactive` + * @return $this + */ + protected function setStatus(string $status) + { + if (in_array($status, ['active', 'impersonated', 'pending', 'inactive']) !== true) { + throw new InvalidArgumentException([ + 'data' => ['argument' => '$props[\'status\']', 'method' => 'Status::__construct'] + ]); + } + + $this->status = $status; + return $this; + } } diff --git a/kirby/src/Cms/Auth/TotpChallenge.php b/kirby/src/Cms/Auth/TotpChallenge.php deleted file mode 100644 index 67142db..0000000 --- a/kirby/src/Cms/Auth/TotpChallenge.php +++ /dev/null @@ -1,65 +0,0 @@ - - * @link https://getkirby.com - * @copyright Bastian Allgeier - * @license https://getkirby.com/license - */ -class TotpChallenge extends Challenge -{ - /** - * Checks whether the challenge is available - * for the passed user and purpose - * - * @param \Kirby\Cms\User $user User the code will be generated for - * @param 'login'|'password-reset'|'2fa' $mode Purpose of the code - */ - public static function isAvailable(User $user, string $mode): bool - { - // user needs to have a TOTP secret set up - return $user->secret('totp') !== null; - } - - /** - * Generates a random one-time auth code and returns that code - * for later verification - * - * @param \Kirby\Cms\User $user User to generate the code for - * @param array $options Details of the challenge request: - * - 'mode': Purpose of the code ('login', 'password-reset' or '2fa') - * - 'timeout': Number of seconds the code will be valid for - * @todo set return type to `null` once support for PHP 8.1 is dropped - */ - public static function create(User $user, array $options): string|null - { - // the user's app will generate the code, we only verify it - return null; - } - - /** - * Verifies the provided code against the created one - * - * @param \Kirby\Cms\User $user User to check the code for - * @param string $code Code to verify - */ - public static function verify(User $user, string $code): bool - { - // verify if code is current, previous or next TOTP code - $secret = $user->secret('totp'); - $totp = new Totp($secret); - return $totp->verify($code); - } -} diff --git a/kirby/src/Cms/Block.php b/kirby/src/Cms/Block.php index f83c547..97f04a7 100644 --- a/kirby/src/Cms/Block.php +++ b/kirby/src/Cms/Block.php @@ -2,8 +2,6 @@ namespace Kirby\Cms; -use Kirby\Content\Content; -use Kirby\Content\Field; use Kirby\Exception\InvalidArgumentException; use Kirby\Toolkit\Str; use Throwable; @@ -24,21 +22,38 @@ class Block extends Item { use HasMethods; - public const ITEMS_CLASS = Blocks::class; + public const ITEMS_CLASS = '\Kirby\Cms\Blocks'; + + /** + * @var \Kirby\Cms\Content + */ + protected $content; + + /** + * @var bool + */ + protected $isHidden; /** * Registry with all block models + * + * @var array */ - public static array $models = []; + public static $models = []; - protected Content $content; - protected bool $isHidden; - protected string $type; + /** + * @var string + */ + protected $type; /** * Proxy for content fields + * + * @param string $method + * @param array $args + * @return \Kirby\Cms\Field */ - public function __call(string $method, array $args = []): mixed + public function __call(string $method, array $args = []) { // block methods if ($this->hasMethod($method)) { @@ -51,19 +66,13 @@ class Block extends Item /** * Creates a new block object * + * @param array $params * @throws \Kirby\Exception\InvalidArgumentException */ public function __construct(array $params) { parent::__construct($params); - // @deprecated import old builder format - // @todo block.converter remove eventually - // @codeCoverageIgnoreStart - $params = BlockConverter::builderBlock($params); - $params = BlockConverter::editorBlock($params); - // @codeCoverageIgnoreEnd - if (isset($params['type']) === false) { throw new InvalidArgumentException('The block type is missing'); } @@ -74,15 +83,18 @@ class Block extends Item $params['content'] = []; } + $this->content = $params['content']; $this->isHidden = $params['isHidden'] ?? false; $this->type = $params['type']; // create the content object - $this->content = new Content($params['content'], $this->parent); + $this->content = new Content($this->content, $this->parent); } /** * Converts the object to a string + * + * @return string */ public function __toString(): string { @@ -91,14 +103,18 @@ class Block extends Item /** * Returns the content object + * + * @return \Kirby\Cms\Content */ - public function content(): Content + public function content() { return $this->content; } /** * Controller for the block snippet + * + * @return array */ public function controller(): array { @@ -117,38 +133,40 @@ class Block extends Item * Converts the block to HTML and then * uses the Str::excerpt method to create * a non-formatted, shortened excerpt from it + * + * @param mixed ...$args + * @return string */ - public function excerpt(mixed ...$args): string + public function excerpt(...$args) { return Str::excerpt($this->toHtml(), ...$args); } /** * Constructs a block object with registering blocks models - * @internal * + * @param array $params + * @return static * @throws \Kirby\Exception\InvalidArgumentException + * @internal */ - public static function factory(array $params): static + public static function factory(array $params) { $type = $params['type'] ?? null; - if ( - empty($type) === false && - $class = (static::$models[$type] ?? null) - ) { + if (empty($type) === false && $class = (static::$models[$type] ?? null)) { $object = new $class($params); - if ($object instanceof self) { + if (is_a($object, 'Kirby\Cms\Block') === true) { return $object; } } // default model for blocks - if ($class = (static::$models['default'] ?? null)) { + if ($class = (static::$models['Kirby\Cms\Block'] ?? null)) { $object = new $class($params); - if ($object instanceof self) { + if (is_a($object, 'Kirby\Cms\Block') === true) { return $object; } } @@ -158,6 +176,8 @@ class Block extends Item /** * Checks if the block is empty + * + * @return bool */ public function isEmpty(): bool { @@ -167,6 +187,8 @@ class Block extends Item /** * Checks if the block is hidden * from being rendered in the frontend + * + * @return bool */ public function isHidden(): bool { @@ -175,6 +197,8 @@ class Block extends Item /** * Checks if the block is not empty + * + * @return bool */ public function isNotEmpty(): bool { @@ -183,14 +207,18 @@ class Block extends Item /** * Returns the sibling collection that filtered by block status + * + * @return \Kirby\Cms\Collection */ - protected function siblingsCollection(): Blocks + protected function siblingsCollection() { return $this->siblings->filter('isHidden', $this->isHidden()); } /** * Returns the block type + * + * @return string */ public function type(): string { @@ -200,6 +228,8 @@ class Block extends Item /** * The result is being sent to the editor * via the API in the panel + * + * @return array */ public function toArray(): array { @@ -216,24 +246,24 @@ class Block extends Item * and then places that inside a field * object. This can be used further * with all available field methods + * + * @return \Kirby\Cms\Field */ - public function toField(): Field + public function toField() { return new Field($this->parent(), $this->id(), $this->toHtml()); } /** * Converts the block to HTML + * + * @return string */ public function toHtml(): string { try { $kirby = $this->parent()->kirby(); - return (string)$kirby->snippet( - 'blocks/' . $this->type(), - $this->controller(), - true - ); + return (string)$kirby->snippet('blocks/' . $this->type(), $this->controller(), true); } catch (Throwable $e) { if ($kirby->option('debug') === true) { return '

      Block error: "' . $e->getMessage() . '" in block type: "' . $this->type() . '"

      '; diff --git a/kirby/src/Cms/BlockConverter.php b/kirby/src/Cms/BlockConverter.php deleted file mode 100644 index 6065fe2..0000000 --- a/kirby/src/Cms/BlockConverter.php +++ /dev/null @@ -1,285 +0,0 @@ - - * @link https://getkirby.com - * @copyright Bastian Allgeier GmbH - * @license https://getkirby.com/license - */ -class BlockConverter -{ - public static function builderBlock(array $params): array - { - if (isset($params['_key']) === false) { - return $params; - } - - $params['type'] = $params['_key']; - $params['content'] = $params; - unset($params['_uid']); - - return $params; - } - - public static function editorBlock(array $params): array - { - if (static::isEditorBlock($params) === false) { - return $params; - } - - $method = 'editor' . $params['type']; - - if (method_exists(static::class, $method) === true) { - $params = static::$method($params); - } else { - $params = static::editorCustom($params); - } - - return $params; - } - - public static function editorBlocks(array $blocks = []): array - { - if (empty($blocks) === true) { - return $blocks; - } - - if (static::isEditorBlock($blocks[0]) === false) { - return $blocks; - } - - $list = []; - $listStart = null; - - foreach ($blocks as $index => $block) { - if (in_array($block['type'], ['ul', 'ol']) === true) { - $prev = $blocks[$index - 1] ?? null; - $next = $blocks[$index + 1] ?? null; - - // new list starts here - if (!$prev || $prev['type'] !== $block['type']) { - $listStart = $index; - } - - // add the block to the list - $list[] = $block; - - // list ends here - if (!$next || $next['type'] !== $block['type']) { - $blocks[$listStart] = [ - 'content' => [ - 'text' => - '<' . $block['type'] . '>' . - implode(array_map( - fn ($item) => '
    • ' . $item['content'] . '
    • ', - $list - )) . - '', - ], - 'type' => 'list' - ]; - - $start = $listStart + 1; - $end = $listStart + count($list); - - for ($x = $start; $x <= $end; $x++) { - $blocks[$x] = false; - } - - $listStart = null; - $list = []; - } - } else { - $blocks[$index] = static::editorBlock($block); - } - } - - return array_filter($blocks); - } - - public static function editorBlockquote(array $params): array - { - return [ - 'content' => [ - 'text' => $params['content'] - ], - 'type' => 'quote' - ]; - } - - public static function editorCode(array $params): array - { - return [ - 'content' => [ - 'language' => $params['attrs']['language'] ?? null, - 'code' => $params['content'] - ], - 'type' => 'code' - ]; - } - - public static function editorCustom(array $params): array - { - return [ - 'content' => array_merge( - $params['attrs'] ?? [], - [ - 'body' => $params['content'] ?? null - ] - ), - 'type' => $params['type'] ?? 'unknown' - ]; - } - - public static function editorH1(array $params): array - { - return static::editorHeading($params, 'h1'); - } - - public static function editorH2(array $params): array - { - return static::editorHeading($params, 'h2'); - } - - public static function editorH3(array $params): array - { - return static::editorHeading($params, 'h3'); - } - - public static function editorH4(array $params): array - { - return static::editorHeading($params, 'h4'); - } - - public static function editorH5(array $params): array - { - return static::editorHeading($params, 'h5'); - } - - public static function editorH6(array $params): array - { - return static::editorHeading($params, 'h6'); - } - - public static function editorHr(array $params): array - { - return [ - 'content' => [], - 'type' => 'line' - ]; - } - - public static function editorHeading(array $params, string $level = 'h1'): array - { - return [ - 'content' => [ - 'level' => $level, - 'text' => $params['content'] - ], - 'type' => 'heading' - ]; - } - - public static function editorImage(array $params): array - { - // internal image - if (isset($params['attrs']['id']) === true) { - return [ - 'content' => [ - 'alt' => $params['attrs']['alt'] ?? null, - 'caption' => $params['attrs']['caption'] ?? null, - 'image' => $params['attrs']['id'] ?? $params['attrs']['src'] ?? null, - 'location' => 'kirby', - 'ratio' => $params['attrs']['ratio'] ?? null, - ], - 'type' => 'image' - ]; - } - - return [ - 'content' => [ - 'alt' => $params['attrs']['alt'] ?? null, - 'caption' => $params['attrs']['caption'] ?? null, - 'src' => $params['attrs']['src'] ?? null, - 'location' => 'web', - 'ratio' => $params['attrs']['ratio'] ?? null, - ], - 'type' => 'image' - ]; - } - - public static function editorKirbytext(array $params): array - { - return [ - 'content' => [ - 'text' => $params['content'] - ], - 'type' => 'markdown' - ]; - } - - public static function editorOl(array $params): array - { - return [ - 'content' => [ - 'text' => $params['content'] - ], - 'type' => 'list' - ]; - } - - public static function editorParagraph(array $params): array - { - return [ - 'content' => [ - 'text' => '

      ' . $params['content'] . '

      ' - ], - 'type' => 'text' - ]; - } - - public static function editorUl(array $params): array - { - return [ - 'content' => [ - 'text' => $params['content'] - ], - 'type' => 'list' - ]; - } - - public static function editorVideo(array $params): array - { - return [ - 'content' => [ - 'caption' => $params['attrs']['caption'] ?? null, - 'url' => $params['attrs']['src'] ?? null - ], - 'type' => 'video' - ]; - } - - public static function isEditorBlock(array $params): bool - { - if (isset($params['attrs']) === true) { - return true; - } - - if (is_string($params['content'] ?? null) === true) { - return true; - } - - return false; - } -} diff --git a/kirby/src/Cms/Blocks.php b/kirby/src/Cms/Blocks.php index 6ea7a6c..49589ec 100644 --- a/kirby/src/Cms/Blocks.php +++ b/kirby/src/Cms/Blocks.php @@ -2,12 +2,9 @@ namespace Kirby\Cms; -use Exception; use Kirby\Data\Json; -use Kirby\Data\Yaml; use Kirby\Parsley\Parsley; use Kirby\Parsley\Schema\Blocks as BlockSchema; -use Kirby\Toolkit\A; use Kirby\Toolkit\Str; use Throwable; @@ -23,16 +20,13 @@ use Throwable; */ class Blocks extends Items { - public const ITEM_CLASS = Block::class; - - /** - * All registered blocks methods - */ - public static array $methods = []; + public const ITEM_CLASS = '\Kirby\Cms\Block'; /** * Return HTML when the collection is * converted to a string + * + * @return string */ public function __toString(): string { @@ -43,8 +37,11 @@ class Blocks extends Items * Converts the blocks to HTML and then * uses the Str::excerpt method to create * a non-formatted, shortened excerpt from it + * + * @param mixed ...$args + * @return string */ - public function excerpt(mixed ...$args): string + public function excerpt(...$args) { return Str::excerpt($this->toHtml(), ...$args); } @@ -52,24 +49,23 @@ class Blocks extends Items /** * Wrapper around the factory to * catch blocks from layouts + * + * @param array $items + * @param array $params + * @return \Kirby\Cms\Blocks */ - public static function factory( - array $items = null, - array $params = [] - ): static { + public static function factory(array $items = null, array $params = []) + { $items = static::extractFromLayouts($items); - // @deprecated old editor format - // @todo block.converter remove eventually - // @codeCoverageIgnoreStart - $items = BlockConverter::editorBlocks($items); - // @codeCoverageIgnoreEnd - return parent::factory($items, $params); } /** * Pull out blocks from layouts + * + * @param array $input + * @return array */ protected static function extractFromLayouts(array $input): array { @@ -77,13 +73,8 @@ class Blocks extends Items return []; } - if ( - // no columns = no layout - array_key_exists('columns', $input[0]) === false || - // @deprecated checks if this is a block for the builder plugin - // @todo block.converter remove eventually - array_key_exists('_key', $input[0]) === true - ) { + // no columns = no layout + if (array_key_exists('columns', $input[0]) === false) { return $input; } @@ -103,6 +94,9 @@ class Blocks extends Items /** * Checks if a given block type exists in the collection * @since 3.6.0 + * + * @param string $type + * @return bool */ public function hasType(string $type): bool { @@ -111,40 +105,18 @@ class Blocks extends Items /** * Parse and sanitize various block formats + * + * @param array|string $input + * @return array */ - public static function parse(array|string|null $input): array + public static function parse($input): array { if (empty($input) === false && is_array($input) === false) { try { $input = Json::decode((string)$input); - } catch (Throwable) { - // @deprecated try to import the old YAML format - // @todo block.converter remove eventually - // @codeCoverageIgnoreStart - try { - $yaml = Yaml::decode((string)$input); - $first = A::first($yaml); - - // check for valid yaml - if ( - empty($yaml) === true || - ( - isset($first['_key']) === false && - isset($first['type']) === false - ) - ) { - throw new Exception('Invalid YAML'); - } else { - $input = $yaml; - } - } catch (Throwable $e) { - // the next 2 lines remain after removing block.converter - // @codeCoverageIgnoreEnd - $parser = new Parsley((string)$input, new BlockSchema()); - $input = $parser->blocks(); - // @codeCoverageIgnoreStart - } - // @codeCoverageIgnoreEnd + } catch (Throwable $e) { + $parser = new Parsley((string)$input, new BlockSchema()); + $input = $parser->blocks(); } } @@ -157,10 +129,16 @@ class Blocks extends Items /** * Convert all blocks to HTML + * + * @return string */ public function toHtml(): string { - $html = A::map($this->data, fn ($block) => $block->toHtml()); + $html = []; + + foreach ($this->data as $block) { + $html[] = $block->toHtml(); + } return implode($html); } diff --git a/kirby/src/Cms/Blueprint.php b/kirby/src/Cms/Blueprint.php index 7895c85..bd257c2 100644 --- a/kirby/src/Cms/Blueprint.php +++ b/kirby/src/Cms/Blueprint.php @@ -34,12 +34,14 @@ class Blueprint protected $sections = []; protected $tabs = []; - protected array|null $fileTemplates = null; - /** * Magic getter/caller for any blueprint prop + * + * @param string $key + * @param array|null $arguments + * @return mixed */ - public function __call(string $key, array $arguments = null): mixed + public function __call(string $key, array $arguments = null) { return $this->props[$key] ?? null; } @@ -47,6 +49,7 @@ class Blueprint /** * Creates a new blueprint object with the given props * + * @param array $props * @throws \Kirby\Exception\InvalidArgumentException If the blueprint model is missing */ public function __construct(array $props) @@ -55,7 +58,7 @@ class Blueprint throw new InvalidArgumentException('A blueprint model is required'); } - if ($props['model'] instanceof ModelWithContent === false) { + if (is_a($props['model'], ModelWithContent::class) === false) { throw new InvalidArgumentException('Invalid blueprint model'); } @@ -65,7 +68,7 @@ class Blueprint unset($props['model']); // extend the blueprint in general - $props = static::extend($props); + $props = $this->extend($props); // apply any blueprint preset $props = $this->preset($props); @@ -74,8 +77,7 @@ class Blueprint $props['name'] ??= 'default'; // normalize and translate the title - $props['title'] ??= ucfirst($props['name']); - $props['title'] = $this->i18n($props['title']); + $props['title'] = $this->i18n($props['title'] ?? ucfirst($props['name'])); // convert all shortcuts $props = $this->convertFieldsToSections('main', $props); @@ -91,130 +93,23 @@ class Blueprint /** * Improved `var_dump` output * - * @codeCoverageIgnore + * @return array */ public function __debugInfo(): array { return $this->props ?? []; } - /** - * Gathers what file templates are allowed in - * this model based on the blueprint - */ - public function acceptedFileTemplates(string $inSection = null): array - { - // get cached results for the current file model - // (except when collecting for a specific section) - if ($inSection === null && $this->fileTemplates !== null) { - return $this->fileTemplates; // @codeCoverageIgnore - } - - $templates = []; - - // collect all allowed file templates from blueprint… - foreach ($this->sections() as $section) { - // if collecting for a specific section, skip all others - if ($inSection !== null && $section->name() !== $inSection) { - continue; - } - - $templates = match ($section->type()) { - 'files' => [...$templates, $section->template() ?? 'default'], - 'fields' => [ - ...$templates, - ...$this->acceptedFileTemplatesFromFields($section->fields()) - ], - default => $templates - }; - } - - // no caching for when collecting for specific section - if ($inSection !== null) { - return $templates; // @codeCoverageIgnore - } - - return $this->fileTemplates = $templates; - } - - /** - * Gathers the allowed file templates from model's fields - */ - protected function acceptedFileTemplatesFromFields(array $fields): array - { - $templates = []; - - foreach ($fields as $field) { - // fields with uploads settings - if (isset($field['uploads']) === true && is_array($field['uploads']) === true) { - $templates = [ - ...$templates, - ...$this->acceptedFileTemplatesFromFieldUploads($field['uploads']) - ]; - continue; - } - - // structure and object fields - if (isset($field['fields']) === true && is_array($field['fields']) === true) { - $templates = [ - ...$templates, - ...$this->acceptedFileTemplatesFromFields($field['fields']), - ]; - continue; - } - - // layout and blocks fields - if (isset($field['fieldsets']) === true && is_array($field['fieldsets']) === true) { - $templates = [ - ...$templates, - ...$this->acceptedFileTemplatesFromFieldsets($field['fieldsets']) - ]; - continue; - } - } - - return $templates; - } - - /** - * Gathers the allowed file templates from fieldsets - */ - protected function acceptedFileTemplatesFromFieldsets(array $fieldsets): array - { - $templates = []; - - foreach ($fieldsets as $fieldset) { - foreach (($fieldset['tabs'] ?? []) as $tab) { - $templates = array_merge($templates, $this->acceptedFileTemplatesFromFields($tab['fields'] ?? [])); - } - } - - return $templates; - } - - /** - * Extracts templates from field uploads settings - */ - protected function acceptedFileTemplatesFromFieldUploads(array $uploads): array - { - // only if the `uploads` parent is this model - if ($target = $uploads['parent'] ?? null) { - if ($this->model->id() !== $target) { - return []; - } - } - - return [($uploads['template'] ?? 'default')]; - } - /** * Converts all column definitions, that * are not wrapped in a tab, into a generic tab + * + * @param string $tabName + * @param array $props + * @return array */ - protected function convertColumnsToTabs( - string $tabName, - array $props - ): array { + protected function convertColumnsToTabs(string $tabName, array $props): array + { if (isset($props['columns']) === false) { return $props; } @@ -235,11 +130,13 @@ class Blueprint * Converts all field definitions, that are not * wrapped in a fields section into a generic * fields section. + * + * @param string $tabName + * @param array $props + * @return array */ - protected function convertFieldsToSections( - string $tabName, - array $props - ): array { + protected function convertFieldsToSections(string $tabName, array $props): array + { if (isset($props['fields']) === false) { return $props; } @@ -260,11 +157,13 @@ class Blueprint /** * Converts all sections that are not wrapped in * columns, into a single generic column. + * + * @param string $tabName + * @param array $props + * @return array */ - protected function convertSectionsToColumns( - string $tabName, - array $props - ): array { + protected function convertSectionsToColumns(string $tabName, array $props): array + { if (isset($props['sections']) === false) { return $props; } @@ -288,6 +187,7 @@ class Blueprint * props is just a string * * @param array|string $props + * @return array */ public static function extend($props): array { @@ -297,35 +197,41 @@ class Blueprint ]; } - if ($extends = $props['extends'] ?? null) { - foreach (A::wrap($extends) as $extend) { - try { - $mixin = static::find($extend); - $mixin = static::extend($mixin); - $props = A::merge($mixin, $props, A::MERGE_REPLACE); - } catch (Exception) { - // keep the props unextended if the snippet wasn't found - } - } + $extends = $props['extends'] ?? null; - // remove the extends flag - unset($props['extends']); + if ($extends === null) { + return $props; } + foreach (A::wrap($extends) as $extend) { + try { + $mixin = static::find($extend); + $mixin = static::extend($mixin); + $props = A::merge($mixin, $props, A::MERGE_REPLACE); + } catch (Exception $e) { + // keep the props unextended if the snippet wasn't found + } + } + + // remove the extends flag + unset($props['extends']); + return $props; } /** * Create a new blueprint for a model + * + * @param string $name + * @param string|null $fallback + * @param \Kirby\Cms\Model $model + * @return static|null */ - public static function factory( - string $name, - string $fallback = null, - ModelWithContent $model - ): static|null { + public static function factory(string $name, string $fallback = null, Model $model) + { try { $props = static::load($name); - } catch (Exception) { + } catch (Exception $e) { $props = $fallback !== null ? static::load($fallback) : null; } @@ -341,14 +247,19 @@ class Blueprint /** * Returns a single field definition by name + * + * @param string $name + * @return array|null */ - public function field(string $name): array|null + public function field(string $name): ?array { return $this->fields[$name] ?? null; } /** * Returns all field definitions + * + * @return array */ public function fields(): array { @@ -358,6 +269,8 @@ class Blueprint /** * Find a blueprint by name * + * @param string $name + * @return array * @throws \Kirby\Exception\NotFoundException If the blueprint cannot be found */ public static function find(string $name): array @@ -370,10 +283,8 @@ class Blueprint $root = $kirby->root('blueprints'); $file = $root . '/' . $name . '.yml'; - // first try to find the blueprint in the `site/blueprints` root, - // then check in the plugin extensions which includes some default - // core blueprints (e.g. page, file, site and block defaults) - // as well as blueprints provided by plugins + // first try to find a site blueprint, + // then check in the plugin extensions if (F::exists($file, $root) !== true) { $file = $kirby->extension('blueprints', $name); } @@ -386,9 +297,7 @@ class Blueprint // now ensure that we always return the data array if (is_string($file) === true && F::exists($file) === true) { return static::$loaded[$name] = Data::read($file); - } - - if (is_array($file) === true) { + } elseif (is_array($file) === true) { return static::$loaded[$name] = $file; } @@ -401,14 +310,20 @@ class Blueprint /** * Used to translate any label, heading, etc. + * + * @param mixed $value + * @param mixed $fallback + * @return mixed */ - protected function i18n(mixed $value, mixed $fallback = null): mixed + protected function i18n($value, $fallback = null) { - return I18n::translate($value, $fallback) ?? $value; + return I18n::translate($value, $fallback ?? $value); } /** * Checks if this is the default blueprint + * + * @return bool */ public function isDefault(): bool { @@ -417,33 +332,44 @@ class Blueprint /** * Loads a blueprint from file or array + * + * @param string $name + * @return array */ public static function load(string $name): array { $props = static::find($name); - // inject the filename as name if no name is set - $props['name'] ??= $name; + $normalize = function ($props) use ($name) { + // inject the filename as name if no name is set + $props['name'] ??= $name; - // normalize the title - $title = $props['title'] ?? ucfirst($props['name']); + // normalize the title + $title = $props['title'] ?? ucfirst($props['name']); - // translate the title - $props['title'] = I18n::translate($title) ?? $title; + // translate the title + $props['title'] = I18n::translate($title, $title); - return $props; + return $props; + }; + + return $normalize($props); } /** * Returns the parent model + * + * @return \Kirby\Cms\Model */ - public function model(): ModelWithContent + public function model() { return $this->model; } /** * Returns the blueprint name + * + * @return string */ public function name(): string { @@ -452,6 +378,10 @@ class Blueprint /** * Normalizes all required props in a column setup + * + * @param string $tabName + * @param array $columns + * @return array */ protected function normalizeColumns(string $tabName, array $columns): array { @@ -462,35 +392,32 @@ class Blueprint continue; } - $columnProps = $this->convertFieldsToSections( - $tabName . '-col-' . $columnKey, - $columnProps - ); + $columnProps = $this->convertFieldsToSections($tabName . '-col-' . $columnKey, $columnProps); // inject getting started info, if the sections are empty if (empty($columnProps['sections']) === true) { $columnProps['sections'] = [ $tabName . '-info-' . $columnKey => [ - 'label' => 'Column (' . ($columnProps['width'] ?? '1/1') . ')', - 'type' => 'info', - 'text' => 'No sections yet' + 'headline' => 'Column (' . ($columnProps['width'] ?? '1/1') . ')', + 'type' => 'info', + 'text' => 'No sections yet' ] ]; } - $columns[$columnKey] = [ - ...$columnProps, + $columns[$columnKey] = array_merge($columnProps, [ 'width' => $columnProps['width'] ?? '1/1', - 'sections' => $this->normalizeSections( - $tabName, - $columnProps['sections'] ?? [] - ) - ]; + 'sections' => $this->normalizeSections($tabName, $columnProps['sections'] ?? []) + ]); } return $columns; } + /** + * @param array $items + * @return string + */ public static function helpList(array $items): string { $md = []; @@ -505,9 +432,11 @@ class Blueprint /** * Normalize field props for a single field * + * @param array|string $props + * @return array * @throws \Kirby\Exception\InvalidArgumentException If the filed name is missing or the field type is invalid */ - public static function fieldProps(array|string $props): array + public static function fieldProps($props): array { $props = static::extend($props); @@ -529,34 +458,28 @@ class Blueprint // groups don't need all the crap if ($type === 'group') { - $fields = $props['fields']; - - if (isset($props['when']) === true) { - $fields = array_map( - fn ($field) => array_replace_recursive(['when' => $props['when']], $field), - $fields - ); - } - return [ - 'fields' => $fields, + 'fields' => $props['fields'], 'name' => $name, - 'type' => $type + 'type' => $type, ]; } // add some useful defaults - return [ - ...$props, + return array_merge($props, [ 'label' => $props['label'] ?? ucfirst($name), 'name' => $name, 'type' => $type, 'width' => $props['width'] ?? '1/1', - ]; + ]); } /** * Creates an error field with the given error message + * + * @param string $name + * @param string $message + * @return array */ public static function fieldError(string $name, string $message): array { @@ -572,6 +495,9 @@ class Blueprint /** * Normalizes all fields and adds automatic labels, * types and widths. + * + * @param array $fields + * @return array */ public static function fieldsProps($fields): array { @@ -611,16 +537,11 @@ class Blueprint // resolve field groups if ($fieldProps['type'] === 'group') { - if ( - empty($fieldProps['fields']) === false && - is_array($fieldProps['fields']) === true - ) { + if (empty($fieldProps['fields']) === false && is_array($fieldProps['fields']) === true) { $index = array_search($fieldName, array_keys($fields)); - $fields = [ - ...array_slice($fields, 0, $index), - ...$fieldProps['fields'] ?? [], - ...array_slice($fields, $index + 1) - ]; + $before = array_slice($fields, 0, $index); + $after = array_slice($fields, $index + 1); + $fields = array_merge($before, $fieldProps['fields'] ?? [], $after); } else { unset($fields[$fieldName]); } @@ -635,12 +556,14 @@ class Blueprint /** * Normalizes blueprint options. This must be used in the * constructor of an extended class, if you want to make use of it. + * + * @param array|true|false|null|string $options + * @param array $defaults + * @param array $aliases + * @return array */ - protected function normalizeOptions( - array|string|bool|null $options, - array $defaults, - array $aliases = [] - ): array { + protected function normalizeOptions($options, array $defaults, array $aliases = []): array + { // return defaults when options are not defined or set to true if ($options === true) { return $defaults; @@ -652,7 +575,7 @@ class Blueprint } // extend options if possible - $options = static::extend($options); + $options = $this->extend($options); foreach ($options as $key => $value) { $alias = $aliases[$key] ?? null; @@ -663,16 +586,18 @@ class Blueprint } } - return [...$defaults, ...$options]; + return array_merge($defaults, $options); } /** * Normalizes all required keys in sections + * + * @param string $tabName + * @param array $sections + * @return array */ - protected function normalizeSections( - string $tabName, - array $sections - ): array { + protected function normalizeSections(string $tabName, array $sections): array + { foreach ($sections as $sectionName => $sectionProps) { // unset / remove section if its property is false if ($sectionProps === false) { @@ -686,27 +611,26 @@ class Blueprint } // inject all section extensions - $sectionProps = static::extend($sectionProps); + $sectionProps = $this->extend($sectionProps); - $sections[$sectionName] = $sectionProps = [ - ...$sectionProps, + $sections[$sectionName] = $sectionProps = array_merge($sectionProps, [ 'name' => $sectionName, 'type' => $type = $sectionProps['type'] ?? $sectionName - ]; + ]); if (empty($type) === true || is_string($type) === false) { $sections[$sectionName] = [ - 'name' => $sectionName, - 'label' => 'Invalid section type for section "' . $sectionName . '"', - 'type' => 'info', - 'text' => 'The following section types are available: ' . static::helpList(array_keys(Section::$types)) + 'name' => $sectionName, + 'headline' => 'Invalid section type for section "' . $sectionName . '"', + 'type' => 'info', + 'text' => 'The following section types are available: ' . $this->helpList(array_keys(Section::$types)) ]; } elseif (isset(Section::$types[$type]) === false) { $sections[$sectionName] = [ - 'name' => $sectionName, - 'label' => 'Invalid section type ("' . $type . '")', - 'type' => 'info', - 'text' => 'The following section types are available: ' . static::helpList(array_keys(Section::$types)) + 'name' => $sectionName, + 'headline' => 'Invalid section type ("' . $type . '")', + 'type' => 'info', + 'text' => 'The following section types are available: ' . $this->helpList(array_keys(Section::$types)) ]; } @@ -742,13 +666,16 @@ class Blueprint } // store all normalized sections - $this->sections = [...$this->sections, ...$sections]; + $this->sections = array_merge($this->sections, $sections); return $sections; } /** * Normalizes all required keys in tabs + * + * @param array $tabs + * @return array */ protected function normalizeTabs($tabs): array { @@ -764,7 +691,7 @@ class Blueprint } // inject all tab extensions - $tabProps = static::extend($tabProps); + $tabProps = $this->extend($tabProps); // inject a preset if available $tabProps = $this->preset($tabProps); @@ -772,14 +699,13 @@ class Blueprint $tabProps = $this->convertFieldsToSections($tabName, $tabProps); $tabProps = $this->convertSectionsToColumns($tabName, $tabProps); - $tabs[$tabName] = [ - ...$tabProps, + $tabs[$tabName] = array_merge($tabProps, [ 'columns' => $this->normalizeColumns($tabName, $tabProps['columns'] ?? []), 'icon' => $tabProps['icon'] ?? null, 'label' => $this->i18n($tabProps['label'] ?? ucfirst($tabName)), 'link' => $this->model->panel()->url(true) . '/?tab=' . $tabName, 'name' => $tabName, - ]; + ]); } return $this->tabs = $tabs; @@ -787,6 +713,9 @@ class Blueprint /** * Injects a blueprint preset + * + * @param array $props + * @return array */ protected function preset(array $props): array { @@ -801,7 +730,7 @@ class Blueprint $preset = static::$presets[$props['preset']]; if (is_string($preset) === true) { - $preset = F::load($preset, allowOutput: false); + $preset = require $preset; } return $preset($props); @@ -809,17 +738,16 @@ class Blueprint /** * Returns a single section by name + * + * @param string $name + * @return \Kirby\Cms\Section|null */ - public function section(string $name): Section|null + public function section(string $name) { if (empty($this->sections[$name]) === true) { return null; } - if ($this->sections[$name] instanceof Section) { - return $this->sections[$name]; //@codeCoverageIgnore - } - // get all props $props = $this->sections[$name]; @@ -827,27 +755,29 @@ class Blueprint $props['model'] = $this->model(); // create a new section object - return $this->sections[$name] = new Section($props['type'], $props); + return new Section($props['type'], $props); } /** * Returns all sections + * + * @return array */ public function sections(): array { return A::map( $this->sections, - fn ($section) => match (true) { - $section instanceof Section => $section, - default => $this->section($section['name']) - } + fn ($section) => $this->section($section['name']) ); } /** * Returns a single tab by name + * + * @param string|null $name + * @return array|null */ - public function tab(string|null $name = null): array|null + public function tab(?string $name = null): ?array { if ($name === null) { return A::first($this->tabs); @@ -858,6 +788,8 @@ class Blueprint /** * Returns all tabs + * + * @return array */ public function tabs(): array { @@ -866,6 +798,8 @@ class Blueprint /** * Returns the blueprint title + * + * @return string */ public function title(): string { @@ -874,6 +808,8 @@ class Blueprint /** * Converts the blueprint object to a plain array + * + * @return array */ public function toArray(): array { diff --git a/kirby/src/Cms/Collection.php b/kirby/src/Cms/Collection.php index a4a5cb6..fb8f5f9 100644 --- a/kirby/src/Cms/Collection.php +++ b/kirby/src/Cms/Collection.php @@ -6,7 +6,6 @@ use Closure; use Kirby\Exception\InvalidArgumentException; use Kirby\Toolkit\Collection as BaseCollection; use Kirby\Toolkit\Str; -use Kirby\Uuid\Uuid; /** * The Collection class serves as foundation @@ -66,29 +65,19 @@ class Collection extends BaseCollection } /** - * Internal setter for each object in the Collection; - * override from the Toolkit Collection is needed to - * make the CMS collections case-sensitive; - * child classes can override it again to add validation - * and custom behavior depending on the object type + * Internal setter for each object in the Collection. + * This takes care of Component validation and of setting + * the collection prop on each object correctly. * + * @param string $id * @param object $object + * @return void */ public function __set(string $id, $object): void { $this->data[$id] = $object; } - /** - * Internal remover for each object in the Collection; - * override from the Toolkit Collection is needed to - * make the CMS collections case-sensitive - */ - public function __unset($id) - { - unset($this->data[$id]); - } - /** * Adds a single object or * an entire second collection to the @@ -98,12 +87,9 @@ class Collection extends BaseCollection */ public function add($object) { - if ($object instanceof self) { + if (is_a($object, self::class) === true) { $this->data = array_merge($this->data, $object->data); - } elseif ( - is_object($object) === true && - method_exists($object, 'id') === true - ) { + } elseif (is_object($object) === true && method_exists($object, 'id') === true) { $this->__set($object->id(), $object); } else { $this->append($object); @@ -124,46 +110,26 @@ class Collection extends BaseCollection { if (count($args) === 1) { // try to determine the key from the provided item - if ( - is_object($args[0]) === true && - is_callable([$args[0], 'id']) === true - ) { + if (is_object($args[0]) === true && is_callable([$args[0], 'id']) === true) { return parent::append($args[0]->id(), $args[0]); + } else { + return parent::append($args[0]); } - - return parent::append($args[0]); } return parent::append(...$args); } - /** - * Find a single element by an attribute and its value - * - * @param mixed $value - * @return mixed|null - */ - public function findBy(string $attribute, $value) - { - // $value: cast UUID object to string to allow uses - // like `$pages->findBy('related', $page->uuid())` - if ($value instanceof Uuid) { - $value = $value->toString(); - } - - return parent::findBy($attribute, $value); - } - /** * Groups the items by a given field or callback. Returns a collection * with an item for each group and a collection for each group. * * @param string|Closure $field - * @param bool $caseInsensitive Ignore upper/lowercase for group names + * @param bool $i Ignore upper/lowercase for group names * @return \Kirby\Cms\Collection * @throws \Kirby\Exception\Exception */ - public function group($field, bool $caseInsensitive = true) + public function group($field, bool $i = true) { if (is_string($field) === true) { $groups = new Collection([], $this->parent()); @@ -176,10 +142,8 @@ class Collection extends BaseCollection throw new InvalidArgumentException('Invalid grouping value for key: ' . $key); } - $value = (string)$value; - // ignore upper/lowercase for group names - if ($caseInsensitive === true) { + if ($i) { $value = Str::lower($value); } @@ -195,7 +159,7 @@ class Collection extends BaseCollection return $groups; } - return parent::group($field, $caseInsensitive); + return parent::group($field, $i); } /** @@ -203,6 +167,7 @@ class Collection extends BaseCollection * is in the collection * * @param string|object $key + * @return bool */ public function has($key): bool { @@ -219,8 +184,9 @@ class Collection extends BaseCollection * or ids and then search accordingly. * * @param string|object $needle + * @return int */ - public function indexOf($needle): int|false + public function indexOf($needle): int { if (is_string($needle) === true) { return array_search($needle, $this->keys()); @@ -242,9 +208,7 @@ class Collection extends BaseCollection foreach ($keys as $key) { if (is_array($key) === true) { return $this->not(...$key); - } - - if ($key instanceof BaseCollection) { + } elseif (is_a($key, 'Kirby\Toolkit\Collection') === true) { $collection = $collection->not(...$key->keys()); } elseif (is_object($key) === true) { $key = $key->id(); @@ -260,31 +224,20 @@ class Collection extends BaseCollection * Add pagination and return a sliced set of data. * * @param mixed ...$arguments - * @return $this|static + * @return \Kirby\Cms\Collection */ public function paginate(...$arguments) { $this->pagination = Pagination::for($this, ...$arguments); // slice and clone the collection according to the pagination - return $this->slice( - $this->pagination->offset(), - $this->pagination->limit() - ); - } - - /** - * Get the pagination object - * - * @return \Kirby\Cms\Pagination|null - */ - public function pagination() - { - return $this->pagination; + return $this->slice($this->pagination->offset(), $this->pagination->limit()); } /** * Returns the parent model + * + * @return \Kirby\Cms\Model */ public function parent() { @@ -303,14 +256,11 @@ class Collection extends BaseCollection { if (count($args) === 1) { // try to determine the key from the provided item - if ( - is_object($args[0]) === true && - is_callable([$args[0], 'id']) === true - ) { + if (is_object($args[0]) === true && is_callable([$args[0], 'id']) === true) { return parent::prepend($args[0]->id(), $args[0]); + } else { + return parent::prepend($args[0]); } - - return parent::prepend($args[0]); } return parent::prepend(...$args); @@ -321,6 +271,7 @@ class Collection extends BaseCollection * offset, limit, search and paginate on the collection. * Any part of the query is optional. * + * @param array $arguments * @return static */ public function query(array $arguments = []) @@ -363,11 +314,13 @@ class Collection extends BaseCollection /** * Searches the collection + * + * @param string|null $query + * @param array $params + * @return self */ - public function search( - string $query = null, - string|array $params = [] - ): static { + public function search(string $query = null, $params = []) + { return Search::collection($this, $query, $params); } @@ -375,6 +328,9 @@ class Collection extends BaseCollection * Converts all objects in the collection * to an array. This can also take a callback * function to further modify the array result. + * + * @param \Closure|null $map + * @return array */ public function toArray(Closure $map = null): array { diff --git a/kirby/src/Cms/Collections.php b/kirby/src/Cms/Collections.php index beafe8d..542ed03 100644 --- a/kirby/src/Cms/Collections.php +++ b/kirby/src/Cms/Collections.php @@ -2,7 +2,6 @@ namespace Kirby\Cms; -use Closure; use Kirby\Exception\NotFoundException; use Kirby\Filesystem\F; use Kirby\Toolkit\Controller; @@ -28,20 +27,25 @@ class Collections * has been called, to avoid further * processing on sequential calls to * the same collection. + * + * @var array */ - protected array $cache = []; + protected $cache = []; /** * Store of all collections + * + * @var array */ - protected array $collections = []; + protected $collections = []; /** * Magic caller to enable something like * `$collections->myCollection()` * - * @return \Kirby\Toolkit\Collection|null - * @todo 5.0 Add return type declaration + * @param string $name + * @param array $arguments + * @return \Kirby\Cms\Collection|null */ public function __call(string $name, array $arguments = []) { @@ -51,19 +55,23 @@ class Collections /** * Loads a collection by name if registered * - * @return \Kirby\Toolkit\Collection|null - * @todo 5.0 Add deprecation warning when anything else than a Collection is returned - * @todo 6.0 Add PHP return type declaration for `Toolkit\Collection` + * @param string $name + * @param array $data + * @return \Kirby\Cms\Collection|null */ public function get(string $name, array $data = []) { // if not yet loaded - $this->collections[$name] ??= $this->load($name); + if (isset($this->collections[$name]) === false) { + $this->collections[$name] = $this->load($name); + } // if not yet cached - if (($this->cache[$name]['data'] ?? null) !== $data) { + if ( + isset($this->cache[$name]) === false || + $this->cache[$name]['data'] !== $data + ) { $controller = new Controller($this->collections[$name]); - $this->cache[$name] = [ 'result' => $controller->call(null, $data), 'data' => $data @@ -80,6 +88,9 @@ class Collections /** * Checks if a collection exists + * + * @param string $name + * @return bool */ public function has(string $name): bool { @@ -90,7 +101,7 @@ class Collections try { $this->load($name); return true; - } catch (NotFoundException) { + } catch (NotFoundException $e) { return false; } } @@ -99,9 +110,11 @@ class Collections * Loads collection from php file in a * given directory or from plugin extension. * + * @param string $name + * @return mixed * @throws \Kirby\Exception\NotFoundException */ - public function load(string $name): mixed + public function load(string $name) { $kirby = App::instance(); @@ -109,9 +122,9 @@ class Collections $file = $kirby->root('collections') . '/' . $name . '.php'; if (is_file($file) === true) { - $collection = F::load($file, allowOutput: false); + $collection = F::load($file); - if ($collection instanceof Closure) { + if (is_a($collection, 'Closure')) { return $collection; } } @@ -119,7 +132,10 @@ class Collections // fallback to collections from plugins $collections = $kirby->extensions('collections'); - return $collections[$name] ?? - throw new NotFoundException('The collection cannot be found'); + if (isset($collections[$name]) === true) { + return $collections[$name]; + } + + throw new NotFoundException('The collection cannot be found'); } } diff --git a/kirby/src/Content/Content.php b/kirby/src/Cms/Content.php similarity index 67% rename from kirby/src/Content/Content.php rename to kirby/src/Cms/Content.php index 978c8d2..d0a6e11 100644 --- a/kirby/src/Content/Content.php +++ b/kirby/src/Cms/Content.php @@ -1,16 +1,14 @@ * @link https://getkirby.com * @copyright Bastian Allgeier @@ -20,29 +18,39 @@ class Content { /** * The raw data array + * + * @var array */ - protected array $data = []; + protected $data = []; /** * Cached field objects * Once a field is being fetched * it is added to this array for * later reuse + * + * @var array */ - protected array $fields = []; + protected $fields = []; /** * A potential parent object. * Not necessarily needed. Especially * for testing, but field methods might * need it. + * + * @var Model */ - protected ModelWithContent|null $parent; + protected $parent; /** * Magic getter for content fields + * + * @param string $name + * @param array $arguments + * @return \Kirby\Cms\Field */ - public function __call(string $name, array $arguments = []): Field + public function __call(string $name, array $arguments = []) { return $this->get($name); } @@ -50,13 +58,12 @@ class Content /** * Creates a new Content object * + * @param array|null $data + * @param object|null $parent * @param bool $normalize Set to `false` if the input field keys are already lowercase */ - public function __construct( - array $data = [], - ModelWithContent $parent = null, - bool $normalize = true - ) { + public function __construct(array $data = [], $parent = null, bool $normalize = true) + { if ($normalize === true) { $data = array_change_key_case($data, CASE_LOWER); } @@ -68,9 +75,9 @@ class Content /** * Same as `self::data()` to improve * `var_dump` output - * @codeCoverageIgnore * * @see self::data() + * @return array */ public function __debugInfo(): array { @@ -79,6 +86,9 @@ class Content /** * Converts the content to a new blueprint + * + * @param string $to + * @return array */ public function convertTo(string $to): array { @@ -89,21 +99,11 @@ class Content // blueprints $old = $this->parent->blueprint(); $subfolder = dirname($old->name()); - $new = Blueprint::factory( - $subfolder . '/' . $to, - $subfolder . '/default', - $this->parent - ); + $new = Blueprint::factory($subfolder . '/' . $to, $subfolder . '/default', $this->parent); // forms - $oldForm = new Form([ - 'fields' => $old->fields(), - 'model' => $this->parent - ]); - $newForm = new Form([ - 'fields' => $new->fields(), - 'model' => $this->parent - ]); + $oldForm = new Form(['fields' => $old->fields(), 'model' => $this->parent]); + $newForm = new Form(['fields' => $new->fields(), 'model' => $this->parent]); // fields $oldFields = $oldForm->fields(); @@ -115,7 +115,7 @@ class Content $oldField = $oldFields->get($name); // field name and type matches with old template - if ($oldField?->type() === $newField->type()) { + if ($oldField && $oldField->type() === $newField->type()) { $data[$name] = $content->get($name)->value(); } else { $data[$name] = $newField->default(); @@ -128,6 +128,8 @@ class Content /** * Returns the raw data array + * + * @return array */ public function data(): array { @@ -136,6 +138,8 @@ class Content /** * Returns all registered field objects + * + * @return array */ public function fields(): array { @@ -148,8 +152,11 @@ class Content /** * Returns either a single field object * or all registered fields + * + * @param string|null $key + * @return \Kirby\Cms\Field|array */ - public function get(string $key = null): Field|array + public function get(string $key = null) { if ($key === null) { return $this->fields(); @@ -157,15 +164,20 @@ class Content $key = strtolower($key); - return $this->fields[$key] ??= new Field( - $this->parent, - $key, - $this->data()[$key] ?? null - ); + if (isset($this->fields[$key])) { + return $this->fields[$key]; + } + + $value = $this->data()[$key] ?? null; + + return $this->fields[$key] = new Field($this->parent, $key, $value); } /** * Checks if a content field is set + * + * @param string $key + * @return bool */ public function has(string $key): bool { @@ -174,6 +186,8 @@ class Content /** * Returns all field keys + * + * @return array */ public function keys(): array { @@ -184,11 +198,14 @@ class Content * Returns a clone of the content object * without the fields, specified by the * passed key(s) + * + * @param string ...$keys + * @return static */ - public function not(string ...$keys): static + public function not(...$keys) { $copy = clone $this; - $copy->fields = []; + $copy->fields = null; foreach ($keys as $key) { unset($copy->data[strtolower($key)]); @@ -200,8 +217,10 @@ class Content /** * Returns the parent * Site, Page, File or User object + * + * @return \Kirby\Cms\Model */ - public function parent(): ModelWithContent|null + public function parent() { return $this->parent; } @@ -209,9 +228,10 @@ class Content /** * Set the parent model * + * @param \Kirby\Cms\Model $parent * @return $this */ - public function setParent(ModelWithContent $parent): static + public function setParent(Model $parent) { $this->parent = $parent; return $this; @@ -221,6 +241,7 @@ class Content * Returns the raw data array * * @see self::data() + * @return array */ public function toArray(): array { @@ -231,12 +252,12 @@ class Content * Updates the content and returns * a cloned object * + * @param array|null $content + * @param bool $overwrite * @return $this */ - public function update( - array $content = null, - bool $overwrite = false - ): static { + public function update(array $content = null, bool $overwrite = false) + { $content = array_change_key_case((array)$content, CASE_LOWER); $this->data = $overwrite === true ? $content : array_merge($this->data, $content); diff --git a/kirby/src/Cms/ContentLock.php b/kirby/src/Cms/ContentLock.php index 1186a3f..f938116 100644 --- a/kirby/src/Cms/ContentLock.php +++ b/kirby/src/Cms/ContentLock.php @@ -2,9 +2,9 @@ namespace Kirby\Cms; -use Kirby\Exception\AuthException; use Kirby\Exception\DuplicateException; use Kirby\Exception\LogicException; +use Kirby\Exception\PermissionException; /** * Takes care of content lock and unlock information @@ -17,16 +17,33 @@ use Kirby\Exception\LogicException; */ class ContentLock { - protected array $data; + /** + * Lock data + * + * @var array + */ + protected $data; - public function __construct( - protected ModelWithContent $model - ) { - $this->data = $this->kirby()->locks()->get($model); + /** + * The model to manage locking/unlocking for + * + * @var ModelWithContent + */ + protected $model; + + /** + * @param \Kirby\Cms\ModelWithContent $model + */ + public function __construct(ModelWithContent $model) + { + $this->model = $model; + $this->data = $this->kirby()->locks()->get($model); } /** * Clears the lock unconditionally + * + * @return bool */ protected function clearLock(): bool { @@ -44,6 +61,7 @@ class ContentLock /** * Sets lock with the current user * + * @return bool * @throws \Kirby\Exception\DuplicateException */ public function create(): bool @@ -68,8 +86,10 @@ class ContentLock /** * Returns either `false` or array with `user`, `email`, * `time` and `unlockable` keys + * + * @return array|bool */ - public function get(): array|bool + public function get() { $data = $this->data['lock'] ?? []; @@ -94,6 +114,8 @@ class ContentLock /** * Returns if the model is locked by another user + * + * @return bool */ public function isLocked(): bool { @@ -108,6 +130,8 @@ class ContentLock /** * Returns if the current user's lock has been removed by another user + * + * @return bool */ public function isUnlocked(): bool { @@ -118,6 +142,8 @@ class ContentLock /** * Returns the app instance + * + * @return \Kirby\Cms\App */ protected function kirby(): App { @@ -127,6 +153,7 @@ class ContentLock /** * Removes lock of current user * + * @return bool * @throws \Kirby\Exception\LogicException */ public function remove(): bool @@ -149,6 +176,8 @@ class ContentLock /** * Removes unlock information for current user + * + * @return bool */ public function resolve(): bool { @@ -166,33 +195,10 @@ class ContentLock return $this->kirby()->locks()->set($this->model, $this->data); } - /** - * Returns the state for the - * form buttons in the frontend - */ - public function state(): string|null - { - return match (true) { - $this->isUnlocked() => 'unlock', - $this->isLocked() => 'lock', - default => null - }; - } - - /** - * Returns a usable lock array - * for the frontend - */ - public function toArray(): array - { - return [ - 'state' => $this->state(), - 'data' => $this->get() - ]; - } - /** * Removes current lock and adds lock user to unlock data + * + * @return bool */ public function unlock(): bool { @@ -212,11 +218,15 @@ class ContentLock * Returns currently authenticated user; * throws exception if none is authenticated * + * @return \Kirby\Cms\User * @throws \Kirby\Exception\PermissionException */ protected function user(): User { - return $this->kirby()->user() ?? - throw new AuthException('No user authenticated.'); + if ($user = $this->kirby()->user()) { + return $user; + } + + throw new PermissionException('No user authenticated.'); } } diff --git a/kirby/src/Cms/ContentLocks.php b/kirby/src/Cms/ContentLocks.php index 2d7c400..2d08d9f 100644 --- a/kirby/src/Cms/ContentLocks.php +++ b/kirby/src/Cms/ContentLocks.php @@ -22,14 +22,18 @@ class ContentLocks * Data from the `.lock` files * that have been read so far * cached by `.lock` file path + * + * @var array */ - protected array $data = []; + protected $data = []; /** * PHP file handles for all currently * open `.lock` files + * + * @var array */ - protected array $handles = []; + protected $handles = []; /** * Closes the open file handles @@ -46,9 +50,11 @@ class ContentLocks /** * Removes the file lock and closes the file handle * + * @param string $file + * @return void * @throws \Kirby\Exception\Exception */ - protected function closeHandle(string $file): void + protected function closeHandle(string $file) { if (isset($this->handles[$file]) === false) { return; @@ -66,15 +72,20 @@ class ContentLocks /** * Returns the path to a model's lock file + * + * @param \Kirby\Cms\ModelWithContent $model + * @return string */ public static function file(ModelWithContent $model): string { - $root = $model::CLASS_ALIAS === 'file' ? dirname($model->root()) : $model->root(); - return $root . '/.lock'; + return $model->contentFileDirectory() . '/.lock'; } /** * Returns the lock/unlock data for the specified model + * + * @param \Kirby\Cms\ModelWithContent $model + * @return array */ public function get(ModelWithContent $model): array { @@ -110,6 +121,7 @@ class ContentLocks /** * Returns the file handle to a `.lock` file * + * @param string $file * @param bool $create Whether to create the file if it does not exist * @return resource|null File handle * @throws \Kirby\Exception\Exception @@ -143,6 +155,9 @@ class ContentLocks /** * Returns model ID used as the key for the data array; * prepended with a slash because the $site otherwise won't have an ID + * + * @param \Kirby\Cms\ModelWithContent $model + * @return string */ public static function id(ModelWithContent $model): string { @@ -152,6 +167,9 @@ class ContentLocks /** * Sets and writes the lock/unlock data for the specified model * + * @param \Kirby\Cms\ModelWithContent $model + * @param array $data + * @return bool * @throws \Kirby\Exception\Exception */ public function set(ModelWithContent $model, array $data): bool diff --git a/kirby/src/Cms/ContentTranslation.php b/kirby/src/Cms/ContentTranslation.php new file mode 100644 index 0000000..5ffa744 --- /dev/null +++ b/kirby/src/Cms/ContentTranslation.php @@ -0,0 +1,248 @@ + + * @link https://getkirby.com + * @copyright Bastian Allgeier + * @license https://getkirby.com/license + */ +class ContentTranslation +{ + use Properties; + + /** + * @var string + */ + protected $code; + + /** + * @var array + */ + protected $content; + + /** + * @var string + */ + protected $contentFile; + + /** + * @var Model + */ + protected $parent; + + /** + * @var string + */ + protected $slug; + + /** + * Creates a new translation object + * + * @param array $props + */ + public function __construct(array $props) + { + $this->setRequiredProperties($props, ['parent', 'code']); + $this->setOptionalProperties($props, ['slug', 'content']); + } + + /** + * Improve `var_dump` output + * + * @return array + */ + public function __debugInfo(): array + { + return $this->toArray(); + } + + /** + * Returns the language code of the + * translation + * + * @return string + */ + public function code(): string + { + return $this->code; + } + + /** + * Returns the translation content + * as plain array + * + * @return array + */ + public function content(): array + { + $parent = $this->parent(); + + if ($this->content === null) { + $this->content = $parent->readContent($this->code()); + } + + $content = $this->content; + + // merge with the default content + if ($this->isDefault() === false && $defaultLanguage = $parent->kirby()->defaultLanguage()) { + $default = []; + + if ($defaultTranslation = $parent->translation($defaultLanguage->code())) { + $default = $defaultTranslation->content(); + } + + $content = array_merge($default, $content); + } + + return $content; + } + + /** + * Absolute path to the translation content file + * + * @return string + */ + public function contentFile(): string + { + return $this->contentFile = $this->parent->contentFile($this->code, true); + } + + /** + * Checks if the translation file exists + * + * @return bool + */ + public function exists(): bool + { + return file_exists($this->contentFile()) === true; + } + + /** + * Returns the translation code as id + * + * @return string + */ + public function id(): string + { + return $this->code(); + } + + /** + * Checks if the this is the default translation + * of the model + * + * @return bool + */ + public function isDefault(): bool + { + if ($defaultLanguage = $this->parent->kirby()->defaultLanguage()) { + return $this->code() === $defaultLanguage->code(); + } + + return false; + } + + /** + * Returns the parent page, file or site object + * + * @return \Kirby\Cms\Model + */ + public function parent() + { + return $this->parent; + } + + /** + * @param string $code + * @return $this + */ + protected function setCode(string $code) + { + $this->code = $code; + return $this; + } + + /** + * @param array|null $content + * @return $this + */ + protected function setContent(array $content = null) + { + if ($content !== null) { + $this->content = array_change_key_case($content); + } else { + $this->content = null; + } + + return $this; + } + + /** + * @param \Kirby\Cms\Model $parent + * @return $this + */ + protected function setParent(Model $parent) + { + $this->parent = $parent; + return $this; + } + + /** + * @param string|null $slug + * @return $this + */ + protected function setSlug(string $slug = null) + { + $this->slug = $slug; + return $this; + } + + /** + * Returns the custom translation slug + * + * @return string|null + */ + public function slug(): ?string + { + return $this->slug ??= ($this->content()['slug'] ?? null); + } + + /** + * Merge the old and new data + * + * @param array|null $data + * @param bool $overwrite + * @return $this + */ + public function update(array $data = null, bool $overwrite = false) + { + $data = array_change_key_case((array)$data); + $this->content = $overwrite === true ? $data : array_merge($this->content(), $data); + return $this; + } + + /** + * Converts the most important translation + * props to an array + * + * @return array + */ + public function toArray(): array + { + return [ + 'code' => $this->code(), + 'content' => $this->content(), + 'exists' => $this->exists(), + 'slug' => $this->slug(), + ]; + } +} diff --git a/kirby/src/Cms/Core.php b/kirby/src/Cms/Core.php index 11ca635..48ce72e 100644 --- a/kirby/src/Cms/Core.php +++ b/kirby/src/Cms/Core.php @@ -2,15 +2,6 @@ namespace Kirby\Cms; -use Kirby\Cache\ApcuCache; -use Kirby\Cache\FileCache; -use Kirby\Cache\MemCached; -use Kirby\Cache\MemoryCache; -use Kirby\Cms\Auth\EmailChallenge; -use Kirby\Cms\Auth\TotpChallenge; -use Kirby\Form\Field\BlocksField; -use Kirby\Form\Field\LayoutField; - /** * The Core class lists all parts of Kirby * that need to be loaded or initalized in order @@ -31,16 +22,27 @@ use Kirby\Form\Field\LayoutField; class Core { /** - * Optional override for the auto-detected index root + * @var array */ - public static string|null $indexRoot = null; + protected $cache = []; - protected array $cache = []; - protected string $root; + /** + * @var \Kirby\Cms\App + */ + protected $kirby; - public function __construct(protected App $kirby) + /** + * @var string + */ + protected $root; + + /** + * @param \Kirby\Cms\App $kirby + */ + public function __construct(App $kirby) { - $this->root = dirname(__DIR__, 2) . '/config'; + $this->kirby = $kirby; + $this->root = dirname(__DIR__, 2) . '/config'; } /** @@ -48,8 +50,11 @@ class Core * * This is a shortcut for `$kirby->core()->load()->area()` * to give faster access to original area code in plugins. + * + * @param string $name + * @return array|null */ - public function area(string $name): array|null + public function area(string $name): ?array { return $this->load()->area($name); } @@ -58,17 +63,17 @@ class Core * Returns a list of all paths to area definition files * * They are located in `/kirby/config/areas` + * + * @return array */ public function areas(): array { return [ 'account' => $this->root . '/areas/account.php', 'installation' => $this->root . '/areas/installation.php', - 'lab' => $this->root . '/areas/lab.php', 'languages' => $this->root . '/areas/languages.php', 'login' => $this->root . '/areas/login.php', 'logout' => $this->root . '/areas/logout.php', - 'search' => $this->root . '/areas/search.php', 'site' => $this->root . '/areas/site.php', 'system' => $this->root . '/areas/system.php', 'users' => $this->root . '/areas/users.php', @@ -77,12 +82,13 @@ class Core /** * Returns a list of all default auth challenge classes + * + * @return array */ public function authChallenges(): array { return [ - 'email' => EmailChallenge::class, - 'totp' => TotpChallenge::class, + 'email' => 'Kirby\Cms\Auth\EmailChallenge' ]; } @@ -90,6 +96,8 @@ class Core * Returns a list of all paths to blueprint presets * * They are located in `/kirby/config/presets` + * + * @return array */ public function blueprintPresets(): array { @@ -101,10 +109,12 @@ class Core } /** - * Returns a list of paths to core blueprints or - * the blueprint in array form + * Returns a list of all paths to core blueprints * + * They are located in `/kirby/config/blueprints`. * Block blueprints are located in `/kirby/config/blocks` + * + * @return array */ public function blueprints(): array { @@ -123,45 +133,28 @@ class Core 'blocks/video' => $this->root . '/blocks/video/video.yml', // file blueprints - 'files/default' => ['title' => 'File'], + 'files/default' => $this->root . '/blueprints/files/default.yml', // page blueprints - 'pages/default' => ['title' => 'Page'], + 'pages/default' => $this->root . '/blueprints/pages/default.yml', // site blueprints - 'site' => [ - 'title' => 'Site', - 'sections' => [ - 'pages' => [ - 'headline' => ['*' => 'pages'], - 'type' => 'pages' - ] - ] - ] - ]; - } - - /** - * Returns a list of all core caches - */ - public function caches(): array - { - return [ - 'updates' => true, - 'uuid' => true, + 'site' => $this->root . '/blueprints/site.yml' ]; } /** * Returns a list of all cache driver classes + * + * @return array */ public function cacheTypes(): array { return [ - 'apcu' => ApcuCache::class, - 'file' => FileCache::class, - 'memcached' => MemCached::class, - 'memory' => MemoryCache::class, + 'apcu' => 'Kirby\Cache\ApcuCache', + 'file' => 'Kirby\Cache\FileCache', + 'memcached' => 'Kirby\Cache\MemCached', + 'memory' => 'Kirby\Cache\MemoryCache', ]; } @@ -170,6 +163,8 @@ class Core * * The component functions can be found in * `/kirby/config/components.php` + * + * @return array */ public function components(): array { @@ -178,6 +173,8 @@ class Core /** * Returns a map of all field method aliases + * + * @return array */ public function fieldMethodAliases(): array { @@ -202,6 +199,8 @@ class Core * Returns an array of all field method functions * * Field methods are stored in `/kirby/config/methods.php` + * + * @return array */ public function fieldMethods(): array { @@ -212,6 +211,8 @@ class Core * Returns an array of paths for field mixins * * They are located in `/kirby/config/fields/mixins` + * + * @return array */ public function fieldMixins(): array { @@ -235,13 +236,14 @@ class Core * * The more complex field classes can be found in * `/kirby/src/Form/Fields` + * + * @return array */ public function fields(): array { return [ - 'blocks' => BlocksField::class, + 'blocks' => 'Kirby\Form\Field\BlocksField', 'checkboxes' => $this->root . '/fields/checkboxes.php', - 'color' => $this->root . '/fields/color.php', 'date' => $this->root . '/fields/date.php', 'email' => $this->root . '/fields/email.php', 'files' => $this->root . '/fields/files.php', @@ -249,13 +251,11 @@ class Core 'headline' => $this->root . '/fields/headline.php', 'hidden' => $this->root . '/fields/hidden.php', 'info' => $this->root . '/fields/info.php', - 'layout' => LayoutField::class, + 'layout' => 'Kirby\Form\Field\LayoutField', 'line' => $this->root . '/fields/line.php', - 'link' => $this->root . '/fields/link.php', 'list' => $this->root . '/fields/list.php', 'multiselect' => $this->root . '/fields/multiselect.php', 'number' => $this->root . '/fields/number.php', - 'object' => $this->root . '/fields/object.php', 'pages' => $this->root . '/fields/pages.php', 'radio' => $this->root . '/fields/radio.php', 'range' => $this->root . '/fields/range.php', @@ -277,6 +277,8 @@ class Core /** * Returns a map of all kirbytag aliases + * + * @return array */ public function kirbyTagAliases(): array { @@ -290,6 +292,8 @@ class Core * Returns an array of all kirbytag definitions * * They are located in `/kirby/config/tags.php` + * + * @return array */ public function kirbyTags(): array { @@ -302,8 +306,10 @@ class Core * The loader is set to not include plugins. * This way, you can access original Kirby core code * through this load method. + * + * @return \Kirby\Cms\Loader */ - public function load(): Loader + public function load() { return new Loader($this->kirby, false); } @@ -312,6 +318,8 @@ class Core * Returns all absolute paths to important directories * * Roots are resolved and baked in `\Kirby\Cms\App::bakeRoots()` + * + * @return array */ public function roots(): array { @@ -321,7 +329,7 @@ class Core 'i18n:translations' => fn (array $roots) => $roots['i18n'] . '/translations', 'i18n:rules' => fn (array $roots) => $roots['i18n'] . '/rules', - 'index' => fn (array $roots) => static::$indexRoot ?? dirname(__DIR__, 3), + 'index' => fn (array $roots) => dirname(__DIR__, 3), 'assets' => fn (array $roots) => $roots['index'] . '/assets', 'content' => fn (array $roots) => $roots['index'] . '/content', 'media' => fn (array $roots) => $roots['index'] . '/media', @@ -331,7 +339,6 @@ class Core 'blueprints' => fn (array $roots) => $roots['site'] . '/blueprints', 'cache' => fn (array $roots) => $roots['site'] . '/cache', 'collections' => fn (array $roots) => $roots['site'] . '/collections', - 'commands' => fn (array $roots) => $roots['site'] . '/commands', 'config' => fn (array $roots) => $roots['site'] . '/config', 'controllers' => fn (array $roots) => $roots['site'] . '/controllers', 'languages' => fn (array $roots) => $roots['site'] . '/languages', @@ -352,6 +359,8 @@ class Core * Routes are split into `before` and `after` routes. * * Plugin routes will be injected inbetween. + * + * @return array */ public function routes(): array { @@ -362,6 +371,8 @@ class Core * Returns a list of all paths to core block snippets * * They are located in `/kirby/config/blocks` + * + * @return array */ public function snippets(): array { @@ -384,6 +395,8 @@ class Core * Returns a list of paths to section mixins * * They are located in `/kirby/config/sections/mixins` + * + * @return array */ public function sectionMixins(): array { @@ -406,6 +419,8 @@ class Core * Returns a list of all section definitions * * They are located in `/kirby/config/sections` + * + * @return array */ public function sections(): array { @@ -422,6 +437,8 @@ class Core * Returns a list of paths to all system templates * * They are located in `/kirby/config/templates` + * + * @return array */ public function templates(): array { @@ -435,6 +452,8 @@ class Core * Returns an array with all system URLs * * URLs are resolved and baked in `\Kirby\Cms\App::bakeUrls()` + * + * @return array */ public function urls(): array { @@ -446,9 +465,9 @@ class Core if (empty($path) === true) { return $urls['index']; + } else { + return $urls['base'] . '/' . $path; } - - return $urls['base'] . '/' . $path; }, 'assets' => fn (array $urls) => $urls['base'] . '/assets', 'api' => fn (array $urls) => $urls['base'] . '/' . $this->kirby->option('api.slug', 'api'), diff --git a/kirby/src/Cms/Email.php b/kirby/src/Cms/Email.php index 80900dc..6009792 100644 --- a/kirby/src/Cms/Email.php +++ b/kirby/src/Cms/Email.php @@ -4,7 +4,6 @@ namespace Kirby\Cms; use Kirby\Exception\InvalidArgumentException; use Kirby\Exception\NotFoundException; -use Kirby\Template\Template; /** * Wrapper around our Email package, which @@ -22,14 +21,18 @@ class Email { /** * Options configured through the `email` CMS option + * + * @var array */ - protected array $options; + protected $options; /** * Props for the email object; will be passed to the * Kirby\Email\Email class + * + * @var array */ - protected array $props; + protected $props; /** * Class constructor @@ -37,19 +40,23 @@ class Email * @param string|array $preset Preset name from the config or a simple props array * @param array $props Props array to override the $preset */ - public function __construct(string|array $preset = [], array $props = []) + public function __construct($preset = [], array $props = []) { - $this->options = App::instance()->option('email', []); + $this->options = App::instance()->option('email'); // build a prop array based on preset and props $preset = $this->preset($preset); $this->props = array_merge($preset, $props); // add transport settings - $this->props['transport'] ??= $this->options['transport'] ?? []; + if (isset($this->props['transport']) === false) { + $this->props['transport'] = $this->options['transport'] ?? []; + } // add predefined beforeSend option - $this->props['beforeSend'] ??= $this->options['beforeSend'] ?? null; + if (isset($this->props['beforeSend']) === false) { + $this->props['beforeSend'] = $this->options['beforeSend'] ?? null; + } // transform model objects to values $this->transformUserSingle('from', 'fromName'); @@ -68,9 +75,10 @@ class Email * prop arrays in case a preset is not needed * * @param string|array $preset Preset name or simple prop array + * @return array * @throws \Kirby\Exception\NotFoundException */ - protected function preset(string|array $preset): array + protected function preset($preset): array { // only passed props, not preset name if (is_array($preset) === true) { @@ -92,6 +100,7 @@ class Email * Renders the email template(s) and sets the body props * to the result * + * @return void * @throws \Kirby\Exception\NotFoundException */ protected function template(): void @@ -124,14 +133,20 @@ class Email /** * Returns an email template by name and type + * + * @param string $name Template name + * @param string|null $type `html` or `text` + * @return \Kirby\Cms\Template */ - protected function getTemplate(string $name, string $type = null): Template + protected function getTemplate(string $name, string $type = null) { return App::instance()->template('emails/' . $name, $type, 'text'); } /** * Returns the prop array + * + * @return array */ public function toArray(): array { @@ -143,10 +158,11 @@ class Email * supports simple strings, file objects or collections/arrays of either * * @param string $prop Prop to transform + * @return void */ protected function transformFile(string $prop): void { - $this->props[$prop] = $this->transformModel($prop, File::class, 'root'); + $this->props[$prop] = $this->transformModel($prop, 'Kirby\Cms\File', 'root'); } /** @@ -159,12 +175,8 @@ class Email * returns a simple value-only array if not given * @return array Simple key-value or just value array with the transformed prop data */ - protected function transformModel( - string $prop, - string $class, - string $contentValue, - string $contentKey = null - ): array { + protected function transformModel(string $prop, string $class, string $contentValue, string $contentKey = null): array + { $value = $this->props[$prop] ?? []; // ensure consistent input by making everything an iterable value @@ -181,7 +193,7 @@ class Email } else { $result[] = $item; } - } elseif ($item instanceof $class) { + } elseif (is_a($item, $class) === true) { // value is a model object, get value through content method(s) if ($contentKey !== null) { $result[(string)$item->$contentKey()] = (string)$item->$contentValue(); @@ -204,12 +216,11 @@ class Email * * @param string $addressProp Prop with the email address * @param string $nameProp Prop with the name corresponding to the $addressProp + * @return void */ - protected function transformUserSingle( - string $addressProp, - string $nameProp - ): void { - $result = $this->transformModel($addressProp, User::class, 'name', 'email'); + protected function transformUserSingle(string $addressProp, string $nameProp): void + { + $result = $this->transformModel($addressProp, 'Kirby\Cms\User', 'name', 'email'); $address = array_keys($result)[0] ?? null; $name = $result[$address] ?? null; @@ -224,7 +235,9 @@ class Email $this->props[$addressProp] = $address; // only use the name from the user if no custom name was set - $this->props[$nameProp] ??= $name; + if (isset($this->props[$nameProp]) === false || $this->props[$nameProp] === null) { + $this->props[$nameProp] = $name; + } } /** @@ -232,9 +245,10 @@ class Email * supports simple strings, user objects or collections/arrays of either * * @param string $prop Prop to transform + * @return void */ protected function transformUserMultiple(string $prop): void { - $this->props[$prop] = $this->transformModel($prop, User::class, 'name', 'email'); + $this->props[$prop] = $this->transformModel($prop, 'Kirby\Cms\User', 'name', 'email'); } } diff --git a/kirby/src/Cms/Event.php b/kirby/src/Cms/Event.php index f4dd6f1..c6ed0c2 100644 --- a/kirby/src/Cms/Event.php +++ b/kirby/src/Cms/Event.php @@ -24,31 +24,41 @@ class Event /** * The full event name * (e.g. `page.create:after`) + * + * @var string */ - protected string $name; + protected $name; /** * The event type * (e.g. `page` in `page.create:after`) + * + * @var string */ - protected string $type; + protected $type; /** * The event action * (e.g. `create` in `page.create:after`) + * + * @var string|null */ - protected string|null $action; + protected $action; /** * The event state * (e.g. `after` in `page.create:after`) + * + * @var string|null */ - protected string|null $state; + protected $state; /** * The event arguments + * + * @var array */ - protected array $arguments = []; + protected $arguments = []; /** * Class constructor @@ -73,15 +83,20 @@ class Event /** * Magic caller for event arguments + * + * @param string $method + * @param array $arguments + * @return mixed */ - public function __call(string $method, array $arguments = []): mixed + public function __call(string $method, array $arguments = []) { return $this->argument($method); } /** * Improved `var_dump` output - * @codeCoverageIgnore + * + * @return array */ public function __debugInfo(): array { @@ -91,6 +106,8 @@ class Event /** * Makes it possible to simply echo * or stringify the entire object + * + * @return string */ public function __toString(): string { @@ -100,22 +117,33 @@ class Event /** * Returns the action of the event (e.g. `create`) * or `null` if the event name does not include an action + * + * @return string|null */ - public function action(): string|null + public function action(): ?string { return $this->action; } /** * Returns a specific event argument + * + * @param string $name + * @return mixed */ - public function argument(string $name): mixed + public function argument(string $name) { - return $this->arguments[$name] ?? null; + if (isset($this->arguments[$name]) === true) { + return $this->arguments[$name]; + } + + return null; } /** * Returns the arguments of the event + * + * @return array */ public function arguments(): array { @@ -127,8 +155,10 @@ class Event * the hook's return value * * @param object|null $bind Optional object to bind to the hook function + * @param \Closure $hook + * @return mixed */ - public function call(object|null $bind, Closure $hook): mixed + public function call(?object $bind, Closure $hook) { // collect the list of possible hook arguments $data = $this->arguments(); @@ -141,6 +171,8 @@ class Event /** * Returns the full name of the event + * + * @return string */ public function name(): string { @@ -150,16 +182,13 @@ class Event /** * Returns the full list of possible wildcard * event names based on the current event name + * + * @return array */ public function nameWildcards(): array { - // if the event is already a wildcard event, - // no further variation is possible - if ( - $this->type === '*' || - $this->action === '*' || - $this->state === '*' - ) { + // if the event is already a wildcard event, no further variation is possible + if ($this->type === '*' || $this->action === '*' || $this->state === '*') { return []; } @@ -175,9 +204,7 @@ class Event '*:' . $this->state, '*' ]; - } - - if ($this->state !== null) { + } elseif ($this->state !== null) { // event without action: $type:$state return [ @@ -185,9 +212,7 @@ class Event '*:' . $this->state, '*' ]; - } - - if ($this->action !== null) { + } elseif ($this->action !== null) { // event without state: $type.$action return [ @@ -195,22 +220,27 @@ class Event '*.' . $this->action, '*' ]; - } + } else { + // event with a simple name - // event with a simple name - return ['*']; + return ['*']; + } } /** * Returns the state of the event (e.g. `after`) + * + * @return string|null */ - public function state(): string|null + public function state(): ?string { return $this->state; } /** * Returns the event data as array + * + * @return array */ public function toArray(): array { @@ -222,6 +252,8 @@ class Event /** * Returns the event name as string + * + * @return string */ public function toString(): string { @@ -230,6 +262,8 @@ class Event /** * Returns the type of the event (e.g. `page`) + * + * @return string */ public function type(): string { @@ -240,6 +274,9 @@ class Event * Updates a given argument with a new value * * @internal + * @param string $name + * @param mixed $value + * @return void * @throws \Kirby\Exception\InvalidArgumentException */ public function updateArgument(string $name, $value): void diff --git a/kirby/src/Content/Field.php b/kirby/src/Cms/Field.php similarity index 66% rename from kirby/src/Content/Field.php rename to kirby/src/Cms/Field.php index 0082063..d3f97a5 100644 --- a/kirby/src/Content/Field.php +++ b/kirby/src/Cms/Field.php @@ -1,9 +1,8 @@ myField()->lower(); * ``` * - * @package Kirby Content + * @package Kirby Cms * @author Bastian Allgeier * @link https://getkirby.com * @copyright Bastian Allgeier @@ -29,48 +28,49 @@ class Field { /** * Field method aliases + * + * @var array */ - public static array $aliases = []; + public static $aliases = []; /** * The field name + * + * @var string */ - protected string $key; + protected $key; /** * Registered field methods + * + * @var array */ - public static array $methods = []; + public static $methods = []; /** * The parent object if available. * This will be the page, site, user or file * to which the content belongs + * + * @var Model */ - protected ModelWithContent|null $parent; + protected $parent; /** * The value of the field + * + * @var mixed */ - public mixed $value; - - /** - * Creates a new field object - */ - public function __construct( - ModelWithContent|null $parent, - string $key, - mixed $value - ) { - $this->key = $key; - $this->value = $value; - $this->parent = $parent; - } + public $value; /** * Magic caller for field methods + * + * @param string $method + * @param array $arguments + * @return mixed */ - public function __call(string $method, array $arguments = []): mixed + public function __call(string $method, array $arguments = []) { $method = strtolower($method); @@ -89,13 +89,27 @@ class Field return $this; } + /** + * Creates a new field object + * + * @param object|null $parent + * @param string $key + * @param mixed $value + */ + public function __construct(?object $parent, string $key, $value) + { + $this->key = $key; + $this->value = $value; + $this->parent = $parent; + } + /** * Simplifies the var_dump result - * @codeCoverageIgnore * * @see Field::toArray + * @return array */ - public function __debugInfo(): array + public function __debugInfo() { return $this->toArray(); } @@ -105,6 +119,7 @@ class Field * or stringify the entire object * * @see Field::toString + * @return string */ public function __toString(): string { @@ -113,6 +128,8 @@ class Field /** * Checks if the field exists in the content data array + * + * @return bool */ public function exists(): bool { @@ -121,16 +138,18 @@ class Field /** * Checks if the field content is empty + * + * @return bool */ public function isEmpty(): bool { - return - empty($this->value) === true && - in_array($this->value, [0, '0', false], true) === false; + return empty($this->value) === true && in_array($this->value, [0, '0', false], true) === false; } /** * Checks if the field content is not empty + * + * @return bool */ public function isNotEmpty(): bool { @@ -139,6 +158,8 @@ class Field /** * Returns the name of the field + * + * @return string */ public function key(): string { @@ -147,8 +168,9 @@ class Field /** * @see Field::parent() + * @return \Kirby\Cms\Model|null */ - public function model(): ModelWithContent|null + public function model() { return $this->parent; } @@ -156,15 +178,16 @@ class Field /** * Provides a fallback if the field value is empty * + * @param mixed $fallback * @return $this|static */ - public function or(mixed $fallback = null): static + public function or($fallback = null) { if ($this->isNotEmpty()) { return $this; } - if ($fallback instanceof self) { + if (is_a($fallback, 'Kirby\Cms\Field') === true) { return $fallback; } @@ -175,14 +198,18 @@ class Field /** * Returns the parent object of the field + * + * @return \Kirby\Cms\Model|null */ - public function parent(): ModelWithContent|null + public function parent() { return $this->parent; } /** * Converts the Field object to an array + * + * @return array */ public function toArray(): array { @@ -191,6 +218,8 @@ class Field /** * Returns the field value as string + * + * @return string */ public function toString(): string { @@ -201,19 +230,27 @@ class Field * Returns the field content. If a new value is passed, * the modified field will be returned. Otherwise it * will return the field value. + * + * @param string|\Closure $value + * @return mixed + * @throws \Kirby\Exception\InvalidArgumentException */ - public function value(string|Closure $value = null): mixed + public function value($value = null) { if ($value === null) { return $this->value; } - if ($value instanceof Closure) { - $value = $value->call($this, $this->value); + if (is_scalar($value)) { + $value = (string)$value; + } elseif (is_callable($value)) { + $value = (string)$value->call($this, $this->value); + } else { + throw new InvalidArgumentException('Invalid field value type: ' . gettype($value)); } $clone = clone $this; - $clone->value = (string)$value; + $clone->value = $value; return $clone; } diff --git a/kirby/src/Cms/Fieldset.php b/kirby/src/Cms/Fieldset.php index 20338f7..0b49fd4 100644 --- a/kirby/src/Cms/Fieldset.php +++ b/kirby/src/Cms/Fieldset.php @@ -19,23 +19,26 @@ use Kirby\Toolkit\Str; */ class Fieldset extends Item { - public const ITEMS_CLASS = Fieldsets::class; + public const ITEMS_CLASS = '\Kirby\Cms\Fieldsets'; - protected bool $disabled; - protected bool $editable; - protected array $fields = []; - protected string|null $icon; - protected string|null $label; - protected string|null $name; - protected string|bool|null $preview; - protected array $tabs; - protected bool $translate; - protected string $type; - protected bool $unset; - protected bool $wysiwyg; + protected $disabled; + protected $editable; + protected $fields = []; + protected $icon; + protected $label; + protected $model; + protected $name; + protected $preview; + protected $tabs; + protected $translate; + protected $type; + protected $unset; + protected $wysiwyg; /** * Creates a new Fieldset object + * + * @param array $params */ public function __construct(array $params = []) { @@ -47,17 +50,17 @@ class Fieldset extends Item parent::__construct($params); - $this->disabled = $params['disabled'] ?? false; - $this->editable = $params['editable'] ?? true; - $this->icon = $params['icon'] ?? null; - $params['title'] ??= $params['name'] ?? Str::ucfirst($this->type); - $this->name = $this->createName($params['title']); - $this->label = $this->createLabel($params['label'] ?? null); - $this->preview = $params['preview'] ?? null; - $this->tabs = $this->createTabs($params); - $this->translate = $params['translate'] ?? true; - $this->unset = $params['unset'] ?? false; - $this->wysiwyg = $params['wysiwyg'] ?? false; + $this->disabled = $params['disabled'] ?? false; + $this->editable = $params['editable'] ?? true; + $this->icon = $params['icon'] ?? null; + $this->model = $this->parent; + $this->name = $this->createName($params['title'] ?? $params['name'] ?? Str::ucfirst($this->type)); + $this->label = $this->createLabel($params['label'] ?? null); + $this->preview = $params['preview'] ?? null; + $this->tabs = $this->createTabs($params); + $this->translate = $params['translate'] ?? true; + $this->unset = $params['unset'] ?? false; + $this->wysiwyg = $params['wysiwyg'] ?? false; if ( $this->translate === false && @@ -70,6 +73,10 @@ class Fieldset extends Item } } + /** + * @param array $fields + * @return array + */ protected function createFields(array $fields = []): array { $fields = Blueprint::fieldsProps($fields); @@ -81,16 +88,28 @@ class Fieldset extends Item return $fields; } - protected function createName(array|string $name): string|null + /** + * @param array|string $name + * @return string|null + */ + protected function createName($name): ?string { return I18n::translate($name, $name); } - protected function createLabel(array|string|null $label = null): string|null + /** + * @param array|string $label + * @return string|null + */ + protected function createLabel($label = null): ?string { return I18n::translate($label, $label); } + /** + * @param array $params + * @return array + */ protected function createTabs(array $params = []): array { $tabs = $params['tabs'] ?? []; @@ -114,10 +133,9 @@ class Fieldset extends Item $tab = Blueprint::extend($tab); - $tab['fields'] = $this->createFields($tab['fields'] ?? []); - $tab['label'] ??= Str::ucfirst($name); - $tab['label'] = $this->createLabel($tab['label']); - $tab['name'] = $name; + $tab['fields'] = $this->createFields($tab['fields'] ?? []); + $tab['label'] = $this->createLabel($tab['label'] ?? Str::ucfirst($name)); + $tab['name'] = $name; $tabs[$name] = $tab; } @@ -125,11 +143,17 @@ class Fieldset extends Item return $tabs; } + /** + * @return bool + */ public function disabled(): bool { return $this->disabled; } + /** + * @return bool + */ public function editable(): bool { if ($this->editable === false) { @@ -143,6 +167,9 @@ class Fieldset extends Item return true; } + /** + * @return array + */ public function fields(): array { return $this->fields; @@ -150,57 +177,88 @@ class Fieldset extends Item /** * Creates a form for the given fields + * + * @param array $fields + * @param array $input + * @return \Kirby\Form\Form */ - public function form(array $fields, array $input = []): Form + public function form(array $fields, array $input = []) { return new Form([ 'fields' => $fields, - 'model' => $this->parent, + 'model' => $this->model, 'strict' => true, 'values' => $input, ]); } - public function icon(): string|null + /** + * @return string|null + */ + public function icon(): ?string { return $this->icon; } - public function label(): string|null + /** + * @return string|null + */ + public function label(): ?string { return $this->label; } - public function model(): ModelWithContent + /** + * @return \Kirby\Cms\ModelWithContent + */ + public function model() { - return $this->parent; + return $this->model; } + /** + * @return string + */ public function name(): string { return $this->name; } - public function preview(): string|bool|null + /** + * @return string|bool + */ + public function preview() { return $this->preview; } + /** + * @return array + */ public function tabs(): array { return $this->tabs; } + /** + * @return bool + */ public function translate(): bool { return $this->translate; } + /** + * @return string + */ public function type(): string { return $this->type; } + /** + * @return array + */ public function toArray(): array { return [ @@ -218,11 +276,17 @@ class Fieldset extends Item ]; } + /** + * @return bool + */ public function unset(): bool { return $this->unset; } + /** + * @return bool + */ public function wysiwyg(): bool { return $this->wysiwyg; diff --git a/kirby/src/Cms/Fieldsets.php b/kirby/src/Cms/Fieldsets.php index 181f1c4..6189b22 100644 --- a/kirby/src/Cms/Fieldsets.php +++ b/kirby/src/Cms/Fieldsets.php @@ -19,17 +19,12 @@ use Kirby\Toolkit\Str; */ class Fieldsets extends Items { - public const ITEM_CLASS = Fieldset::class; + public const ITEM_CLASS = '\Kirby\Cms\Fieldset'; - /** - * All registered fieldsets methods - */ - public static array $methods = []; - - protected static function createFieldsets(array $params): array + protected static function createFieldsets($params) { $fieldsets = []; - $groups = []; + $groups = []; foreach ($params as $type => $fieldset) { if (is_int($type) === true && is_string($fieldset)) { @@ -73,10 +68,8 @@ class Fieldsets extends Items ]; } - public static function factory( - array $items = null, - array $params = [] - ): static { + public static function factory(array $items = null, array $params = []) + { $items ??= App::instance()->option('blocks.fieldsets', [ 'code' => 'blocks/code', 'gallery' => 'blocks/gallery', @@ -92,10 +85,7 @@ class Fieldsets extends Items $result = static::createFieldsets($items); - return parent::factory( - $result['fieldsets'], - ['groups' => $result['groups']] + $params - ); + return parent::factory($result['fieldsets'], ['groups' => $result['groups']] + $params); } public function groups(): array @@ -103,7 +93,7 @@ class Fieldsets extends Items return $this->options['groups'] ?? []; } - public function toArray(Closure|null $map = null): array + public function toArray(?Closure $map = null): array { return A::map( $this->data, diff --git a/kirby/src/Cms/File.php b/kirby/src/Cms/File.php index 41208db..bc81c7d 100644 --- a/kirby/src/Cms/File.php +++ b/kirby/src/Cms/File.php @@ -2,12 +2,10 @@ namespace Kirby\Cms; -use Exception; -use IntlDateFormatter; -use Kirby\Exception\InvalidArgumentException; use Kirby\Filesystem\F; use Kirby\Filesystem\IsFile; use Kirby\Panel\File as Panel; +use Kirby\Toolkit\A; use Kirby\Toolkit\Str; /** @@ -41,64 +39,64 @@ class File extends ModelWithContent public const CLASS_ALIAS = 'file'; /** - * All registered file methods - * @todo Remove when support for PHP 8.2 is dropped + * Cache for the initialized blueprint object + * + * @var \Kirby\Cms\FileBlueprint */ - public static array $methods = []; + protected $blueprint; /** - * Cache for the initialized blueprint object + * @var string */ - protected FileBlueprint|null $blueprint = null; + protected $filename; - protected string $filename; + /** + * @var string + */ + protected $id; - protected string $id; + /** + * All registered file methods + * + * @var array + */ + public static $methods = []; /** * The parent object + * + * @var \Kirby\Cms\Model */ - protected Page|Site|User|null $parent = null; + protected $parent; /** * The absolute path to the file + * + * @var string|null */ - protected string|null $root; + protected $root; - protected string|null $template; + /** + * @var string + */ + protected $template; /** * The public file Url + * + * @var string */ - protected string|null $url; - - /** - * Creates a new File object - */ - public function __construct(array $props) - { - parent::__construct($props); - - if (isset($props['filename'], $props['parent']) === false) { - throw new InvalidArgumentException('The filename and parent are required'); - } - - $this->filename = $props['filename']; - $this->parent = $props['parent']; - $this->template = $props['template'] ?? null; - // Always set the root to null, to invoke - // auto root detection - $this->root = null; - $this->url = $props['url'] ?? null; - - $this->setBlueprint($props['blueprint'] ?? null); - } + protected $url; /** * Magic caller for file methods * and content fields. (in this order) + * + * @param string $method + * @param array $arguments + * @return mixed */ - public function __call(string $method, array $arguments = []): mixed + public function __call(string $method, array $arguments = []) { // public property access if (isset($this->$method) === true) { @@ -119,8 +117,25 @@ class File extends ModelWithContent return $this->content()->get($method); } + /** + * Creates a new File object + * + * @param array $props + */ + public function __construct(array $props) + { + // set filename as the most important prop first + // TODO: refactor later to avoid redundant prop setting + $this->setProperty('filename', $props['filename'] ?? null, true); + + // set other properties + $this->setProperties($props); + } + /** * Improved `var_dump` output + * + * @return array */ public function __debugInfo(): array { @@ -132,7 +147,10 @@ class File extends ModelWithContent /** * Returns the url to api endpoint + * * @internal + * @param bool $relative + * @return string */ public function apiUrl(bool $relative = false): string { @@ -141,144 +159,73 @@ class File extends ModelWithContent /** * Returns the FileBlueprint object for the file + * + * @return \Kirby\Cms\FileBlueprint */ - public function blueprint(): FileBlueprint + public function blueprint() { - return $this->blueprint ??= FileBlueprint::factory( - 'files/' . $this->template(), - 'files/default', - $this - ); - } - - /** - * Returns an array with all blueprints that are available for the file - * by comparing files sections and files fields of the parent model - */ - public function blueprints(string $inSection = null): array - { - // get cached results for the current file model - // (except when collecting for a specific section) - if ($inSection === null && $this->blueprints !== null) { - return $this->blueprints; // @codeCoverageIgnore + if (is_a($this->blueprint, 'Kirby\Cms\FileBlueprint') === true) { + return $this->blueprint; } - // always include the current template as option - $templates = [ - $this->template() ?? 'default', - ...$this->parent()->blueprint()->acceptedFileTemplates($inSection) - ]; - - // make sure every template is only included once - $templates = array_unique(array_filter($templates)); - - // load the blueprint details for each collected template name - $blueprints = []; - - foreach ($templates as $template) { - // default template doesn't need to exist as file - // to be included in the list - if ($template === 'default') { - $blueprints[$template] = [ - 'name' => 'default', - 'title' => '– (default)', - ]; - continue; - } - - if ($blueprint = FileBlueprint::factory('files/' . $template, null, $this)) { - try { - // ensure that file matches `accept` option, - // if not remove template from available list - $this->match($blueprint->accept()); - - $blueprints[$template] = [ - 'name' => $name = Str::after($blueprint->name(), '/'), - 'title' => $blueprint->title() . ' (' . $name . ')', - ]; - } catch (Exception) { - // skip when `accept` doesn't match - } - } - } - - $blueprints = array_values($blueprints); - - // sort blueprints alphabetically while - // making sure the default blueprint is on top of list - usort($blueprints, fn ($a, $b) => match (true) { - $a['name'] === 'default' => -1, - $b['name'] === 'default' => 1, - default => strnatcmp($a['title'], $b['title']) - }); - - // no caching for when collecting for specific section - if ($inSection !== null) { - return $blueprints; // @codeCoverageIgnore - } - - return $this->blueprints = $blueprints; + return $this->blueprint = FileBlueprint::factory('files/' . $this->template(), 'files/default', $this); } /** * Store the template in addition to the * other content. + * * @internal + * @param array $data + * @param string|null $languageCode + * @return array */ - public function contentFileData( - array $data, - string $languageCode = null - ): array { - // only add the template in, if the $data array - // doesn't explicitly unsets it - if ( - array_key_exists('template', $data) === false && - $template = $this->template() - ) { - $data['template'] = $template; - } - - return $data; + public function contentFileData(array $data, string $languageCode = null): array + { + return A::append($data, [ + 'template' => $this->template(), + ]); } /** * Returns the directory in which * the content file is located + * * @internal - * @deprecated 4.0.0 - * @todo Remove in v5 - * @codeCoverageIgnore + * @return string */ public function contentFileDirectory(): string { - Helpers::deprecated('The internal $model->contentFileDirectory() method has been deprecated. Please let us know via a GitHub issue if you need this method and tell us your use case.', 'model-content-file'); return dirname($this->root()); } /** * Filename for the content file + * * @internal - * @deprecated 4.0.0 - * @todo Remove in v5 - * @codeCoverageIgnore + * @return string */ public function contentFileName(): string { - Helpers::deprecated('The internal $model->contentFileName() method has been deprecated. Please let us know via a GitHub issue if you need this method and tell us your use case.', 'model-content-file'); return $this->filename(); } /** * Constructs a File object + * * @internal + * @param mixed $props + * @return static */ - public static function factory(array $props): static + public static function factory($props) { return new static($props); } /** * Returns the filename with extension + * + * @return string */ public function filename(): string { @@ -287,14 +234,19 @@ class File extends ModelWithContent /** * Returns the parent Files collection + * + * @return \Kirby\Cms\Files */ - public function files(): Files + public function files() { return $this->siblingsCollection(); } /** * Converts the file to html + * + * @param array $attr + * @return string */ public function html(array $attr = []): string { @@ -306,91 +258,58 @@ class File extends ModelWithContent /** * Returns the id + * + * @return string */ public function id(): string { - if ( - $this->parent() instanceof Page || - $this->parent() instanceof User - ) { - return $this->id ??= $this->parent()->id() . '/' . $this->filename(); + if ($this->id !== null) { + return $this->id; } - return $this->id ??= $this->filename(); + if (is_a($this->parent(), 'Kirby\Cms\Page') === true) { + return $this->id = $this->parent()->id() . '/' . $this->filename(); + } elseif (is_a($this->parent(), 'Kirby\Cms\User') === true) { + return $this->id = $this->parent()->id() . '/' . $this->filename(); + } + + return $this->id = $this->filename(); } /** * Compares the current object with the given file object + * + * @param \Kirby\Cms\File $file + * @return bool */ public function is(File $file): bool { return $this->id() === $file->id(); } - /** - * Checks if the files is accessible. - * This permission depends on the `read` option until v5 - */ - public function isAccessible(): bool - { - // TODO: remove this check when `read` option deprecated in v5 - if ($this->isReadable() === false) { - return false; - } - - static $accessible = []; - - if ($template = $this->template()) { - return $accessible[$template] ??= $this->permissions()->can('access'); - } - - return $accessible['__none__'] ??= $this->permissions()->can('access'); - } - - /** - * Check if the file can be listable by the current user - * This permission depends on the `read` option until v5 - */ - public function isListable(): bool - { - // TODO: remove this check when `read` option deprecated in v5 - if ($this->isReadable() === false) { - return false; - } - - // not accessible also means not listable - if ($this->isAccessible() === false) { - return false; - } - - static $listable = []; - - if ($template = $this->template()) { - return $listable[$template] ??= $this->permissions()->can('list'); - } - - return $listable['__none__'] ??= $this->permissions()->can('list'); - } - /** * Check if the file can be read by the current user * - * @todo Deprecate `read` option in v5 and make the necessary changes for `access` and `list` options. + * @return bool */ public function isReadable(): bool { static $readable = []; - if ($template = $this->template()) { - return $readable[$template] ??= $this->permissions()->can('read'); + $template = $this->template(); + + if (isset($readable[$template]) === true) { + return $readable[$template]; } - return $readable['__none__'] ??= $this->permissions()->can('read'); + return $readable[$template] = $this->permissions()->can('read'); } /** * Creates a unique media hash + * * @internal + * @return string */ public function mediaHash(): string { @@ -399,7 +318,9 @@ class File extends ModelWithContent /** * Returns the absolute path to the file in the public media folder + * * @internal + * @return string */ public function mediaRoot(): string { @@ -408,7 +329,9 @@ class File extends ModelWithContent /** * Creates a non-guessable token string for this file + * * @internal + * @return string */ public function mediaToken(): string { @@ -418,7 +341,9 @@ class File extends ModelWithContent /** * Returns the absolute Url to the file in the public media folder + * * @internal + * @return string */ public function mediaUrl(): string { @@ -428,16 +353,17 @@ class File extends ModelWithContent /** * Get the file's last modification time. * + * @param string|\IntlDateFormatter|null $format * @param string|null $handler date, intl or strftime + * @param string|null $languageCode + * @return mixed */ - public function modified( - string|IntlDateFormatter|null $format = null, - string|null $handler = null, - string|null $languageCode = null - ): string|int|false { + public function modified($format = null, string $handler = null, string $languageCode = null) + { $file = $this->modifiedFile(); $content = $this->modifiedContent($languageCode); $modified = max($file, $content); + $handler ??= $this->kirby()->option('date.handler', 'date'); return Str::date($modified, $format, $handler); } @@ -445,15 +371,20 @@ class File extends ModelWithContent /** * Timestamp of the last modification * of the content file + * + * @param string|null $languageCode + * @return int */ protected function modifiedContent(string $languageCode = null): int { - return $this->storage()->modified('published', $languageCode) ?? 0; + return F::modified($this->contentFile($languageCode)); } /** * Timestamp of the last modification * of the source file + * + * @return int */ protected function modifiedFile(): int { @@ -462,35 +393,39 @@ class File extends ModelWithContent /** * Returns the parent Page object + * + * @return \Kirby\Cms\Page|null */ - public function page(): Page|null + public function page() { - if ($this->parent() instanceof Page) { - return $this->parent(); - } - - return null; + return is_a($this->parent(), 'Kirby\Cms\Page') === true ? $this->parent() : null; } /** * Returns the panel info object + * + * @return \Kirby\Panel\File */ - public function panel(): Panel + public function panel() { return new Panel($this); } /** - * Returns the parent object + * Returns the parent Model object + * + * @return \Kirby\Cms\Model */ - public function parent(): Page|Site|User + public function parent() { return $this->parent ??= $this->kirby()->site(); } /** * Returns the parent id if a parent exists + * * @internal + * @return string */ public function parentId(): string { @@ -499,40 +434,34 @@ class File extends ModelWithContent /** * Returns a collection of all parent pages + * + * @return \Kirby\Cms\Pages */ - public function parents(): Pages + public function parents() { - if ($this->parent() instanceof Page) { - return $this->parent()->parents()->prepend( - $this->parent()->id(), - $this->parent() - ); + if (is_a($this->parent(), 'Kirby\Cms\Page') === true) { + return $this->parent()->parents()->prepend($this->parent()->id(), $this->parent()); } return new Pages(); } - /** - * Return the permanent URL to the file using its UUID - * @since 3.8.0 - */ - public function permalink(): string|null - { - return $this->uuid()?->url(); - } - /** * Returns the permissions object for this file + * + * @return \Kirby\Cms\FilePermissions */ - public function permissions(): FilePermissions + public function permissions() { return new FilePermissions($this); } /** * Returns the absolute root to the file + * + * @return string|null */ - public function root(): string|null + public function root(): ?string { return $this->root ??= $this->parent()->root() . '/' . $this->filename(); } @@ -540,8 +469,10 @@ class File extends ModelWithContent /** * Returns the FileRules class to * validate any important action. + * + * @return \Kirby\Cms\FileRules */ - protected function rules(): FileRules + protected function rules() { return new FileRules(); } @@ -549,9 +480,10 @@ class File extends ModelWithContent /** * Sets the Blueprint object * + * @param array|null $blueprint * @return $this */ - protected function setBlueprint(array $blueprint = null): static + protected function setBlueprint(array $blueprint = null) { if ($blueprint !== null) { $blueprint['model'] = $this; @@ -561,39 +493,103 @@ class File extends ModelWithContent return $this; } + /** + * Sets the filename + * + * @param string $filename + * @return $this + */ + protected function setFilename(string $filename) + { + $this->filename = $filename; + return $this; + } + + /** + * Sets the parent model object + * + * @param \Kirby\Cms\Model $parent + * @return $this + */ + protected function setParent(Model $parent) + { + $this->parent = $parent; + return $this; + } + + /** + * Always set the root to null, to invoke + * auto root detection + * + * @param string|null $root + * @return $this + */ + protected function setRoot(string $root = null) + { + $this->root = null; + return $this; + } + + /** + * @param string|null $template + * @return $this + */ + protected function setTemplate(string $template = null) + { + $this->template = $template; + return $this; + } + + /** + * Sets the url + * + * @param string|null $url + * @return $this + */ + protected function setUrl(string $url = null) + { + $this->url = $url; + return $this; + } + /** * Returns the parent Files collection * @internal + * + * @return \Kirby\Cms\Files */ - protected function siblingsCollection(): Files + protected function siblingsCollection() { return $this->parent()->files(); } /** * Returns the parent Site object + * + * @return \Kirby\Cms\Site */ - public function site(): Site + public function site() { - if ($this->parent() instanceof Site) { - return $this->parent(); - } - - return $this->kirby()->site(); + return is_a($this->parent(), 'Kirby\Cms\Site') === true ? $this->parent() : $this->kirby()->site(); } /** * Returns the final template + * + * @return string|null */ - public function template(): string|null + public function template(): ?string { return $this->template ??= $this->content()->get('template')->value(); } /** * Returns siblings with the same template + * + * @param bool $self + * @return \Kirby\Cms\Files */ - public function templateSiblings(bool $self = true): Files + public function templateSiblings(bool $self = true) { return $this->siblings($self)->filter('template', $this->template()); } @@ -602,27 +598,122 @@ class File extends ModelWithContent * Extended info for the array export * by injecting the information from * the asset. + * + * @return array */ public function toArray(): array { - return array_merge(parent::toArray(), $this->asset()->toArray(), [ - 'id' => $this->id(), - 'template' => $this->template(), - ]); + return array_merge($this->asset()->toArray(), parent::toArray()); } /** * Returns the Url + * + * @return string */ public function url(): string { return $this->url ??= ($this->kirby()->component('file::url'))($this->kirby(), $this); } + + /** + * Deprecated! + */ + + /** + * Provides a kirbytag or markdown + * tag for the file, which will be + * used in the panel, when the file + * gets dragged onto a textarea + * + * @todo Remove in 3.8.0 + * + * @internal + * @param string|null $type (null|auto|kirbytext|markdown) + * @param bool $absolute + * @return string + * @codeCoverageIgnore + */ + public function dragText(string $type = null, bool $absolute = false): string + { + Helpers::deprecated('Cms\File::dragText() has been deprecated and will be removed in Kirby 3.8.0. Use $file->panel()->dragText() instead.'); + return $this->panel()->dragText($type, $absolute); + } + + /** + * Returns an array of all actions + * that can be performed in the Panel + * + * @todo Remove in 3.8.0 + * + * @since 3.3.0 This also checks for the lock status + * @since 3.5.1 This also checks for matching accept settings + * + * @param array $unlock An array of options that will be force-unlocked + * @return array + * @codeCoverageIgnore + */ + public function panelOptions(array $unlock = []): array + { + Helpers::deprecated('Cms\File::panelOptions() has been deprecated and will be removed in Kirby 3.8.0. Use $file->panel()->options() instead.'); + return $this->panel()->options($unlock); + } + + /** + * Returns the full path without leading slash + * + * @todo Remove in 3.8.0 + * + * @internal + * @return string + * @codeCoverageIgnore + */ + public function panelPath(): string + { + Helpers::deprecated('Cms\File::panelPath() has been deprecated and will be removed in Kirby 3.8.0. Use $file->panel()->path() instead.'); + return $this->panel()->path(); + } + + /** + * Prepares the response data for file pickers + * and file fields + * + * @todo Remove in 3.8.0 + * + * @param array|null $params + * @return array + * @codeCoverageIgnore + */ + public function panelPickerData(array $params = []): array + { + Helpers::deprecated('Cms\File::panelPickerData() has been deprecated and will be removed in Kirby 3.8.0. Use $file->panel()->pickerData() instead.'); + return $this->panel()->pickerData($params); + } + + /** + * Returns the url to the editing view + * in the panel + * + * @todo Remove in 3.8.0 + * + * @internal + * @param bool $relative + * @return string + * @codeCoverageIgnore + */ + public function panelUrl(bool $relative = false): string + { + Helpers::deprecated('Cms\File::panelUrl() has been deprecated and will be removed in Kirby 3.8.0. Use $file->panel()->url() instead.'); + return $this->panel()->url($relative); + } + /** * Simplified File URL that uses the parent * Page URL and the filename as a more stable * alternative for the media URLs. + * + * @return string */ public function previewUrl(): string { diff --git a/kirby/src/Cms/FileActions.php b/kirby/src/Cms/FileActions.php index f6d57fb..e82171a 100644 --- a/kirby/src/Cms/FileActions.php +++ b/kirby/src/Cms/FileActions.php @@ -7,8 +7,6 @@ use Kirby\Exception\InvalidArgumentException; use Kirby\Exception\LogicException; use Kirby\Filesystem\F; use Kirby\Form\Form; -use Kirby\Uuid\Uuid; -use Kirby\Uuid\Uuids; /** * FileActions @@ -21,56 +19,31 @@ use Kirby\Uuid\Uuids; */ trait FileActions { - protected function changeExtension( - File $file, - string|null $extension = null - ): File { - if ( - $extension === null || - $extension === $file->extension() - ) { - return $file; - } - - return $file->changeName($file->name(), false, $extension); - } - /** - * Renames the file (optionally also the extension). + * Renames the file without touching the extension * The store is used to actually execute this. * + * @param string $name + * @param bool $sanitize + * @return $this|static * @throws \Kirby\Exception\LogicException */ - public function changeName( - string $name, - bool $sanitize = true, - string|null $extension = null - ): static { + public function changeName(string $name, bool $sanitize = true) + { if ($sanitize === true) { - // sanitize the basename part only - // as the extension isn't included in $name - $name = F::safeBasename($name, false); + $name = F::safeName($name); } - // if no extension is passed, make sure to maintain current one - $extension ??= $this->extension(); - // don't rename if not necessary - if ( - $name === $this->name() && - $extension === $this->extension() - ) { + if ($name === $this->name()) { return $this; } - return $this->commit('changeName', ['file' => $this, 'name' => $name, 'extension' => $extension], function ($oldFile, $name, $extension) { + return $this->commit('changeName', ['file' => $this, 'name' => $name], function ($oldFile, $name) { $newFile = $oldFile->clone([ - 'filename' => $name . '.' . $extension, + 'filename' => $name . '.' . $oldFile->extension(), ]); - // remove all public versions, lock and clear UUID cache - $oldFile->unpublish(); - if ($oldFile->exists() === false) { return $newFile; } @@ -79,17 +52,29 @@ trait FileActions throw new LogicException('The new file exists and cannot be overwritten'); } + // remove the lock of the old file + if ($lock = $oldFile->lock()) { + $lock->remove(); + } + + // remove all public versions + $oldFile->unpublish(); + // rename the main file F::move($oldFile->root(), $newFile->root()); - // move the content storage versions - foreach ($oldFile->storage()->all() as $version => $lang) { - $content = $oldFile->storage()->read($version, $lang); - $oldFile->storage()->delete($version, $lang); - $newFile->storage()->create($version, $lang, $content); + if ($newFile->kirby()->multilang() === true) { + foreach ($newFile->translations() as $translation) { + $translationCode = $translation->code(); + + // rename the content file + F::move($oldFile->contentFile($translationCode), $newFile->contentFile($translationCode)); + } + } else { + // rename the content file + F::move($oldFile->contentFile(), $newFile->contentFile()); } - // update collections $newFile->parent()->files()->remove($oldFile->id()); $newFile->parent()->files()->set($newFile->id(), $newFile); @@ -99,14 +84,12 @@ trait FileActions /** * Changes the file's sorting number in the meta file + * + * @param int $sort + * @return static */ - public function changeSort(int $sort): static + public function changeSort(int $sort) { - // skip if the sort number stays the same - if ($this->sort()->value() === $sort) { - return $this; - } - return $this->commit( 'changeSort', ['file' => $this, 'position' => $sort], @@ -114,40 +97,6 @@ trait FileActions ); } - /** - * @return $this|static - */ - public function changeTemplate(string|null $template): static - { - if ($template === $this->template()) { - return $this; - } - - $arguments = [ - 'file' => $this, - 'template' => $template ?? 'default' - ]; - - return $this->commit('changeTemplate', $arguments, function ($oldFile, $template) { - // convert to new template/blueprint incl. content - $file = $oldFile->convertTo($template); - - // update template, prefer unset over writing `default` - if ($template === 'default') { - $template = null; - } - - $file = $file->update(['template' => $template]); - - // rename and/or resize the file if configured by new blueprint - $create = $file->blueprint()->create(); - $file = $file->manipulate($create); - $file = $file->changeExtension($file, $create['format'] ?? null); - - return $file; - }); - } - /** * Commits a file action, by following these steps * @@ -156,12 +105,14 @@ trait FileActions * 3. commits the store action * 4. sends the after hook * 5. returns the result + * + * @param string $action + * @param array $arguments + * @param Closure $callback + * @return mixed */ - protected function commit( - string $action, - array $arguments, - Closure $callback - ): mixed { + protected function commit(string $action, array $arguments, Closure $callback) + { $old = $this->hardcopy(); $kirby = $this->kirby(); $argumentValues = array_values($arguments); @@ -171,12 +122,13 @@ trait FileActions $result = $callback(...$argumentValues); - $argumentsAfter = match ($action) { - 'create' => ['file' => $result], - 'delete' => ['status' => $result, 'file' => $old], - default => ['newFile' => $result, 'oldFile' => $old] - }; - + if ($action === 'create') { + $argumentsAfter = ['file' => $result]; + } elseif ($action === 'delete') { + $argumentsAfter = ['status' => $result, 'file' => $old]; + } else { + $argumentsAfter = ['newFile' => $result, 'oldFile' => $old]; + } $kirby->trigger('file.' . $action . ':after', $argumentsAfter); $kirby->cache('pages')->flush(); @@ -185,27 +137,25 @@ trait FileActions /** * Copy the file to the given page + * + * @param \Kirby\Cms\Page $page + * @return \Kirby\Cms\File */ - public function copy(Page $page): static + public function copy(Page $page) { F::copy($this->root(), $page->root() . '/' . $this->filename()); - $copy = $page->clone()->file($this->filename()); - foreach ($this->storage()->all() as $version => $lang) { - $content = $this->storage()->read($version, $lang); - $copy->storage()->create($version, $lang, $content); + if ($this->kirby()->multilang() === true) { + foreach ($this->kirby()->languages() as $language) { + $contentFile = $this->contentFile($language->code()); + F::copy($contentFile, $page->root() . '/' . basename($contentFile)); + } + } else { + $contentFile = $this->contentFile(); + F::copy($contentFile, $page->root() . '/' . basename($contentFile)); } - // ensure the content is re-read after copying it - // @todo find a more elegant way - $copy = $page->clone()->file($this->filename()); - - // overwrite with new UUID (remove old, add new) - if (Uuids::enabled() === true) { - $copy = $copy->save(['uuid' => Uuid::generate()]); - } - - return $copy; + return $page->clone()->file($this->filename()); } /** @@ -214,11 +164,12 @@ trait FileActions * writing, so it can be replaced by any other * way of generating files. * - * @param bool $move If set to `true`, the source will be deleted + * @param array $props + * @return static * @throws \Kirby\Exception\InvalidArgumentException * @throws \Kirby\Exception\LogicException */ - public static function create(array $props, bool $move = false): File + public static function create(array $props) { if (isset($props['source'], $props['parent']) === false) { throw new InvalidArgumentException('Please provide the "source" and "parent" props for the File'); @@ -233,66 +184,33 @@ trait FileActions $file = static::factory($props); $upload = $file->asset($props['source']); - // gather content - $content = $props['content'] ?? []; - - // make sure that a UUID gets generated - // and added to content right away - if ( - Uuids::enabled() === true && - empty($content['uuid']) === true - ) { - // sets the current uuid if it is the exact same file - if ($file->exists() === true) { - $existing = $file->parent()->file($file->filename()); - - if ( - $file->sha1() === $upload->sha1() && - $file->template() === $existing->template() - ) { - // use existing content data if it is the exact same file - $content = $existing->content()->toArray(); - } - } - - $content['uuid'] ??= Uuid::generate(); - } - // create a form for the file - $form = Form::for($file, ['values' => $content]); + $form = Form::for($file, [ + 'values' => $props['content'] ?? [] + ]); // inject the content $file = $file->clone(['content' => $form->strings(true)]); - // if the format is different from the original, - // we need to already rename it so that the correct file rules - // are applied - $create = $file->blueprint()->create(); - // run the hook - $arguments = compact('file', 'upload'); - return $file->commit('create', $arguments, function ($file, $upload) use ($create, $move) { - // remove all public versions, lock and clear UUID cache + return $file->commit('create', compact('file', 'upload'), function ($file, $upload) { + // delete all public versions $file->unpublish(); - // only move the original source if intended - $method = $move === true ? 'move' : 'copy'; - // overwrite the original - if (F::$method($upload->root(), $file->root(), true) !== true) { + if (F::copy($upload->root(), $file->root(), true) !== true) { throw new LogicException('The file could not be created'); } - // resize the file on upload if configured - $file = $file->manipulate($create); - $file = $file->changeExtension($file, $create['format'] ?? null); + // always create pages in the default language + if ($file->kirby()->multilang() === true) { + $languageCode = $file->kirby()->defaultLanguage()->code(); + } else { + $languageCode = null; + } // store the content if necessary - // (always create files in the default language) - $file->save( - $file->content()->toArray(), - $file->kirby()->defaultLanguage()?->code() - ); + $file->save($file->content()->toArray(), $languageCode); // add the file to the list of siblings $file->siblings()->append($file->id(), $file); @@ -305,15 +223,26 @@ trait FileActions /** * Deletes the file. The store is used to * manipulate the filesystem or whatever you prefer. + * + * @return bool */ public function delete(): bool { return $this->commit('delete', ['file' => $this], function ($file) { - // remove all public versions, lock and clear UUID cache + // remove all versions in the media folder $file->unpublish(); - foreach ($file->storage()->all() as $version => $lang) { - $file->storage()->delete($version, $lang); + // remove the lock of the old file + if ($lock = $file->lock()) { + $lock->remove(); + } + + if ($file->kirby()->multilang() === true) { + foreach ($file->translations() as $translation) { + F::remove($file->contentFile($translation->code())); + } + } else { + F::remove($file->contentFile()); } F::remove($file->root()); @@ -325,29 +254,13 @@ trait FileActions }); } - /** - * Resizes/crops the original file with Kirby's thumb handler - */ - public function manipulate(array|null $options = []): static - { - // nothing to process - if (empty($options) === true || $this->isResizable() === false) { - return $this; - } - - // generate image file and overwrite it in place - $this->kirby()->thumb($this->root(), $this->root(), $options); - - return $this->clone([]); - } - /** * Move the file to the public media folder * if it's not already there. * * @return $this */ - public function publish(): static + public function publish() { Media::publish($this, $this->mediaRoot()); return $this; @@ -360,10 +273,11 @@ trait FileActions * finally decides what it will support as * source. * - * @param bool $move If set to `true`, the source will be deleted + * @param string $source + * @return static * @throws \Kirby\Exception\LogicException */ - public function replace(string $source, bool $move = false): static + public function replace(string $source) { $file = $this->clone(); @@ -372,82 +286,28 @@ trait FileActions 'upload' => $file->asset($source) ]; - return $this->commit('replace', $arguments, function ($file, $upload) use ($move) { + return $this->commit('replace', $arguments, function ($file, $upload) { // delete all public versions - $file->unpublish(true); - - // only move the original source if intended - $method = $move === true ? 'move' : 'copy'; + $file->unpublish(); // overwrite the original - if (F::$method($upload->root(), $file->root(), true) !== true) { + if (F::copy($upload->root(), $file->root(), true) !== true) { throw new LogicException('The file could not be created'); } - // apply the resizing/crop options from the blueprint - $create = $file->blueprint()->create(); - $file = $file->manipulate($create); - $file = $file->changeExtension($file, $create['format'] ?? null); - // return a fresh clone return $file->clone(); }); } - /** - * Stores the content on disk - * @internal - */ - public function save( - array $data = null, - string $languageCode = null, - bool $overwrite = false - ): static { - $file = parent::save($data, $languageCode, $overwrite); - - // update model in siblings collection - $file->parent()->files()->set($file->id(), $file); - - return $file; - } - /** * Remove all public versions of this file * * @return $this */ - public function unpublish(bool $onlyMedia = false): static + public function unpublish() { - // unpublish media files Media::unpublish($this->parent()->mediaRoot(), $this); - - if ($onlyMedia !== true) { - // remove the lock - $this->lock()?->remove(); - - // clear UUID cache - $this->uuid()?->clear(); - } - return $this; } - - /** - * Updates the file's data and ensures that - * media files get wiped if `focus` changed - * - * @throws \Kirby\Exception\InvalidArgumentException If the input array contains invalid values - */ - public function update( - array $input = null, - string $languageCode = null, - bool $validate = false - ): static { - // delete all public media versions when focus field gets changed - if (($input['focus'] ?? null) !== $this->focus()->value()) { - $this->unpublish(true); - } - - return parent::update($input, $languageCode, $validate); - } } diff --git a/kirby/src/Cms/FileBlueprint.php b/kirby/src/Cms/FileBlueprint.php index 1cc50be..aee9b8b 100644 --- a/kirby/src/Cms/FileBlueprint.php +++ b/kirby/src/Cms/FileBlueprint.php @@ -3,7 +3,6 @@ namespace Kirby\Cms; use Kirby\Filesystem\F; -use Kirby\Filesystem\Mime; use Kirby\Toolkit\Str; /** @@ -21,8 +20,10 @@ class FileBlueprint extends Blueprint /** * `true` if the default accepted * types are being used + * + * @var bool */ - protected bool $defaultTypes = false; + protected $defaultTypes = false; public function __construct(array $props) { @@ -33,15 +34,12 @@ class FileBlueprint extends Blueprint $this->props['options'] ?? true, // defaults [ - 'access' => null, - 'changeName' => null, - 'changeTemplate' => null, - 'create' => null, - 'delete' => null, - 'list' => null, - 'read' => null, - 'replace' => null, - 'update' => null, + 'changeName' => null, + 'create' => null, + 'delete' => null, + 'read' => null, + 'replace' => null, + 'update' => null, ] ); @@ -49,6 +47,9 @@ class FileBlueprint extends Blueprint $this->props['accept'] = $this->normalizeAccept($this->props['accept'] ?? []); } + /** + * @return array + */ public function accept(): array { return $this->props['accept']; @@ -58,8 +59,7 @@ class FileBlueprint extends Blueprint * Returns the list of all accepted MIME types for * file upload or `*` if all MIME types are allowed * - * @deprecated 4.2.0 Use `acceptAttribute` instead - * @todo 5.0.0 Remove method + * @return string */ public function acceptMime(): string { @@ -81,10 +81,7 @@ class FileBlueprint extends Blueprint if (is_array($accept['extension']) === true) { // determine the main MIME type for each extension - $restrictions[] = array_map( - [Mime::class, 'fromExtension'], - $accept['extension'] - ); + $restrictions[] = array_map(['Kirby\Filesystem\Mime', 'fromExtension'], $accept['extension']); } if (is_array($accept['type']) === true) { @@ -92,10 +89,7 @@ class FileBlueprint extends Blueprint $mimes = []; foreach ($accept['type'] as $type) { if ($extensions = F::typeToExtensions($type)) { - $mimes[] = array_map( - [Mime::class, 'fromExtension'], - $extensions - ); + $mimes[] = array_map(['Kirby\Filesystem\Mime', 'fromExtension'], $extensions); } } @@ -120,84 +114,24 @@ class FileBlueprint extends Blueprint } /** - * Returns the list of all accepted file extensions - * for file upload or `*` if all extensions are allowed - * - * If a MIME type is specified in the blueprint, the `extension` and `type` options are ignored for the browser. - * Extensions and types, however, are still used to validate an uploaded file on the server. - * This behavior might change in the future to better represent which file extensions are actually allowed. - * - * If no MIME type is specified, the intersection between manually defined extensions and the Kirby "file types" is returned. - * If the intersection is empty, an empty string is returned. - * This behavior might change in the future to instead return the union of `mime`, `extension` and `type`. - * - * @since 4.2.0 + * @param mixed $accept + * @return array */ - public function acceptAttribute(): string + protected function normalizeAccept($accept = null): array { - // don't disclose the specific default types - if ($this->defaultTypes === true) { - return '*'; - } - - $accept = $this->accept(); - - // get extensions from "mime" option - if (is_array($accept['mime']) === true) { - // determine the extensions for each MIME type - $extensions = array_map( - fn ($pattern) => Mime::toExtensions($pattern, true), - $accept['mime'] - ); - - $fromMime = array_unique(array_merge(...array_values($extensions))); - - // return early to ignore the other options - return implode(',', array_map(fn ($ext) => ".$ext", $fromMime)); - } - - $restrictions = []; - - // get extensions from "type" option - if (is_array($accept['type']) === true) { - $extensions = array_map( - fn ($type) => F::typeToExtensions($type) ?? [], - $accept['type'] - ); - - $fromType = array_merge(...array_values($extensions)); - $restrictions[] = $fromType; - } - - // get extensions from "extension" option - if (is_array($accept['extension']) === true) { - $restrictions[] = $accept['extension']; - } - - // intersect all restrictions - $list = match (count($restrictions)) { - 0 => [], - 1 => $restrictions[0], - default => array_intersect(...$restrictions) - }; - - $list = array_unique($list); - - // format the list to include a leading dot on each extension - return implode(',', array_map(fn ($ext) => ".$ext", $list)); - } - - protected function normalizeAccept(mixed $accept = null): array - { - $accept = match (true) { - is_string($accept) => ['mime' => $accept], + if (is_string($accept) === true) { + $accept = [ + 'mime' => $accept + ]; + } elseif ($accept === true) { // explicitly no restrictions at all - $accept === true => ['mime' => null], + $accept = [ + 'mime' => null + ]; + } elseif (empty($accept) === true) { // no custom restrictions - empty($accept) === true => [], - // custom restrictions - default => $accept - }; + $accept = []; + } $accept = array_change_key_case($accept); diff --git a/kirby/src/Cms/FileModifications.php b/kirby/src/Cms/FileModifications.php index d1a256d..9e2ca70 100644 --- a/kirby/src/Cms/FileModifications.php +++ b/kirby/src/Cms/FileModifications.php @@ -2,9 +2,7 @@ namespace Kirby\Cms; -use Kirby\Content\Field; use Kirby\Exception\InvalidArgumentException; -use Kirby\Filesystem\Asset; /** * Trait for image resizing, blurring etc. @@ -19,36 +17,43 @@ trait FileModifications { /** * Blurs the image by the given amount of pixels + * + * @param bool $pixels + * @return \Kirby\Cms\FileVersion|\Kirby\Cms\File */ - public function blur(int|bool $pixels = true): FileVersion|File|Asset + public function blur($pixels = true) { return $this->thumb(['blur' => $pixels]); } /** * Converts the image to black and white + * + * @return \Kirby\Cms\FileVersion|\Kirby\Cms\File */ - public function bw(): FileVersion|File|Asset + public function bw() { return $this->thumb(['grayscale' => true]); } /** * Crops the image by the given width and height + * + * @param int $width + * @param int|null $height + * @param string|array $options + * @return \Kirby\Cms\FileVersion|\Kirby\Cms\File */ - public function crop( - int $width, - int $height = null, - $options = null - ): FileVersion|File|Asset { + public function crop(int $width, int $height = null, $options = null) + { $quality = null; - $crop = true; + $crop = 'center'; if (is_int($options) === true) { $quality = $options; } elseif (is_string($options)) { $crop = $options; - } elseif ($options instanceof Field) { + } elseif (is_a($options, 'Kirby\Cms\Field') === true) { $crop = $options->value(); } elseif (is_array($options)) { $quality = $options['quality'] ?? $quality; @@ -65,24 +70,31 @@ trait FileModifications /** * Alias for File::bw() + * + * @return \Kirby\Cms\FileVersion|\Kirby\Cms\File */ - public function grayscale(): FileVersion|File|Asset + public function grayscale() { return $this->thumb(['grayscale' => true]); } /** * Alias for File::bw() + * + * @return \Kirby\Cms\FileVersion|\Kirby\Cms\File */ - public function greyscale(): FileVersion|File|Asset + public function greyscale() { return $this->thumb(['grayscale' => true]); } /** * Sets the JPEG compression quality + * + * @param int $quality + * @return \Kirby\Cms\FileVersion|\Kirby\Cms\File */ - public function quality(int $quality): FileVersion|File|Asset + public function quality(int $quality) { return $this->thumb(['quality' => $quality]); } @@ -91,13 +103,14 @@ trait FileModifications * Resizes the file with the given width and height * while keeping the aspect ratio. * + * @param int|null $width + * @param int|null $height + * @param int|null $quality + * @return \Kirby\Cms\FileVersion|\Kirby\Cms\File * @throws \Kirby\Exception\InvalidArgumentException */ - public function resize( - int $width = null, - int $height = null, - int $quality = null - ): FileVersion|File|Asset { + public function resize(int $width = null, int $height = null, int $quality = null) + { return $this->thumb([ 'width' => $width, 'height' => $height, @@ -105,21 +118,16 @@ trait FileModifications ]); } - /** - * Sharpens the image - */ - public function sharpen(int $amount = 50): FileVersion|File|Asset - { - return $this->thumb(['sharpen' => $amount]); - } - /** * Create a srcset definition for the given sizes * Sizes can be defined as a simple array. They can * also be set up in the config with the thumbs.srcsets option. * @since 3.1.0 + * + * @param array|string|null $sizes + * @return string|null */ - public function srcset(array|string|null $sizes = null): string|null + public function srcset($sizes = null): ?string { if (empty($sizes) === true) { $sizes = $this->kirby()->option('thumbs.srcsets.default', []); @@ -166,11 +174,12 @@ trait FileModifications * could potentially also be a CDN or any other * place. * + * @param array|null|string $options + * @return \Kirby\Cms\FileVersion|\Kirby\Cms\File * @throws \Kirby\Exception\InvalidArgumentException */ - public function thumb( - array|string|null $options = null - ): FileVersion|File|Asset { + public function thumb($options = null) + { // thumb presets if (empty($options) === true) { $options = $this->kirby()->option('thumbs.presets.default'); @@ -182,15 +191,6 @@ trait FileModifications return $this; } - // fallback to content file options - if (($options['crop'] ?? false) === true) { - if ($this instanceof ModelWithContent === true) { - $options['crop'] = $this->focus()->value() ?? 'center'; - } else { - $options['crop'] = 'center'; - } - } - // fallback to global config options if (isset($options['format']) === false) { if ($format = $this->kirby()->option('thumbs.format')) { @@ -202,9 +202,9 @@ trait FileModifications $result = $component($this->kirby(), $this, $options); if ( - $result instanceof FileVersion === false && - $result instanceof File === false && - $result instanceof Asset === false + is_a($result, 'Kirby\Cms\FileVersion') === false && + is_a($result, 'Kirby\Cms\File') === false && + is_a($result, 'Kirby\Filesystem\Asset') === false ) { throw new InvalidArgumentException('The file::version component must return a File, FileVersion or Asset object'); } diff --git a/kirby/src/Cms/FilePermissions.php b/kirby/src/Cms/FilePermissions.php index 2f8b777..e296de5 100644 --- a/kirby/src/Cms/FilePermissions.php +++ b/kirby/src/Cms/FilePermissions.php @@ -13,14 +13,5 @@ namespace Kirby\Cms; */ class FilePermissions extends ModelPermissions { - protected string $category = 'files'; - - protected function canChangeTemplate(): bool - { - if (count($this->model->blueprints()) <= 1) { - return false; - } - - return true; - } + protected $category = 'files'; } diff --git a/kirby/src/Cms/FilePicker.php b/kirby/src/Cms/FilePicker.php index 1391110..ea30ce1 100644 --- a/kirby/src/Cms/FilePicker.php +++ b/kirby/src/Cms/FilePicker.php @@ -19,6 +19,8 @@ class FilePicker extends Picker { /** * Extends the basic defaults + * + * @return array */ public function defaults(): array { @@ -31,21 +33,21 @@ class FilePicker extends Picker /** * Search all files for the picker * + * @return \Kirby\Cms\Files|null * @throws \Kirby\Exception\InvalidArgumentException */ - public function items(): Files|null + public function items() { $model = $this->options['model']; // find the right default query - $query = match (true) { - empty($this->options['query']) === false - => $this->options['query'], - $model instanceof File - => 'file.siblings', - default - => $model::CLASS_ALIAS . '.files' - }; + if (empty($this->options['query']) === false) { + $query = $this->options['query']; + } elseif (is_a($model, 'Kirby\Cms\File') === true) { + $query = 'file.siblings'; + } else { + $query = $model::CLASS_ALIAS . '.files'; + } // fetch all files for the picker $files = $model->query($query); @@ -53,17 +55,15 @@ class FilePicker extends Picker // help mitigate some typical query usage issues // by converting site and page objects to proper // pages by returning their children - $files = match (true) { - $files instanceof Site, - $files instanceof Page, - $files instanceof User => $files->files(), - $files instanceof Files => $files, - - default => throw new InvalidArgumentException('Your query must return a set of files') - }; - - // filter protected and hidden pages - $files = $files->filter('isListable', true); + if (is_a($files, 'Kirby\Cms\Site') === true) { + $files = $files->files(); + } elseif (is_a($files, 'Kirby\Cms\Page') === true) { + $files = $files->files(); + } elseif (is_a($files, 'Kirby\Cms\User') === true) { + $files = $files->files(); + } elseif (is_a($files, 'Kirby\Cms\Files') === false) { + throw new InvalidArgumentException('Your query must return a set of files'); + } // search $files = $this->search($files); diff --git a/kirby/src/Cms/FileRules.php b/kirby/src/Cms/FileRules.php index 33f25e3..09c6b53 100644 --- a/kirby/src/Cms/FileRules.php +++ b/kirby/src/Cms/FileRules.php @@ -4,7 +4,6 @@ namespace Kirby\Cms; use Kirby\Exception\DuplicateException; use Kirby\Exception\InvalidArgumentException; -use Kirby\Exception\LogicException; use Kirby\Exception\PermissionException; use Kirby\Filesystem\File as BaseFile; use Kirby\Toolkit\Str; @@ -24,6 +23,9 @@ class FileRules /** * Validates if the filename can be changed * + * @param \Kirby\Cms\File $file + * @param string $name + * @return bool * @throws \Kirby\Exception\DuplicateException If a file with this name exists * @throws \Kirby\Exception\PermissionException If the user is not allowed to rename the file */ @@ -57,51 +59,22 @@ class FileRules /** * Validates if the file can be sorted + * + * @param \Kirby\Cms\File $file + * @param int $sort + * @return bool */ public static function changeSort(File $file, int $sort): bool { return true; } - /** - * Validates if the template of the file can be changed - * - * @throws \Kirby\Exception\LogicException If the template of the page cannot be changed at all - * @throws \Kirby\Exception\PermissionException If the user is not allowed to change the template - */ - public static function changeTemplate(File $file, string $template): bool - { - if ($file->permissions()->changeTemplate() !== true) { - throw new PermissionException([ - 'key' => 'file.changeTemplate.permission', - 'data' => ['id' => $file->id()] - ]); - } - - $blueprints = $file->blueprints(); - - // ensure that the $template is a valid blueprint - // option for this file - if ( - count($blueprints) <= 1 || - in_array($template, array_column($blueprints, 'name')) === false - ) { - throw new LogicException([ - 'key' => 'file.changeTemplate.invalid', - 'data' => [ - 'id' => $file->id(), - 'template' => $template, - 'blueprints' => implode(', ', array_column($blueprints, 'name')) - ] - ]); - } - - return true; - } - /** * Validates if the file can be created * + * @param \Kirby\Cms\File $file + * @param \Kirby\Filesystem\File $upload + * @return bool * @throws \Kirby\Exception\DuplicateException If a file with the same name exists * @throws \Kirby\Exception\PermissionException If the user is not allowed to create the file */ @@ -148,6 +121,8 @@ class FileRules /** * Validates if the file can be deleted * + * @param \Kirby\Cms\File $file + * @return bool * @throws \Kirby\Exception\PermissionException If the user is not allowed to delete the file */ public static function delete(File $file): bool @@ -162,6 +137,9 @@ class FileRules /** * Validates if the file can be replaced * + * @param \Kirby\Cms\File $file + * @param \Kirby\Filesystem\File $upload + * @return bool * @throws \Kirby\Exception\PermissionException If the user is not allowed to replace the file * @throws \Kirby\Exception\InvalidArgumentException If the file type of the new file is different */ @@ -192,6 +170,9 @@ class FileRules /** * Validates if the file can be updated * + * @param \Kirby\Cms\File $file + * @param array $content + * @return bool * @throws \Kirby\Exception\PermissionException If the user is not allowed to update the file */ public static function update(File $file, array $content = []): bool @@ -206,6 +187,9 @@ class FileRules /** * Validates the file extension * + * @param \Kirby\Cms\File $file + * @param string $extension + * @return bool * @throws \Kirby\Exception\InvalidArgumentException If the extension is missing or forbidden */ public static function validExtension(File $file, string $extension): bool @@ -223,7 +207,7 @@ class FileRules if ( Str::contains($extension, 'php') !== false || Str::contains($extension, 'phar') !== false || - Str::contains($extension, 'pht') !== false + Str::contains($extension, 'phtml') !== false ) { throw new InvalidArgumentException([ 'key' => 'file.type.forbidden', @@ -251,19 +235,20 @@ class FileRules /** * Validates the extension, MIME type and filename * - * @param $mime If not passed, the MIME type is detected from the file, - * if `false`, the MIME type is not validated for performance reasons + * @param \Kirby\Cms\File $file + * @param string|null|false $mime If not passed, the MIME type is detected from the file, + * if `false`, the MIME type is not validated for performance reasons + * @return bool * @throws \Kirby\Exception\InvalidArgumentException If the extension, MIME type or filename is missing or forbidden */ - public static function validFile( - File $file, - string|false|null $mime = null - ): bool { - $validMime = match ($mime) { + public static function validFile(File $file, $mime = null): bool + { + if ($mime === false) { // request to skip the MIME check for performance reasons - false => true, - default => static::validMime($file, $mime ?? $file->mime()) - }; + $validMime = true; + } else { + $validMime = static::validMime($file, $mime ?? $file->mime()); + } return $validMime && @@ -274,6 +259,9 @@ class FileRules /** * Validates the filename * + * @param \Kirby\Cms\File $file + * @param string $filename + * @return bool * @throws \Kirby\Exception\InvalidArgumentException If the filename is missing or forbidden */ public static function validFilename(File $file, string $filename): bool @@ -310,6 +298,9 @@ class FileRules /** * Validates the MIME type * + * @param \Kirby\Cms\File $file + * @param string|null $mime + * @return bool * @throws \Kirby\Exception\InvalidArgumentException If the MIME type is missing or forbidden */ public static function validMime(File $file, string $mime = null): bool diff --git a/kirby/src/Cms/FileVersion.php b/kirby/src/Cms/FileVersion.php index 159da71..8eb47b1 100644 --- a/kirby/src/Cms/FileVersion.php +++ b/kirby/src/Cms/FileVersion.php @@ -17,22 +17,18 @@ class FileVersion { use IsFile; - protected array $modifications; + protected $modifications; protected $original; - public function __construct(array $props) - { - $this->root = $props['root'] ?? null; - $this->url = $props['url'] ?? null; - $this->original = $props['original']; - $this->modifications = $props['modifications'] ?? []; - } - /** * Proxy for public properties, asset methods * and content field getters + * + * @param string $method + * @param array $arguments + * @return mixed */ - public function __call(string $method, array $arguments = []): mixed + public function __call(string $method, array $arguments = []) { // public property access if (isset($this->$method) === true) { @@ -49,13 +45,15 @@ class FileVersion } // content fields - if ($this->original() instanceof File) { - return $this->original()->content()->get($method); + if (is_a($this->original(), 'Kirby\Cms\File') === true) { + return $this->original()->content()->get($method, $arguments); } } /** * Returns the unique ID + * + * @return string */ public function id(): string { @@ -64,24 +62,30 @@ class FileVersion /** * Returns the parent Kirby App instance + * + * @return \Kirby\Cms\App */ - public function kirby(): App + public function kirby() { return $this->original()->kirby(); } /** * Returns an array with all applied modifications + * + * @return array */ public function modifications(): array { - return $this->modifications; + return $this->modifications ?? []; } /** * Returns the instance of the original File object + * + * @return mixed */ - public function original(): mixed + public function original() { return $this->original; } @@ -92,7 +96,7 @@ class FileVersion * * @return $this */ - public function save(): static + public function save() { $this->kirby()->thumb( $this->original()->root(), @@ -102,16 +106,36 @@ class FileVersion return $this; } + /** + * Setter for modifications + * + * @param array|null $modifications + */ + protected function setModifications(array $modifications = null) + { + $this->modifications = $modifications; + } + + /** + * Setter for the original File object + * + * @param $original + */ + protected function setOriginal($original) + { + $this->original = $original; + } /** * Converts the object to an array + * + * @return array */ public function toArray(): array { - $array = array_merge( - $this->asset()->toArray(), - ['modifications' => $this->modifications()] - ); + $array = array_merge($this->asset()->toArray(), [ + 'modifications' => $this->modifications(), + ]); ksort($array); diff --git a/kirby/src/Cms/Files.php b/kirby/src/Cms/Files.php index 70760b2..ab5b249 100644 --- a/kirby/src/Cms/Files.php +++ b/kirby/src/Cms/Files.php @@ -4,7 +4,6 @@ namespace Kirby\Cms; use Kirby\Exception\InvalidArgumentException; use Kirby\Filesystem\F; -use Kirby\Uuid\HasUuids; /** * The `$files` object extends the general @@ -22,12 +21,12 @@ use Kirby\Uuid\HasUuids; */ class Files extends Collection { - use HasUuids; - /** * All registered files methods + * + * @var array */ - public static array $methods = []; + public static $methods = []; /** * Adds a single file or @@ -38,21 +37,18 @@ class Files extends Collection * @return $this * @throws \Kirby\Exception\InvalidArgumentException When no `File` or `Files` object or an ID of an existing file is passed */ - public function add($object): static + public function add($object) { // add a files collection - if ($object instanceof self) { + if (is_a($object, self::class) === true) { $this->data = array_merge($this->data, $object->data); // add a file by id - } elseif ( - is_string($object) === true && - $file = App::instance()->file($object) - ) { + } elseif (is_string($object) === true && $file = App::instance()->file($object)) { $this->__set($file->id(), $file); // add a file object - } elseif ($object instanceof File) { + } elseif (is_a($object, 'Kirby\Cms\File') === true) { $this->__set($object->id(), $object); // give a useful error message on invalid input; @@ -72,7 +68,7 @@ class Files extends Collection * @param int $offset Sorting offset * @return $this */ - public function changeSort(array $files, int $offset = 0): static + public function changeSort(array $files, int $offset = 0) { foreach ($files as $filename) { if ($file = $this->get($filename)) { @@ -86,13 +82,19 @@ class Files extends Collection /** * Creates a files collection from an array of props + * + * @param array $files + * @param \Kirby\Cms\Model $parent + * @return static */ - public static function factory(array $files, Page|Site|User $parent): static + public static function factory(array $files, Model $parent) { $collection = new static([], $parent); + $kirby = $parent->kirby(); foreach ($files as $props) { $props['collection'] = $collection; + $props['kirby'] = $kirby; $props['parent'] = $parent; $file = File::factory($props); @@ -103,17 +105,32 @@ class Files extends Collection return $collection; } + /** + * Tries to find a file by id/filename + * @deprecated 3.7.0 Use `$files->find()` instead + * @todo 3.8.0 Remove method + * @codeCoverageIgnore + * + * @param string $id + * @return \Kirby\Cms\File|null + */ + public function findById(string $id) + { + Helpers::deprecated('Cms\Files::findById() has been deprecated and will be removed in Kirby 3.8.0. Use $files->find() instead.'); + + return $this->findByKey($id); + } + /** * Finds a file by its filename * @internal Use `$files->find()` instead + * + * @param string $key + * @return \Kirby\Cms\File|null */ - public function findByKey(string $key): File|null + public function findByKey(string $key) { - if ($file = $this->findByUuid($key, 'file')) { - return $file; - } - - return $this->get(ltrim($this->parent?->id() . '/' . $key, '/')); + return $this->get(ltrim($this->parent->id() . '/' . $key, '/')); } /** @@ -125,6 +142,7 @@ class Files extends Collection * @param string|null|false $locale Locale for number formatting, * `null` for the current locale, * `false` to disable number formatting + * @return string */ public function niceSize($locale = null): string { @@ -135,6 +153,8 @@ class Files extends Collection * Returns the raw size for all * files in the collection * @since 3.6.0 + * + * @return int */ public function size(): int { @@ -144,8 +164,10 @@ class Files extends Collection /** * Returns the collection sorted by * the sort number and the filename + * + * @return static */ - public function sorted(): static + public function sorted() { return $this->sort('sort', 'asc', 'filename', 'asc'); } @@ -153,9 +175,10 @@ class Files extends Collection /** * Filter all files by the given template * + * @param null|string|array $template * @return $this|static */ - public function template(string|array|null $template): static + public function template($template) { if (empty($template) === true) { return $this; diff --git a/kirby/src/Cms/Find.php b/kirby/src/Cms/Find.php index aa2c363..581d3ab 100644 --- a/kirby/src/Cms/Find.php +++ b/kirby/src/Cms/Find.php @@ -23,18 +23,17 @@ class Find * Returns the file object for the given * parent path and filename * - * @param string $path Path to file's parent model + * @param string|null $path Path to file's parent model + * @param string $filename Filename + * @return \Kirby\Cms\File|null * @throws \Kirby\Exception\NotFoundException if the file cannot be found */ - public static function file( - string $path, - string $filename - ): File|null { + public static function file(string $path = null, string $filename) + { $filename = urldecode($filename); - $parent = empty($path) ? null : static::parent($path); - $file = App::instance()->file($filename, $parent); + $file = static::parent($path)->file($filename); - if ($file?->isAccessible() === true) { + if ($file && $file->isReadable() === true) { return $file; } @@ -50,9 +49,10 @@ class Find * Returns the language object for the given code * * @param string $code Language code + * @return \Kirby\Cms\Language|null * @throws \Kirby\Exception\NotFoundException if the language cannot be found */ - public static function language(string $code): Language|null + public static function language(string $code) { if ($language = App::instance()->language($code)) { return $language; @@ -70,16 +70,15 @@ class Find * Returns the page object for the given id * * @param string $id Page's id + * @return \Kirby\Cms\Page|null * @throws \Kirby\Exception\NotFoundException if the page cannot be found */ - public static function page(string $id): Page|null + public static function page(string $id) { - // decode API ID encoding - $id = str_replace(['+', ' '], '/', $id); - $kirby = App::instance(); - $page = $kirby->page($id, null, true); + $id = str_replace(['+', ' '], '/', $id); + $page = App::instance()->page($id); - if ($page?->isAccessible() === true) { + if ($page && $page->isReadable() === true) { return $page; } @@ -95,10 +94,11 @@ class Find * Returns the model's object for the given path * * @param string $path Path to parent model + * @return \Kirby\Cms\Model|null * @throws \Kirby\Exception\InvalidArgumentException if the model type is invalid * @throws \Kirby\Exception\NotFoundException if the model cannot be found */ - public static function parent(string $path): ModelWithContent + public static function parent(string $path) { $path = trim($path, '/'); $modelType = in_array($path, ['site', 'account']) ? $path : trim(dirname($path), '/'); @@ -117,19 +117,31 @@ class Find $kirby = App::instance(); - $model = match ($modelName) { - 'site' => $kirby->site(), - 'account' => static::user(), - 'page' => static::page(basename($path)), - // regular expression to split the path at the last - // occurrence of /files/ which separates parent path - // and filename - 'file' => static::file(...preg_split('$.*\K(/files/)$', $path)), - 'user' => $kirby->user(basename($path)), - default => throw new InvalidArgumentException('Invalid model type: ' . $modelType) - }; + switch ($modelName) { + case 'site': + $model = $kirby->site(); + break; + case 'account': + $model = static::user(); + break; + case 'page': + $model = static::page(basename($path)); + break; + case 'file': + $model = static::file(...explode('/files/', $path)); + break; + case 'user': + $model = $kirby->user(basename($path)); + break; + default: + throw new InvalidArgumentException('Invalid model type: ' . $modelType); + } - return $model ?? throw new NotFoundException([ + if ($model) { + return $model; + } + + throw new NotFoundException([ 'key' => $modelName . '.undefined' ]); } @@ -140,9 +152,10 @@ class Find * id is passed * * @param string|null $id User's id + * @return \Kirby\Cms\User|null * @throws \Kirby\Exception\NotFoundException if the user for the given id cannot be found */ - public static function user(string $id = null): User|null + public static function user(string $id = null) { // account is a reserved word to find the current // user. It's used in various API and area routes. @@ -154,18 +167,21 @@ class Find // get the authenticated user if ($id === null) { - $user = $kirby->user( - null, - $kirby->option('api.allowImpersonation', false) - ); + if ($user = $kirby->user(null, $kirby->option('api.allowImpersonation', false))) { + return $user; + } - return $user ?? throw new NotFoundException([ + throw new NotFoundException([ 'key' => 'user.undefined' ]); } // get a specific user by id - return $kirby->user($id) ?? throw new NotFoundException([ + if ($user = $kirby->user($id)) { + return $user; + } + + throw new NotFoundException([ 'key' => 'user.notFound', 'data' => [ 'name' => $id diff --git a/kirby/src/Cms/HasChildren.php b/kirby/src/Cms/HasChildren.php index 4bc88da..cb2a75e 100644 --- a/kirby/src/Cms/HasChildren.php +++ b/kirby/src/Cms/HasChildren.php @@ -18,40 +18,72 @@ trait HasChildren { /** * The list of available published children + * + * @var \Kirby\Cms\Pages|null */ - public Pages|null $children = null; + public $children; /** * The list of available draft children + * + * @var \Kirby\Cms\Pages|null */ - public Pages|null $drafts = null; + public $drafts; /** * The combined list of available published * and draft children + * + * @var \Kirby\Cms\Pages|null */ - public Pages|null $childrenAndDrafts = null; + public $childrenAndDrafts; /** * Returns all published children + * + * @return \Kirby\Cms\Pages */ - public function children(): Pages + public function children() { - return $this->children ??= Pages::factory($this->inventory()['children'], $this); + if (is_a($this->children, 'Kirby\Cms\Pages') === true) { + return $this->children; + } + + return $this->children = Pages::factory($this->inventory()['children'], $this); } /** * Returns all published and draft children at the same time + * + * @return \Kirby\Cms\Pages */ - public function childrenAndDrafts(): Pages + public function childrenAndDrafts() { - return $this->childrenAndDrafts ??= $this->children()->merge($this->drafts()); + if (is_a($this->childrenAndDrafts, 'Kirby\Cms\Pages') === true) { + return $this->childrenAndDrafts; + } + + return $this->childrenAndDrafts = $this->children()->merge($this->drafts()); + } + + /** + * Returns a list of IDs for the model's + * `toArray` method + * + * @return array + */ + protected function convertChildrenToArray(): array + { + return $this->children()->keys(); } /** * Searches for a draft child by ID + * + * @param string $path + * @return \Kirby\Cms\Page|null */ - public function draft(string $path): Page|null + public function draft(string $path) { $path = str_replace('_drafts/', '', $path); @@ -81,10 +113,12 @@ trait HasChildren /** * Returns all draft children + * + * @return \Kirby\Cms\Pages */ - public function drafts(): Pages + public function drafts() { - if ($this->drafts instanceof Pages) { + if (is_a($this->drafts, 'Kirby\Cms\Pages') === true) { return $this->drafts; } @@ -103,30 +137,40 @@ trait HasChildren /** * Finds one or multiple published children by ID + * + * @param string ...$arguments + * @return \Kirby\Cms\Page|\Kirby\Cms\Pages|null */ - public function find(string|array ...$arguments): Page|Pages|null + public function find(...$arguments) { return $this->children()->find(...$arguments); } /** * Finds a single published or draft child + * + * @param string $path + * @return \Kirby\Cms\Page|null */ - public function findPageOrDraft(string $path): Page|null + public function findPageOrDraft(string $path) { return $this->children()->find($path) ?? $this->drafts()->find($path); } /** * Returns a collection of all published children of published children + * + * @return \Kirby\Cms\Pages */ - public function grandChildren(): Pages + public function grandChildren() { return $this->children()->children(); } /** * Checks if the model has any published children + * + * @return bool */ public function hasChildren(): bool { @@ -135,6 +179,8 @@ trait HasChildren /** * Checks if the model has any draft children + * + * @return bool */ public function hasDrafts(): bool { @@ -143,6 +189,8 @@ trait HasChildren /** * Checks if the page has any listed children + * + * @return bool */ public function hasListedChildren(): bool { @@ -151,6 +199,8 @@ trait HasChildren /** * Checks if the page has any unlisted children + * + * @return bool */ public function hasUnlistedChildren(): bool { @@ -161,22 +211,24 @@ trait HasChildren * Creates a flat child index * * @param bool $drafts If set to `true`, draft children are included + * @return \Kirby\Cms\Pages */ - public function index(bool $drafts = false): Pages + public function index(bool $drafts = false) { if ($drafts === true) { return $this->childrenAndDrafts()->index($drafts); + } else { + return $this->children()->index(); } - - return $this->children()->index(); } /** * Sets the published children collection * + * @param array|null $children * @return $this */ - protected function setChildren(array $children = null): static + protected function setChildren(array $children = null) { if ($children !== null) { $this->children = Pages::factory($children, $this); @@ -188,9 +240,10 @@ trait HasChildren /** * Sets the draft children collection * + * @param array|null $drafts * @return $this */ - protected function setDrafts(array $drafts = null): static + protected function setDrafts(array $drafts = null) { if ($drafts !== null) { $this->drafts = Pages::factory($drafts, $this, true); diff --git a/kirby/src/Cms/HasFiles.php b/kirby/src/Cms/HasFiles.php index 86788d2..cb4102d 100644 --- a/kirby/src/Cms/HasFiles.php +++ b/kirby/src/Cms/HasFiles.php @@ -2,8 +2,6 @@ namespace Kirby\Cms; -use Kirby\Uuid\Uuid; - /** * HasFiles * @@ -17,64 +15,81 @@ trait HasFiles { /** * The Files collection + * + * @var \Kirby\Cms\Files */ - protected Files|array|null $files = null; + protected $files; /** * Filters the Files collection by type audio + * + * @return \Kirby\Cms\Files */ - public function audio(): Files + public function audio() { return $this->files()->filter('type', '==', 'audio'); } /** * Filters the Files collection by type code + * + * @return \Kirby\Cms\Files */ - public function code(): Files + public function code() { return $this->files()->filter('type', '==', 'code'); } + /** + * Returns a list of file ids + * for the toArray method of the model + * + * @return array + */ + protected function convertFilesToArray(): array + { + return $this->files()->keys(); + } + /** * Creates a new file * - * @param bool $move If set to `true`, the source will be deleted + * @param array $props + * @return \Kirby\Cms\File */ - public function createFile(array $props, bool $move = false): File + public function createFile(array $props) { $props = array_merge($props, [ 'parent' => $this, 'url' => null ]); - return File::create($props, $move); + return File::create($props); } /** * Filters the Files collection by type documents + * + * @return \Kirby\Cms\Files */ - public function documents(): Files + public function documents() { return $this->files()->filter('type', '==', 'document'); } /** * Returns a specific file by filename or the first one + * + * @param string|null $filename + * @param string $in + * @return \Kirby\Cms\File|null */ - public function file( - string $filename = null, - string $in = 'files' - ): File|null { + public function file(string $filename = null, string $in = 'files') + { if ($filename === null) { return $this->$in()->first(); } - // find by global UUID - if (Uuid::is($filename, 'file') === true) { - return Uuid::for($filename, $this->$in())->model(); - } - if (strpos($filename, '/') !== false) { $path = dirname($filename); $filename = basename($filename); @@ -91,10 +106,12 @@ trait HasFiles /** * Returns the Files collection + * + * @return \Kirby\Cms\Files */ - public function files(): Files + public function files() { - if ($this->files instanceof Files) { + if (is_a($this->files, 'Kirby\Cms\Files') === true) { return $this->files; } @@ -103,6 +120,8 @@ trait HasFiles /** * Checks if the Files collection has any audio files + * + * @return bool */ public function hasAudio(): bool { @@ -111,6 +130,8 @@ trait HasFiles /** * Checks if the Files collection has any code files + * + * @return bool */ public function hasCode(): bool { @@ -119,6 +140,8 @@ trait HasFiles /** * Checks if the Files collection has any document files + * + * @return bool */ public function hasDocuments(): bool { @@ -127,6 +150,8 @@ trait HasFiles /** * Checks if the Files collection has any files + * + * @return bool */ public function hasFiles(): bool { @@ -135,6 +160,8 @@ trait HasFiles /** * Checks if the Files collection has any images + * + * @return bool */ public function hasImages(): bool { @@ -143,6 +170,8 @@ trait HasFiles /** * Checks if the Files collection has any videos + * + * @return bool */ public function hasVideos(): bool { @@ -151,16 +180,21 @@ trait HasFiles /** * Returns a specific image by filename or the first one + * + * @param string|null $filename + * @return \Kirby\Cms\File|null */ - public function image(string $filename = null): File|null + public function image(string $filename = null) { return $this->file($filename, 'images'); } /** * Filters the Files collection by type image + * + * @return \Kirby\Cms\Files */ - public function images(): Files + public function images() { return $this->files()->filter('type', '==', 'image'); } @@ -168,9 +202,10 @@ trait HasFiles /** * Sets the Files collection * + * @param \Kirby\Cms\Files|null $files * @return $this */ - protected function setFiles(array $files = null): static + protected function setFiles(array $files = null) { if ($files !== null) { $this->files = Files::factory($files, $this); @@ -181,8 +216,10 @@ trait HasFiles /** * Filters the Files collection by type videos + * + * @return \Kirby\Cms\Files */ - public function videos(): Files + public function videos() { return $this->files()->filter('type', '==', 'video'); } diff --git a/kirby/src/Cms/HasMethods.php b/kirby/src/Cms/HasMethods.php index 9e08d5b..053eb8b 100644 --- a/kirby/src/Cms/HasMethods.php +++ b/kirby/src/Cms/HasMethods.php @@ -2,7 +2,6 @@ namespace Kirby\Cms; -use Closure; use Kirby\Exception\BadMethodCallException; /** @@ -18,17 +17,22 @@ trait HasMethods { /** * All registered methods + * + * @var array */ - public static array $methods = []; + public static $methods = []; /** * Calls a registered method class with the * passed arguments - * @internal * + * @internal + * @param string $method + * @param array $args + * @return mixed * @throws \Kirby\Exception\BadMethodCallException */ - public function callMethod(string $method, array $args = []): mixed + public function callMethod(string $method, array $args = []) { $closure = $this->getMethod($method); @@ -41,7 +45,10 @@ trait HasMethods /** * Checks if the object has a registered method + * * @internal + * @param string $method + * @return bool */ public function hasMethod(string $method): bool { @@ -52,8 +59,11 @@ trait HasMethods * Returns a registered method by name, either from * the current class or from a parent class ordered by * inheritance order (top to bottom) + * + * @param string $method + * @return \Closure|null */ - protected function getMethod(string $method): Closure|null + protected function getMethod(string $method) { if (isset(static::$methods[$method]) === true) { return static::$methods[$method]; diff --git a/kirby/src/Cms/HasSiblings.php b/kirby/src/Cms/HasSiblings.php index 86e63e9..ad6fa7d 100644 --- a/kirby/src/Cms/HasSiblings.php +++ b/kirby/src/Cms/HasSiblings.php @@ -18,26 +18,31 @@ trait HasSiblings * Returns the position / index in the collection * * @param \Kirby\Cms\Collection|null $collection + * + * @return int */ - public function indexOf($collection = null): int|false + public function indexOf($collection = null): int { - $collection ??= $this->siblingsCollection(); + if ($collection === null) { + $collection = $this->siblingsCollection(); + } + return $collection->indexOf($this); } /** * Returns the next item in the collection if available - * @todo `static` return type hint is not 100% accurate because of - * quirks in the `Form` classes; would break if enforced - * (https://github.com/getkirby/kirby/pull/5175) * * @param \Kirby\Cms\Collection|null $collection * - * @return static|null + * @return \Kirby\Cms\Model|null */ public function next($collection = null) { - $collection ??= $this->siblingsCollection(); + if ($collection === null) { + $collection = $this->siblingsCollection(); + } + return $collection->nth($this->indexOf($collection) + 1); } @@ -50,23 +55,26 @@ trait HasSiblings */ public function nextAll($collection = null) { - $collection ??= $this->siblingsCollection(); + if ($collection === null) { + $collection = $this->siblingsCollection(); + } + return $collection->slice($this->indexOf($collection) + 1); } /** * Returns the previous item in the collection if available - * @todo `static` return type hint is not 100% accurate because of - * quirks in the `Form` classes; would break if enforced - * (https://github.com/getkirby/kirby/pull/5175) * * @param \Kirby\Cms\Collection|null $collection * - * @return static|null + * @return \Kirby\Cms\Model|null */ public function prev($collection = null) { - $collection ??= $this->siblingsCollection(); + if ($collection === null) { + $collection = $this->siblingsCollection(); + } + return $collection->nth($this->indexOf($collection) - 1); } @@ -79,13 +87,17 @@ trait HasSiblings */ public function prevAll($collection = null) { - $collection ??= $this->siblingsCollection(); + if ($collection === null) { + $collection = $this->siblingsCollection(); + } + return $collection->slice(0, $this->indexOf($collection)); } /** * Returns all sibling elements * + * @param bool $self * @return \Kirby\Cms\Collection */ public function siblings(bool $self = true) @@ -103,6 +115,8 @@ trait HasSiblings * Checks if there's a next item in the collection * * @param \Kirby\Cms\Collection|null $collection + * + * @return bool */ public function hasNext($collection = null): bool { @@ -113,6 +127,8 @@ trait HasSiblings * Checks if there's a previous item in the collection * * @param \Kirby\Cms\Collection|null $collection + * + * @return bool */ public function hasPrev($collection = null): bool { @@ -123,10 +139,15 @@ trait HasSiblings * Checks if the item is the first in the collection * * @param \Kirby\Cms\Collection|null $collection + * + * @return bool */ public function isFirst($collection = null): bool { - $collection ??= $this->siblingsCollection(); + if ($collection === null) { + $collection = $this->siblingsCollection(); + } + return $collection->first()->is($this); } @@ -134,10 +155,15 @@ trait HasSiblings * Checks if the item is the last in the collection * * @param \Kirby\Cms\Collection|null $collection + * + * @return bool */ public function isLast($collection = null): bool { - $collection ??= $this->siblingsCollection(); + if ($collection === null) { + $collection = $this->siblingsCollection(); + } + return $collection->last()->is($this); } @@ -145,6 +171,9 @@ trait HasSiblings * Checks if the item is at a certain position * * @param \Kirby\Cms\Collection|null $collection + * @param int $n + * + * @return bool */ public function isNth(int $n, $collection = null): bool { diff --git a/kirby/src/Cms/Helpers.php b/kirby/src/Cms/Helpers.php index 9e27f42..a7c92fa 100644 --- a/kirby/src/Cms/Helpers.php +++ b/kirby/src/Cms/Helpers.php @@ -18,82 +18,33 @@ use Kirby\Toolkit\Str; */ class Helpers { - /** - * Allows to disable specific deprecation warnings - * by setting them to `false`. - * You can do this by putting the following code in - * `site/config/config.php`: - * - * ```php - * Helpers::$deprecations[''] = false; - * ``` - */ - public static $deprecations = [ - // The internal `$model->contentFile*()` methods have been deprecated - 'model-content-file' => true, - - // Passing an `info` array inside the `extends` array - // has been deprecated. Pass the individual entries (e.g. root, version) - // directly as named arguments. - // TODO: switch to true in v6 - 'plugin-extends-root' => false, - - // Passing a single space as value to `Xml::attr()` has been - // deprecated. In a future version, passing a single space won't - // render an empty value anymore but a single space. - // To render an empty value, please pass an empty string. - 'xml-attr-single-space' => true, - ]; - /** * Triggers a deprecation warning if debug mode is active - * and warning has not been surpressed via `Helpers::$deprecations` * - * @param string|null $key If given, the key will be checked against the static array + * @param string $message * @return bool Whether the warning was triggered */ - public static function deprecated( - string $message, - string|null $key = null - ): bool { - // only trigger warning in debug mode or when running PHPUnit tests - // @codeCoverageIgnoreStart - if ( - App::instance()->option('debug') !== true && - (defined('KIRBY_TESTING') !== true || KIRBY_TESTING !== true) - ) { - return false; - } - // @codeCoverageIgnoreEnd - - // don't trigger the warning if disabled by default or by the dev - if ($key !== null && (static::$deprecations[$key] ?? true) === false) { - return false; + public static function deprecated(string $message): bool + { + if (App::instance()->option('debug') === true) { + return trigger_error($message, E_USER_DEPRECATED) === true; } - return trigger_error($message, E_USER_DEPRECATED) === true; + return false; } /** * Simple object and variable dumper * to help with debugging. + * + * @param mixed $variable + * @param bool $echo + * @return string */ - public static function dump(mixed $variable, bool $echo = true): string + public static function dump($variable, bool $echo = true): string { - $kirby = App::instance(); - $output = print_r($variable, true); - - if ($kirby->environment()->cli() === true) { - $output .= PHP_EOL; - } else { - $output = Str::wrap($output, '
      ', '
      '); - } - - if ($echo === true) { - echo $output; - } - - return $output; + $kirby = App::instance(); + return ($kirby->component('dump'))($kirby, $variable, $echo); } /** @@ -102,56 +53,36 @@ class Helpers * @since 3.7.4 * * @param \Closure $action Any action that may cause an error or warning - * @param \Closure $condition Closure that returns bool to determine if to - * suppress an error, receives arguments for - * `set_error_handler()` - * @param mixed $fallback Value to return when error is suppressed - * @return mixed Return value of the `$action` closure, - * possibly overridden by `$fallback` + * @param \Closure $handler Custom callback like for `set_error_handler()`; + * the first argument is a return value override passed + * by reference, the additional arguments come from + * `set_error_handler()`; returning `false` activates + * error handling by Whoops and/or PHP + * @return mixed Return value of the `$action` closure, possibly overridden by `$handler` */ - public static function handleErrors( - Closure $action, - Closure $condition, - $fallback = null - ) { - $override = null; + public static function handleErrors(Closure $action, Closure $handler) + { + $override = $oldHandler = null; + $oldHandler = set_error_handler(function () use (&$override, &$oldHandler, $handler) { + $handlerResult = $handler($override, ...func_get_args()); - /** - * @psalm-suppress UndefinedVariable - */ - $handler = set_error_handler(function () use (&$override, &$handler, $condition, $fallback) { - // check if suppress condition is met - $suppress = $condition(...func_get_args()); - - if ($suppress !== true) { + if ($handlerResult === false) { // handle other warnings with Whoops if loaded - if (is_callable($handler) === true) { - return $handler(...func_get_args()); + if (is_callable($oldHandler) === true) { + return $oldHandler(...func_get_args()); } // otherwise use the standard error handler return false; // @codeCoverageIgnore } - // use fallback to override return for suppressed errors - $override = $fallback; - - if (is_callable($override) === true) { - $override = $override(); - } - // no additional error handling return true; }); - try { - $result = $action(); - } finally { - // always restore the error handler, even if the - // action or the standard error handler threw an - // exception; this avoids modifying global state - restore_error_handler(); - } + $result = $action(); + + restore_error_handler(); return $override ?? $result; } @@ -162,6 +93,7 @@ class Helpers * @internal * * @param string $name Name of the helper + * @return bool */ public static function hasOverride(string $name): bool { @@ -173,9 +105,11 @@ class Helpers * Determines the size/length of numbers, * strings, arrays and countable objects * + * @param mixed $value + * @return int * @throws \Kirby\Exception\InvalidArgumentException */ - public static function size(mixed $value): int + public static function size($value): int { if (is_numeric($value)) { return (int)$value; diff --git a/kirby/src/Cms/Html.php b/kirby/src/Cms/Html.php index 9ab61c4..1af6087 100644 --- a/kirby/src/Cms/Html.php +++ b/kirby/src/Cms/Html.php @@ -23,20 +23,11 @@ class Html extends \Kirby\Toolkit\Html * @since 3.7.0 * * @param string|array $url Relative or absolute URLs, an array of URLs or `@auto` for automatic template css loading - * @param string|array|null $options Pass an array of attributes for the link tag or a media attribute string + * @param string|array $options Pass an array of attributes for the link tag or a media attribute string + * @return string|null */ - public static function css( - string|array|Plugin|PluginAssets $url, - string|array|null $options = null - ): string|null { - if ($url instanceof Plugin) { - $url = $url->assets(); - } - - if ($url instanceof PluginAssets) { - $url = $url->css()->values(fn ($asset) => $asset->url()); - } - + public static function css($url, $options = null): ?string + { if (is_array($url) === true) { $links = A::map($url, fn ($url) => static::css($url, $options)); return implode(PHP_EOL, $links); @@ -54,8 +45,7 @@ class Html extends \Kirby\Toolkit\Html } } - // only valid value for 'rel' is 'alternate stylesheet', - // if 'title' is given as well + // only valid value for 'rel' is 'alternate stylesheet', if 'title' is given as well if ( ($options['rel'] ?? '') !== 'alternate stylesheet' || ($options['title'] ?? '') === '' @@ -78,31 +68,23 @@ class Html extends \Kirby\Toolkit\Html * @param string|null $href Relative or absolute Url * @param string|array|null $text If `null`, the link will be used as link text. If an array is passed, each element will be added unencoded * @param array $attr Additional attributes for the a tag. + * @return string */ - public static function link( - string|null $href = null, - string|array $text = null, - array $attr = [] - ): string { + public static function link(string $href = null, $text = null, array $attr = []): string + { return parent::link(Url::to($href), $text, $attr); } /** * Creates a script tag to load a javascript file * @since 3.7.0 + * + * @param string|array $url + * @param string|array $options + * @return string|null */ - public static function js( - string|array|Plugin|PluginAssets $url, - string|array|bool|null $options = null - ): string|null { - if ($url instanceof Plugin) { - $url = $url->assets(); - } - - if ($url instanceof PluginAssets) { - $url = $url->js()->values(fn ($asset) => $asset->url()); - } - + public static function js($url, $options = null): ?string + { if (is_array($url) === true) { $scripts = A::map($url, fn ($url) => static::js($url, $options)); return implode(PHP_EOL, $scripts); @@ -131,12 +113,15 @@ class Html extends \Kirby\Toolkit\Html * Includes an SVG file by absolute or * relative file path. * @since 3.7.0 + * + * @param string|\Kirby\Cms\File $file + * @return string|false */ - public static function svg(string|File $file): string|false + public static function svg($file) { // support for Kirby's file objects if ( - $file instanceof File && + is_a($file, 'Kirby\Cms\File') === true && $file->extension() === 'svg' ) { return $file->read(); diff --git a/kirby/src/Cms/Ingredients.php b/kirby/src/Cms/Ingredients.php index f9c1c59..42442b3 100644 --- a/kirby/src/Cms/Ingredients.php +++ b/kirby/src/Cms/Ingredients.php @@ -2,8 +2,6 @@ namespace Kirby\Cms; -use Closure; - /** * The Ingredients class is the foundation for * `$kirby->urls()` and `$kirby->roots()` objects. @@ -25,6 +23,8 @@ class Ingredients /** * Creates a new ingredient collection + * + * @param array $ingredients */ public function __construct(array $ingredients) { @@ -33,15 +33,20 @@ class Ingredients /** * Magic getter for single ingredients + * + * @param string $method + * @param array|null $args + * @return mixed */ - public function __call(string $method, array $args = null): mixed + public function __call(string $method, array $args = null) { return $this->ingredients[$method] ?? null; } /** * Improved `var_dump` output - * @codeCoverageIgnore + * + * @return array */ public function __debugInfo(): array { @@ -50,6 +55,9 @@ class Ingredients /** * Get a single ingredient by key + * + * @param string $key + * @return mixed */ public function __get(string $key) { @@ -59,12 +67,15 @@ class Ingredients /** * Resolves all ingredient callbacks * and creates a plain array + * * @internal + * @param array $ingredients + * @return static */ - public static function bake(array $ingredients): static + public static function bake(array $ingredients) { foreach ($ingredients as $name => $ingredient) { - if ($ingredient instanceof Closure) { + if (is_a($ingredient, 'Closure') === true) { $ingredients[$name] = $ingredient($ingredients); } } @@ -74,6 +85,8 @@ class Ingredients /** * Returns all ingredients as plain array + * + * @return array */ public function toArray(): array { diff --git a/kirby/src/Cms/Item.php b/kirby/src/Cms/Item.php index 86dd85a..2f6922e 100644 --- a/kirby/src/Cms/Item.php +++ b/kirby/src/Cms/Item.php @@ -2,7 +2,6 @@ namespace Kirby\Cms; -use Kirby\Content\Field; use Kirby\Toolkit\Str; /** @@ -25,46 +24,58 @@ class Item { use HasSiblings; - public const ITEMS_CLASS = Items::class; + public const ITEMS_CLASS = '\Kirby\Cms\Items'; - protected Field|null $field; + /** + * @var string + */ + protected $id; - protected string $id; - protected array $params; - protected ModelWithContent $parent; - protected Items $siblings; + /** + * @var array + */ + protected $params; + + /** + * @var \Kirby\Cms\Page|\Kirby\Cms\Site|\Kirby\Cms\File|\Kirby\Cms\User + */ + protected $parent; + + /** + * @var \Kirby\Cms\Items + */ + protected $siblings; /** * Creates a new item + * + * @param array $params */ public function __construct(array $params = []) { - $class = static::ITEMS_CLASS; + $siblingsClass = static::ITEMS_CLASS; + $this->id = $params['id'] ?? Str::uuid(); $this->params = $params; - $this->field = $params['field'] ?? null; $this->parent = $params['parent'] ?? App::instance()->site(); - $this->siblings = $params['siblings'] ?? new $class(); + $this->siblings = $params['siblings'] ?? new $siblingsClass(); } /** * Static Item factory + * + * @param array $params + * @return \Kirby\Cms\Item */ - public static function factory(array $params): static + public static function factory(array $params) { return new static($params); } - /** - * Returns the parent field if known - */ - public function field(): Field|null - { - return $this->field; - } - /** * Returns the unique item id (UUID v4) + * + * @return string */ public function id(): string { @@ -73,6 +84,9 @@ class Item /** * Compares the item to another one + * + * @param \Kirby\Cms\Item $item + * @return bool */ public function is(Item $item): bool { @@ -81,16 +95,20 @@ class Item /** * Returns the Kirby instance + * + * @return \Kirby\Cms\App */ - public function kirby(): App + public function kirby() { return $this->parent()->kirby(); } /** * Returns the parent model + * + * @return \Kirby\Cms\Page|\Kirby\Cms\Site|\Kirby\Cms\File|\Kirby\Cms\User */ - public function parent(): ModelWithContent + public function parent() { return $this->parent; } @@ -99,15 +117,18 @@ class Item * Returns the sibling collection * This is required by the HasSiblings trait * + * @return \Kirby\Cms\Items * @psalm-return self::ITEMS_CLASS */ - protected function siblingsCollection(): Items + protected function siblingsCollection() { return $this->siblings; } /** * Converts the item to an array + * + * @return array */ public function toArray(): array { diff --git a/kirby/src/Cms/Items.php b/kirby/src/Cms/Items.php index 97f8104..6bbecb5 100644 --- a/kirby/src/Cms/Items.php +++ b/kirby/src/Cms/Items.php @@ -3,8 +3,7 @@ namespace Kirby\Cms; use Closure; -use Kirby\Content\Field; -use Kirby\Exception\InvalidArgumentException; +use Exception; /** * A collection of items @@ -18,27 +17,28 @@ use Kirby\Exception\InvalidArgumentException; */ class Items extends Collection { - public const ITEM_CLASS = Item::class; - - protected Field|null $field; + public const ITEM_CLASS = '\Kirby\Cms\Item'; /** - * All registered items methods + * @var array */ - public static array $methods = []; - - protected array $options; + protected $options; /** * @var \Kirby\Cms\ModelWithContent */ protected $parent; + /** + * Constructor + * + * @param array $objects + * @param array $options + */ public function __construct($objects = [], array $options = []) { $this->options = $options; $this->parent = $options['parent'] ?? App::instance()->site(); - $this->field = $options['field'] ?? null; parent::__construct($objects, $this->parent); } @@ -46,52 +46,49 @@ class Items extends Collection /** * Creates a new item collection from a * an array of item props + * + * @param array $items + * @param array $params + * @return \Kirby\Cms\Items */ - public static function factory( - array $items = null, - array $params = [] - ): static { + public static function factory(array $items = null, array $params = []) + { + $options = array_merge([ + 'options' => [], + 'parent' => App::instance()->site(), + ], $params); + if (empty($items) === true || is_array($items) === false) { return new static(); } - if (is_array($params) === false) { - throw new InvalidArgumentException('Invalid item options'); + if (is_array($options) === false) { + throw new Exception('Invalid item options'); } // create a new collection of blocks - $collection = new static([], $params); + $collection = new static([], $options); - foreach ($items as $item) { - if (is_array($item) === false) { - throw new InvalidArgumentException('Invalid data for ' . static::ITEM_CLASS); + foreach ($items as $params) { + if (is_array($params) === false) { + continue; } - // inject properties from the parent - $item['field'] = $collection->field(); - $item['options'] = $params['options'] ?? []; - $item['parent'] = $collection->parent(); - $item['siblings'] = $collection; - $item['params'] = $item; - + $params['options'] = $options['options']; + $params['parent'] = $options['parent']; + $params['siblings'] = $collection; $class = static::ITEM_CLASS; - $item = $class::factory($item); + $item = $class::factory($params); $collection->append($item->id(), $item); } return $collection; } - /** - * Returns the parent field if known - */ - public function field(): Field|null - { - return $this->field; - } - /** * Convert the items to an array + * + * @return array */ public function toArray(Closure $map = null): array { diff --git a/kirby/src/Cms/Language.php b/kirby/src/Cms/Language.php index d9e3eba..a5b33f6 100644 --- a/kirby/src/Cms/Language.php +++ b/kirby/src/Cms/Language.php @@ -4,8 +4,6 @@ namespace Kirby\Cms; use Kirby\Data\Data; use Kirby\Exception\Exception; -use Kirby\Exception\InvalidArgumentException; -use Kirby\Exception\LogicException; use Kirby\Exception\PermissionException; use Kirby\Filesystem\F; use Kirby\Toolkit\Locale; @@ -28,54 +26,80 @@ use Throwable; * @copyright Bastian Allgeier * @license https://getkirby.com/license */ -class Language +class Language extends Model { - use HasSiblings; + /** + * @var string + */ + protected $code; /** - * The parent Kirby instance + * @var bool */ - public static App|null $kirby; + protected $default; - protected string $code; - protected bool $default; - protected string $direction; - protected array $locale; - protected string $name; - protected array $slugs; - protected array $smartypants; - protected array $translations; - protected string|null $url; + /** + * @var string + */ + protected $direction; + + /** + * @var array + */ + protected $locale; + + /** + * @var string + */ + protected $name; + + /** + * @var array|null + */ + protected $slugs; + + /** + * @var array|null + */ + protected $smartypants; + + /** + * @var array|null + */ + protected $translations; + + /** + * @var string + */ + protected $url; /** * Creates a new language object + * + * @param array $props */ public function __construct(array $props) { - if (isset($props['code']) === false) { - throw new InvalidArgumentException('The property "code" is required'); - } + $this->setRequiredProperties($props, [ + 'code' + ]); - static::$kirby = $props['kirby'] ?? null; - $this->code = trim($props['code']); - $this->default = ($props['default'] ?? false) === true; - $this->direction = ($props['direction'] ?? null) === 'rtl' ? 'rtl' : 'ltr'; - $this->name = trim($props['name'] ?? $this->code); - $this->slugs = $props['slugs'] ?? []; - $this->smartypants = $props['smartypants'] ?? []; - $this->translations = $props['translations'] ?? []; - $this->url = $props['url'] ?? null; - - if ($locale = $props['locale'] ?? null) { - $this->locale = Locale::normalize($locale); - } else { - $this->locale = [LC_ALL => $this->code]; - } + $this->setOptionalProperties($props, [ + 'default', + 'direction', + 'locale', + 'name', + 'slugs', + 'smartypants', + 'translations', + 'url', + ]); } /** * Improved `var_dump` output - * @codeCoverageIgnore + * + * @return array */ public function __debugInfo(): array { @@ -85,6 +109,8 @@ class Language /** * Returns the language code * when the language is converted to a string + * + * @return string */ public function __toString(): string { @@ -94,6 +120,8 @@ class Language /** * Returns the base Url for the language * without the path or other cruft + * + * @return string */ public function baseUrl(): string { @@ -111,29 +139,12 @@ class Language return Url::base($languageUrl) ?? $kirbyUrl; } - /** - * Creates an instance with the same - * initial properties. - */ - public function clone(array $props = []): static - { - return new static(array_replace_recursive([ - 'code' => $this->code, - 'default' => $this->default, - 'direction' => $this->direction, - 'locale' => $this->locale, - 'name' => $this->name, - 'slugs' => $this->slugs, - 'smartypants' => $this->smartypants, - 'translations' => $this->translations, - 'url' => $this->url, - ], $props)); - } - /** * Returns the language code/id. * The language code is used in * text file names as appendix. + * + * @return string */ public function code(): string { @@ -141,10 +152,54 @@ class Language } /** - * Creates a new language object - * @internal + * Internal converter to create or remove + * translation files. + * + * @param string $from + * @param string $to + * @return bool */ - public static function create(array $props): static + protected static function converter(string $from, string $to): bool + { + $kirby = App::instance(); + $site = $kirby->site(); + + // convert site + foreach ($site->files() as $file) { + F::move($file->contentFile($from, true), $file->contentFile($to, true)); + } + + F::move($site->contentFile($from, true), $site->contentFile($to, true)); + + // convert all pages + foreach ($kirby->site()->index(true) as $page) { + foreach ($page->files() as $file) { + F::move($file->contentFile($from, true), $file->contentFile($to, true)); + } + + F::move($page->contentFile($from, true), $page->contentFile($to, true)); + } + + // convert all users + foreach ($kirby->users() as $user) { + foreach ($user->files() as $file) { + F::move($file->contentFile($from, true), $file->contentFile($to, true)); + } + + F::move($user->contentFile($from, true), $user->contentFile($to, true)); + } + + return true; + } + + /** + * Creates a new language object + * + * @internal + * @param array $props + * @return static + */ + public static function create(array $props) { $kirby = App::instance(); $user = $kirby->user(); @@ -157,6 +212,7 @@ class Language } $props['code'] = Str::slug($props['code'] ?? null); + $kirby = App::instance(); $languages = $kirby->languages(); // make the first language the default language @@ -166,40 +222,17 @@ class Language $language = new static($props); - // trigger before hook - $kirby->trigger( - 'language.create:before', - [ - 'input' => $props, - 'language' => $language - ] - ); - // validate the new language LanguageRules::create($language); $language->save(); if ($languages->count() === 0) { - foreach ($kirby->models() as $model) { - $model->storage()->convertLanguage( - 'default', - $language->code() - ); - } + static::converter('', $language->code()); } // update the main languages collection in the app instance - $kirby->languages(false)->append($language->code(), $language); - - // trigger after hook - $kirby->trigger( - 'language.create:after', - [ - 'input' => $props, - 'language' => $language - ] - ); + App::instance()->languages(false)->append($language->code(), $language); return $language; } @@ -207,15 +240,18 @@ class Language /** * Delete the current language and * all its translation files - * @internal * + * @internal + * @return bool * @throws \Kirby\Exception\Exception */ public function delete(): bool { - $kirby = App::instance(); - $user = $kirby->user(); - $code = $this->code(); + $kirby = App::instance(); + $user = $kirby->user(); + $languages = $kirby->languages(); + $code = $this->code(); + $isLast = $languages->count() === 1; if ( $user === null || @@ -224,40 +260,59 @@ class Language throw new PermissionException(['key' => 'language.delete.permission']); } - if ($this->isDeletable() === false) { - throw new Exception('The language cannot be deleted'); - } - - // trigger before hook - $kirby->trigger('language.delete:before', [ - 'language' => $this - ]); - if (F::remove($this->root()) !== true) { throw new Exception('The language could not be deleted'); } - foreach ($kirby->models() as $model) { - if ($this->isLast() === true) { - $model->storage()->convertLanguage($code, 'default'); - } else { - $model->storage()->deleteLanguage($code); - } + if ($isLast === true) { + $this->converter($code, ''); + } else { + $this->deleteContentFiles($code); } // get the original language collection and remove the current language $kirby->languages(false)->remove($code); - // trigger after hook - $kirby->trigger('language.delete:after', [ - 'language' => $this - ]); + return true; + } + + /** + * When the language is deleted, all content files with + * the language code must be removed as well. + * + * @param mixed $code + * @return bool + */ + protected function deleteContentFiles($code): bool + { + $kirby = App::instance(); + $site = $kirby->site(); + + F::remove($site->contentFile($code, true)); + + foreach ($kirby->site()->index(true) as $page) { + foreach ($page->files() as $file) { + F::remove($file->contentFile($code, true)); + } + + F::remove($page->contentFile($code, true)); + } + + foreach ($kirby->users() as $user) { + foreach ($user->files() as $file) { + F::remove($file->contentFile($code, true)); + } + + F::remove($user->contentFile($code, true)); + } return true; } /** * Reading direction of this language + * + * @return string */ public function direction(): string { @@ -266,6 +321,8 @@ class Language /** * Check if the language file exists + * + * @return bool */ public function exists(): bool { @@ -275,54 +332,31 @@ class Language /** * Checks if this is the default language * for the site. + * + * @return bool */ public function isDefault(): bool { return $this->default; } - /** - * Checks if the language can be deleted - */ - public function isDeletable(): bool - { - // the default language can only be deleted if it's the last - if ($this->isDefault() === true && $this->isLast() === false) { - return false; - } - - return true; - } - - /** - * Checks if this is the last language - */ - public function isLast(): bool - { - return App::instance()->languages()->count() === 1; - } - /** * The id is required for collections * to work properly. The code is used as id + * + * @return string */ public function id(): string { return $this->code; } - /** - * Returns the parent Kirby instance - */ - public function kirby(): App - { - return static::$kirby ??= App::instance(); - } - /** * Loads the language rules for provided locale code + * + * @param string $code */ - public static function loadRules(string $code): array + public static function loadRules(string $code) { $kirby = App::instance(); $code = Str::contains($code, '.') ? Str::before($code, '.') : $code; @@ -334,7 +368,7 @@ class Language try { return Data::read($file); - } catch (\Exception) { + } catch (\Exception $e) { return []; } } @@ -343,19 +377,22 @@ class Language * Returns the PHP locale setting array * * @param int $category If passed, returns the locale for the specified category (e.g. LC_ALL) as string + * @return array|string */ - public function locale(int $category = null): array|string|null + public function locale(int $category = null) { if ($category !== null) { return $this->locale[$category] ?? $this->locale[LC_ALL] ?? null; + } else { + return $this->locale; } - - return $this->locale; } /** * Returns the human-readable name * of the language + * + * @return string */ public function name(): string { @@ -364,6 +401,8 @@ class Language /** * Returns the URL path for the language + * + * @return string */ public function path(): string { @@ -376,6 +415,8 @@ class Language /** * Returns the routing pattern for the language + * + * @return string */ public function pattern(): string { @@ -390,6 +431,8 @@ class Language /** * Returns the absolute path to the language file + * + * @return string */ public function root(): string { @@ -400,15 +443,19 @@ class Language * Returns the LanguageRouter instance * which is used to handle language specific * routes. + * + * @return \Kirby\Cms\LanguageRouter */ - public function router(): LanguageRouter + public function router() { return new LanguageRouter($this); } /** * Get slug rules for language + * * @internal + * @return array */ public function rules(): array { @@ -419,15 +466,15 @@ class Language /** * Saves the language settings in the languages folder - * @internal * + * @internal * @return $this */ - public function save(): static + public function save() { try { $existingData = Data::read($this->root()); - } catch (Throwable) { + } catch (Throwable $e) { $existingData = []; } @@ -451,15 +498,104 @@ class Language } /** - * Private siblings collector + * @param string $code + * @return $this */ - protected function siblingsCollection(): Collection + protected function setCode(string $code) { - return App::instance()->languages(); + $this->code = trim($code); + return $this; + } + + /** + * @param bool $default + * @return $this + */ + protected function setDefault(bool $default = false) + { + $this->default = $default; + return $this; + } + + /** + * @param string $direction + * @return $this + */ + protected function setDirection(string $direction = 'ltr') + { + $this->direction = $direction === 'rtl' ? 'rtl' : 'ltr'; + return $this; + } + + /** + * @param string|array $locale + * @return $this + */ + protected function setLocale($locale = null) + { + if ($locale === null) { + $this->locale = [LC_ALL => $this->code]; + } else { + $this->locale = Locale::normalize($locale); + } + + return $this; + } + + /** + * @param string $name + * @return $this + */ + protected function setName(string $name = null) + { + $this->name = trim($name ?? $this->code); + return $this; + } + + /** + * @param array $slugs + * @return $this + */ + protected function setSlugs(array $slugs = null) + { + $this->slugs = $slugs ?? []; + return $this; + } + + /** + * @param array $smartypants + * @return $this + */ + protected function setSmartypants(array $smartypants = null) + { + $this->smartypants = $smartypants ?? []; + return $this; + } + + /** + * @param array $translations + * @return $this + */ + protected function setTranslations(array $translations = null) + { + $this->translations = $translations ?? []; + return $this; + } + + /** + * @param string $url + * @return $this + */ + protected function setUrl(string $url = null) + { + $this->url = $url; + return $this; } /** * Returns the custom slug rules for this language + * + * @return array */ public function slugs(): array { @@ -468,6 +604,8 @@ class Language /** * Returns the custom SmartyPants options for this language + * + * @return array */ public function smartypants(): array { @@ -477,6 +615,8 @@ class Language /** * Returns the most important * properties as array + * + * @return array */ public function toArray(): array { @@ -493,6 +633,8 @@ class Language /** * Returns the translation strings for this language + * + * @return array */ public function translations(): array { @@ -501,19 +643,28 @@ class Language /** * Returns the absolute Url for the language + * + * @return string */ public function url(): string { - $url = $this->url; - $url ??= '/' . $this->code; + $url = $this->url; + + if ($url === null) { + $url = '/' . $this->code; + } + return Url::makeAbsolute($url, $this->kirby()->url()); } /** * Update language properties and save them + * * @internal + * @param array $props + * @return static */ - public function update(array $props = null): static + public function update(array $props = null) { $kirby = App::instance(); $user = $kirby->user(); @@ -533,67 +684,38 @@ class Language $updated = $this->clone($props); - if (isset($props['translations']) === true) { - $updated->translations = $props['translations']; - } - // validate the updated language LanguageRules::update($updated); - // trigger before hook - $kirby->trigger('language.update:before', [ - 'language' => $this, - 'input' => $props - ]); - - // if language just got promoted to be the new default language… - if ($this->isDefault() === false && $updated->isDefault() === true) { - // convert the current default to a non-default language - $previous = $kirby->defaultLanguage()?->clone(['default' => false])->save(); - $kirby->languages(false)->set($previous->code(), $previous); - - foreach ($kirby->models() as $model) { - $model->storage()->touchLanguage($this); + // convert the current default to a non-default language + if ($updated->isDefault() === true) { + if ($oldDefault = $kirby->defaultLanguage()) { + $oldDefault->clone(['default' => false])->save(); } - } - // if language was the default language and got demoted… - if ( - $this->isDefault() === true && - $updated->isDefault() === false && - $kirby->defaultLanguage()->code() === $this->code() - ) { - // ensure another language has already been set as default - throw new LogicException('Please select another language to be the primary language'); + $code = $this->code(); + $site = $kirby->site(); + + touch($site->contentFile($code)); + + foreach ($kirby->site()->index(true) as $page) { + $files = $page->files(); + + foreach ($files as $file) { + touch($file->contentFile($code)); + } + + touch($page->contentFile($code)); + } + } elseif ($this->isDefault() === true) { + throw new PermissionException('Please select another language to be the primary language'); } $language = $updated->save(); - // make sure the language is also updated in the languages collection - $kirby->languages(false)->set($language->code(), $language); - - // trigger after hook - $kirby->trigger('language.update:after', [ - 'newLanguage' => $language, - 'oldLanguage' => $this, - 'input' => $props - ]); + // make sure the language is also updated in the Kirby language collection + App::instance()->languages(false)->set($language->code(), $language); return $language; } - - /** - * Returns a language variable object - * for the key in the translations array - */ - public function variable(string $key, bool $decode = false): LanguageVariable - { - // allows decoding if base64-url encoded url is sent - // for compatibility of different environments - if ($decode === true) { - $key = rawurldecode(base64_decode($key)); - } - - return new LanguageVariable($this, $key); - } } diff --git a/kirby/src/Cms/LanguageRouter.php b/kirby/src/Cms/LanguageRouter.php index bca5daf..8fafbd7 100644 --- a/kirby/src/Cms/LanguageRouter.php +++ b/kirby/src/Cms/LanguageRouter.php @@ -20,21 +20,36 @@ use Kirby\Toolkit\Str; */ class LanguageRouter { - protected Router $router; + /** + * The parent language + * + * @var Language + */ + protected $language; + + /** + * The router instance + * + * @var Router + */ + protected $router; /** * Creates a new language router instance * for the given language + * + * @param \Kirby\Cms\Language $language */ - public function __construct( - protected Language $language - ) { + public function __construct(Language $language) + { + $this->language = $language; } /** * Fetches all scoped routes for the * current language from the Kirby instance * + * @return array * @throws \Kirby\Exception\NotFoundException */ public function routes(): array @@ -91,34 +106,28 @@ class LanguageRouter * Wrapper around the Router::call method * that injects the Language instance and * if needed also the Page as arguments. + * + * @param string|null $path + * @return mixed */ - public function call(string|null $path = null): mixed + public function call(string $path = null) { - $language = $this->language; - $kirby = $language->kirby(); - $this->router ??= new Router($this->routes()); + $language = $this->language; + $kirby = $language->kirby(); + $router = new Router($this->routes()); try { - return $this->router->call($path, $kirby->request()->method(), function ($route) use ($kirby, $language) { + return $router->call($path, $kirby->request()->method(), function ($route) use ($kirby, $language) { $kirby->setCurrentTranslation($language); $kirby->setCurrentLanguage($language); if ($page = $route->page()) { - return $route->action()->call( - $route, - $language, - $page, - ...$route->arguments() - ); + return $route->action()->call($route, $language, $page, ...$route->arguments()); + } else { + return $route->action()->call($route, $language, ...$route->arguments()); } - - return $route->action()->call( - $route, - $language, - ...$route->arguments() - ); }); - } catch (Exception) { + } catch (Exception $e) { return $kirby->resolve($path, $language->code()); } } diff --git a/kirby/src/Cms/LanguageRoutes.php b/kirby/src/Cms/LanguageRoutes.php index 68bdf42..6d15957 100644 --- a/kirby/src/Cms/LanguageRoutes.php +++ b/kirby/src/Cms/LanguageRoutes.php @@ -8,6 +8,9 @@ class LanguageRoutes { /** * Creates all multi-language routes + * + * @param \Kirby\Cms\App $kirby + * @return array */ public static function create(App $kirby): array { @@ -30,11 +33,7 @@ class LanguageRoutes 'method' => 'ALL', 'env' => 'site', 'action' => function ($path = null) use ($language) { - $result = $language->router()->call($path); - - // explicitly test for null as $result can - // contain falsy values that should still be returned - if ($result !== null) { + if ($result = $language->router()->call($path)) { return $result; } @@ -55,6 +54,9 @@ class LanguageRoutes /** * Create the fallback route * for unprefixed default language URLs. + * + * @param \Kirby\Cms\App $kirby + * @return array */ public static function fallback(App $kirby): array { @@ -67,10 +69,7 @@ class LanguageRoutes $extension = F::extension($path); // try to redirect prefixed pages - if ( - empty($extension) === true && - $page = $kirby->page($path) - ) { + if (empty($extension) === true && $page = $kirby->page($path)) { $url = $kirby->request()->url([ 'query' => null, 'params' => null, @@ -78,17 +77,15 @@ class LanguageRoutes ]); if ($url->toString() !== $page->url()) { - // redirect to translated page directly if translation - // is exists and languages detect is enabled - $lang = $kirby->detectedLanguage()->code(); - + // redirect to translated page directly + // if translation is exists and languages detect is enabled if ( $kirby->option('languages.detect') === true && - $page->translation($lang)->exists() === true + $page->translation($kirby->detectedLanguage()->code())->exists() === true ) { return $kirby ->response() - ->redirect($page->url($lang)); + ->redirect($page->url($kirby->detectedLanguage()->code())); } return $kirby @@ -104,6 +101,9 @@ class LanguageRoutes /** * Create the multi-language home page route + * + * @param \Kirby\Cms\App $kirby + * @return array */ public static function home(App $kirby): array { @@ -114,10 +114,7 @@ class LanguageRoutes 'env' => 'site', 'action' => function () use ($kirby) { // find all languages with the same base url as the current installation - $languages = $kirby->languages()->filter( - 'baseurl', - $kirby->url() - ); + $languages = $kirby->languages()->filter('baseurl', $kirby->url()); // if there's no language with a matching base url, // redirect to the default language @@ -127,8 +124,7 @@ class LanguageRoutes ->redirect($kirby->defaultLanguage()->url()); } - // if there's just one language, - // we take that to render the home page + // if there's just one language, we take that to render the home page if ($languages->count() === 1) { $currentLanguage = $languages->first(); } else { diff --git a/kirby/src/Cms/LanguageRules.php b/kirby/src/Cms/LanguageRules.php index a59a678..31c751e 100644 --- a/kirby/src/Cms/LanguageRules.php +++ b/kirby/src/Cms/LanguageRules.php @@ -20,6 +20,8 @@ class LanguageRules /** * Validates if the language can be created * + * @param \Kirby\Cms\Language $language + * @return bool * @throws \Kirby\Exception\DuplicateException If the language already exists */ public static function create(Language $language): bool @@ -41,8 +43,10 @@ class LanguageRules /** * Validates if the language can be updated + * + * @param \Kirby\Cms\Language $language */ - public static function update(Language $language): void + public static function update(Language $language) { static::validLanguageCode($language); static::validLanguageName($language); @@ -51,6 +55,8 @@ class LanguageRules /** * Validates if the language code is formatted correctly * + * @param \Kirby\Cms\Language $language + * @return bool * @throws \Kirby\Exception\InvalidArgumentException If the language code is not valid */ public static function validLanguageCode(Language $language): bool @@ -71,6 +77,8 @@ class LanguageRules /** * Validates if the language name is formatted correctly * + * @param \Kirby\Cms\Language $language + * @return bool * @throws \Kirby\Exception\InvalidArgumentException If the language name is invalid */ public static function validLanguageName(Language $language): bool diff --git a/kirby/src/Cms/LanguageVariable.php b/kirby/src/Cms/LanguageVariable.php deleted file mode 100644 index b26336e..0000000 --- a/kirby/src/Cms/LanguageVariable.php +++ /dev/null @@ -1,122 +0,0 @@ - - * @link https://getkirby.com - * @copyright Bastian Allgeier - * @license https://getkirby.com/license - */ -class LanguageVariable -{ - protected App $kirby; - - public function __construct( - protected Language $language, - protected string $key - ) { - $this->kirby = App::instance(); - } - - /** - * Creates a new language variable. This will - * be added to the default language first and - * can then be translated in other languages. - */ - public static function create( - string $key, - string|null $value = null - ): static { - if (is_numeric($key) === true) { - throw new InvalidArgumentException('The variable key must not be numeric'); - } - - if (empty($key) === true) { - throw new InvalidArgumentException('The variable needs a valid key'); - } - - $kirby = App::instance(); - $language = $kirby->defaultLanguage(); - $translations = $language->translations(); - - if ($kirby->translation()->get($key) !== null) { - if (isset($translations[$key]) === true) { - throw new DuplicateException('The variable already exists'); - } - - throw new DuplicateException('The variable is part of the core translation and cannot be overwritten'); - } - - $translations[$key] = trim($value ?? ''); - - $language->update(['translations' => $translations]); - - return $language->variable($key); - } - - /** - * Deletes a language variable from the translations array. - * This will go through all language files and delete the - * key from all translation arrays to keep them clean. - */ - public function delete(): bool - { - // go through all languages and remove the variable - foreach ($this->kirby->languages() as $language) { - $variables = $language->translations(); - - unset($variables[$this->key]); - - $language->update(['translations' => $variables]); - } - - return true; - } - - /** - * Checks if a language variable exists in the default language - */ - public function exists(): bool - { - $language = $this->kirby->defaultLanguage(); - return isset($language->translations()[$this->key]) === true; - } - - /** - * Returns the unique key for the variable - */ - public function key(): string - { - return $this->key; - } - - /** - * Sets a new value for the language variable - */ - public function update(string $value): static - { - $translations = $this->language->translations(); - $translations[$this->key] = $value; - - $language = $this->language->update(['translations' => $translations]); - - return $language->variable($this->key); - } - - /** - * Returns the value if the variable has been translated. - */ - public function value(): string|null - { - return $this->language->translations()[$this->key] ?? null; - } -} diff --git a/kirby/src/Cms/Languages.php b/kirby/src/Cms/Languages.php index ba631b9..d746977 100644 --- a/kirby/src/Cms/Languages.php +++ b/kirby/src/Cms/Languages.php @@ -16,21 +16,15 @@ use Kirby\Filesystem\F; */ class Languages extends Collection { - /** - * All registered languages methods - */ - public static array $methods = []; - /** * Creates a new collection with the given language objects * + * @param array $objects `Kirby\Cms\Language` objects * @param null $parent * @throws \Kirby\Exception\DuplicateException */ - public function __construct( - array $objects = [], - $parent = null - ) { + public function __construct($objects = [], $parent = null) + { $defaults = array_filter( $objects, fn ($language) => $language->isDefault() === true @@ -40,45 +34,58 @@ class Languages extends Collection throw new DuplicateException('You cannot have multiple default languages. Please check your language config files.'); } - parent::__construct($objects, null); + parent::__construct($objects, $parent); } /** * Returns all language codes as array + * + * @return array */ public function codes(): array { - return App::instance()->multilang() ? $this->keys() : ['default']; + return $this->keys(); } /** * Creates a new language with the given props + * * @internal + * @param array $props + * @return \Kirby\Cms\Language */ - public function create(array $props): Language + public function create(array $props) { return Language::create($props); } /** * Returns the default language + * + * @return \Kirby\Cms\Language|null */ - public function default(): Language|null + public function default() { - return $this->findBy('isDefault', true) ?? $this->first(); + if ($language = $this->findBy('isDefault', true)) { + return $language; + } else { + return $this->first(); + } } /** * Convert all defined languages to a collection + * * @internal + * @return static */ - public static function load(): static + public static function load() { $languages = []; $files = glob(App::instance()->root('languages') . '/*.php'); foreach ($files as $file) { - $props = F::load($file, allowOutput: false); + $props = F::load($file); if (is_array($props) === true) { // inject the language code from the filename diff --git a/kirby/src/Cms/Layout.php b/kirby/src/Cms/Layout.php index c6920fd..9a27fbf 100644 --- a/kirby/src/Cms/Layout.php +++ b/kirby/src/Cms/Layout.php @@ -2,8 +2,6 @@ namespace Kirby\Cms; -use Kirby\Content\Content; - /** * Represents a single Layout with * multiple columns @@ -19,15 +17,26 @@ class Layout extends Item { use HasMethods; - public const ITEMS_CLASS = Layouts::class; + public const ITEMS_CLASS = '\Kirby\Cms\Layouts'; - protected Content $attrs; - protected LayoutColumns $columns; + /** + * @var \Kirby\Cms\Content + */ + protected $attrs; + + /** + * @var \Kirby\Cms\LayoutColumns + */ + protected $columns; /** * Proxy for attrs + * + * @param string $method + * @param array $args + * @return \Kirby\Cms\Field */ - public function __call(string $method, array $args = []): mixed + public function __call(string $method, array $args = []) { // layout methods if ($this->hasMethod($method) === true) { @@ -39,13 +48,14 @@ class Layout extends Item /** * Creates a new Layout object + * + * @param array $params */ public function __construct(array $params = []) { parent::__construct($params); $this->columns = LayoutColumns::factory($params['columns'] ?? [], [ - 'field' => $this->field, 'parent' => $this->parent ]); @@ -55,16 +65,20 @@ class Layout extends Item /** * Returns the attrs object + * + * @return \Kirby\Cms\Content */ - public function attrs(): Content + public function attrs() { return $this->attrs; } /** * Returns the columns in this layout + * + * @return \Kirby\Cms\LayoutColumns */ - public function columns(): LayoutColumns + public function columns() { return $this->columns; } @@ -72,18 +86,24 @@ class Layout extends Item /** * Checks if the layout is empty * @since 3.5.2 + * + * @return bool */ public function isEmpty(): bool { return $this ->columns() - ->filter('isEmpty', false) + ->filter(function ($column) { + return $column->isNotEmpty(); + }) ->count() === 0; } /** * Checks if the layout is not empty * @since 3.5.2 + * + * @return bool */ public function isNotEmpty(): bool { @@ -93,6 +113,8 @@ class Layout extends Item /** * The result is being sent to the editor * via the API in the panel + * + * @return array */ public function toArray(): array { diff --git a/kirby/src/Cms/LayoutColumn.php b/kirby/src/Cms/LayoutColumn.php index 11d61d7..2f652d1 100644 --- a/kirby/src/Cms/LayoutColumn.php +++ b/kirby/src/Cms/LayoutColumn.php @@ -19,20 +19,28 @@ class LayoutColumn extends Item { use HasMethods; - public const ITEMS_CLASS = LayoutColumns::class; + public const ITEMS_CLASS = '\Kirby\Cms\LayoutColumns'; - protected Blocks $blocks; - protected string $width; + /** + * @var \Kirby\Cms\Blocks + */ + protected $blocks; + + /** + * @var string + */ + protected $width; /** * Creates a new LayoutColumn object + * + * @param array $params */ public function __construct(array $params = []) { parent::__construct($params); $this->blocks = Blocks::factory($params['blocks'] ?? [], [ - 'field' => $this->field, 'parent' => $this->parent ]); @@ -41,8 +49,12 @@ class LayoutColumn extends Item /** * Magic getter function + * + * @param string $method + * @param mixed $args + * @return mixed */ - public function __call(string $method, mixed $args): mixed + public function __call(string $method, $args) { // layout column methods if ($this->hasMethod($method) === true) { @@ -54,8 +66,9 @@ class LayoutColumn extends Item * Returns the blocks collection * * @param bool $includeHidden Sets whether to include hidden blocks + * @return \Kirby\Cms\Blocks */ - public function blocks(bool $includeHidden = false): Blocks + public function blocks(bool $includeHidden = false) { if ($includeHidden === false) { return $this->blocks->filter('isHidden', false); @@ -67,6 +80,8 @@ class LayoutColumn extends Item /** * Checks if the column is empty * @since 3.5.2 + * + * @return bool */ public function isEmpty(): bool { @@ -79,6 +94,8 @@ class LayoutColumn extends Item /** * Checks if the column is not empty * @since 3.5.2 + * + * @return bool */ public function isNotEmpty(): bool { @@ -87,6 +104,9 @@ class LayoutColumn extends Item /** * Returns the number of columns this column spans + * + * @param int $columns + * @return int */ public function span(int $columns = 12): int { @@ -100,6 +120,8 @@ class LayoutColumn extends Item /** * The result is being sent to the editor * via the API in the panel + * + * @return array */ public function toArray(): array { @@ -112,6 +134,8 @@ class LayoutColumn extends Item /** * Returns the width of the column + * + * @return string */ public function width(): string { diff --git a/kirby/src/Cms/LayoutColumns.php b/kirby/src/Cms/LayoutColumns.php index 195e39e..449678b 100644 --- a/kirby/src/Cms/LayoutColumns.php +++ b/kirby/src/Cms/LayoutColumns.php @@ -14,10 +14,5 @@ namespace Kirby\Cms; */ class LayoutColumns extends Items { - public const ITEM_CLASS = LayoutColumn::class; - - /** - * All registered layout columns methods - */ - public static array $methods = []; + public const ITEM_CLASS = '\Kirby\Cms\LayoutColumn'; } diff --git a/kirby/src/Cms/Layouts.php b/kirby/src/Cms/Layouts.php index 1888680..b9f4c90 100644 --- a/kirby/src/Cms/Layouts.php +++ b/kirby/src/Cms/Layouts.php @@ -2,7 +2,7 @@ namespace Kirby\Cms; -use Kirby\Data\Json; +use Kirby\Data\Data; use Kirby\Toolkit\Str; use Throwable; @@ -18,32 +18,14 @@ use Throwable; */ class Layouts extends Items { - public const ITEM_CLASS = Layout::class; - - /** - * All registered layouts methods - */ - public static array $methods = []; - - public static function factory( - array $items = null, - array $params = [] - ): static { - // convert single layout to layouts array - if ( - isset($items['columns']) === true || - isset($items['id']) === true - ) { - $items = [$items]; - } + public const ITEM_CLASS = '\Kirby\Cms\Layout'; + public static function factory(array $items = null, array $params = []) + { $first = $items[0] ?? []; // if there are no wrapping layouts for blocks yet … - if ( - isset($first['content']) === true || - isset($first['type']) === true - ) { + if (array_key_exists('content', $first) === true || array_key_exists('type', $first) === true) { $items = [ [ 'id' => Str::uuid(), @@ -63,6 +45,9 @@ class Layouts extends Items /** * Checks if a given block type exists in the layouts collection * @since 3.6.0 + * + * @param string $type + * @return bool */ public function hasBlockType(string $type): bool { @@ -71,16 +56,16 @@ class Layouts extends Items /** * Parse layouts data + * + * @param array|string $input + * @return array */ - public static function parse(array|string|null $input): array + public static function parse($input): array { - if ( - empty($input) === false && - is_array($input) === false - ) { + if (empty($input) === false && is_array($input) === false) { try { - $input = Json::decode((string)$input); - } catch (Throwable) { + $input = Data::decode($input, 'json'); + } catch (Throwable $e) { return []; } } @@ -97,8 +82,9 @@ class Layouts extends Items * @since 3.6.0 * * @param bool $includeHidden Sets whether to include hidden blocks + * @return \Kirby\Cms\Blocks */ - public function toBlocks(bool $includeHidden = false): Blocks + public function toBlocks(bool $includeHidden = false) { $blocks = []; @@ -112,9 +98,6 @@ class Layouts extends Items } } - return Blocks::factory($blocks, [ - 'field' => $this->field, - 'parent' => $this->parent - ]); + return Blocks::factory($blocks); } } diff --git a/kirby/src/Cms/License.php b/kirby/src/Cms/License.php deleted file mode 100644 index 3ec3869..0000000 --- a/kirby/src/Cms/License.php +++ /dev/null @@ -1,529 +0,0 @@ - - * @link https://getkirby.com - * @copyright Bastian Allgeier - * @license https://getkirby.com/license - */ -class License -{ - protected const HISTORY = [ - '3' => '2019-02-05', - '4' => '2023-11-28' - ]; - - protected const SALT = 'kwAHMLyLPBnHEskzH9pPbJsBxQhKXZnX'; - - // cache - protected LicenseStatus $status; - protected LicenseType $type; - - public function __construct( - protected string|null $activation = null, - protected string|null $code = null, - protected string|null $domain = null, - protected string|null $email = null, - protected string|null $order = null, - protected string|null $date = null, - protected string|null $signature = null, - ) { - // normalize the email address - $this->email = $this->email === null ? null : $this->normalizeEmail($this->email); - } - - /** - * Returns the activation date if available - */ - public function activation( - string|IntlDateFormatter|null $format = null, - string|null $handler = null - ): int|string|null { - return $this->activation !== null ? Str::date(strtotime($this->activation), $format, $handler) : null; - } - - /** - * Returns the license code if available - */ - public function code(bool $obfuscated = false): string|null - { - if ($this->code !== null && $obfuscated === true) { - return Str::substr($this->code, 0, 10) . str_repeat('X', 22); - } - - return $this->code; - } - - /** - * Content for the license file - */ - public function content(): array - { - return [ - 'activation' => $this->activation, - 'code' => $this->code, - 'date' => $this->date, - 'domain' => $this->domain, - 'email' => $this->email, - 'order' => $this->order, - 'signature' => $this->signature, - ]; - } - - /** - * Returns the purchase date if available - */ - public function date( - string|IntlDateFormatter|null $format = null, - string|null $handler = null - ): int|string|null { - return $this->date !== null ? Str::date(strtotime($this->date), $format, $handler) : null; - } - - /** - * Returns the activation domain if available - */ - public function domain(): string|null - { - return $this->domain; - } - - /** - * Returns the activation email if available - */ - public function email(): string|null - { - return $this->email; - } - - /** - * Validates the email address of the license - */ - public function hasValidEmailAddress(): bool - { - return V::email($this->email) === true; - } - - /** - * Hub address - */ - public static function hub(): string - { - return App::instance()->option('hub', 'https://hub.getkirby.com'); - } - - /** - * Checks for all required components of a valid license - */ - public function isComplete(): bool - { - if ( - $this->code !== null && - $this->date !== null && - $this->domain !== null && - $this->email !== null && - $this->order !== null && - $this->signature !== null && - $this->hasValidEmailAddress() === true && - $this->type() !== LicenseType::Invalid - ) { - return true; - } - - return false; - } - - /** - * The license is still valid for the currently - * installed version, but it passed the 3 year period. - */ - public function isInactive(): bool - { - return $this->renewal() < time(); - } - - /** - * Checks for licenses beyond their 3 year period - */ - public function isLegacy(): bool - { - if ($this->type() === LicenseType::Legacy) { - return true; - } - - // without an activation date, the license - // renewal cannot be evaluated and the license - // has to be marked as expired - if ($this->activation === null) { - return true; - } - - // get release date of current major version - $major = Str::before(App::instance()->version(), '.'); - $release = strtotime(static::HISTORY[$major] ?? ''); - - // if there's no matching version in the history - // rather throw an exception to avoid further issues - // @codeCoverageIgnoreStart - if ($release === false) { - throw new InvalidArgumentException('The version for your license could not be found'); - } - // @codeCoverageIgnoreEnd - - // If the renewal date is older than the version launch - // date, the license is expired - return $this->renewal() < $release; - } - - /** - * Runs multiple checks to find out if the license is - * installed and verifiable - */ - public function isMissing(): bool - { - return - $this->isComplete() === false || - $this->isOnCorrectDomain() === false || - $this->isSigned() === false; - } - - /** - * Checks if the license is on the correct domain - */ - public function isOnCorrectDomain(): bool - { - if ($this->domain === null) { - return false; - } - - // compare domains - if ($this->normalizeDomain(App::instance()->system()->indexUrl()) !== $this->normalizeDomain($this->domain)) { - return false; - } - - return true; - } - - /** - * Compares the signature with all ingredients - */ - public function isSigned(): bool - { - if ($this->signature === null) { - return false; - } - - // get the public key - $pubKey = F::read(App::instance()->root('kirby') . '/kirby.pub'); - - // verify the license signature - $data = json_encode($this->signatureData()); - $signature = hex2bin($this->signature); - - return openssl_verify($data, $signature, $pubKey, 'RSA-SHA256') === 1; - } - - /** - * Returns a reliable label for the license type - */ - public function label(): string - { - if ($this->status() === LicenseStatus::Missing) { - return LicenseType::Invalid->label(); - } - - return $this->type()->label(); - } - - /** - * Prepares the email address to be make sure it - * does not have trailing spaces and is lowercase. - */ - protected function normalizeEmail(string $email): string - { - return Str::lower(trim($email)); - } - - /** - * Prepares the domain to be comparable - */ - protected function normalizeDomain(string $domain): string - { - // remove common "testing" subdomains as well as www. - // to ensure that installations of the same site have - // the same license URL; only for installations at /, - // subdirectory installations are difficult to normalize - if (Str::contains($domain, '/') === false) { - if (Str::startsWith($domain, 'www.')) { - return substr($domain, 4); - } - - if (Str::startsWith($domain, 'dev.')) { - return substr($domain, 4); - } - - if (Str::startsWith($domain, 'test.')) { - return substr($domain, 5); - } - - if (Str::startsWith($domain, 'staging.')) { - return substr($domain, 8); - } - } - - return $domain; - } - - /** - * Returns the order id if available - */ - public function order(): string|null - { - return $this->order; - } - - /** - * Support the old license file dataset - * from older licenses - */ - public static function polyfill(array $license): array - { - return [ - 'activation' => $license['activation'] ?? null, - 'code' => $license['code'] ?? $license['license'] ?? null, - 'date' => $license['date'] ?? null, - 'domain' => $license['domain'] ?? null, - 'email' => $license['email'] ?? null, - 'order' => $license['order'] ?? null, - 'signature' => $license['signature'] ?? null, - ]; - } - - /** - * Reads the license file in the config folder - * and creates a new license instance for it. - */ - public static function read(): static - { - try { - $license = Json::read(App::instance()->root('license')); - } catch (Throwable) { - return new static(); - } - - return new static(...static::polyfill($license)); - } - - /** - * Sends a request to the hub to register the license - */ - public function register(): static - { - if ($this->type() === LicenseType::Invalid) { - throw new InvalidArgumentException(['key' => 'license.format']); - } - - if ($this->hasValidEmailAddress() === false) { - throw new InvalidArgumentException(['key' => 'license.email']); - } - - if ($this->domain === null) { - throw new InvalidArgumentException(['key' => 'license.domain']); - } - - // @codeCoverageIgnoreStart - $response = $this->request('register', [ - 'license' => $this->code, - 'email' => $this->email, - 'domain' => $this->domain - ]); - - return $this->update($response); - // @codeCoverageIgnoreEnd - } - - /** - * Returns the renewal date - */ - public function renewal( - string|IntlDateFormatter|null $format = null, - string|null $handler = null - ): int|string|null { - if ($this->activation === null) { - return null; - } - - $time = strtotime('+3 years', $this->activation()); - return Str::date($time, $format, $handler); - } - - /** - * Sends a hub request - */ - public function request(string $path, array $data): array - { - // @codeCoverageIgnoreStart - $response = Remote::get(static::hub() . '/' . $path, [ - 'data' => $data - ]); - - // handle request errors - if ($response->code() !== 200) { - $message = $response->json()['message'] ?? 'The request failed'; - - throw new LogicException($message, $response->code()); - } - - return $response->json(); - // @codeCoverageIgnoreEnd - } - - /** - * Saves the license in the config folder - */ - public function save(): bool - { - if ($this->status()->activatable() !== true) { - throw new InvalidArgumentException([ - 'key' => 'license.verification' - ]); - } - - // where to store the license file - $file = App::instance()->root('license'); - - // save the license information - return Json::write($file, $this->content()); - } - - /** - * Returns the signature if available - */ - public function signature(): string|null - { - return $this->signature; - } - - /** - * Creates the signature data array to compare - * with the signature in ::isSigned - */ - public function signatureData(): array - { - if ($this->type() === LicenseType::Legacy) { - return [ - 'license' => $this->code, - 'order' => $this->order, - 'email' => hash('sha256', $this->email . static::SALT), - 'domain' => $this->domain, - 'date' => $this->date, - ]; - } - - return [ - 'activation' => $this->activation, - 'code' => $this->code, - 'date' => $this->date, - 'domain' => $this->domain, - 'email' => hash('sha256', $this->email . static::SALT), - 'order' => $this->order, - ]; - } - - /** - * Returns the license status as string - * This is used to build the proper UI elements - * for the license activation - */ - public function status(): LicenseStatus - { - return $this->status ??= match (true) { - $this->isMissing() === true => LicenseStatus::Missing, - $this->isLegacy() === true => LicenseStatus::Legacy, - $this->isInactive() === true => LicenseStatus::Inactive, - default => LicenseStatus::Active - }; - } - - /** - * Detects the license type if the license key is available - */ - public function type(): LicenseType - { - return $this->type ??= LicenseType::detect($this->code); - } - - /** - * Updates the license file - */ - public function update(array $data): static - { - // decode the response - $data = static::polyfill($data); - - $this->activation = $data['activation']; - $this->code = $data['code']; - $this->date = $data['date']; - $this->order = $data['order']; - $this->signature = $data['signature']; - - // clear the caches - unset($this->status, $this->type); - - // save the new state of the license - $this->save(); - - return $this; - } - - /** - * Sends an upgrade request to the hub in order - * to either redirect to the upgrade form or - * sync the new license state - * - * @codeCoverageIgnore - */ - public function upgrade(): array - { - $response = $this->request('upgrade', [ - 'domain' => $this->domain, - 'email' => $this->email, - 'license' => $this->code, - ]); - - // the license still needs an upgrade - if (empty($response['url']) === false) { - // validate the redirect URL - if (Str::startsWith($response['url'], static::hub()) === false) { - throw new Exception('We couldn’t redirect you to the Hub'); - } - - return [ - 'status' => 'upgrade', - 'url' => $response['url'] - ]; - } - - // the license has already been upgraded - // and can now be replaced - $this->update($response); - - return [ - 'status' => 'complete', - ]; - } -} diff --git a/kirby/src/Cms/LicenseStatus.php b/kirby/src/Cms/LicenseStatus.php deleted file mode 100644 index 42cdc56..0000000 --- a/kirby/src/Cms/LicenseStatus.php +++ /dev/null @@ -1,144 +0,0 @@ - - * @link https://getkirby.com - * @copyright Bastian Allgeier - * @license https://getkirby.com/license - * - * @codeCoverageIgnore - */ -enum LicenseStatus: string -{ - /** - * The license is valid and active - */ - case Active = 'active'; - - /** - * Only used for the demo instance - */ - case Demo = 'demo'; - - /** - * The included updates period of - * the license is over. - */ - case Inactive = 'inactive'; - - /** - * The installation has an old - * license (v1, v2, v3) - */ - case Legacy = 'legacy'; - - /** - * The installation has no license or - * the license cannot be validated - */ - case Missing = 'missing'; - - /** - * Checks if the license can be saved when it - * was entered in the activation dialog; - * renewable licenses are accepted as well - * to allow renewal from the Panel - */ - public function activatable(): bool - { - return match ($this) { - static::Active, - static::Inactive, - static::Legacy => true, - default => false - }; - } - - /** - * Returns the dialog according to the status - */ - public function dialog(): string|null - { - return match ($this) { - static::Missing => 'registration', - static::Demo => null, - default => 'license' - }; - } - - /** - * Returns the icon according to the status. - * The icon is used for the system view and - * in the license dialog. - */ - public function icon(): string - { - return match ($this) { - static::Missing => 'key', - static::Legacy => 'alert', - static::Inactive => 'clock', - static::Active => 'check', - static::Demo => 'preview', - }; - } - - /** - * The info text is shown in the license dialog - * in the status row. - */ - public function info(string|null $end = null): string - { - return I18n::template('license.status.' . $this->value . '.info', ['date' => $end]); - } - - /** - * Label for the system view - */ - public function label(): string - { - return I18n::translate('license.status.' . $this->value . '.label'); - } - - /** - * Checks if the license can be renewed - * The license dialog will show the renew - * button in this case and redirect to the hub - */ - public function renewable(): bool - { - return match ($this) { - static::Demo, - static::Active => false, - default => true - }; - } - - /** - * Returns the theme according to the status - * The theme is used for the label in the system - * view and the status icon in the license dialog. - */ - public function theme(): string - { - return match ($this) { - static::Missing => 'love', - static::Legacy => 'negative', - static::Inactive => 'notice', - static::Active => 'positive', - static::Demo => 'notice', - }; - } - - /** - * Returns the status as string value - */ - public function value(): string - { - return $this->value; - } -} diff --git a/kirby/src/Cms/LicenseType.php b/kirby/src/Cms/LicenseType.php deleted file mode 100644 index 6a9fea7..0000000 --- a/kirby/src/Cms/LicenseType.php +++ /dev/null @@ -1,111 +0,0 @@ - - * @link https://getkirby.com - * @copyright Bastian Allgeier - * @license https://getkirby.com/license - * - * @codeCoverageIgnore - */ -enum LicenseType: string -{ - /** - * New basic licenses - */ - case Basic = 'basic'; - - /** - * New enterprise licenses - */ - case Enterprise = 'enterprise'; - - /** - * Invalid license codes - */ - case Invalid = 'invalid'; - - /** - * Old Kirby 3 licenses - */ - case Legacy = 'legacy'; - - /** - * Detects the correct LicenseType based on the code - */ - public static function detect(string|null $code): static - { - return match (true) { - static::Basic->isValidCode($code) => static::Basic, - static::Enterprise->isValidCode($code) => static::Enterprise, - static::Legacy->isValidCode($code) => static::Legacy, - default => static::Invalid - }; - } - - /** - * Checks for a valid license code - * by prefix and length. This is just a - * rough validation. - */ - public function isValidCode(string|null $code): bool - { - return - $code !== null && - Str::length($code) === $this->length() && - Str::startsWith($code, $this->prefix()) === true; - } - - /** - * The expected lengths of the license code - */ - public function length(): int - { - return match ($this) { - static::Basic => 38, - static::Enterprise => 38, - static::Legacy => 39, - static::Invalid => 0, - }; - } - - /** - * A human-readable license type label - */ - public function label(): string - { - return match ($this) { - static::Basic => 'Kirby Basic', - static::Enterprise => 'Kirby Enterprise', - static::Legacy => 'Kirby 3', - static::Invalid => I18n::translate('license.unregistered.label'), - }; - } - - /** - * The expected prefix for the license code - */ - public function prefix(): string|null - { - return match ($this) { - static::Basic => 'K-BAS-', - static::Enterprise => 'K-ENT-', - static::Legacy => 'K3-PRO-', - static::Invalid => null, - }; - } - - /** - * Returns the enum value - */ - public function value(): string - { - return $this->value; - } -} diff --git a/kirby/src/Cms/Loader.php b/kirby/src/Cms/Loader.php index 6e71878..0f0cbc4 100644 --- a/kirby/src/Cms/Loader.php +++ b/kirby/src/Cms/Loader.php @@ -50,8 +50,11 @@ class Loader /** * Loads the area definition + * + * @param string $name + * @return array|null */ - public function area(string $name): array|null + public function area(string $name): ?array { return $this->areas()[$name] ?? null; } @@ -59,14 +62,15 @@ class Loader /** * Loads all areas and makes sure that plugins * are injected properly + * + * @return array */ public function areas(): array { $areas = []; $extensions = $this->withPlugins === true ? $this->kirby->extensions('areas') : []; - // load core areas and extend them with elements - // from plugins if they exist + // load core areas and extend them with elements from plugins if they exist foreach ($this->kirby->core()->areas() as $id => $area) { $area = $this->resolveArea($area); @@ -94,14 +98,19 @@ class Loader /** * Loads a core component closure + * + * @param string $name + * @return \Closure|null */ - public function component(string $name): Closure|null + public function component(string $name): ?Closure { return $this->extension('components', $name); } /** * Loads all core component closures + * + * @return array */ public function components(): array { @@ -110,14 +119,21 @@ class Loader /** * Loads a particular extension + * + * @param string $type + * @param string $name + * @return mixed */ - public function extension(string $type, string $name): mixed + public function extension(string $type, string $name) { return $this->extensions($type)[$name] ?? null; } /** * Loads all defined extensions + * + * @param string $type + * @return array */ public function extensions(string $type): array { @@ -136,17 +152,21 @@ class Loader * * 3.) closures will be called and the Kirby instance will be * passed as first argument + * + * @param mixed $item + * @return mixed */ - public function resolve(mixed $item): mixed + public function resolve($item) { if (is_string($item) === true) { - $item = match (F::extension($item)) { - 'php' => F::load($item, allowOutput: false), - default => Data::read($item) - }; + if (F::extension($item) !== 'php') { + $item = Data::read($item); + } else { + $item = require $item; + } } - if (is_callable($item) === true) { + if (is_callable($item)) { $item = $item($this->kirby); } @@ -156,6 +176,9 @@ class Loader /** * Calls `static::resolve()` on all items * in the given array + * + * @param array $items + * @return array */ public function resolveAll(array $items): array { @@ -171,8 +194,11 @@ class Loader /** * Areas need a bit of special treatment * when they are being loaded + * + * @param string|array|Closure $area + * @return array */ - public function resolveArea(string|array|Closure $area): array + public function resolveArea($area): array { $area = $this->resolve($area); $dropdowns = $area['dropdowns'] ?? []; @@ -180,7 +206,7 @@ class Loader // convert closure dropdowns to an array definition // otherwise they cannot be merged properly later foreach ($dropdowns as $key => $dropdown) { - if ($dropdown instanceof Closure) { + if (is_a($dropdown, 'Closure') === true) { $area['dropdowns'][$key] = [ 'options' => $dropdown ]; @@ -192,14 +218,19 @@ class Loader /** * Loads a particular section definition + * + * @param string $name + * @return array|null */ - public function section(string $name): array|null + public function section(string $name): ?array { return $this->resolve($this->extension('sections', $name)); } /** * Loads all section defintions + * + * @return array */ public function sections(): array { @@ -209,6 +240,8 @@ class Loader /** * Returns the status flag, which shows * if plugins are loaded as well. + * + * @return bool */ public function withPlugins(): bool { diff --git a/kirby/src/Cms/Media.php b/kirby/src/Cms/Media.php index 45c8017..32da5af 100644 --- a/kirby/src/Cms/Media.php +++ b/kirby/src/Cms/Media.php @@ -3,8 +3,6 @@ namespace Kirby\Cms; use Kirby\Data\Data; -use Kirby\Exception\InvalidArgumentException; -use Kirby\Exception\NotFoundException; use Kirby\Filesystem\Dir; use Kirby\Filesystem\F; use Kirby\Toolkit\Str; @@ -25,12 +23,14 @@ class Media /** * Tries to find a file by model and filename * and to copy it to the media folder. + * + * @param \Kirby\Cms\Model|null $model + * @param string $hash + * @param string $filename + * @return \Kirby\Cms\Response|false */ - public static function link( - Page|Site|User $model = null, - string $hash, - string $filename - ): Response|false { + public static function link(Model $model = null, string $hash, string $filename) + { if ($model === null) { return false; } @@ -46,10 +46,10 @@ class Media // if at least the token was correct, redirect if (Str::startsWith($hash, $file->mediaToken() . '-') === true) { return Response::redirect($file->mediaUrl(), 307); + } else { + // don't leak the correct token, render the error page + return false; } - - // don't leak the correct token, render the error page - return false; } // send the file to the browser @@ -57,16 +57,15 @@ class Media } // try to generate a thumb for the file - try { - return static::thumb($model, $hash, $filename); - } catch (NotFoundException) { - // render the error page if there is no job for this filename - return false; - } + return static::thumb($model, $hash, $filename); } /** * Copy the file to the final media folder location + * + * @param \Kirby\Cms\File $file + * @param string $dest + * @return bool */ public static function publish(File $file, string $dest): bool { @@ -88,74 +87,66 @@ class Media * Tries to find a job file for the * given filename and then calls the thumb * component to create a thumbnail accordingly + * + * @param \Kirby\Cms\Model|string $model + * @param string $hash + * @param string $filename + * @return \Kirby\Cms\Response|false */ - public static function thumb( - File|Page|Site|User|string $model, - string $hash, - string $filename - ): Response|false { + public static function thumb($model, string $hash, string $filename) + { $kirby = App::instance(); - $root = match (true) { - // assets - is_string($model) - => $kirby->root('media') . '/assets/' . $model . '/' . $hash, - // parent files for file model that already included hash - $model instanceof File - => dirname($model->mediaRoot()), - // model files - default - => $model->mediaRoot() . '/' . $hash - }; - - $thumb = $root . '/' . $filename; - $job = $root . '/.jobs/' . $filename . '.json'; + // assets + if (is_string($model) === true) { + $root = $kirby->root('media') . '/assets/' . $model . '/' . $hash; + // parent files for file model that already included hash + } elseif (is_a($model, '\Kirby\Cms\File')) { + $root = dirname($model->mediaRoot()); + // model files + } else { + $root = $model->mediaRoot() . '/' . $hash; + } try { + $thumb = $root . '/' . $filename; + $job = $root . '/.jobs/' . $filename . '.json'; $options = Data::read($job); - } catch (Throwable) { - // send a customized error message to make clearer what happened here - throw new NotFoundException('The thumbnail configuration could not be found'); - } - if (empty($options['filename']) === true) { - throw new InvalidArgumentException('Incomplete thumbnail configuration'); - } + if (empty($options) === true) { + return false; + } - try { - // find the correct source file depending on the model - // this adds support for custom assets - $source = match (true) { - is_string($model) === true - => $kirby->root('index') . '/' . $model . '/' . $options['filename'], - default - => $model->file($options['filename'])->root() - }; + if (is_string($model) === true) { + $source = $kirby->root('index') . '/' . $model . '/' . $options['filename']; + } else { + $source = $model->file($options['filename'])->root(); + } - // generate the thumbnail and save it in the media folder - $kirby->thumb($source, $thumb, $options); - - // remove the job file once the thumbnail has been created - F::remove($job); - - // read the file and send it to the browser - return Response::file($thumb); + try { + $kirby->thumb($source, $thumb, $options); + F::remove($job); + return Response::file($thumb); + } catch (Throwable $e) { + F::remove($thumb); + return Response::file($source); + } } catch (Throwable $e) { - // remove potentially broken thumbnails - F::remove($thumb); - throw $e; + return false; } } /** * Deletes all versions of the given file * within the parent directory + * + * @param string $directory + * @param \Kirby\Cms\File $file + * @param string|null $ignore + * @return bool */ - public static function unpublish( - string $directory, - File $file, - string|null $ignore = null - ): bool { + public static function unpublish(string $directory, File $file, string $ignore = null): bool + { if (is_dir($directory) === false) { return true; } diff --git a/kirby/src/Cms/Model.php b/kirby/src/Cms/Model.php index b7010d3..94c0317 100644 --- a/kirby/src/Cms/Model.php +++ b/kirby/src/Cms/Model.php @@ -5,7 +5,7 @@ namespace Kirby\Cms; use Kirby\Toolkit\Properties; /** - * @deprecated 4.0.0 will be removed in Kirby 5.0 + * Foundation for Page, Site, File and User models. * * @package Kirby Cms * @author Bastian Allgeier @@ -53,7 +53,7 @@ abstract class Model /** * Each model must return a unique id * - * @return string|null + * @return string|int */ public function id() { diff --git a/kirby/src/Cms/ModelPermissions.php b/kirby/src/Cms/ModelPermissions.php index 0b8cb56..5212c4f 100644 --- a/kirby/src/Cms/ModelPermissions.php +++ b/kirby/src/Cms/ModelPermissions.php @@ -15,13 +15,28 @@ use Kirby\Toolkit\A; */ abstract class ModelPermissions { - protected string $category; - protected ModelWithContent $model; - protected array $options; - protected Permissions $permissions; - protected User $user; + protected $category; + protected $model; + protected $options; + protected $permissions; + protected $user; - public function __construct(ModelWithContent $model) + /** + * @param string $method + * @param array $arguments + * @return bool + */ + public function __call(string $method, array $arguments = []): bool + { + return $this->can($method); + } + + /** + * ModelPermissions constructor + * + * @param \Kirby\Cms\Model $model + */ + public function __construct(Model $model) { $this->model = $model; $this->options = $model->blueprint()->options(); @@ -29,46 +44,33 @@ abstract class ModelPermissions $this->permissions = $this->user->role()->permissions(); } - public function __call(string $method, array $arguments = []): bool - { - return $this->can($method); - } - /** * Improved `var_dump` output - * @codeCoverageIgnore + * + * @return array */ public function __debugInfo(): array { return $this->toArray(); } + /** + * @param string $action + * @return bool + */ public function can(string $action): bool { - $user = $this->user->id(); $role = $this->user->role()->id(); - // users with the `nobody` role can do nothing - // that needs a permission check if ($role === 'nobody') { return false; } - // check for a custom `can` method - // which would take priority over any other - // role-based permission rules - if ( - method_exists($this, 'can' . $action) === true && - $this->{'can' . $action}() === false - ) { + // check for a custom overall can method + if (method_exists($this, 'can' . $action) === true && $this->{'can' . $action}() === false) { return false; } - // the almighty `kirby` user can do anything - if ($user === 'kirby' && $role === 'admin') { - return true; - } - // evaluate the blueprint options block if (isset($this->options[$action]) === true) { $options = $this->options[$action]; @@ -81,28 +83,26 @@ abstract class ModelPermissions return true; } - if ( - is_array($options) === true && - A::isAssociative($options) === true - ) { - if (isset($options[$role]) === true) { - return $options[$role]; - } - - if (isset($options['*']) === true) { - return $options['*']; - } + if (is_array($options) === true && A::isAssociative($options) === true) { + return $options[$role] ?? $options['*'] ?? false; } } return $this->permissions->for($this->category, $action); } + /** + * @param string $action + * @return bool + */ public function cannot(string $action): bool { return $this->can($action) === false; } + /** + * @return array + */ public function toArray(): array { $array = []; diff --git a/kirby/src/Cms/ModelWithContent.php b/kirby/src/Cms/ModelWithContent.php index 1a7baf5..2596ea1 100644 --- a/kirby/src/Cms/ModelWithContent.php +++ b/kirby/src/Cms/ModelWithContent.php @@ -3,18 +3,10 @@ namespace Kirby\Cms; use Closure; -use Kirby\Content\Content; -use Kirby\Content\ContentStorage; -use Kirby\Content\ContentTranslation; -use Kirby\Content\PlainTextContentStorageHandler; +use Kirby\Data\Data; use Kirby\Exception\InvalidArgumentException; -use Kirby\Exception\NotFoundException; use Kirby\Form\Form; -use Kirby\Panel\Model; use Kirby\Toolkit\Str; -use Kirby\Uuid\Identifiable; -use Kirby\Uuid\Uuid; -use Kirby\Uuid\Uuids; use Throwable; /** @@ -26,194 +18,171 @@ use Throwable; * @copyright Bastian Allgeier * @license https://getkirby.com/license */ -abstract class ModelWithContent implements Identifiable +abstract class ModelWithContent extends Model { /** - * Each model must define a CLASS_ALIAS - * which will be used in template queries. - * The CLASS_ALIAS is a short human-readable - * version of the class name, i.e. page. + * The content + * + * @var \Kirby\Cms\Content */ - public const CLASS_ALIAS = null; + public $content; /** - * Cached array of valid blueprints - * that could be used for the model + * @var \Kirby\Cms\Translations */ - public array|null $blueprints = null; - - public Content|null $content; - public static App $kirby; - protected Site|null $site; - protected ContentStorage $storage; - public Collection|null $translations = null; - - /** - * Store values used to initilaize object - */ - protected array $propertyData = []; - - public function __construct(array $props = []) - { - $this->site = $props['site'] ?? null; - - $this->setContent($props['content'] ?? null); - $this->setTranslations($props['translations'] ?? null); - - $this->propertyData = $props; - } + public $translations; /** * Returns the blueprint of the model + * + * @return \Kirby\Cms\Blueprint */ - abstract public function blueprint(): Blueprint; + abstract public function blueprint(); /** * Returns an array with all blueprints that are available + * + * @param string|null $inSection + * @return array */ public function blueprints(string $inSection = null): array { - // helper function - $toBlueprints = function (array $sections): array { - $blueprints = []; + $blueprints = []; + $blueprint = $this->blueprint(); + $sections = $inSection !== null ? [$blueprint->section($inSection)] : $blueprint->sections(); - foreach ($sections as $section) { - if ($section === null) { - continue; - } - - foreach ((array)$section->blueprints() as $blueprint) { - $blueprints[$blueprint['name']] = $blueprint; - } + foreach ($sections as $section) { + if ($section === null) { + continue; } - return array_values($blueprints); - }; - - $blueprint = $this->blueprint(); - - // no caching for when collecting for specific section - if ($inSection !== null) { - return $toBlueprints([$blueprint->section($inSection)]); + foreach ((array)$section->blueprints() as $blueprint) { + $blueprints[$blueprint['name']] = $blueprint; + } } - return $this->blueprints ??= $toBlueprints($blueprint->sections()); - } - - /** - * Creates a new instance with the same - * initial properties - * - * @todo eventually refactor without need of propertyData - */ - public function clone(array $props = []): static - { - return new static(array_replace_recursive($this->propertyData, $props)); + return array_values($blueprints); } /** * Executes any given model action + * + * @param string $action + * @param array $arguments + * @param \Closure $callback + * @return mixed */ - abstract protected function commit( - string $action, - array $arguments, - Closure $callback - ): mixed; + abstract protected function commit(string $action, array $arguments, Closure $callback); /** * Returns the content * + * @param string|null $languageCode + * @return \Kirby\Cms\Content * @throws \Kirby\Exception\InvalidArgumentException If the language for the given code does not exist */ - public function content(string|null $languageCode = null): Content + public function content(string $languageCode = null) { // single language support if ($this->kirby()->multilang() === false) { - if ($this->content instanceof Content) { + if (is_a($this->content, 'Kirby\Cms\Content') === true) { return $this->content; } // don't normalize field keys (already handled by the `Data` class) return $this->content = new Content($this->readContent(), $this, false); + + // multi language support + } else { + // only fetch from cache for the default language + if ($languageCode === null && is_a($this->content, 'Kirby\Cms\Content') === true) { + return $this->content; + } + + // get the translation by code + if ($translation = $this->translation($languageCode)) { + // don't normalize field keys (already handled by the `ContentTranslation` class) + $content = new Content($translation->content(), $this, false); + } else { + throw new InvalidArgumentException('Invalid language: ' . $languageCode); + } + + // only store the content for the current language + if ($languageCode === null) { + $this->content = $content; + } + + return $content; } - - // get the targeted language - $language = $this->kirby()->language($languageCode); - - // stop if the language does not exist - if ($language === null) { - throw new InvalidArgumentException('Invalid language: ' . $languageCode); - } - - // only fetch from cache for the current language - if ($languageCode === null && $this->content instanceof Content) { - return $this->content; - } - - // get the translation by code - $translation = $this->translation($language->code()); - - // don't normalize field keys (already handled by the `ContentTranslation` class) - $content = new Content($translation->content(), $this, false); - - // only store the content for the current language - if ($languageCode === null) { - $this->content = $content; - } - - return $content; } /** - * Returns the absolute path to the content file; - * NOTE: only supports the published content file - * (use `$model->storage()->contentFile()` for other versions) - * @internal - * @deprecated 4.0.0 - * @todo Remove in v5 - * @codeCoverageIgnore + * Returns the absolute path to the content file * + * @internal + * @param string|null $languageCode + * @param bool $force + * @return string * @throws \Kirby\Exception\InvalidArgumentException If the language for the given code does not exist */ - public function contentFile( - string $languageCode = null, - bool $force = false - ): string { - Helpers::deprecated('The internal $model->contentFile() method has been deprecated. You can use $model->storage()->contentFile() instead, however please note that this method is also internal and may be removed in the future.', 'model-content-file'); + public function contentFile(string $languageCode = null, bool $force = false): string + { + $extension = $this->contentFileExtension(); + $directory = $this->contentFileDirectory(); + $filename = $this->contentFileName(); - return $this->storage()->contentFile( - $this->storage()->defaultVersion(), - $languageCode, - $force - ); + // overwrite the language code + if ($force === true) { + if (empty($languageCode) === false) { + return $directory . '/' . $filename . '.' . $languageCode . '.' . $extension; + } else { + return $directory . '/' . $filename . '.' . $extension; + } + } + + // add and validate the language code in multi language mode + if ($this->kirby()->multilang() === true) { + if ($language = $this->kirby()->languageCode($languageCode)) { + return $directory . '/' . $filename . '.' . $language . '.' . $extension; + } else { + throw new InvalidArgumentException('Invalid language: ' . $languageCode); + } + } else { + return $directory . '/' . $filename . '.' . $extension; + } } /** - * Returns an array with all content files; - * NOTE: only supports the published content file - * (use `$model->storage()->contentFiles()` for other versions) - * @deprecated 4.0.0 - * @todo Remove in v5 - * @codeCoverageIgnore + * Returns an array with all content files + * + * @return array */ public function contentFiles(): array { - Helpers::deprecated('The internal $model->contentFiles() method has been deprecated. You can use $model->storage()->contentFiles() instead, however please note that this method is also internal and may be removed in the future.', 'model-content-file'); - - return $this->storage()->contentFiles( - $this->storage()->defaultVersion() - ); + if ($this->kirby()->multilang() === true) { + $files = []; + foreach ($this->kirby()->languages()->codes() as $code) { + $files[] = $this->contentFile($code); + } + return $files; + } else { + return [ + $this->contentFile() + ]; + } } /** * Prepares the content that should be written * to the text file + * * @internal + * @param array $data + * @param string|null $languageCode + * @return array */ - public function contentFileData( - array $data, - string $languageCode = null - ): array { + public function contentFileData(array $data, string $languageCode = null): array + { return $data; } @@ -221,102 +190,44 @@ abstract class ModelWithContent implements Identifiable * Returns the absolute path to the * folder in which the content file is * located + * * @internal - * @deprecated 4.0.0 - * @todo Remove in v5 - * @codeCoverageIgnore + * @return string|null */ - public function contentFileDirectory(): string|null + public function contentFileDirectory(): ?string { - Helpers::deprecated('The internal $model->contentFileDirectory() method has been deprecated. Please let us know via a GitHub issue if you need this method and tell us your use case.', 'model-content-file'); return $this->root(); } /** * Returns the extension of the content file + * * @internal - * @deprecated 4.0.0 - * @todo Remove in v5 - * @codeCoverageIgnore + * @return string */ public function contentFileExtension(): string { - Helpers::deprecated('The internal $model->contentFileName() method has been deprecated. Please let us know via a GitHub issue if you need this method and tell us your use case.', 'model-content-file'); return $this->kirby()->contentExtension(); } /** * Needs to be declared by the final model + * * @internal - * @deprecated 4.0.0 - * @todo Remove in v5 - * @codeCoverageIgnore + * @return string */ abstract public function contentFileName(): string; - /** - * Converts model to new blueprint - * incl. its content for all translations - */ - protected function convertTo(string $blueprint): static - { - // first close object with new blueprint as template - $new = $this->clone(['template' => $blueprint]); - - // temporary compatibility change (TODO: also convert changes) - $identifier = $this->storage()->defaultVersion(); - - // for multilang, we go through all translations and - // covnert the content for each of them, remove the content file - // to rewrite it with converted content afterwards - if ($this->kirby()->multilang() === true) { - $translations = []; - - foreach ($this->kirby()->languages()->codes() as $code) { - if ($this->translation($code)?->exists() === true) { - $content = $this->content($code)->convertTo($blueprint); - - // delete the old text file - $this->storage()->delete( - $identifier, - $code - ); - - // save to re-create the translation content file - // with the converted/updated content - $new->save($content, $code); - } - - $translations[] = [ - 'code' => $code, - 'content' => $content ?? null - ]; - } - - // cloning the object with the new translations content ensures - // that `propertyData` prop does not hold any old translations - // content that could surface on subsequent cloning - return $new->clone(['translations' => $translations]); - } - - // for single language setups, we do the same, - // just once for the main content - $content = $this->content()->convertTo($blueprint); - - // delete the old text file - $this->storage()->delete($identifier, 'default'); - - return $new->save($content); - } - /** * Decrement a given field value + * + * @param string $field + * @param int $by + * @param int $min + * @return static */ - public function decrement( - string $field, - int $by = 1, - int $min = 0 - ): static { + public function decrement(string $field, int $by = 1, int $min = 0) + { $value = (int)$this->content()->get($field)->value() - $by; if ($value < $min) { @@ -328,6 +239,8 @@ abstract class ModelWithContent implements Identifiable /** * Returns all content validation errors + * + * @return array */ public function errors(): array { @@ -340,39 +253,16 @@ abstract class ModelWithContent implements Identifiable return $errors; } - /** - * Creates a clone and fetches all - * lazy-loaded getters to get a full copy - */ - public function hardcopy(): static - { - $clone = $this->clone(); - - foreach (get_object_vars($clone) as $name => $default) { - if (method_exists($clone, $name) === true) { - $clone->$name(); - } - } - - return $clone; - } - - /** - * Each model must return a unique id - */ - public function id(): string|null - { - return null; - } - /** * Increment a given field value + * + * @param string $field + * @param int $by + * @param int|null $max + * @return static */ - public function increment( - string $field, - int $by = 1, - int $max = null - ): static { + public function increment(string $field, int $by = 1, int $max = null) + { $value = (int)$this->content()->get($field)->value() + $by; if ($max && $value > $max) { @@ -384,6 +274,8 @@ abstract class ModelWithContent implements Identifiable /** * Checks if the model is locked for the current user + * + * @return bool */ public function isLocked(): bool { @@ -393,18 +285,12 @@ abstract class ModelWithContent implements Identifiable /** * Checks if the data has any errors + * + * @return bool */ public function isValid(): bool { - return Form::for($this)->isValid() === true; - } - - /** - * Returns the parent Kirby instance - */ - public function kirby(): App - { - return static::$kirby ??= App::instance(); + return Form::for($this)->hasErrors() === false; } /** @@ -412,14 +298,12 @@ abstract class ModelWithContent implements Identifiable * * Only if a content directory exists, * virtual pages will need to overwrite this method + * + * @return \Kirby\Cms\ContentLock|null */ - public function lock(): ContentLock|null + public function lock() { - $dir = $this->root(); - - if ($this::CLASS_ALIAS === 'file') { - $dir = dirname($dir); - } + $dir = $this->contentFileDirectory(); if ( $this->kirby()->option('content.locking', true) && @@ -428,43 +312,33 @@ abstract class ModelWithContent implements Identifiable ) { return new ContentLock($this); } - - return null; } /** * Returns the panel info of the model * @since 3.6.0 + * + * @return \Kirby\Panel\Model */ - abstract public function panel(): Model; + abstract public function panel(); /** * Must return the permissions object for the model - */ - abstract public function permissions(): ModelPermissions; - - /** - * Clean internal caches * - * @return $this + * @return \Kirby\Cms\ModelPermissions */ - public function purge(): static - { - $this->blueprints = null; - $this->content = null; - $this->translations = null; - - return $this; - } + abstract public function permissions(); /** * Creates a string query, starting from the model + * * @internal + * @param string|null $query + * @param string|null $expect + * @return mixed */ - public function query( - string $query = null, - string $expect = null - ): mixed { + public function query(string $query = null, string $expect = null) + { if ($query === null) { return null; } @@ -472,15 +346,15 @@ abstract class ModelWithContent implements Identifiable try { $result = Str::query($query, [ 'kirby' => $this->kirby(), - 'site' => $this instanceof Site ? $this : $this->site(), + 'site' => is_a($this, 'Kirby\Cms\Site') ? $this : $this->site(), 'model' => $this, static::CLASS_ALIAS => $this ]); - } catch (Throwable) { + } catch (Throwable $e) { return null; } - if ($expect !== null && $result instanceof $expect === false) { + if ($expect !== null && is_a($result, $expect) !== true) { return null; } @@ -489,51 +363,54 @@ abstract class ModelWithContent implements Identifiable /** * Read the content from the content file + * * @internal + * @param string|null $languageCode + * @return array */ public function readContent(string $languageCode = null): array { try { - return $this->storage()->read( - $this->storage()->defaultVersion(), - $languageCode - ); - } catch (NotFoundException) { - // only if the content file really does not exist, it's ok - // to return empty content. Otherwise this could lead to - // content loss in case of file reading issues + return Data::read($this->contentFile($languageCode)); + } catch (Throwable $e) { return []; } } /** * Returns the absolute path to the model + * + * @return string|null */ - abstract public function root(): string|null; + abstract public function root(): ?string; /** * Stores the content on disk + * * @internal + * @param array|null $data + * @param string|null $languageCode + * @param bool $overwrite + * @return static */ - public function save( - array|null $data = null, - string|null $languageCode = null, - bool $overwrite = false - ): static { + public function save(array $data = null, string $languageCode = null, bool $overwrite = false) + { if ($this->kirby()->multilang() === true) { return $this->saveTranslation($data, $languageCode, $overwrite); + } else { + return $this->saveContent($data, $overwrite); } - - return $this->saveContent($data, $overwrite); } /** * Save the single language content + * + * @param array|null $data + * @param bool $overwrite + * @return static */ - protected function saveContent( - array $data = null, - bool $overwrite = false - ): static { + protected function saveContent(array $data = null, bool $overwrite = false) + { // create a clone to avoid modifying the original $clone = $this->clone(); @@ -549,13 +426,14 @@ abstract class ModelWithContent implements Identifiable /** * Save a translation * + * @param array|null $data + * @param string|null $languageCode + * @param bool $overwrite + * @return static * @throws \Kirby\Exception\InvalidArgumentException If the language for the given code does not exist */ - protected function saveTranslation( - array $data = null, - string $languageCode = null, - bool $overwrite = false - ): static { + protected function saveTranslation(array $data = null, string $languageCode = null, bool $overwrite = false) + { // create a clone to not touch the original $clone = $this->clone(); @@ -579,11 +457,6 @@ abstract class ModelWithContent implements Identifiable } } - // remove UUID for non-default languages - if (Uuids::enabled() === true && isset($content['uuid']) === true) { - $content['uuid'] = null; - } - // merge the translation with the new data $translation->update($content, true); } @@ -601,9 +474,10 @@ abstract class ModelWithContent implements Identifiable /** * Sets the Content object * + * @param array|null $content * @return $this */ - protected function setContent(array $content = null): static + protected function setContent(array $content = null) { if ($content !== null) { $content = new Content($content, $this); @@ -616,9 +490,10 @@ abstract class ModelWithContent implements Identifiable /** * Create the translations collection from an array * + * @param array|null $translations * @return $this */ - protected function setTranslations(array $translations = null): static + protected function setTranslations(array $translations = null) { if ($translations !== null) { $this->translations = new Collection(); @@ -628,57 +503,22 @@ abstract class ModelWithContent implements Identifiable $translation = new ContentTranslation($props); $this->translations->data[$translation->code()] = $translation; } - } else { - $this->translations = null; } return $this; } - /** - * Returns the parent Site instance - */ - public function site(): Site - { - return $this->site ??= $this->kirby()->site(); - } - - /** - * Returns the content storage handler - * @internal - */ - public function storage(): ContentStorage - { - return $this->storage ??= new ContentStorage( - model: $this, - handler: PlainTextContentStorageHandler::class - ); - } - - /** - * Convert the model to a simple array - */ - public function toArray(): array - { - return [ - 'content' => $this->content()->toArray(), - 'translations' => $this->translations()->toArray() - ]; - } - /** * String template builder with automatic HTML escaping * @since 3.6.0 * * @param string|null $template Template string or `null` to use the model ID - * @param string|null $fallback Fallback for tokens in the template that cannot be replaced - * (`null` to keep the original token) + * @param array $data + * @param string $fallback Fallback for tokens in the template that cannot be replaced + * @return string */ - public function toSafeString( - string $template = null, - array $data = [], - string|null $fallback = '' - ): string { + public function toSafeString(string $template = null, array $data = [], string $fallback = ''): string + { return $this->toString($template, $data, $fallback, 'safeTemplate'); } @@ -686,16 +526,13 @@ abstract class ModelWithContent implements Identifiable * String template builder * * @param string|null $template Template string or `null` to use the model ID - * @param string|null $fallback Fallback for tokens in the template that cannot be replaced - * (`null` to keep the original token) + * @param array $data + * @param string $fallback Fallback for tokens in the template that cannot be replaced * @param string $handler For internal use + * @return string */ - public function toString( - string $template = null, - array $data = [], - string|null $fallback = '', - string $handler = 'template' - ): string { + public function toString(string $template = null, array $data = [], string $fallback = '', string $handler = 'template'): string + { if ($template === null) { return $this->id() ?? ''; } @@ -706,7 +543,7 @@ abstract class ModelWithContent implements Identifiable $result = Str::$handler($template, array_replace([ 'kirby' => $this->kirby(), - 'site' => $this instanceof Site ? $this : $this->site(), + 'site' => is_a($this, 'Kirby\Cms\Site') ? $this : $this->site(), 'model' => $this, static::CLASS_ALIAS => $this, ], $data), ['fallback' => $fallback]); @@ -714,33 +551,24 @@ abstract class ModelWithContent implements Identifiable return $result; } - /** - * Makes it possible to convert the entire model - * to a string. Mostly useful for debugging - */ - public function __toString(): string - { - return $this->id(); - } - /** * Returns a single translation by language code * If no code is specified the current translation is returned + * + * @param string|null $languageCode + * @return \Kirby\Cms\ContentTranslation|null */ - public function translation( - string $languageCode = null - ): ContentTranslation|null { - if ($language = $this->kirby()->language($languageCode)) { - return $this->translations()->find($language->code()); - } - - return null; + public function translation(string $languageCode = null) + { + return $this->translations()->find($languageCode ?? $this->kirby()->language()->code()); } /** * Returns the translations collection + * + * @return \Kirby\Cms\Collection */ - public function translations(): Collection + public function translations() { if ($this->translations !== null) { return $this->translations; @@ -763,13 +591,14 @@ abstract class ModelWithContent implements Identifiable /** * Updates the model data * + * @param array|null $input + * @param string|null $languageCode + * @param bool $validate + * @return static * @throws \Kirby\Exception\InvalidArgumentException If the input array contains invalid values */ - public function update( - array $input = null, - string $languageCode = null, - bool $validate = false - ): static { + public function update(array $input = null, string $languageCode = null, bool $validate = false) + { $form = Form::for($this, [ 'ignoreDisabled' => $validate === false, 'input' => $input, @@ -777,53 +606,96 @@ abstract class ModelWithContent implements Identifiable ]); // validate the input - if ($validate === true && $form->isInvalid() === true) { - throw new InvalidArgumentException([ - 'fallback' => 'Invalid form with errors', - 'details' => $form->errors() - ]); + if ($validate === true) { + if ($form->isInvalid() === true) { + throw new InvalidArgumentException([ + 'fallback' => 'Invalid form with errors', + 'details' => $form->errors() + ]); + } } - return $this->commit( - 'update', - [ - static::CLASS_ALIAS => $this, - 'values' => $form->data(), - 'strings' => $form->strings(), - 'languageCode' => $languageCode - ], - fn ($model, $values, $strings, $languageCode) => - $model->save($strings, $languageCode, true) - ); - } + $arguments = [static::CLASS_ALIAS => $this, 'values' => $form->data(), 'strings' => $form->strings(), 'languageCode' => $languageCode]; + return $this->commit('update', $arguments, function ($model, $values, $strings, $languageCode) { + // save updated values + $model = $model->save($strings, $languageCode, true); - /** - * Returns the model's UUID - * @since 3.8.0 - */ - public function uuid(): Uuid|null - { - return Uuid::for($this); + // update model in siblings collection + $model->siblings()->add($model); + + return $model; + }); } /** * Low level data writer method * to store the given data on disk or anywhere else + * * @internal + * @param array $data + * @param string|null $languageCode + * @return bool */ public function writeContent(array $data, string $languageCode = null): bool { - $data = $this->contentFileData($data, $languageCode); - $id = $this->storage()->defaultVersion(); + return Data::write( + $this->contentFile($languageCode), + $this->contentFileData($data, $languageCode) + ); + } - try { - // we can only update if the version already exists - $this->storage()->update($id, $languageCode, $data); - } catch (NotFoundException) { - // otherwise create a new version - $this->storage()->create($id, $languageCode, $data); - } - return true; + /** + * Deprecated! + */ + + /** + * Returns the panel icon definition + * + * @deprecated 3.6.0 Use `->panel()->image()` instead + * @todo Remove in 3.8.0 + * + * @internal + * @param array|null $params + * @return array|null + * @codeCoverageIgnore + */ + public function panelIcon(array $params = null): ?array + { + Helpers::deprecated('Cms\ModelWithContent::panelIcon() has been deprecated and will be removed in Kirby 3.8.0. Use $model->panel()->image() instead.'); + return $this->panel()->image($params); + } + + /** + * @deprecated 3.6.0 Use `->panel()->image()` instead + * @todo Remove in 3.8.0 + * + * @internal + * @param string|array|false|null $settings + * @return array|null + * @codeCoverageIgnore + */ + public function panelImage($settings = null): ?array + { + Helpers::deprecated('Cms\ModelWithContent::panelImage() has been deprecated and will be removed in Kirby 3.8.0. Use $model->panel()->image() instead.'); + return $this->panel()->image($settings); + } + + /** + * Returns an array of all actions + * that can be performed in the Panel + * This also checks for the lock status + * + * @deprecated 3.6.0 Use `->panel()->options()` instead + * @todo Remove in 3.8.0 + * + * @param array $unlock An array of options that will be force-unlocked + * @return array + * @codeCoverageIgnore + */ + public function panelOptions(array $unlock = []): array + { + Helpers::deprecated('Cms\ModelWithContent::panelOptions() has been deprecated and will be removed in Kirby 3.8.0. Use $model->panel()->options() instead.'); + return $this->panel()->options($unlock); } } diff --git a/kirby/src/Cms/Nest.php b/kirby/src/Cms/Nest.php index 0f8521d..56455b3 100644 --- a/kirby/src/Cms/Nest.php +++ b/kirby/src/Cms/Nest.php @@ -2,8 +2,6 @@ namespace Kirby\Cms; -use Kirby\Content\Field; - /** * The Nest class converts any array type * into a Kirby style collection/object. This @@ -20,10 +18,13 @@ use Kirby\Content\Field; */ class Nest { - public static function create( - $data, - object|null $parent = null - ): NestCollection|NestObject|Field { + /** + * @param $data + * @param null $parent + * @return mixed + */ + public static function create($data, $parent = null) + { if (is_scalar($data) === true) { return new Field($parent, $data, $data); } @@ -38,12 +39,10 @@ class Nest } } - $key = key($data); - - if ($key === null || is_int($key) === true) { + if (is_int(key($data))) { return new NestCollection($result); + } else { + return new NestObject($result); } - - return new NestObject($result); } } diff --git a/kirby/src/Cms/NestCollection.php b/kirby/src/Cms/NestCollection.php index 129668d..b5b1a7b 100644 --- a/kirby/src/Cms/NestCollection.php +++ b/kirby/src/Cms/NestCollection.php @@ -20,6 +20,9 @@ class NestCollection extends BaseCollection * Converts all objects in the collection * to an array. This can also take a callback * function to further modify the array result. + * + * @param \Closure|null $map + * @return array */ public function toArray(Closure $map = null): array { diff --git a/kirby/src/Cms/NestObject.php b/kirby/src/Cms/NestObject.php index 2466023..4744539 100644 --- a/kirby/src/Cms/NestObject.php +++ b/kirby/src/Cms/NestObject.php @@ -2,7 +2,6 @@ namespace Kirby\Cms; -use Kirby\Content\Field; use Kirby\Toolkit\Obj; /** @@ -18,21 +17,20 @@ class NestObject extends Obj { /** * Converts the object to an array + * + * @return array */ public function toArray(): array { $result = []; foreach ((array)$this as $key => $value) { - if ($value instanceof Field) { + if (is_a($value, 'Kirby\Cms\Field') === true) { $result[$key] = $value->value(); continue; } - if ( - is_object($value) === true && - method_exists($value, 'toArray') - ) { + if (is_object($value) === true && method_exists($value, 'toArray')) { $result[$key] = $value->toArray(); continue; } diff --git a/kirby/src/Cms/Page.php b/kirby/src/Cms/Page.php index 3fab7b3..88c95cd 100644 --- a/kirby/src/Cms/Page.php +++ b/kirby/src/Cms/Page.php @@ -2,20 +2,15 @@ namespace Kirby\Cms; -use Closure; -use Kirby\Content\Field; use Kirby\Exception\Exception; use Kirby\Exception\InvalidArgumentException; use Kirby\Exception\NotFoundException; use Kirby\Filesystem\Dir; +use Kirby\Filesystem\F; use Kirby\Http\Response; use Kirby\Http\Uri; use Kirby\Panel\Page as Panel; -use Kirby\Template\Template; use Kirby\Toolkit\A; -use Kirby\Toolkit\LazyValue; -use Kirby\Toolkit\Str; -use Throwable; /** * The `$page` object is the heart and @@ -31,127 +26,141 @@ use Throwable; */ class Page extends ModelWithContent { + use PageActions; + use PageSiblings; use HasChildren; use HasFiles; use HasMethods; use HasSiblings; - use PageActions; - use PageSiblings; public const CLASS_ALIAS = 'page'; /** * All registered page methods - * @todo Remove when support for PHP 8.2 is dropped + * + * @var array */ - public static array $methods = []; + public static $methods = []; /** * Registry with all Page models + * + * @var array */ - public static array $models = []; + public static $models = []; /** * The PageBlueprint object + * + * @var \Kirby\Cms\PageBlueprint */ - protected PageBlueprint|null $blueprint = null; + protected $blueprint; /** * Nesting level + * + * @var int */ - protected int $depth; + protected $depth; /** * Sorting number + slug + * + * @var string */ - protected string|null $dirname; + protected $dirname; /** * Path of dirnames + * + * @var string */ - protected string|null $diruri = null; + protected $diruri; /** * Draft status flag + * + * @var bool */ - protected bool $isDraft; + protected $isDraft; /** * The Page id + * + * @var string */ - protected string|null $id = null; + protected $id; /** * The template, that should be loaded * if it exists + * + * @var \Kirby\Cms\Template */ - protected Template|null $intendedTemplate = null; + protected $intendedTemplate; - protected array|null $inventory = null; + /** + * @var array + */ + protected $inventory; /** * The sorting number + * + * @var int|null */ - protected int|null $num; + protected $num; /** * The parent page + * + * @var \Kirby\Cms\Page|null */ - protected Page|null $parent; + protected $parent; /** * Absolute path to the page directory + * + * @var string */ - protected string|null $root; + protected $root; + + /** + * The parent Site object + * + * @var \Kirby\Cms\Site|null + */ + protected $site; /** * The URL-appendix aka slug + * + * @var string */ - protected string $slug; + protected $slug; /** * The intended page template + * + * @var \Kirby\Cms\Template */ - protected Template|null $template = null; + protected $template; /** * The page url + * + * @var string|null */ - protected string|null $url; - - /** - * Creates a new page object - */ - public function __construct(array $props) - { - if (isset($props['slug']) === false) { - throw new InvalidArgumentException('The page slug is required'); - } - - parent::__construct($props); - - $this->slug = $props['slug']; - // Sets the dirname manually, which works - // more reliable in connection with the inventory - // than computing the dirname afterwards - $this->dirname = $props['dirname'] ?? null; - $this->isDraft = $props['isDraft'] ?? false; - $this->num = $props['num'] ?? null; - $this->parent = $props['parent'] ?? null; - $this->root = $props['root'] ?? null; - - $this->setBlueprint($props['blueprint'] ?? null); - $this->setChildren($props['children'] ?? null); - $this->setDrafts($props['drafts'] ?? null); - $this->setFiles($props['files'] ?? null); - $this->setTemplate($props['template'] ?? null); - $this->setUrl($props['url'] ?? null); - } + protected $url; /** * Magic caller + * + * @param string $method + * @param array $arguments + * @return mixed */ - public function __call(string $method, array $arguments = []): mixed + public function __call(string $method, array $arguments = []) { // public property access if (isset($this->$method) === true) { @@ -167,9 +176,24 @@ class Page extends ModelWithContent return $this->content()->get($method); } + /** + * Creates a new page object + * + * @param array $props + */ + public function __construct(array $props) + { + // set the slug as the first property + $this->slug = $props['slug'] ?? null; + + // add all other properties + $this->setProperties($props); + } + /** * Improved `var_dump` output - * @codeCoverageIgnore + * + * @return array */ public function __debugInfo(): array { @@ -184,42 +208,46 @@ class Page extends ModelWithContent /** * Returns the url to the api endpoint + * * @internal + * @param bool $relative + * @return string */ public function apiUrl(bool $relative = false): string { if ($relative === true) { return 'pages/' . $this->panel()->id(); + } else { + return $this->kirby()->url('api') . '/pages/' . $this->panel()->id(); } - - return $this->kirby()->url('api') . '/pages/' . $this->panel()->id(); } /** * Returns the blueprint object + * + * @return \Kirby\Cms\PageBlueprint */ - public function blueprint(): PageBlueprint + public function blueprint() { - return $this->blueprint ??= PageBlueprint::factory( - 'pages/' . $this->intendedTemplate(), - 'pages/default', - $this - ); + if (is_a($this->blueprint, 'Kirby\Cms\PageBlueprint') === true) { + return $this->blueprint; + } + + return $this->blueprint = PageBlueprint::factory('pages/' . $this->intendedTemplate(), 'pages/default', $this); } /** * Returns an array with all blueprints that are available for the page + * + * @param string|null $inSection + * @return array */ - public function blueprints(string|null $inSection = null): array + public function blueprints(?string $inSection = null): array { if ($inSection !== null) { return $this->blueprint()->section($inSection)->blueprints(); } - if ($this->blueprints !== null) { - return $this->blueprints; - } - $blueprints = []; $templates = $this->blueprint()->changeTemplate() ?? $this->blueprint()->options()['changeTemplate'] ?? []; $currentTemplate = $this->intendedTemplate()->name(); @@ -244,16 +272,19 @@ class Page extends ModelWithContent 'name' => basename($props['name']), 'title' => $props['title'], ]; - } catch (Exception) { + } catch (Exception $e) { // skip invalid blueprints } } - return $this->blueprints = array_values($blueprints); + return array_values($blueprints); } /** * Builds the cache id for the page + * + * @param string $contentType + * @return string */ protected function cacheId(string $contentType): string { @@ -270,12 +301,14 @@ class Page extends ModelWithContent /** * Prepares the content for the write method + * * @internal + * @param array $data + * @param string|null $languageCode + * @return array */ - public function contentFileData( - array $data, - string|null $languageCode = null - ): array { + public function contentFileData(array $data, ?string $languageCode = null): array + { return A::prepend($data, [ 'title' => $data['title'] ?? null, 'slug' => $data['slug'] ?? null @@ -285,75 +318,68 @@ class Page extends ModelWithContent /** * Returns the content text file * which is found by the inventory method + * * @internal - * @deprecated 4.0.0 - * @todo Remove in v5 - * @codeCoverageIgnore + * @param string|null $languageCode + * @return string */ - public function contentFileName(string|null $languageCode = null): string + public function contentFileName(?string $languageCode = null): string { - Helpers::deprecated('The internal $model->contentFileName() method has been deprecated. Please let us know via a GitHub issue if you need this method and tell us your use case.', 'model-content-file'); return $this->intendedTemplate()->name(); } /** * Call the page controller - * @internal * + * @internal + * @param array $data + * @param string $contentType + * @return array * @throws \Kirby\Exception\InvalidArgumentException If the controller returns invalid objects for `kirby`, `site`, `pages` or `page` */ - public function controller( - array $data = [], - string $contentType = 'html' - ): array { + public function controller(array $data = [], string $contentType = 'html'): array + { // create the template data $data = array_merge($data, [ 'kirby' => $kirby = $this->kirby(), 'site' => $site = $this->site(), - 'pages' => new LazyValue(fn () => $site->children()), - 'page' => new LazyValue(fn () => $site->visit($this)) + 'pages' => $site->children(), + 'page' => $site->visit($this) ]); // call the template controller if there's one. - $controllerData = $kirby->controller( - $this->template()->name(), - $data, - $contentType - ); + $controllerData = $kirby->controller($this->template()->name(), $data, $contentType); // merge controller data with original data safely - // to provide original data to template even if - // it wasn't returned by the controller explicitly if (empty($controllerData) === false) { $classes = [ - 'kirby' => App::class, - 'site' => Site::class, - 'pages' => Pages::class, - 'page' => Page::class + 'kirby' => 'Kirby\Cms\App', + 'site' => 'Kirby\Cms\Site', + 'pages' => 'Kirby\Cms\Pages', + 'page' => 'Kirby\Cms\Page' ]; foreach ($controllerData as $key => $value) { - $data[$key] = match (true) { - // original data wasn't overwritten - array_key_exists($key, $classes) === false => $value, - // original data was overwritten, but matches expected type - $value instanceof $classes[$key] => $value, - // throw error if data was overwritten with wrong type - default => throw new InvalidArgumentException('The returned variable "' . $key . '" from the controller "' . $this->template()->name() . '" is not of the required type "' . $classes[$key] . '"') - }; + if (array_key_exists($key, $classes) === true) { + if (is_a($value, $classes[$key]) === true) { + $data[$key] = $value; + } else { + throw new InvalidArgumentException('The returned variable "' . $key . '" from the controller "' . $this->template()->name() . '" is not of the required type "' . $classes[$key] . '"'); + } + } else { + $data[$key] = $value; + } } } - // unwrap remaining lazy values in data - // (happens if the controller didn't override an original lazy Kirby object) - $data = LazyValue::unwrap($data); - return $data; } /** * Returns a number indicating how deep the page * is nested within the content folder + * + * @return int */ public function depth(): int { @@ -362,6 +388,8 @@ class Page extends ModelWithContent /** * Sorting number + Slug + * + * @return string */ public function dirname(): string { @@ -371,13 +399,15 @@ class Page extends ModelWithContent if ($this->num() !== null) { return $this->dirname = $this->num() . Dir::$numSeparator . $this->uid(); + } else { + return $this->dirname = $this->uid(); } - - return $this->dirname = $this->uid(); } /** * Sorting number + Slug + * + * @return string */ public function diruri(): string { @@ -393,13 +423,15 @@ class Page extends ModelWithContent if ($parent = $this->parent()) { return $this->diruri = $parent->diruri() . '/' . $dirname; + } else { + return $this->diruri = $dirname; } - - return $this->diruri = $dirname; } /** * Checks if the page exists on disk + * + * @return bool */ public function exists(): bool { @@ -409,11 +441,18 @@ class Page extends ModelWithContent /** * Constructs a Page object and also * takes page models into account. + * * @internal + * @param mixed $props + * @return static */ - public static function factory($props): static + public static function factory($props) { - return static::model($props['model'] ?? 'default', $props); + if (empty($props['model']) === false) { + return static::model($props['model'], $props); + } + + return new static($props); } /** @@ -425,7 +464,7 @@ class Page extends ModelWithContent * @param array $options Options for `Kirby\Http\Uri` to create URL parts * @param int $code HTTP status code */ - public function go(array $options = [], int $code = 302): void + public function go(array $options = [], int $code = 302) { Response::go($this->url($options), $code); } @@ -433,6 +472,8 @@ class Page extends ModelWithContent /** * Checks if the intended template * for the page exists. + * + * @return bool */ public function hasTemplate(): bool { @@ -441,6 +482,8 @@ class Page extends ModelWithContent /** * Returns the Page Id + * + * @return string */ public function id(): string { @@ -459,8 +502,10 @@ class Page extends ModelWithContent /** * Returns the template that should be * loaded if it exists. + * + * @return \Kirby\Cms\Template */ - public function intendedTemplate(): Template + public function intendedTemplate() { if ($this->intendedTemplate !== null) { return $this->intendedTemplate; @@ -472,7 +517,9 @@ class Page extends ModelWithContent /** * Returns the inventory of files * children and content files + * * @internal + * @return array */ public function inventory(): array { @@ -494,10 +541,11 @@ class Page extends ModelWithContent * Compares the current object with the given page object * * @param \Kirby\Cms\Page|string $page + * @return bool */ public function is($page): bool { - if ($page instanceof self === false) { + if (is_a($page, 'Kirby\Cms\Page') === false) { if (is_string($page) === false) { return false; } @@ -505,42 +553,34 @@ class Page extends ModelWithContent $page = $this->kirby()->page($page); } - if ($page instanceof self === false) { + if (is_a($page, 'Kirby\Cms\Page') === false) { return false; } return $this->id() === $page->id(); } - /** - * Checks if the page is accessible that accessible and listable. - * This permission depends on the `read` option until v5 - */ - public function isAccessible(): bool - { - // TODO: remove this check when `read` option deprecated in v5 - if ($this->isReadable() === false) { - return false; - } - - static $accessible = []; - - $template = $this->intendedTemplate()->name(); - - return $accessible[$template] ??= $this->permissions()->can('access'); - } - /** * Checks if the page is the current page + * + * @return bool */ public function isActive(): bool { - return $this->site()->page()?->is($this) === true; + if ($page = $this->site()->page()) { + if ($page->is($this) === true) { + return true; + } + } + + return false; } /** - * Checks if the page is a direct or indirect ancestor - * of the given $page object + * Checks if the page is a direct or indirect ancestor of the given $page object + * + * @param Page $child + * @return bool */ public function isAncestorOf(Page $child): bool { @@ -551,6 +591,8 @@ class Page extends ModelWithContent * Checks if the page can be cached in the * pages cache. This will also check if one * of the ignore rules from the config kick in. + * + * @return bool */ public function isCacheable(): bool { @@ -583,7 +625,7 @@ class Page extends ModelWithContent } // check for a custom ignore rule - if ($ignore instanceof Closure) { + if (is_a($ignore, 'Closure') === true) { if ($ignore($this) === true) { return false; } @@ -603,16 +645,22 @@ class Page extends ModelWithContent * Checks if the page is a child of the given page * * @param \Kirby\Cms\Page|string $parent + * @return bool */ public function isChildOf($parent): bool { - return $this->parent()?->is($parent) ?? false; + if ($parentObj = $this->parent()) { + return $parentObj->is($parent); + } + + return false; } /** * Checks if the page is a descendant of the given page * * @param \Kirby\Cms\Page|string $parent + * @return bool */ public function isDescendantOf($parent): bool { @@ -629,6 +677,8 @@ class Page extends ModelWithContent /** * Checks if the page is a descendant of the currently active page + * + * @return bool */ public function isDescendantOfActive(): bool { @@ -641,6 +691,8 @@ class Page extends ModelWithContent /** * Checks if the current page is a draft + * + * @return bool */ public function isDraft(): bool { @@ -649,6 +701,8 @@ class Page extends ModelWithContent /** * Checks if the page is the error page + * + * @return bool */ public function isErrorPage(): bool { @@ -657,6 +711,8 @@ class Page extends ModelWithContent /** * Checks if the page is the home page + * + * @return bool */ public function isHomePage(): bool { @@ -667,56 +723,30 @@ class Page extends ModelWithContent * It's often required to check for the * home and error page to stop certain * actions. That's why there's a shortcut. + * + * @return bool */ public function isHomeOrErrorPage(): bool { return $this->isHomePage() === true || $this->isErrorPage() === true; } - /** - * Check if the page can be listable by the current user - * This permission depends on the `read` option until v5 - */ - public function isListable(): bool - { - // TODO: remove this check when `read` option deprecated in v5 - if ($this->isReadable() === false) { - return false; - } - - // not accessible also means not listable - if ($this->isAccessible() === false) { - return false; - } - - static $listable = []; - - $template = $this->intendedTemplate()->name(); - - return $listable[$template] ??= $this->permissions()->can('list'); - } - /** * Checks if the page has a sorting number + * + * @return bool */ public function isListed(): bool { - return $this->isPublished() && $this->num() !== null; - } - - public function isMovableTo(Page|Site $parent): bool - { - try { - return PageRules::move($this, $parent); - } catch (Throwable) { - return false; - } + return $this->num() !== null; } /** * Checks if the page is open. * Open pages are either the current one * or descendants of the current one. + * + * @return bool */ public function isOpen(): bool { @@ -724,8 +754,10 @@ class Page extends ModelWithContent return true; } - if ($this->site()->page()?->parents()->has($this->id()) === true) { - return true; + if ($page = $this->site()->page()) { + if ($page->parents()->has($this->id()) === true) { + return true; + } } return false; @@ -733,6 +765,8 @@ class Page extends ModelWithContent /** * Checks if the page is not a draft. + * + * @return bool */ public function isPublished(): bool { @@ -741,7 +775,8 @@ class Page extends ModelWithContent /** * Check if the page can be read by the current user - * @todo Deprecate `read` option in v5 and make the necessary changes for `access` and `list` options. + * + * @return bool */ public function isReadable(): bool { @@ -749,11 +784,17 @@ class Page extends ModelWithContent $template = $this->intendedTemplate()->name(); - return $readable[$template] ??= $this->permissions()->can('read'); + if (isset($readable[$template]) === true) { + return $readable[$template]; + } + + return $readable[$template] = $this->permissions()->can('read'); } /** * Checks if the page is sortable + * + * @return bool */ public function isSortable(): bool { @@ -762,21 +803,26 @@ class Page extends ModelWithContent /** * Checks if the page has no sorting number + * + * @return bool */ public function isUnlisted(): bool { - return $this->isPublished() && $this->num() === null; + return $this->isListed() === false; } /** * Checks if the page access is verified. * This is only used for drafts so far. + * * @internal + * @param string|null $token + * @return bool */ - public function isVerified(string $token = null): bool + public function isVerified(string $token = null) { if ( - $this->isPublished() === true && + $this->isDraft() === false && $this->parents()->findBy('status', 'draft') === null ) { return true; @@ -791,7 +837,9 @@ class Page extends ModelWithContent /** * Returns the root to the media folder for the page + * * @internal + * @return string */ public function mediaRoot(): string { @@ -800,7 +848,9 @@ class Page extends ModelWithContent /** * The page's base URL for any files + * * @internal + * @return string */ public function mediaUrl(): string { @@ -809,17 +859,18 @@ class Page extends ModelWithContent /** * Creates a page model if it has been registered + * * @internal + * @param string $name + * @param array $props + * @return static */ - public static function model(string $name, array $props = []): static + public static function model(string $name, array $props = []) { - $class = static::$models[$name] ?? null; - $class ??= static::$models['default'] ?? null; - - if ($class !== null) { + if ($class = (static::$models[$name] ?? null)) { $object = new $class($props); - if ($object instanceof self) { + if (is_a($object, 'Kirby\Cms\Page') === true) { return $object; } } @@ -829,74 +880,85 @@ class Page extends ModelWithContent /** * Returns the last modification date of the page + * + * @param string|null $format + * @param string|null $handler + * @param string|null $languageCode + * @return int|string */ - public function modified( - string|null $format = null, - string|null $handler = null, - string|null $languageCode = null - ): int|string|false|null { - $identifier = $this->isDraft() === true ? 'changes' : 'published'; - - $modified = $this->storage()->modified( - $identifier, - $languageCode + public function modified(string $format = null, string $handler = null, string $languageCode = null) + { + return F::modified( + $this->contentFile($languageCode), + $format, + $handler ?? $this->kirby()->option('date.handler', 'date') ); - - if ($modified === null) { - return null; - } - - return Str::date($modified, $format, $handler); } /** * Returns the sorting number + * + * @return int|null */ - public function num(): int|null + public function num(): ?int { return $this->num; } /** * Returns the panel info object + * + * @return \Kirby\Panel\Page */ - public function panel(): Panel + public function panel() { return new Panel($this); } /** * Returns the parent Page object + * + * @return \Kirby\Cms\Page|null */ - public function parent(): Page|null + public function parent() { return $this->parent; } /** * Returns the parent id, if a parent exists + * * @internal + * @return string|null */ - public function parentId(): string|null + public function parentId(): ?string { - return $this->parent()?->id(); + if ($parent = $this->parent()) { + return $parent->id(); + } + + return null; } /** * Returns the parent model, * which can either be another Page * or the Site + * * @internal + * @return \Kirby\Cms\Page|\Kirby\Cms\Site */ - public function parentModel(): Page|Site + public function parentModel() { return $this->parent() ?? $this->site(); } /** * Returns a list of all parents and their parents recursively + * + * @return \Kirby\Cms\Pages */ - public function parents(): Pages + public function parents() { $parents = new Pages(); $page = $this->parent(); @@ -909,28 +971,23 @@ class Page extends ModelWithContent return $parents; } - /** - * Return the permanent URL to the page using its UUID - * @since 3.8.0 - */ - public function permalink(): string|null - { - return $this->uuid()?->url(); - } - /** * Returns the permissions object for this page + * + * @return \Kirby\Cms\PagePermissions */ - public function permissions(): PagePermissions + public function permissions() { return new PagePermissions($this); } /** * Draft preview Url + * * @internal + * @return string|null */ - public function previewUrl(): string|null + public function previewUrl(): ?string { $preview = $this->blueprint()->preview(); @@ -938,10 +995,11 @@ class Page extends ModelWithContent return null; } - $url = match ($preview) { - true => $this->url(), - default => $preview - }; + if ($preview === true) { + $url = $this->url(); + } else { + $url = $preview; + } if ($this->isDraft() === true) { $uri = new Uri($url); @@ -960,7 +1018,9 @@ class Page extends ModelWithContent * render a content representation instead of * the default template. * + * @param array $data * @param string $contentType + * @return string * @throws \Kirby\Exception\NotFoundException If the default template cannot be found */ public function render(array $data = [], $contentType = 'html'): string @@ -1006,24 +1066,9 @@ class Page extends ModelWithContent $kirby->data = $this->controller($data, $contentType); - // trigger before hook and apply for `data` - $kirby->data = $kirby->apply('page.render:before', [ - 'contentType' => $contentType, - 'data' => $kirby->data, - 'page' => $this - ], 'data'); - // render the page $html = $template->render($kirby->data); - // trigger after hook and apply for `html` - $html = $kirby->apply('page.render:after', [ - 'contentType' => $contentType, - 'data' => $kirby->data, - 'html' => $html, - 'page' => $this - ], 'html'); - // cache the result $response = $kirby->response(); if ($cache !== null && $response->cache() === true) { @@ -1041,9 +1086,11 @@ class Page extends ModelWithContent /** * @internal + * @param mixed $type + * @return \Kirby\Cms\Template * @throws \Kirby\Exception\NotFoundException If the content representation cannot be found */ - public function representation(mixed $type): Template + public function representation($type) { $kirby = $this->kirby(); $template = $this->template(); @@ -1059,6 +1106,8 @@ class Page extends ModelWithContent /** * Returns the absolute root to the page directory * No matter if it exists or not. + * + * @return string */ public function root(): string { @@ -1069,16 +1118,22 @@ class Page extends ModelWithContent * Returns the PageRules class instance * which is being used in various methods * to check for valid actions and input. + * + * @return \Kirby\Cms\PageRules */ - protected function rules(): PageRules + protected function rules() { return new PageRules(); } /** * Search all pages within the current page + * + * @param string|null $query + * @param array $params + * @return \Kirby\Cms\Pages */ - public function search(string|null $query = null, string|array $params = []): Pages + public function search(string $query = null, $params = []) { return $this->index()->search($query, $params); } @@ -1086,9 +1141,10 @@ class Page extends ModelWithContent /** * Sets the Blueprint object * + * @param array|null $blueprint * @return $this */ - protected function setBlueprint(array $blueprint = null): static + protected function setBlueprint(array $blueprint = null) { if ($blueprint !== null) { $blueprint['model'] = $this; @@ -1099,11 +1155,86 @@ class Page extends ModelWithContent } /** - * Sets the intended template + * Sets the dirname manually, which works + * more reliable in connection with the inventory + * than computing the dirname afterwards * + * @param string|null $dirname * @return $this */ - protected function setTemplate(string $template = null): static + protected function setDirname(string $dirname = null) + { + $this->dirname = $dirname; + return $this; + } + + /** + * Sets the draft flag + * + * @param bool $isDraft + * @return $this + */ + protected function setIsDraft(bool $isDraft = null) + { + $this->isDraft = $isDraft ?? false; + return $this; + } + + /** + * Sets the sorting number + * + * @param int|null $num + * @return $this + */ + protected function setNum(int $num = null) + { + $this->num = $num === null ? $num : (int)$num; + return $this; + } + + /** + * Sets the parent page object + * + * @param \Kirby\Cms\Page|null $parent + * @return $this + */ + protected function setParent(Page $parent = null) + { + $this->parent = $parent; + return $this; + } + + /** + * Sets the absolute path to the page + * + * @param string|null $root + * @return $this + */ + protected function setRoot(string $root = null) + { + $this->root = $root; + return $this; + } + + /** + * Sets the required Page slug + * + * @param string $slug + * @return $this + */ + protected function setSlug(string $slug) + { + $this->slug = $slug; + return $this; + } + + /** + * Sets the intended template + * + * @param string|null $template + * @return $this + */ + protected function setTemplate(string $template = null) { if ($template !== null) { $this->intendedTemplate = $this->kirby()->template($template); @@ -1115,9 +1246,10 @@ class Page extends ModelWithContent /** * Sets the Url * + * @param string|null $url * @return $this */ - protected function setUrl(string $url = null): static + protected function setUrl(string $url = null) { if (is_string($url) === true) { $url = rtrim($url, '/'); @@ -1129,17 +1261,20 @@ class Page extends ModelWithContent /** * Returns the slug of the page + * + * @param string|null $languageCode + * @return string */ public function slug(string $languageCode = null): string { if ($this->kirby()->multilang() === true) { - $languageCode ??= $this->kirby()->languageCode(); + if ($languageCode === null) { + $languageCode = $this->kirby()->languageCode(); + } + $defaultLanguageCode = $this->kirby()->defaultLanguage()->code(); - if ( - $languageCode !== $defaultLanguageCode && - $translation = $this->translations()->find($languageCode) - ) { + if ($languageCode !== $defaultLanguageCode && $translation = $this->translations()->find($languageCode)) { return $translation->slug() ?? $this->slug; } } @@ -1150,6 +1285,8 @@ class Page extends ModelWithContent /** * Returns the page status, which * can be `draft`, `listed` or `unlisted` + * + * @return string */ public function status(): string { @@ -1166,8 +1303,10 @@ class Page extends ModelWithContent /** * Returns the final template + * + * @return \Kirby\Cms\Template */ - public function template(): Template + public function template() { if ($this->template !== null) { return $this->template; @@ -1184,8 +1323,10 @@ class Page extends ModelWithContent /** * Returns the title field or the slug as fallback + * + * @return \Kirby\Cms\Field */ - public function title(): Field + public function title() { return $this->content()->get('title')->or($this->slug()); } @@ -1193,35 +1334,38 @@ class Page extends ModelWithContent /** * Converts the most important * properties to array + * + * @return array */ public function toArray(): array { - return array_merge(parent::toArray(), [ - 'children' => $this->children()->keys(), - 'files' => $this->files()->keys(), - 'id' => $this->id(), - 'mediaUrl' => $this->mediaUrl(), - 'mediaRoot' => $this->mediaRoot(), - 'num' => $this->num(), - 'parent' => $this->parent()?->id(), - 'slug' => $this->slug(), - 'template' => $this->template(), - 'uid' => $this->uid(), - 'uri' => $this->uri(), - 'url' => $this->url() - ]); + return [ + 'children' => $this->children()->keys(), + 'content' => $this->content()->toArray(), + 'files' => $this->files()->keys(), + 'id' => $this->id(), + 'mediaUrl' => $this->mediaUrl(), + 'mediaRoot' => $this->mediaRoot(), + 'num' => $this->num(), + 'parent' => $this->parent() ? $this->parent()->id() : null, + 'slug' => $this->slug(), + 'template' => $this->template(), + 'translations' => $this->translations()->toArray(), + 'uid' => $this->uid(), + 'uri' => $this->uri(), + 'url' => $this->url() + ]; } /** * Returns a verification token, which * is used for the draft authentication + * + * @return string */ protected function token(): string { - return $this->kirby()->contentToken( - $this, - $this->id() . $this->template() - ); + return $this->kirby()->contentToken($this, $this->id() . $this->template()); } /** @@ -1232,6 +1376,7 @@ class Page extends ModelWithContent * can be translated. * * @see self::slug() + * @return string */ public function uid(): string { @@ -1241,6 +1386,9 @@ class Page extends ModelWithContent /** * The uri is the same as the id, except * that it will be translated in multi-language setups + * + * @param string|null $languageCode + * @return string */ public function uri(string $languageCode = null): string { @@ -1256,15 +1404,16 @@ class Page extends ModelWithContent * Returns the Url * * @param array|string|null $options + * @return string */ public function url($options = null): string { if ($this->kirby()->multilang() === true) { if (is_string($options) === true) { return $this->urlForLanguage($options); + } else { + return $this->urlForLanguage(null, $options); } - - return $this->urlForLanguage(null, $options); } if ($options !== null) { @@ -1282,9 +1431,9 @@ class Page extends ModelWithContent if ($parent = $this->parent()) { if ($parent->isHomePage() === true) { return $this->url = $this->kirby()->url('base') . '/' . $parent->uid() . '/' . $this->uid(); + } else { + return $this->url = $this->parent()->url() . '/' . $this->uid(); } - - return $this->url = $this->parent()->url() . '/' . $this->uid(); } return $this->url = $this->kirby()->url('base') . '/' . $this->uid(); @@ -1295,11 +1444,11 @@ class Page extends ModelWithContent * * @internal * @param string|null $language + * @param array|null $options + * @return string */ - public function urlForLanguage( - $language = null, - array $options = null - ): string { + public function urlForLanguage($language = null, array $options = null): string + { if ($options !== null) { return Url::to($this->urlForLanguage($language), $options); } @@ -1311,11 +1460,104 @@ class Page extends ModelWithContent if ($parent = $this->parent()) { if ($parent->isHomePage() === true) { return $this->url = $this->site()->urlForLanguage($language) . '/' . $parent->slug($language) . '/' . $this->slug($language); + } else { + return $this->url = $this->parent()->urlForLanguage($language) . '/' . $this->slug($language); } - - return $this->url = $this->parent()->urlForLanguage($language) . '/' . $this->slug($language); } return $this->url = $this->site()->urlForLanguage($language) . '/' . $this->slug($language); } + + + /** + * Deprecated! + */ + + /** + * Provides a kirbytag or markdown + * tag for the page, which will be + * used in the panel, when the page + * gets dragged onto a textarea + * + * @deprecated 3.6.0 Use `->panel()->dragText()` instead + * @todo Remove in 3.8.0 + * + * @internal + * @param string|null $type (null|auto|kirbytext|markdown) + * @return string + * @codeCoverageIgnore + */ + public function dragText(string $type = null): string + { + Helpers::deprecated('Cms\Page::dragText() has been deprecated and will be removed in Kirby 3.8.0. Use $page->panel()->dragText() instead.'); + return $this->panel()->dragText($type); + } + + /** + * Returns the escaped Id, which is + * used in the panel to make routing work properly + * + * @deprecated 3.6.0 Use `->panel()->id()` instead + * @todo Remove in 3.8.0 + * + * @internal + * @return string + * @codeCoverageIgnore + */ + public function panelId(): string + { + Helpers::deprecated('Cms\Page::panelId() has been deprecated and will be removed in Kirby 3.8.0. Use $page->panel()->id() instead.'); + return $this->panel()->id(); + } + + /** + * Returns the full path without leading slash + * + * @deprecated 3.6.0 Use `->panel()->path()` instead + * @todo Remove in 3.8.0 + * + * @internal + * @return string + * @codeCoverageIgnore + */ + public function panelPath(): string + { + Helpers::deprecated('Cms\Page::panelPath() has been deprecated and will be removed in Kirby 3.8.0. Use $page->panel()->path() instead.'); + return $this->panel()->path(); + } + + /** + * Prepares the response data for page pickers + * and page fields + * + * @deprecated 3.6.0 Use `->panel()->pickerData()` instead + * @todo Remove in 3.8.0 + * + * @param array|null $params + * @return array + * @codeCoverageIgnore + */ + public function panelPickerData(array $params = []): array + { + Helpers::deprecated('Cms\Page::panelPickerData() has been deprecated and will be removed in Kirby 3.8.0. Use $page->panel()->pickerData() instead.'); + return $this->panel()->pickerData($params); + } + + /** + * Returns the url to the editing view + * in the panel + * + * @deprecated 3.6.0 Use `->panel()->url()` instead + * @todo Remove in 3.8.0 + * + * @internal + * @param bool $relative + * @return string + * @codeCoverageIgnore + */ + public function panelUrl(bool $relative = false): string + { + Helpers::deprecated('Cms\Page::panelUrl() has been deprecated and will be removed in Kirby 3.8.0. Use $page->panel()->url() instead.'); + return $this->panel()->url($relative); + } } diff --git a/kirby/src/Cms/PageActions.php b/kirby/src/Cms/PageActions.php index ac5a9ef..ec9115c 100644 --- a/kirby/src/Cms/PageActions.php +++ b/kirby/src/Cms/PageActions.php @@ -8,12 +8,11 @@ use Kirby\Exception\InvalidArgumentException; use Kirby\Exception\LogicException; use Kirby\Exception\NotFoundException; use Kirby\Filesystem\Dir; +use Kirby\Filesystem\F; use Kirby\Form\Form; use Kirby\Toolkit\A; use Kirby\Toolkit\I18n; use Kirby\Toolkit\Str; -use Kirby\Uuid\Uuid; -use Kirby\Uuid\Uuids; /** * PageActions @@ -26,76 +25,6 @@ use Kirby\Uuid\Uuids; */ trait PageActions { - /** - * Adapts necessary modifications which page uuid, page slug and files uuid - * of copy objects for single or multilang environments - * @internal - */ - protected function adaptCopy(Page $copy, bool $files = false, bool $children = false): Page - { - if ($this->kirby()->multilang() === true) { - foreach ($this->kirby()->languages() as $language) { - // overwrite with new UUID for the page and files - // for default language (remove old, add new) - if ( - Uuids::enabled() === true && - $language->isDefault() === true - ) { - $copy = $copy->save(['uuid' => Uuid::generate()], $language->code()); - - // regenerate UUIDs of page files - if ($files !== false) { - foreach ($copy->files() as $file) { - $file->save(['uuid' => Uuid::generate()], $language->code()); - } - } - - // regenerate UUIDs of all page children - if ($children !== false) { - foreach ($copy->index(true) as $child) { - // always adapt files of subpages as they are currently always copied; - // but don't adapt children because we already operate on the index - $this->adaptCopy($child, true); - } - } - } - - // remove all translated slugs - if ( - $language->isDefault() === false && - $copy->translation($language)->exists() === true - ) { - $copy = $copy->save(['slug' => null], $language->code()); - } - } - - return $copy; - } - - // overwrite with new UUID for the page and files (remove old, add new) - if (Uuids::enabled() === true) { - $copy = $copy->save(['uuid' => Uuid::generate()]); - - // regenerate UUIDs of page files - if ($files !== false) { - foreach ($copy->files() as $file) { - $file->save(['uuid' => Uuid::generate()]); - } - } - - // regenerate UUIDs of all page children - if ($children !== false) { - foreach ($copy->index(true) as $child) { - // always adapt files of subpages as they are currently always copied; - // but don't adapt children because we already operate on the index - $this->adaptCopy($child, true); - } - } - } - - return $copy; - } - /** * Changes the sorting number. * The sorting number must already be correct @@ -103,10 +32,11 @@ trait PageActions * This only affects this page, * siblings will not be resorted. * + * @param int|null $num * @return $this|static * @throws \Kirby\Exception\LogicException If a draft is being sorted or the directory cannot be moved */ - public function changeNum(int|null $num = null): static + public function changeNum(int $num = null) { if ($this->isDraft() === true) { throw new LogicException('Drafts cannot change their sorting number'); @@ -129,7 +59,7 @@ trait PageActions if (Dir::move($oldPage->root(), $newPage->root()) === true) { // Updates the root path of the old page with the root path // of the moved new page to use fly actions on old page in loop - $oldPage->root = $newPage->root(); + $oldPage->setRoot($newPage->root()); } else { throw new LogicException('The page directory cannot be moved'); } @@ -145,21 +75,23 @@ trait PageActions /** * Changes the slug/uid of the page * + * @param string $slug + * @param string|null $languageCode * @return $this|static * @throws \Kirby\Exception\LogicException If the directory cannot be moved */ - public function changeSlug( - string $slug, - string|null $languageCode = null - ): static { + public function changeSlug(string $slug, string $languageCode = null) + { // always sanitize the slug $slug = Str::slug($slug); // in multi-language installations the slug for the non-default // languages is stored in the text file. The changeSlugForLanguage // method takes care of that. - if ($this->kirby()->language($languageCode)?->isDefault() === false) { - return $this->changeSlugForLanguage($slug, $languageCode); + if ($language = $this->kirby()->language($languageCode)) { + if ($language->isDefault() === false) { + return $this->changeSlugForLanguage($slug, $languageCode); + } } // if the slug stays exactly the same, @@ -176,12 +108,11 @@ trait PageActions 'root' => null ]); - // clear UUID cache recursively (for children and files as well) - $oldPage->uuid()?->clear(true); - if ($oldPage->exists() === true) { // remove the lock of the old page - $oldPage->lock()?->remove(); + if ($lock = $oldPage->lock()) { + $lock->remove(); + } // actually move stuff on disk if (Dir::move($oldPage->root(), $newPage->root()) !== true) { @@ -204,13 +135,14 @@ trait PageActions /** * Change the slug for a specific language * + * @param string $slug + * @param string|null $languageCode + * @return static * @throws \Kirby\Exception\NotFoundException If the language for the given language code cannot be found * @throws \Kirby\Exception\InvalidArgumentException If the slug for the default language is being changed */ - protected function changeSlugForLanguage( - string $slug, - string|null $languageCode = null - ): static { + protected function changeSlugForLanguage(string $slug, string $languageCode = null) + { $language = $this->kirby()->language($languageCode); if (!$language) { @@ -221,7 +153,7 @@ trait PageActions throw new InvalidArgumentException('Use the changeSlug method to change the slug for the default language'); } - $arguments = ['page' => $this, 'slug' => $slug, 'languageCode' => $language->code()]; + $arguments = ['page' => $this, 'slug' => $slug, 'languageCode' => $languageCode]; return $this->commit('changeSlug', $arguments, function ($page, $slug, $languageCode) { // remove the slug if it's the same as the folder name if ($slug === $page->uid()) { @@ -245,19 +177,27 @@ trait PageActions * * @param string $status "draft", "listed" or "unlisted" * @param int|null $position Optional sorting number + * @return static * @throws \Kirby\Exception\InvalidArgumentException If an invalid status is being passed */ - public function changeStatus(string $status, int|null $position = null): static + public function changeStatus(string $status, int $position = null) { - return match ($status) { - 'draft' => $this->changeStatusToDraft(), - 'listed' => $this->changeStatusToListed($position), - 'unlisted' => $this->changeStatusToUnlisted(), - default => throw new InvalidArgumentException('Invalid status: ' . $status) - }; + switch ($status) { + case 'draft': + return $this->changeStatusToDraft(); + case 'listed': + return $this->changeStatusToListed($position); + case 'unlisted': + return $this->changeStatusToUnlisted(); + default: + throw new InvalidArgumentException('Invalid status: ' . $status); + } } - protected function changeStatusToDraft(): static + /** + * @return static + */ + protected function changeStatusToDraft() { $arguments = ['page' => $this, 'status' => 'draft', 'position' => null]; $page = $this->commit( @@ -270,9 +210,10 @@ trait PageActions } /** + * @param int|null $position * @return $this|static */ - protected function changeStatusToListed(int|null $position = null): static + protected function changeStatusToListed(int $position = null) { // create a sorting number for the page $num = $this->createNum($position); @@ -282,16 +223,10 @@ trait PageActions return $this; } - $page = $this->commit( - 'changeStatus', - [ - 'page' => $this, - 'status' => 'listed', - 'position' => $num - ], - fn ($page, $status, $position) => - $page->publish()->changeNum($position) - ); + $arguments = ['page' => $this, 'status' => 'listed', 'position' => $num]; + $page = $this->commit('changeStatus', $arguments, function ($page, $status, $position) { + return $page->publish()->changeNum($position); + }); if ($this->blueprint()->num() === 'default') { $page->resortSiblingsAfterListing($num); @@ -303,21 +238,16 @@ trait PageActions /** * @return $this|static */ - protected function changeStatusToUnlisted(): static + protected function changeStatusToUnlisted() { if ($this->status() === 'unlisted') { return $this; } - $page = $this->commit( - 'changeStatus', - [ - 'page' => $this, - 'status' => 'unlisted', - 'position' => null - ], - fn ($page) => $page->publish()->changeNum(null) - ); + $arguments = ['page' => $this, 'status' => 'unlisted', 'position' => null]; + $page = $this->commit('changeStatus', $arguments, function ($page) { + return $page->publish()->changeNum(null); + }); $this->resortSiblingsAfterUnlisting(); @@ -329,9 +259,10 @@ trait PageActions * collection. Siblings will be resorted. If the page * status isn't yet `listed`, it will be changed to it. * + * @param int|null $position * @return $this|static */ - public function changeSort(int|null $position = null): static + public function changeSort(int $position = null) { return $this->changeStatus('listed', $position); } @@ -339,18 +270,51 @@ trait PageActions /** * Changes the page template * + * @param string $template * @return $this|static * @throws \Kirby\Exception\LogicException If the textfile cannot be renamed/moved */ - public function changeTemplate(string $template): static + public function changeTemplate(string $template) { if ($template === $this->intendedTemplate()->name()) { return $this; } return $this->commit('changeTemplate', ['page' => $this, 'template' => $template], function ($oldPage, $template) { - // convert for new template/blueprint - $page = $oldPage->convertTo($template); + if ($this->kirby()->multilang() === true) { + $newPage = $this->clone([ + 'template' => $template + ]); + + foreach ($this->kirby()->languages()->codes() as $code) { + if ($oldPage->translation($code)->exists() !== true) { + continue; + } + + $content = $oldPage->content($code)->convertTo($template); + + if (F::remove($oldPage->contentFile($code)) !== true) { + throw new LogicException('The old text file could not be removed'); + } + + // save the language file + $newPage->save($content, $code); + } + + // return a fresh copy of the object + $page = $newPage->clone(); + } else { + $newPage = $this->clone([ + 'content' => $this->content()->convertTo($template), + 'template' => $template + ]); + + if (F::remove($oldPage->contentFile()) !== true) { + throw new LogicException('The old text file could not be removed'); + } + + $page = $newPage->save(); + } // update the parent collection static::updateParentCollections($page, 'set'); @@ -361,24 +325,14 @@ trait PageActions /** * Change the page title + * + * @param string $title + * @param string|null $languageCode + * @return static */ - public function changeTitle( - string $title, - string|null $languageCode = null - ): static { - // if the `$languageCode` argument is not set and is not the default language - // the `$languageCode` argument is sent as the current language - if ( - $languageCode === null && - $language = $this->kirby()->language() - ) { - if ($language->isDefault() === false) { - $languageCode = $language->code(); - } - } - + public function changeTitle(string $title, string $languageCode = null) + { $arguments = ['page' => $this, 'title' => $title, 'languageCode' => $languageCode]; - return $this->commit('changeTitle', $arguments, function ($page, $title, $languageCode) { $page = $page->save(['title' => $title], $languageCode); @@ -397,12 +351,14 @@ trait PageActions * 3. commits the store action * 4. sends the after hook * 5. returns the result + * + * @param string $action + * @param array $arguments + * @param \Closure $callback + * @return mixed */ - protected function commit( - string $action, - array $arguments, - Closure $callback - ): mixed { + protected function commit(string $action, array $arguments, Closure $callback) + { $old = $this->hardcopy(); $kirby = $this->kirby(); $argumentValues = array_values($arguments); @@ -430,9 +386,11 @@ trait PageActions /** * Copies the page to a new parent * + * @param array $options + * @return \Kirby\Cms\Page * @throws \Kirby\Exception\DuplicateException If the page already exists */ - public function copy(array $options = []): static + public function copy(array $options = []) { $slug = $options['slug'] ?? $this->slug(); $isDraft = $options['isDraft'] ?? $this->isDraft(); @@ -471,8 +429,7 @@ trait PageActions $ignore[] = $file->root(); // append all content files - array_push($ignore, ...$file->storage()->contentFiles('published')); - array_push($ignore, ...$file->storage()->contentFiles('changes')); + array_push($ignore, ...$file->contentFiles()); } } @@ -480,8 +437,14 @@ trait PageActions $copy = $parentModel->clone()->findPageOrDraft($slug); - // normalize copy object - $copy = $this->adaptCopy($copy, $files, $children); + // remove all translated slugs + if ($this->kirby()->multilang() === true) { + foreach ($this->kirby()->languages() as $language) { + if ($language->isDefault() === false && $copy->translation($language)->exists() === true) { + $copy = $copy->save(['slug' => null], $language->code()); + } + } + } // add copy to siblings static::updateParentCollections($copy, 'append', $parentModel); @@ -491,62 +454,45 @@ trait PageActions /** * Creates and stores a new page + * + * @param array $props + * @return static */ - public static function create(array $props): Page + public static function create(array $props) { // clean up the slug - $props['slug'] = Str::slug($props['slug'] ?? $props['content']['title'] ?? null); - $props['template'] = $props['model'] = strtolower($props['template'] ?? 'default'); - $props['isDraft'] ??= $props['draft'] ?? true; - - // make sure that a UUID gets generated and - // added to content right away - $props['content'] ??= []; - - if (Uuids::enabled() === true) { - $props['content']['uuid'] ??= Uuid::generate(); - } + $props['slug'] = Str::slug($props['slug'] ?? $props['content']['title'] ?? null); + $props['template'] = $props['model'] = strtolower($props['template'] ?? 'default'); + $props['isDraft'] = ($props['draft'] ?? true); // create a temporary page object $page = Page::factory($props); - // always create pages in the default language - if ($page->kirby()->multilang() === true) { - $languageCode = $page->kirby()->defaultLanguage()->code(); - } else { - $languageCode = null; - } - // create a form for the page - // use always default language to fill form with default values - $form = Form::for( - $page, - [ - 'language' => $languageCode, - 'values' => $props['content'] - ] - ); + $form = Form::for($page, [ + 'values' => $props['content'] ?? [] + ]); // inject the content $page = $page->clone(['content' => $form->strings(true)]); // run the hooks and creation action - $page = $page->commit( - 'create', - [ - 'page' => $page, - 'input' => $props - ], - function ($page, $props) use ($languageCode) { - // write the content file - $page = $page->save($page->content()->toArray(), $languageCode); - - // flush the parent cache to get children and drafts right - static::updateParentCollections($page, 'append'); - - return $page; + $page = $page->commit('create', ['page' => $page, 'input' => $props], function ($page, $props) { + // always create pages in the default language + if ($page->kirby()->multilang() === true) { + $languageCode = $page->kirby()->defaultLanguage()->code(); + } else { + $languageCode = null; } - ); + + // write the content file + $page = $page->save($page->content()->toArray(), $languageCode); + + // flush the parent cache to get children and drafts right + static::updateParentCollections($page, 'append'); + + return $page; + }); // publish the new page if a number is given if (isset($props['num']) === true) { @@ -558,8 +504,11 @@ trait PageActions /** * Creates a child of the current page + * + * @param array $props + * @return static */ - public function createChild(array $props): Page + public function createChild(array $props) { $props = array_merge($props, [ 'url' => null, @@ -568,13 +517,16 @@ trait PageActions 'site' => $this->site(), ]); - $modelClass = Page::$models[$props['template'] ?? null] ?? Page::class; + $modelClass = Page::$models[$props['template']] ?? Page::class; return $modelClass::create($props); } /** * Create the sorting number for the page * depending on the blueprint settings + * + * @param int|null $num + * @return int */ public function createNum(int $num = null): int { @@ -602,7 +554,9 @@ trait PageActions ->count(); // default positioning at the end - $num ??= $max; + if ($num === null) { + $num = $max; + } // avoid zeros or negative numbers if ($num < 1) { @@ -632,13 +586,13 @@ trait PageActions /** * Deletes the page + * + * @param bool $force + * @return bool */ public function delete(bool $force = false): bool { return $this->commit('delete', ['page' => $this, 'force' => $force], function ($page, $force) { - // clear UUID cache - $page->uuid()?->clear(); - // delete all files individually foreach ($page->files() as $file) { $file->delete(); @@ -681,8 +635,12 @@ trait PageActions /** * Duplicates the page with the given * slug and optionally copies all files + * + * @param string|null $slug + * @param array $options + * @return \Kirby\Cms\Page */ - public function duplicate(string|null $slug = null, array $options = []): static + public function duplicate(string $slug = null, array $options = []) { // create the slug for the duplicate $slug = Str::slug($slug ?? $this->slug() . '-' . Str::slug(I18n::translate('page.duplicate.appendix'))); @@ -710,60 +668,11 @@ trait PageActions }); } - /** - * Moves the page to a new parent if the - * new parent accepts the page type - */ - public function move(Site|Page $parent): Page - { - // nothing to move - if ($this->parentModel()->is($parent) === true) { - return $this; - } - - $arguments = [ - 'page' => $this, - 'parent' => $parent - ]; - - return $this->commit('move', $arguments, function ($page, $parent) { - // remove the uuid cache for this page - $page->uuid()?->clear(true); - - // move drafts into the drafts folder of the parent - if ($page->isDraft() === true) { - $newRoot = $parent->root() . '/_drafts/' . $page->dirname(); - } else { - $newRoot = $parent->root() . '/' . $page->dirname(); - } - - // try to move the page directory on disk - if (Dir::move($page->root(), $newRoot) !== true) { - throw new LogicException([ - 'key' => 'page.move.directory' - ]); - } - - // flush all collection caches to be sure that - // the new child is included afterwards - $parent->purge(); - - // double-check if the new child can actually be found - if (!$newPage = $parent->childrenAndDrafts()->find($page->slug())) { - throw new LogicException([ - 'key' => 'page.move.notFound' - ]); - } - - return $newPage; - }); - } - /** * @return $this|static * @throws \Kirby\Exception\LogicException If the folder cannot be moved */ - public function publish(): static + public function publish() { if ($this->isDraft() === false) { return $this; @@ -804,24 +713,25 @@ trait PageActions /** * Clean internal caches - * * @return $this */ - public function purge(): static + public function purge() { - parent::purge(); - $this->blueprint = null; $this->children = null; $this->childrenAndDrafts = null; + $this->content = null; $this->drafts = null; $this->files = null; $this->inventory = null; + $this->translations = null; return $this; } /** + * @param int|null $position + * @return bool * @throws \Kirby\Exception\LogicException If the page is not included in the siblings collection */ protected function resortSiblingsAfterListing(int $position = null): bool @@ -855,9 +765,9 @@ trait PageActions foreach ($sorted as $key => $id) { if ($id === $this->id()) { continue; + } elseif ($sibling = $siblings->get($id)) { + $sibling->changeNum($key + 1); } - - $siblings->get($id)?->changeNum($key + 1); } $parent = $this->parentModel(); @@ -868,7 +778,7 @@ trait PageActions } /** - * @internal + * @return bool */ public function resortSiblingsAfterUnlisting(): bool { @@ -893,23 +803,6 @@ trait PageActions return true; } - /** - * Stores the content on disk - * @internal - */ - public function save( - array|null $data = null, - string|null $languageCode = null, - bool $overwrite = false - ): static { - $page = parent::save($data, $languageCode, $overwrite); - - // overwrite the updated page in the parent collection - static::updateParentCollections($page, 'set'); - - return $page; - } - /** * Convert a page from listed or * unlisted to draft. @@ -917,7 +810,7 @@ trait PageActions * @return $this|static * @throws \Kirby\Exception\LogicException If the folder cannot be moved */ - public function unpublish(): static + public function unpublish() { if ($this->isDraft() === true) { return $this; @@ -954,12 +847,14 @@ trait PageActions /** * Updates the page data + * + * @param array|null $input + * @param string|null $languageCode + * @param bool $validate + * @return static */ - public function update( - array|null $input = null, - string|null $languageCode = null, - bool $validate = false - ): static { + public function update(array $input = null, string $languageCode = null, bool $validate = false) + { if ($this->isDraft() === true) { $validate = false; } @@ -967,10 +862,7 @@ trait PageActions $page = parent::update($input, $languageCode, $validate); // if num is created from page content, update num on content update - if ( - $page->isListed() === true && - in_array($page->blueprint()->num(), ['zero', 'default']) === false - ) { + if ($page->isListed() === true && in_array($page->blueprint()->num(), ['zero', 'default']) === false) { $page = $page->changeNum($page->createNum()); } @@ -987,12 +879,10 @@ trait PageActions * @param \Kirby\Cms\Page $page * @param string $method Method to call on the parent collections * @param \Kirby\Cms\Page|null $parentMdel + * @return void */ - protected static function updateParentCollections( - $page, - string $method, - $parentModel = null - ): void { + protected static function updateParentCollections($page, string $method, $parentModel = null): void + { $parentModel ??= $page->parentModel(); // method arguments depending on the called method diff --git a/kirby/src/Cms/PageBlueprint.php b/kirby/src/Cms/PageBlueprint.php index 79be695..87e4937 100644 --- a/kirby/src/Cms/PageBlueprint.php +++ b/kirby/src/Cms/PageBlueprint.php @@ -16,6 +16,8 @@ class PageBlueprint extends Blueprint /** * Creates a new page blueprint object * with the given props + * + * @param array $props */ public function __construct(array $props) { @@ -26,7 +28,6 @@ class PageBlueprint extends Blueprint $this->props['options'] ?? true, // defaults [ - 'access' => null, 'changeSlug' => null, 'changeStatus' => null, 'changeTemplate' => null, @@ -34,10 +35,8 @@ class PageBlueprint extends Blueprint 'create' => null, 'delete' => null, 'duplicate' => null, - 'list' => null, - 'move' => null, - 'preview' => null, 'read' => null, + 'preview' => null, 'sort' => null, 'update' => null, ], @@ -59,6 +58,8 @@ class PageBlueprint extends Blueprint /** * Returns the page numbering mode + * + * @return string */ public function num(): string { @@ -69,6 +70,7 @@ class PageBlueprint extends Blueprint * Normalizes the ordering number * * @param mixed $num + * @return string */ protected function normalizeNum($num): string { @@ -77,13 +79,18 @@ class PageBlueprint extends Blueprint 'sort' => 'default', ]; - return $aliases[$num] ?? $num; + if (isset($aliases[$num]) === true) { + return $aliases[$num]; + } + + return $num; } /** * Normalizes the available status options for the page * * @param mixed $status + * @return array */ protected function normalizeStatus($status): array { @@ -137,7 +144,9 @@ class PageBlueprint extends Blueprint } // also make sure to have the text field set - $status[$key]['text'] ??= null; + if (isset($status[$key]['text']) === false) { + $status[$key]['text'] = null; + } // translate text and label if necessary $status[$key]['label'] = $this->i18n($status[$key]['label'], $status[$key]['label']); @@ -160,6 +169,8 @@ class PageBlueprint extends Blueprint /** * Returns the options object * that handles page options and permissions + * + * @return array */ public function options(): array { @@ -171,8 +182,10 @@ class PageBlueprint extends Blueprint * The preview setting controls the "Open" * button in the panel and redirects it to a * different URL if necessary. + * + * @return string|bool */ - public function preview(): string|bool + public function preview() { $preview = $this->props['options']['preview'] ?? true; @@ -185,6 +198,8 @@ class PageBlueprint extends Blueprint /** * Returns the status array + * + * @return array */ public function status(): array { diff --git a/kirby/src/Cms/PagePermissions.php b/kirby/src/Cms/PagePermissions.php index b4ca118..53fcb84 100644 --- a/kirby/src/Cms/PagePermissions.php +++ b/kirby/src/Cms/PagePermissions.php @@ -13,21 +13,33 @@ namespace Kirby\Cms; */ class PagePermissions extends ModelPermissions { - protected string $category = 'pages'; + /** + * @var string + */ + protected $category = 'pages'; + /** + * @return bool + */ protected function canChangeSlug(): bool { return $this->model->isHomeOrErrorPage() !== true; } + /** + * @return bool + */ protected function canChangeStatus(): bool { return $this->model->isErrorPage() !== true; } + /** + * @return bool + */ protected function canChangeTemplate(): bool { - if ($this->model->isErrorPage() === true) { + if ($this->model->isHomeOrErrorPage() === true) { return false; } @@ -38,16 +50,17 @@ class PagePermissions extends ModelPermissions return true; } + /** + * @return bool + */ protected function canDelete(): bool { return $this->model->isHomeOrErrorPage() !== true; } - protected function canMove(): bool - { - return $this->model->isHomeOrErrorPage() !== true; - } - + /** + * @return bool + */ protected function canSort(): bool { if ($this->model->isErrorPage() === true) { diff --git a/kirby/src/Cms/PagePicker.php b/kirby/src/Cms/PagePicker.php index f8dccf8..802e7e8 100644 --- a/kirby/src/Cms/PagePicker.php +++ b/kirby/src/Cms/PagePicker.php @@ -18,14 +18,25 @@ use Kirby\Exception\InvalidArgumentException; */ class PagePicker extends Picker { - // TODO: null only due to our Properties setters, - // remove once our implementation is better - protected Pages|null $items = null; - protected Pages|null $itemsForQuery = null; - protected Page|Site|null $parent = null; + /** + * @var \Kirby\Cms\Pages + */ + protected $items; + + /** + * @var \Kirby\Cms\Pages + */ + protected $itemsForQuery; + + /** + * @var \Kirby\Cms\Page|\Kirby\Cms\Site|null + */ + protected $parent; /** * Extends the basic defaults + * + * @return array */ public function defaults(): array { @@ -44,8 +55,10 @@ class PagePicker extends Picker * also be any subpage. When a query is given * and subpage navigation is deactivated, * there will be no model available at all. + * + * @return \Kirby\Cms\Page|\Kirby\Cms\Site|null */ - public function model(): Page|Site|null + public function model() { // no subpages navigation = no model if ($this->options['subpages'] === false) { @@ -64,29 +77,38 @@ class PagePicker extends Picker * Returns a model object for the given * query, depending on the parent and subpages * options. + * + * @return \Kirby\Cms\Page|\Kirby\Cms\Site|null */ - public function modelForQuery(): Page|Site|null + public function modelForQuery() { if ($this->options['subpages'] === true && empty($this->options['parent']) === false) { return $this->parent(); } - return $this->items()?->parent(); + if ($items = $this->items()) { + return $items->parent(); + } + + return null; } /** * Returns basic information about the * parent model that is currently selected * in the page picker. + * + * @param \Kirby\Cms\Site|\Kirby\Cms\Page|null + * @return array|null */ - public function modelToArray(Page|Site $model = null): array|null + public function modelToArray($model = null): ?array { if ($model === null) { return null; } // the selected model is the site. there's nothing above - if ($model instanceof Site) { + if (is_a($model, 'Kirby\Cms\Site') === true) { return [ 'id' => null, 'parent' => null, @@ -114,8 +136,10 @@ class PagePicker extends Picker /** * Search all pages for the picker + * + * @return \Kirby\Cms\Pages|null */ - public function items(): Pages|null + public function items() { // cache if ($this->items !== null) { @@ -137,8 +161,8 @@ class PagePicker extends Picker $items = $this->itemsForQuery(); } - // filter protected and hidden pages - $items = $items->filter('isListable', true); + // filter protected pages + $items = $items->filter('isReadable', true); // search $items = $this->search($items); @@ -149,8 +173,10 @@ class PagePicker extends Picker /** * Search for pages by parent + * + * @return \Kirby\Cms\Pages */ - public function itemsForParent(): Pages + public function itemsForParent() { return $this->parent()->children(); } @@ -158,9 +184,10 @@ class PagePicker extends Picker /** * Search for pages by query string * + * @return \Kirby\Cms\Pages * @throws \Kirby\Exception\InvalidArgumentException */ - public function itemsForQuery(): Pages + public function itemsForQuery() { // cache if ($this->itemsForQuery !== null) { @@ -173,13 +200,13 @@ class PagePicker extends Picker // help mitigate some typical query usage issues // by converting site and page objects to proper // pages by returning their children - $items = match (true) { - $items instanceof Site, - $items instanceof Page => $items->children(), - $items instanceof Pages => $items, - - default => throw new InvalidArgumentException('Your query must return a set of pages') - }; + if (is_a($items, 'Kirby\Cms\Site') === true) { + $items = $items->children(); + } elseif (is_a($items, 'Kirby\Cms\Page') === true) { + $items = $items->children(); + } elseif (is_a($items, 'Kirby\Cms\Pages') === false) { + throw new InvalidArgumentException('Your query must return a set of pages'); + } return $this->itemsForQuery = $items; } @@ -189,21 +216,33 @@ class PagePicker extends Picker * The model will be used to fetch * subpages unless there's a specific * query to find pages instead. + * + * @return \Kirby\Cms\Page|\Kirby\Cms\Site */ - public function parent(): Page|Site + public function parent() { - return $this->parent ??= $this->kirby->page($this->options['parent']) ?? $this->site; + if ($this->parent !== null) { + return $this->parent; + } + + return $this->parent = $this->kirby->page($this->options['parent']) ?? $this->site; } /** * Calculates the top-most model (page or site) * that can be accessed when navigating * through pages. + * + * @return \Kirby\Cms\Page|\Kirby\Cms\Site */ - public function start(): Page|Site + public function start() { if (empty($this->options['query']) === false) { - return $this->itemsForQuery()?->parent() ?? $this->site; + if ($items = $this->itemsForQuery()) { + return $items->parent(); + } + + return $this->site; } return $this->site; @@ -213,6 +252,8 @@ class PagePicker extends Picker * Returns an associative array * with all information for the picker. * This will be passed directly to the API. + * + * @return array */ public function toArray(): array { diff --git a/kirby/src/Cms/PageRules.php b/kirby/src/Cms/PageRules.php index b981058..68cc711 100644 --- a/kirby/src/Cms/PageRules.php +++ b/kirby/src/Cms/PageRules.php @@ -6,7 +6,6 @@ use Kirby\Exception\DuplicateException; use Kirby\Exception\InvalidArgumentException; use Kirby\Exception\LogicException; use Kirby\Exception\PermissionException; -use Kirby\Toolkit\A; use Kirby\Toolkit\Str; /** @@ -23,6 +22,9 @@ class PageRules /** * Validates if the sorting number of the page can be changed * + * @param \Kirby\Cms\Page $page + * @param int|null $num + * @return bool * @throws \Kirby\Exception\InvalidArgumentException If the given number is invalid */ public static function changeNum(Page $page, int $num = null): bool @@ -37,6 +39,9 @@ class PageRules /** * Validates if the slug for the page can be changed * + * @param \Kirby\Cms\Page $page + * @param string $slug + * @return bool * @throws \Kirby\Exception\DuplicateException If a page with this slug already exists * @throws \Kirby\Exception\PermissionException If the user is not allowed to change the slug */ @@ -52,27 +57,30 @@ class PageRules } self::validateSlugLength($slug); - self::validateSlugProtectedPaths($page, $slug); $siblings = $page->parentModel()->children(); $drafts = $page->parentModel()->drafts(); - if ($siblings->find($slug)?->is($page) === false) { - throw new DuplicateException([ - 'key' => 'page.duplicate', - 'data' => [ - 'slug' => $slug - ] - ]); + if ($duplicate = $siblings->find($slug)) { + if ($duplicate->is($page) === false) { + throw new DuplicateException([ + 'key' => 'page.duplicate', + 'data' => [ + 'slug' => $slug + ] + ]); + } } - if ($drafts->find($slug)?->is($page) === false) { - throw new DuplicateException([ - 'key' => 'page.draft.duplicate', - 'data' => [ - 'slug' => $slug - ] - ]); + if ($duplicate = $drafts->find($slug)) { + if ($duplicate->is($page) === false) { + throw new DuplicateException([ + 'key' => 'page.draft.duplicate', + 'data' => [ + 'slug' => $slug + ] + ]); + } } return true; @@ -81,31 +89,38 @@ class PageRules /** * Validates if the status for the page can be changed * + * @param \Kirby\Cms\Page $page + * @param string $status + * @param int|null $position + * @return bool * @throws \Kirby\Exception\InvalidArgumentException If the given status is invalid */ - public static function changeStatus( - Page $page, - string $status, - int $position = null - ): bool { + public static function changeStatus(Page $page, string $status, int $position = null): bool + { if (isset($page->blueprint()->status()[$status]) === false) { throw new InvalidArgumentException(['key' => 'page.status.invalid']); } - return match ($status) { - 'draft' => static::changeStatusToDraft($page), - 'listed' => static::changeStatusToListed($page, $position), - 'unlisted' => static::changeStatusToUnlisted($page), - default => throw new InvalidArgumentException(['key' => 'page.status.invalid']) - }; + switch ($status) { + case 'draft': + return static::changeStatusToDraft($page); + case 'listed': + return static::changeStatusToListed($page, $position); + case 'unlisted': + return static::changeStatusToUnlisted($page); + default: + throw new InvalidArgumentException(['key' => 'page.status.invalid']); + } } /** * Validates if a page can be converted to a draft * + * @param \Kirby\Cms\Page $page + * @return bool * @throws \Kirby\Exception\PermissionException If the user is not allowed to change the status or the page cannot be converted to a draft */ - public static function changeStatusToDraft(Page $page): bool + public static function changeStatusToDraft(Page $page) { if ($page->permissions()->changeStatus() !== true) { throw new PermissionException([ @@ -131,10 +146,13 @@ class PageRules /** * Validates if the status of a page can be changed to listed * + * @param \Kirby\Cms\Page $page + * @param int $position + * @return bool * @throws \Kirby\Exception\InvalidArgumentException If the given position is invalid * @throws \Kirby\Exception\PermissionException If the user is not allowed to change the status or the status for the page cannot be changed by any user */ - public static function changeStatusToListed(Page $page, int $position): bool + public static function changeStatusToListed(Page $page, int $position) { // no need to check for status changing permissions, // instead we need to check for sorting permissions @@ -163,6 +181,8 @@ class PageRules /** * Validates if the status of a page can be changed to unlisted * + * @param \Kirby\Cms\Page $page + * @return bool * @throws \Kirby\Exception\PermissionException If the user is not allowed to change the status */ public static function changeStatusToUnlisted(Page $page) @@ -175,6 +195,9 @@ class PageRules /** * Validates if the template of the page can be changed * + * @param \Kirby\Cms\Page $page + * @param string $template + * @return bool * @throws \Kirby\Exception\LogicException If the template of the page cannot be changed at all * @throws \Kirby\Exception\PermissionException If the user is not allowed to change the template */ @@ -189,12 +212,7 @@ class PageRules ]); } - $blueprints = $page->blueprints(); - - if ( - count($blueprints) <= 1 || - in_array($template, array_column($blueprints, 'name')) === false - ) { + if (count($page->blueprints()) <= 1) { throw new LogicException([ 'key' => 'page.changeTemplate.invalid', 'data' => ['slug' => $page->slug()] @@ -207,6 +225,9 @@ class PageRules /** * Validates if the title of the page can be changed * + * @param \Kirby\Cms\Page $page + * @param string $title + * @return bool * @throws \Kirby\Exception\InvalidArgumentException If the new title is empty * @throws \Kirby\Exception\PermissionException If the user is not allowed to change the title */ @@ -221,7 +242,11 @@ class PageRules ]); } - static::validateTitleLength($title); + if (Str::length($title) === 0) { + throw new InvalidArgumentException([ + 'key' => 'page.changeTitle.empty', + ]); + } return true; } @@ -229,6 +254,8 @@ class PageRules /** * Validates if the page can be created * + * @param \Kirby\Cms\Page $page + * @return bool * @throws \Kirby\Exception\DuplicateException If the same page or a draft already exists * @throws \Kirby\Exception\InvalidArgumentException If the slug is invalid * @throws \Kirby\Exception\PermissionException If the user is not allowed to create this page @@ -245,7 +272,6 @@ class PageRules } self::validateSlugLength($page->slug()); - self::validateSlugProtectedPaths($page, $page->slug()); if ($page->exists() === true) { throw new DuplicateException([ @@ -280,6 +306,9 @@ class PageRules /** * Validates if the page can be deleted * + * @param \Kirby\Cms\Page $page + * @param bool $force + * @return bool * @throws \Kirby\Exception\LogicException If the page has children and should not be force-deleted * @throws \Kirby\Exception\PermissionException If the user is not allowed to delete the page */ @@ -304,13 +333,14 @@ class PageRules /** * Validates if the page can be duplicated * + * @param \Kirby\Cms\Page $page + * @param string $slug + * @param array $options + * @return bool * @throws \Kirby\Exception\PermissionException If the user is not allowed to duplicate the page */ - public static function duplicate( - Page $page, - string $slug, - array $options = [] - ): bool { + public static function duplicate(Page $page, string $slug, array $options = []): bool + { if ($page->permissions()->duplicate() !== true) { throw new PermissionException([ 'key' => 'page.duplicate.permission', @@ -325,82 +355,12 @@ class PageRules return true; } - /** - * Check if the page can be moved - * to the given parent - */ - public static function move(Page $page, Site|Page $parent): bool - { - // if nothing changes, there's no need for checks - if ($parent->is($page->parent()) === true) { - return true; - } - - if ($page->permissions()->move() !== true) { - throw new PermissionException([ - 'key' => 'page.move.permission', - 'data' => [ - 'slug' => $page->slug() - ] - ]); - } - - // the page cannot be moved into itself - if ($parent instanceof Page && ($page->is($parent) === true || $page->isAncestorOf($parent) === true)) { - throw new LogicException([ - 'key' => 'page.move.ancestor', - ]); - } - - // check for duplicates - if ($parent->childrenAndDrafts()->find($page->slug())) { - throw new DuplicateException([ - 'key' => 'page.move.duplicate', - 'data' => [ - 'slug' => $page->slug(), - ] - ]); - } - - $allowed = []; - - // collect all allowed subpage templates - foreach ($parent->blueprint()->sections() as $section) { - // only take pages sections into consideration - if ($section->type() !== 'pages') { - continue; - } - - // only consider page sections that list pages - // of the targeted new parent page - if ($section->parent() !== $parent) { - continue; - } - - // go through all allowed blueprints and - // add the name to the allow list - foreach ($section->blueprints() as $blueprint) { - $allowed[] = $blueprint['name']; - } - } - - // check if the template of this page is allowed as subpage type - if (in_array($page->intendedTemplate()->name(), $allowed) === false) { - throw new PermissionException([ - 'key' => 'page.move.template', - 'data' => [ - 'template' => $page->intendedTemplate()->name(), - 'parent' => $parent->id() ?? '/', - ] - ]); - } - - return true; - } - /** * Check if the page can be published * (status change from draft to listed or unlisted) + * + * @param Page $page + * @return bool */ public static function publish(Page $page): bool { @@ -426,6 +386,9 @@ class PageRules /** * Validates if the page can be updated * + * @param \Kirby\Cms\Page $page + * @param array $content + * @return bool * @throws \Kirby\Exception\PermissionException If the user is not allowed to update the page */ public static function update(Page $page, array $content = []): bool @@ -446,9 +409,11 @@ class PageRules * Ensures that the slug is not empty and doesn't exceed the maximum length * to make sure that the directory name will be accepted by the filesystem * + * @param string $slug New slug to check + * @return void * @throws \Kirby\Exception\InvalidArgumentException If the slug is empty or too long */ - public static function validateSlugLength(string $slug): void + protected static function validateSlugLength(string $slug): void { $slugLength = Str::length($slug); @@ -471,48 +436,4 @@ class PageRules } } } - - - /** - * Ensure that a top-level page path does not start with one of - * the reserved URL paths, e.g. for API or the Panel - * - * @throws \Kirby\Exception\InvalidArgumentException If the page ID starts as one of the disallowed paths - */ - protected static function validateSlugProtectedPaths( - Page $page, - string $slug - ): void { - if ($page->parent() === null) { - $paths = A::map( - ['api', 'assets', 'media', 'panel'], - fn ($url) => $page->kirby()->url($url, true)->path()->toString() - ); - - $index = array_search($slug, $paths); - - if ($index !== false) { - throw new InvalidArgumentException([ - 'key' => 'page.changeSlug.reserved', - 'data' => [ - 'path' => $paths[$index] - ] - ]); - } - } - } - - /** - * Ensures that the page title is not empty - * - * @throws \Kirby\Exception\InvalidArgumentException If the title is empty - */ - public static function validateTitleLength(string $title): void - { - if (Str::length($title) === 0) { - throw new InvalidArgumentException([ - 'key' => 'page.changeTitle.empty', - ]); - } - } } diff --git a/kirby/src/Cms/PageSiblings.php b/kirby/src/Cms/PageSiblings.php index 04f9f63..2507a1d 100644 --- a/kirby/src/Cms/PageSiblings.php +++ b/kirby/src/Cms/PageSiblings.php @@ -18,6 +18,8 @@ trait PageSiblings * page in the siblings collection * * @param \Kirby\Cms\Collection|null $collection + * + * @return bool */ public function hasNextListed($collection = null): bool { @@ -29,6 +31,8 @@ trait PageSiblings * page in the siblings collection * * @param \Kirby\Cms\Collection|null $collection + * + * @return bool */ public function hasNextUnlisted($collection = null): bool { @@ -40,6 +44,8 @@ trait PageSiblings * page in the siblings collection * * @param \Kirby\Cms\Collection|null $collection + * + * @return bool */ public function hasPrevListed($collection = null): bool { @@ -51,6 +57,8 @@ trait PageSiblings * page in the siblings collection * * @param \Kirby\Cms\Collection|null $collection + * + * @return bool */ public function hasPrevUnlisted($collection = null): bool { @@ -114,14 +122,15 @@ trait PageSiblings { if ($this->isDraft() === true) { return $this->parentModel()->drafts(); + } else { + return $this->parentModel()->children(); } - - return $this->parentModel()->children(); } /** * Returns siblings with the same template * + * @param bool $self * @return \Kirby\Cms\Pages */ public function templateSiblings(bool $self = true) diff --git a/kirby/src/Cms/Pages.php b/kirby/src/Cms/Pages.php index 692d047..5aa3959 100644 --- a/kirby/src/Cms/Pages.php +++ b/kirby/src/Cms/Pages.php @@ -3,7 +3,6 @@ namespace Kirby\Cms; use Kirby\Exception\InvalidArgumentException; -use Kirby\Uuid\HasUuids; /** * The `$pages` object refers to a @@ -23,8 +22,6 @@ use Kirby\Uuid\HasUuids; */ class Pages extends Collection { - use HasUuids; - /** * Cache for the index only listed and unlisted pages * @@ -41,8 +38,10 @@ class Pages extends Collection /** * All registered pages methods + * + * @var array */ - public static array $methods = []; + public static $methods = []; /** * Adds a single page or @@ -53,23 +52,20 @@ class Pages extends Collection * @return $this * @throws \Kirby\Exception\InvalidArgumentException When no `Page` or `Pages` object or an ID of an existing page is passed */ - public function add($object): static + public function add($object) { $site = App::instance()->site(); // add a pages collection - if ($object instanceof self) { + if (is_a($object, self::class) === true) { $this->data = array_merge($this->data, $object->data); // add a page by id - } elseif ( - is_string($object) === true && - $page = $site->find($object) - ) { + } elseif (is_string($object) === true && $page = $site->find($object)) { $this->__set($page->id(), $page); // add a page object - } elseif ($object instanceof Page) { + } elseif (is_a($object, 'Kirby\Cms\Page') === true) { $this->__set($object->id(), $object); // give a useful error message on invalid input; @@ -83,16 +79,20 @@ class Pages extends Collection /** * Returns all audio files of all children + * + * @return \Kirby\Cms\Files */ - public function audio(): Files + public function audio() { return $this->files()->filter('type', 'audio'); } /** * Returns all children for each page in the array + * + * @return \Kirby\Cms\Pages */ - public function children(): Pages + public function children() { $children = new Pages([]); @@ -107,24 +107,30 @@ class Pages extends Collection /** * Returns all code files of all children + * + * @return \Kirby\Cms\Files */ - public function code(): Files + public function code() { return $this->files()->filter('type', 'code'); } /** * Returns all documents of all children + * + * @return \Kirby\Cms\Files */ - public function documents(): Files + public function documents() { return $this->files()->filter('type', 'document'); } /** * Fetch all drafts for all pages in the collection + * + * @return \Kirby\Cms\Pages */ - public function drafts(): Pages + public function drafts() { $drafts = new Pages([]); @@ -139,16 +145,19 @@ class Pages extends Collection /** * Creates a pages collection from an array of props + * + * @param array $pages + * @param \Kirby\Cms\Model|null $model + * @param bool $draft + * @return static */ - public static function factory( - array $pages, - Page|Site $model = null, - bool $draft = null - ): static { + public static function factory(array $pages, Model $model = null, bool $draft = false) + { $model ??= App::instance()->site(); $children = new static([], $model); + $kirby = $model->kirby(); - if ($model instanceof Page) { + if (is_a($model, 'Kirby\Cms\Page') === true) { $parent = $model; $site = $model->site(); } else { @@ -157,9 +166,10 @@ class Pages extends Collection } foreach ($pages as $props) { + $props['kirby'] = $kirby; $props['parent'] = $parent; $props['site'] = $site; - $props['isDraft'] = $draft ?? $props['isDraft'] ?? $props['draft'] ?? false; + $props['isDraft'] = $draft; $page = Page::factory($props); @@ -171,8 +181,10 @@ class Pages extends Collection /** * Returns all files of all children + * + * @return \Kirby\Cms\Files */ - public function files(): Files + public function files() { $files = new Files([], $this->parent); @@ -185,20 +197,82 @@ class Pages extends Collection return $files; } + /** + * Finds a page in the collection by id. + * This works recursively for children and + * children of children, etc. + * @deprecated 3.7.0 Use `$pages->get()` or `$pages->find()` instead + * @todo 3.8.0 Remove method + * @codeCoverageIgnore + * + * @param string|null $id + * @return mixed + */ + public function findById(string $id = null) + { + Helpers::deprecated('Cms\Pages::findById() has been deprecated and will be removed in Kirby 3.8.0. Use $pages->get() or $pages->find() instead.'); + + return $this->findByKey($id); + } + + /** + * Finds a child or child of a child recursively. + * @deprecated 3.7.0 Use `$pages->find()` instead + * @todo 3.8.0 Integrate code into `findByKey()` and remove this method + * + * @param string $id + * @param string|null $startAt + * @param bool $multiLang + * @return mixed + */ + public function findByIdRecursive(string $id, string $startAt = null, bool $multiLang = false, bool $silenceWarning = false) + { + // @codeCoverageIgnoreStart + if ($silenceWarning !== true) { + Helpers::deprecated('Cms\Pages::findByIdRecursive() has been deprecated and will be removed in Kirby 3.8.0. Use $pages->find() instead.'); + } + // @codeCoverageIgnoreEnd + + $path = explode('/', $id); + $item = null; + $query = $startAt; + + foreach ($path as $key) { + $collection = $item ? $item->children() : $this; + $query = ltrim($query . '/' . $key, '/'); + $item = $collection->get($query) ?? null; + + if ($item === null && $multiLang === true && !App::instance()->language()->isDefault()) { + if (count($path) > 1 || $collection->parent()) { + // either the desired path is definitely not a slug, or collection is the children of another collection + $item = $collection->findBy('slug', $key); + } else { + // desired path _could_ be a slug or a "top level" uri + $item = $collection->findBy('uri', $key); + } + } + + if ($item === null) { + return null; + } + } + + return $item; + } + /** * Finds a page by its ID or URI * @internal Use `$pages->find()` instead + * + * @param string|null $key + * @return \Kirby\Cms\Page|null */ - public function findByKey(string|null $key = null): Page|null + public function findByKey(?string $key = null) { if ($key === null) { return null; } - if ($page = $this->findByUuid($key, 'page')) { - return $page; - } - // remove trailing or leading slashes $key = trim($key, '/'); @@ -218,21 +292,17 @@ class Pages extends Collection return $page; } - $kirby = App::instance(); - $multiLang = $kirby->multilang(); - - // try to find the page by its (translated) URI - // by stepping through the page tree - $start = $this->parent instanceof Page ? $this->parent->id() : ''; - if ($page = $this->findByKeyRecursive($key, $start, $multiLang)) { + // try to find the page by its (translated) URI by stepping through the page tree + $start = is_a($this->parent, 'Kirby\Cms\Page') === true ? $this->parent->id() : ''; + if ($page = $this->findByIdRecursive($key, $start, App::instance()->multilang(), true)) { return $page; } // for secondary languages, try the full translated URI // (for collections without parent that won't have a result above) if ( - $multiLang === true && - $kirby->language()->isDefault() === false && + App::instance()->multilang() === true && + App::instance()->language()->isDefault() === false && $page = $this->findBy('uri', $key) ) { return $page; @@ -242,51 +312,27 @@ class Pages extends Collection } /** - * Finds a child or child of a child recursively + * Alias for `$pages->find()` + * @deprecated 3.7.0 Use `$pages->find()` instead + * @todo 3.8.0 Remove method + * @codeCoverageIgnore * - * @return mixed + * @param string $id + * @return \Kirby\Cms\Page|null */ - protected function findByKeyRecursive( - string $id, - string $startAt = null, - bool $multiLang = false - ) { - $path = explode('/', $id); - $item = null; - $query = $startAt; + public function findByUri(string $id) + { + Helpers::deprecated('Cms\Pages::findByUri() has been deprecated and will be removed in Kirby 3.8.0. Use $pages->find() instead.'); - foreach ($path as $key) { - $collection = $item?->children() ?? $this; - $query = ltrim($query . '/' . $key, '/'); - $item = $collection->get($query) ?? null; - - if ( - $item === null && - $multiLang === true && - App::instance()->language()->isDefault() === false - ) { - if (count($path) > 1 || $collection->parent()) { - // either the desired path is definitely not a slug, - // or collection is the children of another collection - $item = $collection->findBy('slug', $key); - } else { - // desired path _could_ be a slug or a "top level" uri - $item = $collection->findBy('uri', $key); - } - } - - if ($item === null) { - return null; - } - } - - return $item; + return $this->findByKey($id); } /** * Finds the currently open page + * + * @return \Kirby\Cms\Page|null */ - public function findOpen(): Page|null + public function findOpen() { return $this->findBy('isOpen', true); } @@ -314,8 +360,10 @@ class Pages extends Collection /** * Returns all images of all children + * + * @return \Kirby\Cms\Files */ - public function images(): Files + public function images() { return $this->files()->filter('type', 'image'); } @@ -324,6 +372,7 @@ class Pages extends Collection * Create a recursive flat index of all * pages and subpages, etc. * + * @param bool $drafts * @return \Kirby\Cms\Pages */ public function index(bool $drafts = false) @@ -331,7 +380,7 @@ class Pages extends Collection // get object property by cache mode $index = $drafts === true ? $this->indexWithDrafts : $this->index; - if ($index instanceof self) { + if (is_a($index, 'Kirby\Cms\Pages') === true) { return $index; } @@ -357,16 +406,20 @@ class Pages extends Collection /** * Returns all listed pages in the collection + * + * @return \Kirby\Cms\Pages */ - public function listed(): static + public function listed() { return $this->filter('isListed', '==', true); } /** * Returns all unlisted pages in the collection + * + * @return \Kirby\Cms\Pages */ - public function unlisted(): static + public function unlisted() { return $this->filter('isUnlisted', '==', true); } @@ -398,14 +451,14 @@ class Pages extends Collection } // merge an entire collection - if ($args[0] instanceof self) { + if (is_a($args[0], self::class) === true) { $collection = clone $this; $collection->data = array_merge($collection->data, $args[0]->data); return $collection; } // append a single page - if ($args[0] instanceof Page) { + if (is_a($args[0], 'Kirby\Cms\Page') === true) { $collection = clone $this; return $collection->set($args[0]->id(), $args[0]); } @@ -443,22 +496,27 @@ class Pages extends Collection $templates = [$templates]; } - return $this->filter( - fn ($page) => - !in_array($page->intendedTemplate()->name(), $templates) - ); + return $this->filter(function ($page) use ($templates) { + return !in_array($page->intendedTemplate()->name(), $templates); + }); } /** * Returns an array with all page numbers + * + * @return array */ public function nums(): array { return $this->pluck('num'); } - // Returns all listed and unlisted pages in the collection - public function published(): static + /* + * Returns all listed and unlisted pages in the collection + * + * @return \Kirby\Cms\Pages + */ + public function published() { return $this->filter('isDraft', '==', false); } @@ -479,16 +537,17 @@ class Pages extends Collection $templates = [$templates]; } - return $this->filter( - fn ($page) => - in_array($page->intendedTemplate()->name(), $templates) - ); + return $this->filter(function ($page) use ($templates) { + return in_array($page->intendedTemplate()->name(), $templates); + }); } /** * Returns all video files of all children + * + * @return \Kirby\Cms\Files */ - public function videos(): Files + public function videos() { return $this->files()->filter('type', 'video'); } diff --git a/kirby/src/Cms/Pagination.php b/kirby/src/Cms/Pagination.php index fdefddd..13f6ef2 100644 --- a/kirby/src/Cms/Pagination.php +++ b/kirby/src/Cms/Pagination.php @@ -60,6 +60,8 @@ class Pagination extends BasePagination * 'url' => new Uri('https://getkirby.com/blog') * ]); * ``` + * + * @param array $params */ public function __construct(array $params = []) { @@ -93,16 +95,20 @@ class Pagination extends BasePagination /** * Returns the Url for the first page + * + * @return string|null */ - public function firstPageUrl(): string|null + public function firstPageUrl(): ?string { return $this->pageUrl(1); } /** * Returns the Url for the last page + * + * @return string|null */ - public function lastPageUrl(): string|null + public function lastPageUrl(): ?string { return $this->pageUrl($this->lastPage()); } @@ -110,8 +116,10 @@ class Pagination extends BasePagination /** * Returns the Url for the next page. * Returns null if there's no next page. + * + * @return string|null */ - public function nextPageUrl(): string|null + public function nextPageUrl(): ?string { if ($page = $this->nextPage()) { return $this->pageUrl($page); @@ -124,8 +132,11 @@ class Pagination extends BasePagination * Returns the URL of the current page. * If the `$page` variable is set, the URL * for that page will be returned. + * + * @param int|null $page + * @return string|null */ - public function pageUrl(int $page = null): string|null + public function pageUrl(int $page = null): ?string { if ($page === null) { return $this->pageUrl($this->page()); @@ -154,8 +165,10 @@ class Pagination extends BasePagination /** * Returns the Url for the previous page. * Returns null if there's no previous page. + * + * @return string|null */ - public function prevPageUrl(): string|null + public function prevPageUrl(): ?string { if ($page = $this->prevPage()) { return $this->pageUrl($page); diff --git a/kirby/src/Cms/Permissions.php b/kirby/src/Cms/Permissions.php index 4c9ab41..7838ca5 100644 --- a/kirby/src/Cms/Permissions.php +++ b/kirby/src/Cms/Permissions.php @@ -17,9 +17,15 @@ use Kirby\Exception\InvalidArgumentException; */ class Permissions { - public static array $extendedActions = []; + /** + * @var array + */ + public static $extendedActions = []; - protected array $actions = [ + /** + * @var array + */ + protected $actions = [ 'access' => [ 'account' => true, 'languages' => true, @@ -29,15 +35,12 @@ class Permissions 'users' => true, ], 'files' => [ - 'access' => true, - 'changeName' => true, - 'changeTemplate' => true, - 'create' => true, - 'delete' => true, - 'list' => true, - 'read' => true, - 'replace' => true, - 'update' => true + 'changeName' => true, + 'create' => true, + 'delete' => true, + 'read' => true, + 'replace' => true, + 'update' => true ], 'languages' => [ 'create' => true, @@ -45,7 +48,6 @@ class Permissions 'update' => true ], 'pages' => [ - 'access' => true, 'changeSlug' => true, 'changeStatus' => true, 'changeTemplate' => true, @@ -53,8 +55,6 @@ class Permissions 'create' => true, 'delete' => true, 'duplicate' => true, - 'list' => true, - 'move' => true, 'preview' => true, 'read' => true, 'sort' => true, @@ -88,9 +88,10 @@ class Permissions /** * Permissions constructor * + * @param array $settings * @throws \Kirby\Exception\InvalidArgumentException */ - public function __construct(array|bool|null $settings = []) + public function __construct($settings = []) { // dynamically register the extended actions foreach (static::$extendedActions as $key => $actions) { @@ -110,6 +111,11 @@ class Permissions } } + /** + * @param string|null $category + * @param string|null $action + * @return bool + */ public function for(string $category = null, string $action = null): bool { if ($action === null) { @@ -127,26 +133,39 @@ class Permissions return $this->actions[$category][$action]; } + /** + * @param string $category + * @param string $action + * @return bool + */ protected function hasAction(string $category, string $action): bool { - return - $this->hasCategory($category) === true && - array_key_exists($action, $this->actions[$category]) === true; + return $this->hasCategory($category) === true && array_key_exists($action, $this->actions[$category]) === true; } + /** + * @param string $category + * @return bool + */ protected function hasCategory(string $category): bool { return array_key_exists($category, $this->actions) === true; } /** + * @param string $category + * @param string $action + * @param $setting * @return $this */ - protected function setAction( - string $category, - string $action, - $setting - ): static { + protected function setAction(string $category, string $action, $setting) + { + // deprecated fallback for the settings/system view + // TODO: remove in 3.8.0 + if ($category === 'access' && $action === 'settings') { + $action = 'system'; + } + // wildcard to overwrite the entire category if ($action === '*') { return $this->setCategory($category, $setting); @@ -158,9 +177,10 @@ class Permissions } /** + * @param bool $setting * @return $this */ - protected function setAll(bool $setting): static + protected function setAll(bool $setting) { foreach ($this->actions as $categoryName => $actions) { $this->setCategory($categoryName, $setting); @@ -170,9 +190,10 @@ class Permissions } /** + * @param array $settings * @return $this */ - protected function setCategories(array $settings): static + protected function setCategories(array $settings) { foreach ($settings as $categoryName => $categoryActions) { if (is_bool($categoryActions) === true) { @@ -190,10 +211,12 @@ class Permissions } /** + * @param string $category + * @param bool $setting * @return $this * @throws \Kirby\Exception\InvalidArgumentException */ - protected function setCategory(string $category, bool $setting): static + protected function setCategory(string $category, bool $setting) { if ($this->hasCategory($category) === false) { throw new InvalidArgumentException('Invalid permissions category'); @@ -206,6 +229,9 @@ class Permissions return $this; } + /** + * @return array + */ public function toArray(): array { return $this->actions; diff --git a/kirby/src/Cms/Picker.php b/kirby/src/Cms/Picker.php index da4b7a5..7c26ad6 100644 --- a/kirby/src/Cms/Picker.php +++ b/kirby/src/Cms/Picker.php @@ -14,12 +14,25 @@ namespace Kirby\Cms; */ abstract class Picker { - protected App $kirby; - protected array $options; - protected Site $site; + /** + * @var \Kirby\Cms\App + */ + protected $kirby; + + /** + * @var array + */ + protected $options; + + /** + * @var \Kirby\Cms\Site + */ + protected $site; /** * Creates a new Picker instance + * + * @param array $params */ public function __construct(array $params = []) { @@ -30,6 +43,8 @@ abstract class Picker /** * Return the array of default values + * + * @return array */ protected function defaults(): array { @@ -40,7 +55,7 @@ abstract class Picker // query template for the info field 'info' => false, // listing style: list, cards, cardlets - 'layout' => 'list', + 'layout' =>'list', // number of users displayed per pagination page 'limit' => 20, // optional mapping function for the result array @@ -60,15 +75,20 @@ abstract class Picker /** * Fetches all items for the picker + * + * @return \Kirby\Cms\Collection|null */ - abstract public function items(): Collection|null; + abstract public function items(); /** * Converts all given items to an associative * array that is already optimized for the * panel picker component. + * + * @param \Kirby\Cms\Collection|null $items + * @return array */ - public function itemsToArray(Collection $items = null): array + public function itemsToArray($items = null): array { if ($items === null) { return []; @@ -96,8 +116,11 @@ abstract class Picker /** * Apply pagination to the collection * of items according to the options. + * + * @param \Kirby\Cms\Collection $items + * @return \Kirby\Cms\Collection */ - public function paginate(Collection $items): Collection + public function paginate(Collection $items) { return $items->paginate([ 'limit' => $this->options['limit'], @@ -108,6 +131,9 @@ abstract class Picker /** * Return the most relevant pagination * info as array + * + * @param \Kirby\Cms\Pagination $pagination + * @return array */ public function paginationToArray(Pagination $pagination): array { @@ -121,8 +147,11 @@ abstract class Picker /** * Search through the collection of items * if not deactivate in the options + * + * @param \Kirby\Cms\Collection $items + * @return \Kirby\Cms\Collection */ - public function search(Collection $items): Collection + public function search(Collection $items) { if (empty($this->options['search']) === false) { return $items->search($this->options['search']); @@ -135,6 +164,8 @@ abstract class Picker * Returns an associative array * with all information for the picker. * This will be passed directly to the API. + * + * @return array */ public function toArray(): array { diff --git a/kirby/src/Cms/Plugin.php b/kirby/src/Cms/Plugin.php index d20a4c3..ae5e07f 100644 --- a/kirby/src/Cms/Plugin.php +++ b/kirby/src/Cms/Plugin.php @@ -2,15 +2,10 @@ namespace Kirby\Cms; -use Composer\InstalledVersions; use Exception; -use Kirby\Cms\System\UpdateStatus; use Kirby\Data\Data; use Kirby\Exception\InvalidArgumentException; -use Kirby\Toolkit\A; -use Kirby\Toolkit\Str; use Kirby\Toolkit\V; -use Throwable; /** * Represents a Plugin and handles parsing of @@ -23,84 +18,44 @@ use Throwable; * @copyright Bastian Allgeier * @license https://getkirby.com/license */ -class Plugin +class Plugin extends Model { - protected PluginAssets $assets; - protected UpdateStatus|null $updateStatus = null; + protected $extends; + protected $info; + protected $name; + protected $root; /** - * @param string $name Plugin name within Kirby (`vendor/plugin`) - * @param array $extends Associative array of plugin extensions - * - * @throws \Kirby\Exception\InvalidArgumentException If the plugin name has an invalid format + * @param string $key + * @param array|null $arguments + * @return mixed|null */ - public function __construct( - protected string $name, - protected array $extends = [], - protected array $info = [], - protected string|null $root = null, - protected string|null $version = null, - ) { - static::validateName($name); - - // TODO: Remove in v7 - if ($root = $extends['root'] ?? null) { - Helpers::deprecated('Plugin "' . $name . '": Passing the `root` inside the `extends` array has been deprecated. Pass it directly as named argument `root`.', 'plugin-extends-root'); - $this->root ??= $root; - unset($this->extends['root']); - } - - $this->root ??= dirname(debug_backtrace()[0]['file']); - - // TODO: Remove in v7 - if ($info = $extends['info'] ?? null) { - Helpers::deprecated('Plugin "' . $name . '": Passing an `info` array inside the `extends` array has been deprecated. Pass the individual entries directly as named `info` argument.', 'plugin-extends-root'); - - if (empty($info) === false && is_array($info) === true) { - $this->info = [...$info, ...$this->info]; - } - - unset($this->extends['info']); - } - - // read composer.json and use as info fallback - try { - $info = Data::read($this->manifest()); - } catch (Exception) { - // there is no manifest file or it is invalid - $info = []; - } - - $this->info = [...$info, ...$this->info]; - } - - /** - * Allows access to any composer.json field by method call - */ - public function __call(string $key, array $arguments = null): mixed + public function __call(string $key, array $arguments = null) { return $this->info()[$key] ?? null; } /** - * Returns the plugin asset object for a specific asset + * Plugin constructor + * + * @param string $name + * @param array $extends */ - public function asset(string $path): PluginAsset|null + public function __construct(string $name, array $extends = []) { - return $this->assets()->get($path); - } + $this->setName($name); + $this->extends = $extends; + $this->root = $extends['root'] ?? dirname(debug_backtrace()[0]['file']); + $this->info = empty($extends['info']) === false && is_array($extends['info']) ? $extends['info'] : null; - /** - * Returns the plugin assets collection - */ - public function assets(): PluginAssets - { - return $this->assets ??= PluginAssets::factory($this); + unset($this->extends['root'], $this->extends['info']); } /** * Returns the array with author information - * from the composer.json file + * from the composer file + * + * @return array */ public function authors(): array { @@ -109,6 +64,8 @@ class Plugin /** * Returns a comma-separated list with all author names + * + * @return string */ public function authorsNames(): string { @@ -122,7 +79,7 @@ class Plugin } /** - * Returns the associative array of extensions the plugin bundles + * @return array */ public function extends(): array { @@ -130,8 +87,9 @@ class Plugin } /** - * Returns the unique ID for the plugin - * (alias for the plugin name) + * Returns the unique id for the plugin + * + * @return string */ public function id(): string { @@ -139,25 +97,30 @@ class Plugin } /** - * Returns the info data (from composer.json) + * @return array */ public function info(): array { - return $this->info; - } + if (is_array($this->info) === true) { + return $this->info; + } - /** - * Current $kirby instance - */ - public function kirby(): App - { - return App::instance(); + try { + $info = Data::read($this->manifest()); + } catch (Exception $e) { + // there is no manifest file or it is invalid + $info = []; + } + + return $this->info = $info; } /** * Returns the link to the plugin homepage + * + * @return string|null */ - public function link(): string|null + public function link(): ?string { $info = $this->info(); $homepage = $info['homepage'] ?? null; @@ -170,7 +133,7 @@ class Plugin } /** - * Returns the path to the plugin's composer.json + * @return string */ public function manifest(): string { @@ -178,7 +141,7 @@ class Plugin } /** - * Returns the root where plugin assets are copied to + * @return string */ public function mediaRoot(): string { @@ -186,7 +149,7 @@ class Plugin } /** - * Returns the base URL for plugin assets + * @return string */ public function mediaUrl(): string { @@ -194,7 +157,7 @@ class Plugin } /** - * Returns the plugin name (`vendor/plugin`) + * @return string */ public function name(): string { @@ -202,7 +165,8 @@ class Plugin } /** - * Returns a Kirby option value for this plugin + * @param string $key + * @return mixed */ public function option(string $key) { @@ -210,7 +174,7 @@ class Plugin } /** - * Returns the option prefix (`vendor.plugin`) + * @return string */ public function prefix(): string { @@ -218,7 +182,7 @@ class Plugin } /** - * Returns the root where the plugin files are stored + * @return string */ public function root(): string { @@ -226,7 +190,22 @@ class Plugin } /** - * Returns all available plugin metadata + * @param string $name + * @return $this + * @throws \Kirby\Exception\InvalidArgumentException + */ + protected function setName(string $name) + { + if (preg_match('!^[a-z0-9-]+\/[a-z0-9-]+$!i', $name) !== 1) { + throw new InvalidArgumentException('The plugin name must follow the format "a-z0-9-/a-z0-9-"'); + } + + $this->name = $name; + return $this; + } + + /** + * @return array */ public function toArray(): array { @@ -240,102 +219,4 @@ class Plugin 'version' => $this->version() ]; } - - /** - * Returns the update status object unless the - * update check has been disabled for the plugin - * @since 3.8.0 - * - * @param array|null $data Custom override for the getkirby.com update data - */ - public function updateStatus(array|null $data = null): UpdateStatus|null - { - if ($this->updateStatus !== null) { - return $this->updateStatus; - } - - $kirby = $this->kirby(); - $option = $kirby->option('updates.plugins'); - - // specific configuration per plugin - if (is_array($option) === true) { - // filter all option values by glob match - $option = A::filter( - $option, - fn ($value, $key) => fnmatch($key, $this->name()) === true - ); - - // sort the matches by key length (with longest key first) - $keys = array_map('strlen', array_keys($option)); - array_multisort($keys, SORT_DESC, $option); - - if (count($option) > 0) { - // use the first and therefore longest key (= most specific match) - $option = reset($option); - } else { - // fallback to the default option value - $option = true; - } - } - - $option ??= $kirby->option('updates') ?? true; - - if ($option !== true) { - return null; - } - - return $this->updateStatus = new UpdateStatus($this, false, $data); - } - - /** - * Checks if the name follows the required pattern - * and throws an exception if not - * - * @throws \Kirby\Exception\InvalidArgumentException - */ - public static function validateName(string $name): void - { - if (preg_match('!^[a-z0-9-]+\/[a-z0-9-]+$!i', $name) !== 1) { - throw new InvalidArgumentException('The plugin name must follow the format "a-z0-9-/a-z0-9-"'); - } - } - - /** - * Returns the normalized version number - * from the composer.json file - */ - public function version(): string|null - { - $name = $this->info()['name'] ?? null; - - try { - // try to get version from "vendor/composer/installed.php", - // this is the most reliable source for the version - $version = InstalledVersions::getPrettyVersion($name); - } catch (Throwable) { - $version = null; - } - - // fallback to the version provided in the plugin's index.php: as named - // argument, entry in the info array or from the composer.json file - $version ??= $this->version ?? $this->info()['version'] ?? null; - - if ( - is_string($version) !== true || - $version === '' || - Str::endsWith($version, '+no-version-set') - ) { - return null; - } - - // normalize the version number to be without leading `v` - $version = ltrim($version, 'vV'); - - // ensure that the version number now starts with a digit - if (preg_match('/^[0-9]/', $version) !== 1) { - return null; - } - - return $version; - } } diff --git a/kirby/src/Cms/PluginAsset.php b/kirby/src/Cms/PluginAsset.php deleted file mode 100644 index f5f7f69..0000000 --- a/kirby/src/Cms/PluginAsset.php +++ /dev/null @@ -1,120 +0,0 @@ - - * @link https://getkirby.com - * @copyright Bastian Allgeier - * @license https://getkirby.com/license - */ -class PluginAsset -{ - public function __construct( - protected string $path, - protected string $root, - protected Plugin $plugin - ) { - } - - public function extension(): string - { - return F::extension($this->path()); - } - - public function filename(): string - { - return F::filename($this->path()); - } - - /** - * Create a unique media hash - */ - public function mediaHash(): string - { - return crc32($this->filename()) . '-' . $this->modified(); - } - - /** - * Absolute path to the asset file in the media folder - */ - public function mediaRoot(): string - { - return $this->plugin()->mediaRoot() . '/' . $this->mediaHash() . '/' . $this->path(); - } - - /** - * Public accessible url path for the asset - */ - public function mediaUrl(): string - { - return $this->plugin()->mediaUrl() . '/' . $this->mediaHash() . '/' . $this->path(); - } - - /** - * Timestamp when asset file was last modified - */ - public function modified(): int|false - { - return F::modified($this->root()); - } - - public function path(): string - { - return $this->path; - } - - public function plugin(): Plugin - { - return $this->plugin; - } - - /** - * Publishes the asset file to the plugin's media folder - * by creating a symlink - */ - public function publish(): void - { - F::link($this->root(), $this->mediaRoot(), 'symlink'); - } - - /** - * @internal - * @since 4.0.0 - * @deprecated 4.0.0 - * @codeCoverageIgnore - */ - public function publishAt(string $path): void - { - $media = $this->plugin()->mediaRoot() . '/' . $path; - F::link($this->root(), $media, 'symlink'); - } - - public function root(): string - { - return $this->root; - } - - /** - * @see ::mediaUrl - */ - public function url(): string - { - return $this->mediaUrl(); - } - - /** - * @see ::url - */ - public function __toString(): string - { - return $this->url(); - } -} diff --git a/kirby/src/Cms/PluginAssets.php b/kirby/src/Cms/PluginAssets.php index 45c415f..a05ffea 100644 --- a/kirby/src/Cms/PluginAssets.php +++ b/kirby/src/Cms/PluginAssets.php @@ -2,11 +2,9 @@ namespace Kirby\Cms; -use Closure; use Kirby\Filesystem\Dir; use Kirby\Filesystem\F; use Kirby\Http\Response; -use Kirby\Toolkit\Str; /** * Plugin assets are automatically copied/linked @@ -15,167 +13,65 @@ use Kirby\Toolkit\Str; * * @package Kirby Cms * @author Bastian Allgeier - * @author Nico Hoffmann * @link https://getkirby.com * @copyright Bastian Allgeier * @license https://getkirby.com/license */ -class PluginAssets extends Collection +class PluginAssets { /** * Clean old/deprecated assets on every resolve + * + * @param string $pluginName + * @return void */ public static function clean(string $pluginName): void { if ($plugin = App::instance()->plugin($pluginName)) { - $media = $plugin->mediaRoot(); - $assets = $plugin->assets(); - - // get all media files - $files = Dir::index($media, true); - - // get all active assets' paths from the plugin - $active = $assets->values( - function ($asset) { - $path = $asset->mediaHash() . '/' . $asset->path(); - $paths = []; - $parts = explode('/', $path); - - // collect all path segments - // (e.g. foo/, foo/bar/, foo/bar/baz.css) for the asset - for ($i = 1, $max = count($parts); $i <= $max; $i++) { - $paths[] = implode('/', array_slice($parts, 0, $i)); - - // TODO: remove when media hash is enforced as mandatory - $paths[] = implode('/', array_slice($parts, 1, $i)); - } - - return $paths; - } - ); - - // flatten the array and remove duplicates - $active = array_unique(array_merge(...array_values($active))); - - // get outdated media files by comparing all - // files in the media folder against the set of asset paths - $stale = array_diff($files, $active); - - foreach ($stale as $file) { - $root = $media . '/' . $file; - - if (is_file($root) === true) { - F::remove($root); - } else { - Dir::remove($root); - } - } - } - } - - /** - * Filters assets collection by CSS files - */ - public function css(): static - { - return $this->filter(fn ($asset) => $asset->extension() === 'css'); - } - - /** - * Creates a new collection for the plugin's assets - * by considering the plugin's `asset` extension - * (and `assets` directory as fallback) - */ - public static function factory(Plugin $plugin): static - { - // get assets defined in the plugin extension - if ($assets = $plugin->extends()['assets'] ?? null) { - if ($assets instanceof Closure) { - $assets = $assets(); - } - - // normalize array: use relative path as - // key when no key is defined - foreach ($assets as $key => $root) { - if (is_int($key) === true) { - unset($assets[$key]); - $path = Str::after($root, $plugin->root() . '/'); - $assets[$path] = $root; - } - } - } - - // fallback: if no assets are defined in the plugin extension, - // use all files in the plugin's `assets` directory - if ($assets === null) { - $assets = []; $root = $plugin->root() . '/assets'; + $media = $plugin->mediaRoot(); + $assets = Dir::index($media, true); - foreach (Dir::index($root, true) as $path) { - if (is_file($root . '/' . $path) === true) { - $assets[$path] = $root . '/' . $path; + foreach ($assets as $asset) { + $original = $root . '/' . $asset; + + if (file_exists($original) === false) { + $assetRoot = $media . '/' . $asset; + + if (is_file($assetRoot) === true) { + F::remove($assetRoot); + } else { + Dir::remove($assetRoot); + } } } } - - $collection = new static([], $plugin); - - foreach ($assets as $path => $root) { - $collection->data[$path] = new PluginAsset($path, $root, $plugin); - } - - return $collection; - } - - /** - * Filters assets collection by JavaScript files - */ - public function js(): static - { - return $this->filter(fn ($asset) => $asset->extension() === 'js'); - } - - public function plugin(): Plugin - { - return $this->parent; } /** * Create a symlink for a plugin asset and * return the public URL + * + * @param string $pluginName + * @param string $filename + * @return \Kirby\Cms\Response|null */ - public static function resolve( - string $pluginName, - string $hash, - string $path - ): Response|null { + public static function resolve(string $pluginName, string $filename) + { if ($plugin = App::instance()->plugin($pluginName)) { - // do some spring cleaning for older files - static::clean($pluginName); + $source = $plugin->root() . '/assets/' . $filename; - // @codeCoverageIgnoreStart - // TODO: deprecated media URL without hash - if (empty($hash) === true) { - $asset = $plugin->asset($path); - $asset->publishAt($path); - return Response::file($asset->root()); - } + if (F::exists($source, $plugin->root()) === true) { + // do some spring cleaning for older files + static::clean($pluginName); - // TODO: deprecated media URL with hash (but path) - if ($asset = $plugin->asset($hash . '/' . $path)) { - $asset->publishAt($hash . '/' . $path); - return Response::file($asset->root()); - } - // @codeCoverageIgnoreEnd + $target = $plugin->mediaRoot() . '/' . $filename; - if ($asset = $plugin->asset($path)) { - if ($asset->mediaHash() === $hash) { - // create a symlink if possible - $asset->publish(); + // create a symlink if possible + F::link($source, $target, 'symlink'); - // return the file response - return Response::file($asset->root()); - } + // return the file response + return Response::file($source); } } diff --git a/kirby/src/Cms/R.php b/kirby/src/Cms/R.php index 312fc2b..5ef5df9 100644 --- a/kirby/src/Cms/R.php +++ b/kirby/src/Cms/R.php @@ -2,7 +2,6 @@ namespace Kirby\Cms; -use Kirby\Http\Request; use Kirby\Toolkit\Facade; /** @@ -16,7 +15,10 @@ use Kirby\Toolkit\Facade; */ class R extends Facade { - public static function instance(): Request + /** + * @return \Kirby\Http\Request + */ + public static function instance() { return App::instance()->request(); } diff --git a/kirby/src/Cms/Responder.php b/kirby/src/Cms/Responder.php index e99ce56..7f3d38e 100644 --- a/kirby/src/Cms/Responder.php +++ b/kirby/src/Cms/Responder.php @@ -20,50 +20,68 @@ class Responder /** * Timestamp when the response expires * in Kirby's cache + * + * @var int|null */ - protected int|null $expires = null; + protected $expires = null; /** * HTTP status code + * + * @var int */ - protected int|null $code = null; + protected $code = null; /** * Response body + * + * @var string */ - protected string|null $body = null; + protected $body = null; /** * Flag that defines whether the current * response can be cached by Kirby's cache + * + * @var bool */ - protected bool $cache = true; + protected $cache = true; /** * HTTP headers + * + * @var array */ - protected array $headers = []; + protected $headers = []; /** * Content type + * + * @var string */ - protected string|null $type = null; + protected $type = null; /** * Flag that defines whether the current * response uses the HTTP `Authorization` * request header + * + * @var bool */ - protected bool $usesAuth = false; + protected $usesAuth = false; /** * List of cookie names the response * relies on + * + * @var array */ - protected array $usesCookies = []; + protected $usesCookies = []; /** * Creates and sends the response + * + * @return string */ public function __toString(): string { @@ -73,9 +91,10 @@ class Responder /** * Setter and getter for the response body * - * @return $this|string|null + * @param string|null $body + * @return string|$this */ - public function body(string $body = null): static|string|null + public function body(string $body = null) { if ($body === null) { return $this->body; @@ -91,9 +110,10 @@ class Responder * by Kirby's cache * @since 3.5.5 * + * @param bool|null $cache * @return bool|$this */ - public function cache(bool|null $cache = null): bool|static + public function cache(?bool $cache = null) { if ($cache === null) { // never ever cache private responses @@ -114,9 +134,10 @@ class Responder * `Authorization` request header * @since 3.7.0 * + * @param bool|null $usesAuth * @return bool|$this */ - public function usesAuth(bool|null $usesAuth = null): bool|static + public function usesAuth(?bool $usesAuth = null) { if ($usesAuth === null) { return $this->usesAuth; @@ -130,6 +151,9 @@ class Responder * Setter for a cookie name that is * used by the response * @since 3.7.0 + * + * @param string $name + * @return void */ public function usesCookie(string $name): void { @@ -144,9 +168,10 @@ class Responder * names the response relies on * @since 3.7.0 * + * @param array|null $usesCookies * @return array|$this */ - public function usesCookies(array|null $usesCookies = null) + public function usesCookies(?array $usesCookies = null) { if ($usesCookies === null) { return $this->usesCookies; @@ -208,6 +233,7 @@ class Responder /** * Setter and getter for the status code * + * @param int|null $code * @return int|$this */ public function code(int $code = null) @@ -222,6 +248,8 @@ class Responder /** * Construct response from an array + * + * @param array $response */ public function fromArray(array $response): void { @@ -238,6 +266,7 @@ class Responder /** * Setter and getter for a single header * + * @param string $key * @param string|false|null $value * @param bool $lazy If `true`, an existing header value is not overridden * @return string|$this @@ -264,6 +293,7 @@ class Responder /** * Setter and getter for all headers * + * @param array|null $headers * @return array|$this */ public function headers(array $headers = null) @@ -303,6 +333,7 @@ class Responder /** * Shortcut to configure a json response * + * @param array|null $json * @return string|$this */ public function json(array $json = null) @@ -317,12 +348,12 @@ class Responder /** * Shortcut to create a redirect response * + * @param string|null $location + * @param int|null $code * @return $this */ - public function redirect( - string|null $location = null, - int|null $code = null - ) { + public function redirect(?string $location = null, ?int $code = null) + { $location = Url::to($location ?? '/'); $location = Url::unIdn($location); @@ -333,8 +364,11 @@ class Responder /** * Creates and returns the response object from the config + * + * @param string|null $body + * @return \Kirby\Cms\Response */ - public function send(string $body = null): Response + public function send(string $body = null) { if ($body !== null) { $this->body($body); @@ -346,6 +380,8 @@ class Responder /** * Converts the response configuration * to an array + * + * @return array */ public function toArray(): array { @@ -363,6 +399,7 @@ class Responder /** * Setter and getter for the content type * + * @param string|null $type * @return string|$this */ public function type(string $type = null) @@ -386,6 +423,10 @@ class Responder * is actually used/relied on by the response * @since 3.7.0 * @internal + * + * @param bool $usesAuth + * @param array $usesCookies + * @return bool */ public static function isPrivate(bool $usesAuth, array $usesCookies): bool { diff --git a/kirby/src/Cms/Response.php b/kirby/src/Cms/Response.php index 5a21bc6..9674440 100644 --- a/kirby/src/Cms/Response.php +++ b/kirby/src/Cms/Response.php @@ -18,11 +18,13 @@ class Response extends \Kirby\Http\Response * Adjusted redirect creation which * parses locations with the Url::to method * first. + * + * @param string $location + * @param int $code + * @return static */ - public static function redirect( - string $location = '/', - int $code = 302 - ): static { + public static function redirect(string $location = '/', int $code = 302) + { return parent::redirect(Url::to($location), $code); } } diff --git a/kirby/src/Cms/Role.php b/kirby/src/Cms/Role.php index 3579b62..aa22264 100644 --- a/kirby/src/Cms/Role.php +++ b/kirby/src/Cms/Role.php @@ -17,46 +17,52 @@ use Kirby\Toolkit\I18n; * @copyright Bastian Allgeier * @license https://getkirby.com/license */ -class Role +class Role extends Model { - protected string|null $description; - protected string $name; - protected Permissions $permissions; - protected string|null $title; + protected $description; + protected $name; + protected $permissions; + protected $title; public function __construct(array $props) { - $this->name = $props['name']; - $this->permissions = new Permissions($props['permissions'] ?? null); - $title = $props['title'] ?? null; - $this->title = I18n::translate($title) ?? $title; - $description = $props['description'] ?? null; - $this->description = I18n::translate($description) ?? $description; + $this->setProperties($props); } /** * Improved `var_dump` output - * @codeCoverageIgnore + * + * @return array */ public function __debugInfo(): array { return $this->toArray(); } + /** + * @return string + */ public function __toString(): string { return $this->name(); } - public static function admin(array $inject = []): static + /** + * @param array $inject + * @return static + */ + public static function admin(array $inject = []) { try { return static::load('admin'); - } catch (Exception) { + } catch (Exception $e) { return static::factory(static::defaults()['admin'], $inject); } } + /** + * @return array + */ protected static function defaults(): array { return [ @@ -75,32 +81,54 @@ class Role ]; } - public function description(): string|null + /** + * @return mixed + */ + public function description() { return $this->description; } - public static function factory(array $props, array $inject = []): static + /** + * @param array $props + * @param array $inject + * @return static + */ + public static function factory(array $props, array $inject = []) { return new static($props + $inject); } + /** + * @return string + */ public function id(): string { return $this->name(); } + /** + * @return bool + */ public function isAdmin(): bool { return $this->name() === 'admin'; } + /** + * @return bool + */ public function isNobody(): bool { return $this->name() === 'nobody'; } - public static function load(string $file, array $inject = []): static + /** + * @param string $file + * @param array $inject + * @return static + */ + public static function load(string $file, array $inject = []) { $data = Data::read($file); $data['name'] = F::name($file); @@ -108,25 +136,78 @@ class Role return static::factory($data, $inject); } + /** + * @return string + */ public function name(): string { return $this->name; } - public static function nobody(array $inject = []): static + /** + * @param array $inject + * @return static + */ + public static function nobody(array $inject = []) { try { return static::load('nobody'); - } catch (Exception) { + } catch (Exception $e) { return static::factory(static::defaults()['nobody'], $inject); } } - public function permissions(): Permissions + /** + * @return \Kirby\Cms\Permissions + */ + public function permissions() { return $this->permissions; } + /** + * @param mixed $description + * @return $this + */ + protected function setDescription($description = null) + { + $this->description = I18n::translate($description, $description); + return $this; + } + + /** + * @param string $name + * @return $this + */ + protected function setName(string $name) + { + $this->name = $name; + return $this; + } + + /** + * @param mixed $permissions + * @return $this + */ + protected function setPermissions($permissions = null) + { + $this->permissions = new Permissions($permissions); + return $this; + } + + /** + * @param mixed $title + * @return $this + */ + protected function setTitle($title = null) + { + $this->title = I18n::translate($title, $title); + return $this; + } + + /** + * @return string + */ public function title(): string { return $this->title ??= ucfirst($this->name()); @@ -135,6 +216,8 @@ class Role /** * Converts the most important role * properties to an array + * + * @return array */ public function toArray(): array { diff --git a/kirby/src/Cms/Roles.php b/kirby/src/Cms/Roles.php index 11be6c9..fb99dd0 100644 --- a/kirby/src/Cms/Roles.php +++ b/kirby/src/Cms/Roles.php @@ -18,11 +18,6 @@ namespace Kirby\Cms; */ class Roles extends Collection { - /** - * All registered roles methods - */ - public static array $methods = []; - /** * Returns a filtered list of all * roles that can be created by the @@ -31,7 +26,7 @@ class Roles extends Collection * @return $this|static * @throws \Exception */ - public function canBeChanged(): static + public function canBeChanged() { if (App::instance()->user()) { return $this->filter(function ($role) { @@ -55,7 +50,7 @@ class Roles extends Collection * @return $this|static * @throws \Exception */ - public function canBeCreated(): static + public function canBeCreated() { if (App::instance()->user()) { return $this->filter(function ($role) { @@ -71,7 +66,12 @@ class Roles extends Collection return $this; } - public static function factory(array $roles, array $inject = []): static + /** + * @param array $roles + * @param array $inject + * @return static + */ + public static function factory(array $roles, array $inject = []) { $collection = new static(); @@ -90,7 +90,12 @@ class Roles extends Collection return $collection->sort('name', 'asc'); } - public static function load(string $root = null, array $inject = []): static + /** + * @param string|null $root + * @param array $inject + * @return static + */ + public static function load(string $root = null, array $inject = []) { $kirby = App::instance(); $roles = new static(); diff --git a/kirby/src/Cms/S.php b/kirby/src/Cms/S.php index 260ee30..cced071 100644 --- a/kirby/src/Cms/S.php +++ b/kirby/src/Cms/S.php @@ -2,7 +2,6 @@ namespace Kirby\Cms; -use Kirby\Session\Session; use Kirby\Toolkit\Facade; /** @@ -16,7 +15,10 @@ use Kirby\Toolkit\Facade; */ class S extends Facade { - public static function instance(): Session + /** + * @return \Kirby\Session\Session + */ + public static function instance() { return App::instance()->session(); } diff --git a/kirby/src/Cms/Search.php b/kirby/src/Cms/Search.php index 14add5c..0169b40 100644 --- a/kirby/src/Cms/Search.php +++ b/kirby/src/Cms/Search.php @@ -16,36 +16,47 @@ namespace Kirby\Cms; */ class Search { - public static function files( - string $query = null, - array $params = [] - ): Files { + /** + * @param string|null $query + * @param array $params + * @return \Kirby\Cms\Files + */ + public static function files(string $query = null, $params = []) + { return App::instance()->site()->index()->files()->search($query, $params); } /** * Native search method to search for anything within the collection + * + * @param \Kirby\Cms\Collection $collection + * @param string|null $query + * @param mixed $params + * @return \Kirby\Cms\Collection|bool */ - public static function collection( - Collection $collection, - string|null $query = null, - string|array $params = [] - ): Collection { + public static function collection(Collection $collection, string $query = null, $params = []) + { $kirby = App::instance(); return ($kirby->component('search'))($kirby, $collection, $query, $params); } - public static function pages( - string $query = null, - array $params = [] - ): Pages { + /** + * @param string|null $query + * @param array $params + * @return \Kirby\Cms\Pages + */ + public static function pages(string $query = null, $params = []) + { return App::instance()->site()->index()->search($query, $params); } - public static function users( - string $query = null, - array $params = [] - ): Users { + /** + * @param string|null $query + * @param array $params + * @return \Kirby\Cms\Users + */ + public static function users(string $query = null, $params = []) + { return App::instance()->users()->search($query, $params); } } diff --git a/kirby/src/Cms/Section.php b/kirby/src/Cms/Section.php index 42ee388..d68b3c2 100644 --- a/kirby/src/Cms/Section.php +++ b/kirby/src/Cms/Section.php @@ -2,7 +2,6 @@ namespace Kirby\Cms; -use Closure; use Kirby\Exception\InvalidArgumentException; use Kirby\Toolkit\Component; @@ -19,15 +18,24 @@ class Section extends Component { /** * Registry for all component mixins + * + * @var array */ - public static array $mixins = []; + public static $mixins = []; /** * Registry for all component types + * + * @var array */ - public static array $types = []; + public static $types = []; + /** + * Section constructor. + * + * @param string $type + * @param array $attrs * @throws \Kirby\Exception\InvalidArgumentException */ public function __construct(string $type, array $attrs = []) @@ -36,7 +44,7 @@ class Section extends Component throw new InvalidArgumentException('Undefined section model'); } - if ($attrs['model'] instanceof ModelWithContent === false) { + if (is_a($attrs['model'], 'Kirby\Cms\Model') === false) { throw new InvalidArgumentException('Invalid section model'); } @@ -47,21 +55,6 @@ class Section extends Component parent::__construct($type, $attrs); } - /** - * Returns field api call - */ - public function api(): mixed - { - if ( - isset($this->options['api']) === true && - $this->options['api'] instanceof Closure - ) { - return $this->options['api']->call($this); - } - - return null; - } - public function errors(): array { if (array_key_exists('errors', $this->methods) === true) { @@ -71,16 +64,25 @@ class Section extends Component return $this->errors ?? []; } - public function kirby(): App + /** + * @return \Kirby\Cms\App + */ + public function kirby() { return $this->model()->kirby(); } - public function model(): ModelWithContent + /** + * @return \Kirby\Cms\Model + */ + public function model() { return $this->model; } + /** + * @return array + */ public function toArray(): array { $array = parent::toArray(); @@ -90,6 +92,9 @@ class Section extends Component return $array; } + /** + * @return array + */ public function toResponse(): array { return array_merge([ diff --git a/kirby/src/Cms/Site.php b/kirby/src/Cms/Site.php index cab166d..2343ed7 100644 --- a/kirby/src/Cms/Site.php +++ b/kirby/src/Cms/Site.php @@ -22,83 +22,87 @@ use Kirby\Toolkit\A; */ class Site extends ModelWithContent { + use SiteActions; use HasChildren; use HasFiles; use HasMethods; - use SiteActions; public const CLASS_ALIAS = 'site'; /** * The SiteBlueprint object + * + * @var \Kirby\Cms\SiteBlueprint */ - protected SiteBlueprint|null $blueprint = null; + protected $blueprint; /** * The error page object + * + * @var \Kirby\Cms\Page */ - protected Page|null $errorPage = null; + protected $errorPage; /** * The id of the error page, which is * fetched in the errorPage method + * + * @var string */ - protected string $errorPageId; + protected $errorPageId = 'error'; /** * The home page object + * + * @var \Kirby\Cms\Page */ - protected Page|null $homePage = null; + protected $homePage; /** * The id of the home page, which is * fetched in the errorPage method + * + * @var string */ - protected string $homePageId; + protected $homePageId = 'home'; /** * Cache for the inventory array + * + * @var array */ - protected array|null $inventory = null; + protected $inventory; /** * The current page object + * + * @var \Kirby\Cms\Page */ - protected Page|null $page; + protected $page; /** * The absolute path to the site directory + * + * @var string */ - protected string $root; + protected $root; /** * The page url + * + * @var string */ - protected string|null $url; - - /** - * Creates a new Site object - */ - public function __construct(array $props = []) - { - parent::__construct($props); - - $this->errorPageId = $props['errorPageId'] ?? 'error'; - $this->homePageId = $props['homePageId'] ?? 'home'; - $this->page = $props['page'] ?? null; - $this->url = $props['url'] ?? null; - - $this->setBlueprint($props['blueprint'] ?? null); - $this->setChildren($props['children'] ?? null); - $this->setDrafts($props['drafts'] ?? null); - $this->setFiles($props['files'] ?? null); - } + protected $url; /** * Modified getter to also return fields * from the content + * + * @param string $method + * @param array $arguments + * @return mixed */ - public function __call(string $method, array $arguments = []): mixed + public function __call(string $method, array $arguments = []) { // public property access if (isset($this->$method) === true) { @@ -114,9 +118,20 @@ class Site extends ModelWithContent return $this->content()->get($method); } + /** + * Creates a new Site object + * + * @param array $props + */ + public function __construct(array $props = []) + { + $this->setProperties($props); + } + /** * Improved `var_dump` output - * @codeCoverageIgnore + * + * @return array */ public function __debugInfo(): array { @@ -130,6 +145,8 @@ class Site extends ModelWithContent /** * Makes it possible to convert the site model * to a string. Mostly useful for debugging. + * + * @return string */ public function __toString(): string { @@ -138,23 +155,28 @@ class Site extends ModelWithContent /** * Returns the url to the api endpoint + * * @internal + * @param bool $relative + * @return string */ public function apiUrl(bool $relative = false): string { if ($relative === true) { return 'site'; + } else { + return $this->kirby()->url('api') . '/site'; } - - return $this->kirby()->url('api') . '/site'; } /** * Returns the blueprint object + * + * @return \Kirby\Cms\SiteBlueprint */ - public function blueprint(): SiteBlueprint + public function blueprint() { - if ($this->blueprint instanceof SiteBlueprint) { + if (is_a($this->blueprint, 'Kirby\Cms\SiteBlueprint') === true) { return $this->blueprint; } @@ -163,8 +185,10 @@ class Site extends ModelWithContent /** * Builds a breadcrumb collection + * + * @return \Kirby\Cms\Pages */ - public function breadcrumb(): Pages + public function breadcrumb() { // get all parents and flip the order $crumb = $this->page()->parents()->flip(); @@ -180,39 +204,53 @@ class Site extends ModelWithContent /** * Prepares the content for the write method + * * @internal + * @param array $data + * @param string|null $languageCode + * @return array */ - public function contentFileData( - array $data, - string|null $languageCode = null - ): array { - return A::prepend($data, ['title' => $data['title'] ?? null]); + public function contentFileData(array $data, ?string $languageCode = null): array + { + return A::prepend($data, [ + 'title' => $data['title'] ?? null, + ]); } /** * Filename for the content file + * * @internal - * @deprecated 4.0.0 - * @todo Remove in v5 - * @codeCoverageIgnore + * @return string */ public function contentFileName(): string { - Helpers::deprecated('The internal $model->contentFileName() method has been deprecated. Please let us know via a GitHub issue if you need this method and tell us your use case.', 'model-content-file'); return 'site'; } /** * Returns the error page object + * + * @return \Kirby\Cms\Page|null */ - public function errorPage(): Page|null + public function errorPage() { - return $this->errorPage ??= $this->find($this->errorPageId()); + if (is_a($this->errorPage, 'Kirby\Cms\Page') === true) { + return $this->errorPage; + } + + if ($error = $this->find($this->errorPageId())) { + return $this->errorPage = $error; + } + + return null; } /** * Returns the global error page id + * * @internal + * @return string */ public function errorPageId(): string { @@ -221,6 +259,8 @@ class Site extends ModelWithContent /** * Checks if the site exists on disk + * + * @return bool */ public function exists(): bool { @@ -229,15 +269,27 @@ class Site extends ModelWithContent /** * Returns the home page object + * + * @return \Kirby\Cms\Page|null */ - public function homePage(): Page|null + public function homePage() { - return $this->homePage ??= $this->find($this->homePageId()); + if (is_a($this->homePage, 'Kirby\Cms\Page') === true) { + return $this->homePage; + } + + if ($home = $this->find($this->homePageId())) { + return $this->homePage = $home; + } + + return null; } /** * Returns the global home page id + * * @internal + * @return string */ public function homePageId(): string { @@ -247,7 +299,9 @@ class Site extends ModelWithContent /** * Creates an inventory of all files * and children in the site directory + * * @internal + * @return array */ public function inventory(): array { @@ -269,10 +323,11 @@ class Site extends ModelWithContent * Compares the current object with the given site object * * @param mixed $site + * @return bool */ public function is($site): bool { - if ($site instanceof self === false) { + if (is_a($site, 'Kirby\Cms\Site') === false) { return false; } @@ -281,7 +336,9 @@ class Site extends ModelWithContent /** * Returns the root to the media folder for the site + * * @internal + * @return string */ public function mediaRoot(): string { @@ -290,7 +347,9 @@ class Site extends ModelWithContent /** * The site's base url for any files + * * @internal + * @return string */ public function mediaUrl(): string { @@ -300,12 +359,18 @@ class Site extends ModelWithContent /** * Gets the last modification date of all pages * in the content folder. + * + * @param string|null $format + * @param string|null $handler + * @return int|string */ - public function modified( - string|null $format = null, - string|null $handler = null - ): int|string { - return Dir::modified($this->root(), $format, $handler); + public function modified(?string $format = null, ?string $handler = null) + { + return Dir::modified( + $this->root(), + $format, + $handler ?? $this->kirby()->option('date.handler', 'date') + ); } /** @@ -319,53 +384,62 @@ class Site extends ModelWithContent * * @param string|null $path omit for current page, * otherwise e.g. `notes/across-the-ocean` + * @return \Kirby\Cms\Page|null */ - public function page(string|null $path = null): Page|null + public function page(?string $path = null) { if ($path !== null) { return $this->find($path); } - if ($this->page instanceof Page) { + if (is_a($this->page, 'Kirby\Cms\Page') === true) { return $this->page; } try { return $this->page = $this->homePage(); - } catch (LogicException) { + } catch (LogicException $e) { return $this->page = null; } } /** * Alias for `Site::children()` + * + * @return \Kirby\Cms\Pages */ - public function pages(): Pages + public function pages() { return $this->children(); } /** * Returns the panel info object + * + * @return \Kirby\Panel\Site */ - public function panel(): Panel + public function panel() { return new Panel($this); } /** * Returns the permissions object for this site + * + * @return \Kirby\Cms\SitePermissions */ - public function permissions(): SitePermissions + public function permissions() { return new SitePermissions($this); } /** * Preview Url + * * @internal + * @return string|null */ - public function previewUrl(): string|null + public function previewUrl(): ?string { $preview = $this->blueprint()->preview(); @@ -384,6 +458,8 @@ class Site extends ModelWithContent /** * Returns the absolute path to the content directory + * + * @return string */ public function root(): string { @@ -394,16 +470,22 @@ class Site extends ModelWithContent * Returns the SiteRules class instance * which is being used in various methods * to check for valid actions and input. + * + * @return \Kirby\Cms\SiteRules */ - protected function rules(): SiteRules + protected function rules() { return new SiteRules(); } /** * Search all pages in the site + * + * @param string|null $query + * @param array $params + * @return \Kirby\Cms\Pages */ - public function search(string|null $query = null, string|array $params = []): Pages + public function search(?string $query = null, $params = []) { return $this->index()->search($query, $params); } @@ -411,9 +493,10 @@ class Site extends ModelWithContent /** * Sets the Blueprint object * + * @param array|null $blueprint * @return $this */ - protected function setBlueprint(array|null $blueprint = null): static + protected function setBlueprint(?array $blueprint = null) { if ($blueprint !== null) { $blueprint['model'] = $this; @@ -423,27 +506,88 @@ class Site extends ModelWithContent return $this; } + /** + * Sets the id of the error page, which + * is used in the errorPage method + * to get the default error page if nothing + * else is set. + * + * @param string $id + * @return $this + */ + protected function setErrorPageId(string $id = 'error') + { + $this->errorPageId = $id; + return $this; + } + + /** + * Sets the id of the home page, which + * is used in the homePage method + * to get the default home page if nothing + * else is set. + * + * @param string $id + * @return $this + */ + protected function setHomePageId(string $id = 'home') + { + $this->homePageId = $id; + return $this; + } + + /** + * Sets the current page object + * + * @internal + * @param \Kirby\Cms\Page|null $page + * @return $this + */ + public function setPage(?Page $page = null) + { + $this->page = $page; + return $this; + } + + /** + * Sets the Url + * + * @param string|null $url + * @return $this + */ + protected function setUrl(?string $url = null) + { + $this->url = $url; + return $this; + } + /** * Converts the most important site * properties to an array + * + * @return array */ public function toArray(): array { - return array_merge(parent::toArray(), [ - 'children' => $this->children()->keys(), - 'errorPage' => $this->errorPage()?->id() ?? false, - 'files' => $this->files()->keys(), - 'homePage' => $this->homePage()?->id() ?? false, - 'page' => $this->page()?->id() ?? false, - 'title' => $this->title()->value(), - 'url' => $this->url(), - ]); + return [ + 'children' => $this->children()->keys(), + 'content' => $this->content()->toArray(), + 'errorPage' => $this->errorPage() ? $this->errorPage()->id() : false, + 'files' => $this->files()->keys(), + 'homePage' => $this->homePage() ? $this->homePage()->id() : false, + 'page' => $this->page() ? $this->page()->id() : false, + 'title' => $this->title()->value(), + 'url' => $this->url(), + ]; } /** * Returns the Url + * + * @param string|null $language + * @return string */ - public function url(string|null $language = null): string + public function url(?string $language = null): string { if ($language !== null || $this->kirby()->multilang() === true) { return $this->urlForLanguage($language); @@ -454,12 +598,14 @@ class Site extends ModelWithContent /** * Returns the translated url + * * @internal + * @param string|null $languageCode + * @param array|null $options + * @return string */ - public function urlForLanguage( - string|null $languageCode = null, - array|null $options = null - ): string { + public function urlForLanguage(?string $languageCode = null, ?array $options = null): string + { if ($language = $this->kirby()->language($languageCode)) { return $language->url(); } @@ -471,38 +617,83 @@ class Site extends ModelWithContent * Sets the current page by * id or page object and * returns the current page + * * @internal + * @param string|\Kirby\Cms\Page $page + * @param string|null $languageCode + * @return \Kirby\Cms\Page */ - public function visit( - string|Page $page, - string|null $languageCode = null - ): Page { + public function visit($page, ?string $languageCode = null) + { if ($languageCode !== null) { $this->kirby()->setCurrentTranslation($languageCode); $this->kirby()->setCurrentLanguage($languageCode); } // convert ids to a Page object - if (is_string($page) === true) { + if (is_string($page)) { $page = $this->find($page); } // handle invalid pages - if ($page instanceof Page === false) { + if (is_a($page, 'Kirby\Cms\Page') === false) { throw new InvalidArgumentException('Invalid page object'); } - // set and return the current active page - return $this->page = $page; + // set the current active page + $this->setPage($page); + + // return the page + return $page; } /** * Checks if any content of the site has been * modified after the given unix timestamp * This is mainly used to auto-update the cache + * + * @param mixed $time + * @return bool */ - public function wasModifiedAfter(int $time): bool + public function wasModifiedAfter($time): bool { return Dir::wasModifiedAfter($this->root(), $time); } + + + /** + * Deprecated! + */ + + /** + * Returns the full path without leading slash + * + * @todo Remove in 3.8.0 + * + * @internal + * @return string + * @codeCoverageIgnore + */ + public function panelPath(): string + { + Helpers::deprecated('Cms\Site::panelPath() has been deprecated and will be removed in Kirby 3.8.0. Use $site->panel()->path() instead.'); + return $this->panel()->path(); + } + + /** + * Returns the url to the editing view + * in the panel + * + * @todo Remove in 3.8.0 + * + * @internal + * @param bool $relative + * @return string + * @codeCoverageIgnore + */ + public function panelUrl(bool $relative = false): string + { + Helpers::deprecated('Cms\Site::panelUrl() has been deprecated and will be removed in Kirby 3.8.0. Use $site->panel()->url() instead.'); + return $this->panel()->url($relative); + } } diff --git a/kirby/src/Cms/SiteActions.php b/kirby/src/Cms/SiteActions.php index 9d67d5d..dd1ceb9 100644 --- a/kirby/src/Cms/SiteActions.php +++ b/kirby/src/Cms/SiteActions.php @@ -23,12 +23,14 @@ trait SiteActions * 3. commits the store action * 4. sends the after hook * 5. returns the result + * + * @param string $action + * @param mixed ...$arguments + * @param Closure $callback + * @return mixed */ - protected function commit( - string $action, - array $arguments, - Closure $callback - ): mixed { + protected function commit(string $action, array $arguments, Closure $callback) + { $old = $this->hardcopy(); $kirby = $this->kirby(); $argumentValues = array_values($arguments); @@ -46,35 +48,29 @@ trait SiteActions /** * Change the site title + * + * @param string $title + * @param string|null $languageCode + * @return static */ - public function changeTitle( - string $title, - string|null $languageCode = null - ): static { - // if the `$languageCode` argument is not set and is not the default language - // the `$languageCode` argument is sent as the current language - if ( - $languageCode === null && - $language = $this->kirby()->language() - ) { - if ($language->isDefault() === false) { - $languageCode = $language->code(); - } - } + public function changeTitle(string $title, string $languageCode = null) + { + $site = $this; + $title = trim($title); + $arguments = compact('site', 'title', 'languageCode'); - $arguments = ['site' => $this, 'title' => trim($title), 'languageCode' => $languageCode]; - - return $this->commit( - 'changeTitle', - $arguments, - fn ($site, $title, $languageCode) => $site->save(['title' => $title], $languageCode) - ); + return $this->commit('changeTitle', $arguments, function ($site, $title, $languageCode) { + return $site->save(['title' => $title], $languageCode); + }); } /** * Creates a main page + * + * @param array $props + * @return \Kirby\Cms\Page */ - public function createChild(array $props): Page + public function createChild(array $props) { $props = array_merge($props, [ 'url' => null, @@ -91,16 +87,14 @@ trait SiteActions * * @return $this */ - public function purge(): static + public function purge() { - parent::purge(); - - $this->blueprint = null; - $this->children = null; - $this->childrenAndDrafts = null; - $this->drafts = null; - $this->files = null; - $this->inventory = null; + $this->blueprint = null; + $this->children = null; + $this->content = null; + $this->files = null; + $this->inventory = null; + $this->translations = null; return $this; } diff --git a/kirby/src/Cms/SiteBlueprint.php b/kirby/src/Cms/SiteBlueprint.php index 5f8b751..ce38ab9 100644 --- a/kirby/src/Cms/SiteBlueprint.php +++ b/kirby/src/Cms/SiteBlueprint.php @@ -17,6 +17,8 @@ class SiteBlueprint extends Blueprint /** * Creates a new page blueprint object * with the given props + * + * @param array $props */ public function __construct(array $props) { @@ -42,8 +44,10 @@ class SiteBlueprint extends Blueprint * The preview setting controls the "Open" * button in the panel and redirects it to a * different URL if necessary. + * + * @return string|bool */ - public function preview(): string|bool + public function preview() { $preview = $this->props['options']['preview'] ?? true; diff --git a/kirby/src/Cms/SitePermissions.php b/kirby/src/Cms/SitePermissions.php index 8e58415..b6ce350 100644 --- a/kirby/src/Cms/SitePermissions.php +++ b/kirby/src/Cms/SitePermissions.php @@ -13,5 +13,5 @@ namespace Kirby\Cms; */ class SitePermissions extends ModelPermissions { - protected string $category = 'site'; + protected $category = 'site'; } diff --git a/kirby/src/Cms/SiteRules.php b/kirby/src/Cms/SiteRules.php index 08da997..07db1b9 100644 --- a/kirby/src/Cms/SiteRules.php +++ b/kirby/src/Cms/SiteRules.php @@ -20,6 +20,9 @@ class SiteRules /** * Validates if the site title can be changed * + * @param \Kirby\Cms\Site $site + * @param string $title + * @return bool * @throws \Kirby\Exception\InvalidArgumentException If the title is empty * @throws \Kirby\Exception\PermissionException If the user is not allowed to change the title */ @@ -39,6 +42,9 @@ class SiteRules /** * Validates if the site can be updated * + * @param \Kirby\Cms\Site $site + * @param array $content + * @return bool * @throws \Kirby\Exception\PermissionException If the user is not allowed to update the site */ public static function update(Site $site, array $content = []): bool diff --git a/kirby/src/Cms/Structure.php b/kirby/src/Cms/Structure.php index 222881d..d86e611 100644 --- a/kirby/src/Cms/Structure.php +++ b/kirby/src/Cms/Structure.php @@ -2,6 +2,8 @@ namespace Kirby\Cms; +use Kirby\Exception\InvalidArgumentException; + /** * The Structure class wraps * array data into a nicely chainable @@ -16,38 +18,49 @@ namespace Kirby\Cms; * @copyright Bastian Allgeier * @license https://getkirby.com/license */ -class Structure extends Items +class Structure extends Collection { - public const ITEM_CLASS = StructureObject::class; + /** + * Creates a new Collection with the given objects + * + * @param array $objects Kirby\Cms\StructureObject` objects or props arrays + * @param object|null $parent + */ + public function __construct($objects = [], $parent = null) + { + $this->parent = $parent; + $this->set($objects); + } /** - * All registered structure methods + * The internal setter for collection items. + * This makes sure that nothing unexpected ends + * up in the collection. You can pass arrays or + * StructureObjects + * + * @param string $id + * @param array|StructureObject $props + * @return void + * + * @throws \Kirby\Exception\InvalidArgumentException */ - public static array $methods = []; + public function __set(string $id, $props): void + { + if (is_a($props, 'Kirby\Cms\StructureObject') === true) { + $object = $props; + } else { + if (is_array($props) === false) { + throw new InvalidArgumentException('Invalid structure data'); + } - /** - * Creates a new structure collection from a - * an array of item props - */ - public static function factory( - array $items = null, - array $params = [] - ): static { - if (is_array($items) === true) { - $items = array_map(function ($item, $index) { - if (is_array($item) === true) { - // pass a clean content array without special `Item` keys - $item['content'] = $item; - - // bake-in index as ID for all items - // TODO: remove when adding UUID supports to Structures - $item['id'] ??= $index; - } - - return $item; - }, $items, array_keys($items)); + $object = new StructureObject([ + 'content' => $props, + 'id' => $props['id'] ?? $id, + 'parent' => $this->parent, + 'structure' => $this + ]); } - return parent::factory($items, $params); + parent::__set($object->id(), $object); } } diff --git a/kirby/src/Cms/StructureObject.php b/kirby/src/Cms/StructureObject.php index 9806b7d..2b0bddd 100644 --- a/kirby/src/Cms/StructureObject.php +++ b/kirby/src/Cms/StructureObject.php @@ -2,8 +2,6 @@ namespace Kirby\Cms; -use Kirby\Content\Content; - /** * The StructureObject represents each item * in a Structure collection. StructureObjects @@ -20,38 +18,44 @@ use Kirby\Content\Content; * @copyright Bastian Allgeier * @license https://getkirby.com/license */ -class StructureObject extends Item +class StructureObject extends Model { - use HasMethods; - - public const ITEMS_CLASS = Structure::class; - - protected Content $content; + use HasSiblings; /** - * Creates a new StructureObject with the given props + * The content + * + * @var Content */ - public function __construct(array $params = []) - { - parent::__construct($params); + protected $content; - $this->content = new Content( - $params['content'] ?? $params['params'] ?? [], - $this->parent - ); - } + /** + * @var string + */ + protected $id; + + /** + * @var \Kirby\Cms\Site|\Kirby\Cms\Page|\Kirby\Cms\File|\Kirby\Cms\User|null + */ + protected $parent; + + /** + * The parent Structure collection + * + * @var Structure + */ + protected $structure; /** * Modified getter to also return fields * from the object's content + * + * @param string $method + * @param array $arguments + * @return mixed */ - public function __call(string $method, array $args = []): mixed + public function __call(string $method, array $arguments = []) { - // structure object methods - if ($this->hasMethod($method) === true) { - return $this->callMethod($method, $args); - } - // public property access if (isset($this->$method) === true) { return $this->$method; @@ -61,25 +65,145 @@ class StructureObject extends Item } /** - * Returns the content + * Creates a new StructureObject with the given props + * + * @param array $props */ - public function content(): Content + public function __construct(array $props) { - return $this->content; + $this->setProperties($props); + } + + /** + * Returns the content + * + * @return \Kirby\Cms\Content + */ + public function content() + { + if (is_a($this->content, 'Kirby\Cms\Content') === true) { + return $this->content; + } + + if (is_array($this->content) !== true) { + $this->content = []; + } + + return $this->content = new Content($this->content, $this->parent()); + } + + /** + * Returns the required id + * + * @return string + */ + public function id(): string + { + return $this->id; + } + + /** + * Compares the current object with the given structure object + * + * @param mixed $structure + * @return bool + */ + public function is($structure): bool + { + if (is_a($structure, 'Kirby\Cms\StructureObject') === false) { + return false; + } + + return $this === $structure; + } + + /** + * Returns the parent Model object + * + * @return \Kirby\Cms\Model + */ + public function parent() + { + return $this->parent; + } + + /** + * Sets the Content object with the given parent + * + * @param array|null $content + * @return $this + */ + protected function setContent(array $content = null) + { + $this->content = $content; + return $this; + } + + /** + * Sets the id of the object. + * The id is required. The structure + * class will use the index, if no id is + * specified. + * + * @param string $id + * @return $this + */ + protected function setId(string $id) + { + $this->id = $id; + return $this; + } + + /** + * Sets the parent Model + * + * @return $this + * @param \Kirby\Cms\Site|\Kirby\Cms\Page|\Kirby\Cms\File|\Kirby\Cms\User|null $parent + */ + protected function setParent(Model $parent = null) + { + $this->parent = $parent; + return $this; + } + + /** + * Sets the parent Structure collection + * + * @param \Kirby\Cms\Structure|null $structure + * @return $this + */ + protected function setStructure(Structure $structure = null) + { + $this->structure = $structure; + return $this; + } + + /** + * Returns the parent Structure collection as siblings + * + * @return \Kirby\Cms\Structure + */ + protected function siblingsCollection() + { + return $this->structure; } /** * Converts all fields in the object to a * plain associative array. The id is - * injected from the parent into the array + * injected into the array afterwards * to make sure it's always present and - * not overloaded by the content. + * not overloaded in the content. + * + * @return array */ public function toArray(): array { - return array_merge( - $this->content()->toArray(), - parent::toArray() - ); + $array = $this->content()->toArray(); + $array['id'] = $this->id(); + + ksort($array); + + return $array; } } diff --git a/kirby/src/Cms/System.php b/kirby/src/Cms/System.php index f1a7ee6..bf19418 100644 --- a/kirby/src/Cms/System.php +++ b/kirby/src/Cms/System.php @@ -2,12 +2,16 @@ namespace Kirby\Cms; -use Kirby\Cms\System\UpdateStatus; +use Kirby\Data\Json; +use Kirby\Exception\Exception; use Kirby\Exception\InvalidArgumentException; use Kirby\Exception\PermissionException; use Kirby\Filesystem\Dir; +use Kirby\Filesystem\F; +use Kirby\Http\Remote; use Kirby\Toolkit\A; use Kirby\Toolkit\Str; +use Kirby\Toolkit\V; use Throwable; /** @@ -26,38 +30,60 @@ use Throwable; */ class System { - // cache - protected License|null $license = null; - protected UpdateStatus|null $updateStatus = null; + /** + * @var \Kirby\Cms\App + */ + protected $app; - public function __construct(protected App $app) + /** + * @param \Kirby\Cms\App $app + */ + public function __construct(App $app) { + $this->app = $app; + // try to create all folders that could be missing $this->init(); } + /** + * Improved `var_dump` output + * + * @return array + */ + public function __debugInfo(): array + { + return $this->toArray(); + } + /** * Check for a writable accounts folder + * + * @return bool */ public function accounts(): bool { - return is_writable($this->app->root('accounts')) === true; + return is_writable($this->app->root('accounts')); } /** * Check for a writable content folder + * + * @return bool */ public function content(): bool { - return is_writable($this->app->root('content')) === true; + return is_writable($this->app->root('content')); } /** * Check for an existing curl extension + * + * @return bool */ public function curl(): bool { - return extension_loaded('curl') === true; + return extension_loaded('curl'); } /** @@ -66,8 +92,9 @@ class System * root. Otherwise it will return null. * * @param string $folder 'git', 'content', 'site', 'kirby' + * @return string|null */ - public function exposedFileUrl(string $folder): string|null + public function exposedFileUrl(string $folder): ?string { if (!$url = $this->folderUrl($folder)) { return null; @@ -75,10 +102,7 @@ class System switch ($folder) { case 'content': - return $url . '/' . basename($this->app->site()->storage()->contentFile( - 'published', - 'default' - )); + return $url . '/' . basename($this->app->site()->contentFile()); case 'git': return $url . '/config'; case 'kirby': @@ -114,20 +138,19 @@ class System * root. Otherwise it will return null. * * @param string $folder 'git', 'content', 'site', 'kirby' + * @return string|null */ - public function folderUrl(string $folder): string|null + public function folderUrl(string $folder): ?string { $index = $this->app->root('index'); - $root = match ($folder) { - 'git' => $index . '/.git', - default => $this->app->root($folder) - }; - if ( - $root === null || - is_dir($root) === false || - is_dir($index) === false - ) { + if ($folder === 'git') { + $root = $index . '/.git'; + } else { + $root = $this->app->root($folder); + } + + if ($root === null || is_dir($root) === false || is_dir($index) === false) { return null; } @@ -153,103 +176,69 @@ class System /** * Returns the app's human-readable * index URL without scheme + * + * @return string */ public function indexUrl(): string { - return $this->app->url('index', true) - ->setScheme(null) - ->setSlash(false) - ->toString(); - } - - /** - * Returns an array with relevant system information - * used for debugging - * @since 4.3.0 - */ - public function info(): array - { - return [ - 'kirby' => $this->app->version(), - 'php' => phpversion(), - 'server' => $this->serverSoftware(), - 'license' => $this->license()->label(), - 'languages' => $this->app->languages()->values( - fn ($lang) => $lang->code() - ) - ]; + return $this->app->url('index', true)->setScheme(null)->setSlash(false)->toString(); } /** * Create the most important folders * if they don't exist yet * + * @return void * @throws \Kirby\Exception\PermissionException */ - public function init(): void + public function init() { // init /site/accounts try { Dir::make($this->app->root('accounts')); - } catch (Throwable) { + } catch (Throwable $e) { throw new PermissionException('The accounts directory could not be created'); } // init /site/sessions try { Dir::make($this->app->root('sessions')); - } catch (Throwable) { + } catch (Throwable $e) { throw new PermissionException('The sessions directory could not be created'); } // init /content try { Dir::make($this->app->root('content')); - } catch (Throwable) { + } catch (Throwable $e) { throw new PermissionException('The content directory could not be created'); } // init /media try { Dir::make($this->app->root('media')); - } catch (Throwable) { + } catch (Throwable $e) { throw new PermissionException('The media directory could not be created'); } } /** - * Check if the Panel has 2FA activated - */ - public function is2FA(): bool - { - return ($this->loginMethods()['password']['2fa'] ?? null) === true; - } - - /** - * Check if the Panel has 2FA with TOTP activated - */ - public function is2FAWithTOTP(): bool - { - return - $this->is2FA() === true && - in_array('totp', $this->app->auth()->enabledChallenges()) === true; - } - - /** - * Check if the Panel is installable. + * Check if the panel is installable. * On a public server the panel.install * option must be explicitly set to true * to get the installer up and running. + * + * @return bool */ public function isInstallable(): bool { - return - $this->isLocal() === true || - $this->app->option('panel.install', false) === true; + return $this->isLocal() === true || $this->app->option('panel.install', false) === true; } /** * Check if Kirby is already installed + * + * @return bool */ public function isInstalled(): bool { @@ -258,6 +247,8 @@ class System /** * Check if this is a local installation + * + * @return bool */ public function isLocal(): bool { @@ -266,6 +257,8 @@ class System /** * Check if all tests pass + * + * @return bool */ public function isOk(): bool { @@ -275,16 +268,108 @@ class System /** * Loads the license file and returns * the license information if available + * + * @return string|bool License key or `false` if the current user has + * permissions for access.settings, otherwise just a + * boolean that tells whether a valid license is active */ - public function license(): License + public function license() { - return $this->license ??= License::read(); + try { + $license = Json::read($this->app->root('license')); + } catch (Throwable $e) { + return false; + } + + // check for all required fields for the validation + if (isset( + $license['license'], + $license['order'], + $license['date'], + $license['email'], + $license['domain'], + $license['signature'] + ) !== true) { + return false; + } + + // build the license verification data + $data = [ + 'license' => $license['license'], + 'order' => $license['order'], + 'email' => hash('sha256', $license['email'] . 'kwAHMLyLPBnHEskzH9pPbJsBxQhKXZnX'), + 'domain' => $license['domain'], + 'date' => $license['date'] + ]; + + + // get the public key + $pubKey = F::read($this->app->root('kirby') . '/kirby.pub'); + + // verify the license signature + if (openssl_verify(json_encode($data), hex2bin($license['signature']), $pubKey, 'RSA-SHA256') !== 1) { + return false; + } + + // verify the URL + if ($this->licenseUrl() !== $this->licenseUrl($license['domain'])) { + return false; + } + + // only return the actual license key if the + // current user has appropriate permissions + $user = $this->app->user(); + if ($user && $user->isAdmin() === true) { + return $license['license']; + } else { + return true; + } + } + + /** + * Normalizes the app's index URL for + * licensing purposes + * + * @param string|null $url Input URL, by default the app's index URL + * @return string Normalized URL + */ + protected function licenseUrl(string $url = null): string + { + if ($url === null) { + $url = $this->indexUrl(); + } + + // remove common "testing" subdomains as well as www. + // to ensure that installations of the same site have + // the same license URL; only for installations at /, + // subdirectory installations are difficult to normalize + if (Str::contains($url, '/') === false) { + if (Str::startsWith($url, 'www.')) { + return substr($url, 4); + } + + if (Str::startsWith($url, 'dev.')) { + return substr($url, 4); + } + + if (Str::startsWith($url, 'test.')) { + return substr($url, 5); + } + + if (Str::startsWith($url, 'staging.')) { + return substr($url, 8); + } + } + + return $url; } /** * Returns the configured UI modes for the login form * with their respective options * + * @return array + * * @throws \Kirby\Exception\InvalidArgumentException If the configuration is invalid * (only in debug mode) */ @@ -343,38 +428,45 @@ class System /** * Check for an existing mbstring extension + * + * @return bool */ public function mbString(): bool { - return extension_loaded('mbstring') === true; + return extension_loaded('mbstring'); } /** * Check for a writable media folder + * + * @return bool */ public function media(): bool { - return is_writable($this->app->root('media')) === true; + return is_writable($this->app->root('media')); } /** * Check for a valid PHP version + * + * @return bool */ public function php(): bool { return - version_compare(PHP_VERSION, '8.1.0', '>=') === true && - version_compare(PHP_VERSION, '8.4.0', '<') === true; + version_compare(PHP_VERSION, '7.4.0', '>=') === true && + version_compare(PHP_VERSION, '8.2.0', '<') === true; } /** * Returns a sorted collection of all * installed plugins + * + * @return \Kirby\Cms\Collection */ - public function plugins(): Collection + public function plugins() { - $plugins = new Collection($this->app->plugins()); - return $plugins->sortBy('name', 'asc'); + return (new Collection(App::instance()->plugins()))->sortBy('name', 'asc'); } /** @@ -382,50 +474,123 @@ class System * and adds it to the .license file in the config * folder if possible. * + * @param string|null $license + * @param string|null $email + * @return bool * @throws \Kirby\Exception\Exception * @throws \Kirby\Exception\InvalidArgumentException */ public function register(string $license = null, string $email = null): bool { - $license = new License( - code: $license, - domain: $this->indexUrl(), - email: $email, - ); + if (Str::startsWith($license, 'K3-PRO-') === false) { + throw new InvalidArgumentException([ + 'key' => 'license.format' + ]); + } + + if (V::email($email) === false) { + throw new InvalidArgumentException([ + 'key' => 'license.email' + ]); + } + + // @codeCoverageIgnoreStart + $response = Remote::get('https://hub.getkirby.com/register', [ + 'data' => [ + 'license' => $license, + 'email' => Str::lower(trim($email)), + 'domain' => $this->indexUrl() + ] + ]); + + if ($response->code() !== 200) { + throw new Exception($response->content()); + } + + // decode the response + $json = Json::decode($response->content()); + + // replace the email with the plaintext version + $json['email'] = $email; + + // where to store the license file + $file = $this->app->root('license'); + + // save the license information + Json::write($file, $json); + + if ($this->license() === false) { + throw new InvalidArgumentException([ + 'key' => 'license.verification' + ]); + } + // @codeCoverageIgnoreEnd - $this->license = $license->register(); return true; } /** - * Returns the detected server software + * Check for a valid server environment + * + * @return bool */ - public function serverSoftware(): string + public function server(): bool { - return $this->app->environment()->get('SERVER_SOFTWARE', '–'); + return $this->serverSoftware() !== null; + } + + /** + * Returns the detected server software + * + * @return string|null + */ + public function serverSoftware(): ?string + { + if ($servers = $this->app->option('servers')) { + $servers = A::wrap($servers); + } else { + $servers = [ + 'apache', + 'caddy', + 'litespeed', + 'nginx', + 'php' + ]; + } + + $software = $this->app->environment()->get('SERVER_SOFTWARE', ''); + + preg_match('!(' . implode('|', $servers) . ')!i', $software, $matches); + + return $matches[0] ?? null; } /** * Check for a writable sessions folder + * + * @return bool */ public function sessions(): bool { - return is_writable($this->app->root('sessions')) === true; + return is_writable($this->app->root('sessions')); } /** * Get an status array of all checks + * + * @return array */ public function status(): array { return [ - 'accounts' => $this->accounts(), - 'content' => $this->content(), - 'curl' => $this->curl(), - 'sessions' => $this->sessions(), - 'mbstring' => $this->mbstring(), - 'media' => $this->media(), - 'php' => $this->php() + 'accounts' => $this->accounts(), + 'content' => $this->content(), + 'curl' => $this->curl(), + 'sessions' => $this->sessions(), + 'mbstring' => $this->mbstring(), + 'media' => $this->media(), + 'php' => $this->php(), + 'server' => $this->server(), ]; } @@ -433,56 +598,35 @@ class System * Returns the site's title as defined in the * content file or `site.yml` blueprint * @since 3.6.0 + * + * @return string */ public function title(): string { $site = $this->app->site(); - if ($site->title()->isNotEmpty() === true) { + if ($site->title()->isNotEmpty()) { return $site->title()->value(); } return $site->blueprint()->title(); } + /** + * @return array + */ public function toArray(): array { return $this->status(); } - /** - * Returns the update status object unless - * the update check for Kirby has been disabled - * @since 3.8.0 - * - * @param array|null $data Custom override for the getkirby.com update data - */ - public function updateStatus(array|null $data = null): UpdateStatus|null - { - if ($this->updateStatus !== null) { - return $this->updateStatus; - } - - $kirby = $this->app; - $option = - $kirby->option('updates.kirby') ?? - $kirby->option('updates', true); - - if ($option === false) { - return null; - } - - return $this->updateStatus = new UpdateStatus( - $kirby, - $option === 'security', - $data - ); - } - /** * Upgrade to the new folder separator + * + * @param string $root + * @return void */ - public static function upgradeContent(string $root): void + public static function upgradeContent(string $root) { $index = Dir::read($root); @@ -496,13 +640,4 @@ class System } } } - - /** - * Improved `var_dump` output - * @codeCoverageIgnore - */ - public function __debugInfo(): array - { - return $this->toArray(); - } } diff --git a/kirby/src/Cms/System/UpdateStatus.php b/kirby/src/Cms/System/UpdateStatus.php deleted file mode 100644 index 8adf65d..0000000 --- a/kirby/src/Cms/System/UpdateStatus.php +++ /dev/null @@ -1,838 +0,0 @@ - - * @link https://getkirby.com - * @copyright Bastian Allgeier - * @license https://getkirby.com/license - */ -class UpdateStatus -{ - /** - * Host to request the update data from - */ - public static string $host = 'https://assets.getkirby.com'; - - /** - * Marker that stores whether a previous remote - * request timed out - */ - protected static bool $timedOut = false; - - // props set in constructor - protected App $app; - protected string|null $currentVersion; - protected array|null $data; - protected string|null $pluginName; - protected bool $securityOnly; - - // props updated throughout the class - protected array $exceptions = []; - protected bool|null $noVulns = null; - - // caches - protected array $messages; - protected array $targetData; - protected array|bool $versionEntry; - protected array $vulnerabilities; - - /** - * @param array|null $data Custom override for the getkirby.com update data - */ - public function __construct( - App|Plugin $package, - bool $securityOnly = false, - array|null $data = null - ) { - if ($package instanceof App) { - $this->app = $package; - $this->pluginName = null; - } else { - $this->app = $package->kirby(); - $this->pluginName = $package->name(); - } - - $this->securityOnly = $securityOnly; - $this->currentVersion = $package->version(); - - $this->data = $data ?? $this->loadData(); - } - - /** - * Returns the currently installed version - */ - public function currentVersion(): string|null - { - return $this->currentVersion; - } - - /** - * Returns the list of exception objects that were - * collected during data fetching and processing - */ - public function exceptions(): array - { - return $this->exceptions; - } - - /** - * Returns the list of exception message strings that - * were collected during data fetching and processing - */ - public function exceptionMessages(): array - { - return array_map(fn ($e) => $e->getMessage(), $this->exceptions()); - } - - /** - * Returns the Panel icon for the status value - * - * @return string 'check'|'alert'|'info' - */ - public function icon(): string - { - return match ($this->status()) { - 'up-to-date', 'not-vulnerable' => 'check', - 'security-update', 'security-upgrade' => 'alert', - 'update', 'upgrade' => 'info', - default => 'question' - }; - } - - /** - * Returns the human-readable and translated label - * for the update status - */ - public function label(): string - { - return I18n::template( - 'system.updateStatus.' . $this->status(), - '?', - ['version' => $this->targetVersion() ?? '?'] - ); - } - - /** - * Returns the latest available version - */ - public function latestVersion(): string|null - { - return $this->data['latest'] ?? null; - } - - /** - * Returns all security messages unless no data - * is available - */ - public function messages(): array|null - { - if (isset($this->messages) === true) { - return $this->messages; - } - - if ( - $this->data === null || - $this->currentVersion === null || - $this->currentVersion === '' - ) { - return null; - } - - $type = $this->pluginName ? 'plugin' : 'kirby'; - - // collect all matching custom messages - $filters = [ - 'kirby' => $this->app->version(), - // some PHP version strings contain extra info that makes them - // invalid so we need to strip it off - 'php' => preg_replace('/^([^~+-]+).*$/', '$1', phpversion()) - ]; - - if ($type === 'plugin') { - $filters['plugin'] = $this->currentVersion; - } - - $messages = $this->filterArrayByVersion( - $this->data['messages'] ?? [], - $filters, - 'while filtering messages' - ); - - // add a message for each vulnerability - // the current version is affected by - foreach ($this->vulnerabilities() as $vulnerability) { - if ($type === 'plugin') { - $vulnerability['plugin'] = $this->pluginName; - } - - $messages[] = [ - 'text' => I18n::template( - 'system.issues.vulnerability.' . $type, - null, - $vulnerability - ), - 'link' => $vulnerability['link'] ?? null, - 'icon' => 'bug' - ]; - } - - // add special message for end-of-life versions - $versionEntry = $this->versionEntry(); - if (($versionEntry['status'] ?? null) === 'end-of-life') { - $messages[] = [ - 'text' => match ($type) { - 'plugin' => I18n::template( - 'system.issues.eol.plugin', - null, - ['plugin' => $this->pluginName] - ), - default => I18n::translate('system.issues.eol.kirby') - }, - 'link' => $versionEntry['status-link'] ?? 'https://getkirby.com/security/end-of-life', - 'icon' => 'bell' - ]; - } - - // add special message for end-of-life PHP versions - $phpMajor = PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION; - $phpEol = $this->data['php'][$phpMajor] ?? null; - if (is_string($phpEol) === true && $eolTime = strtotime($phpEol)) { - // the timestamp is available and valid, now check if it is in the past - if ($eolTime < time()) { - $messages[] = [ - 'text' => I18n::template('system.issues.eol.php', null, ['release' => $phpMajor]), - 'link' => 'https://getkirby.com/security/php-end-of-life', - 'icon' => 'bell' - ]; - } - } - - return $this->messages = $messages; - } - - /** - * Returns the raw status value - * - * @return string 'up-to-date'|'not-vulnerable'|'security-update'| - * 'security-upgrade'|'update'|'upgrade'|'unreleased'|'error' - */ - public function status(): string - { - return $this->targetData()['status']; - } - - /** - * Version that is suggested for the update/upgrade - */ - public function targetVersion(): string|null - { - return $this->targetData()['version']; - } - - /** - * Returns the Panel theme for the status value - * - * @return string 'positive'|'negative'|'info'|'notice' - */ - public function theme(): string - { - return match ($this->status()) { - 'up-to-date', 'not-vulnerable' => 'positive', - 'security-update', 'security-upgrade' => 'negative', - 'update', 'upgrade' => 'info', - default => 'notice' - }; - } - - /** - * Returns the most important human-readable - * status information as array - */ - public function toArray(): array - { - return [ - 'currentVersion' => $this->currentVersion() ?? '?', - 'icon' => $this->icon(), - 'label' => $this->label(), - 'latestVersion' => $this->latestVersion() ?? '?', - 'pluginName' => $this->pluginName, - 'theme' => $this->theme(), - 'url' => $this->url(), - ]; - } - - /** - * URL of the target version with fallback - * to the URL of the current version; - * `null` is returned if no URL is known - */ - public function url(): string|null - { - return $this->targetData()['url']; - } - - /** - * Returns all vulnerabilities the current version - * is affected by unless no data is available - */ - public function vulnerabilities(): array|null - { - if (isset($this->vulnerabilities) === true) { - return $this->vulnerabilities; - } - - if ( - $this->data === null || - $this->currentVersion === null || - $this->currentVersion === '' - ) { - return null; - } - - // shortcut for versions without vulnerabilities - $this->versionEntry(); - if ($this->noVulns === true) { - return $this->vulnerabilities = []; - } - - // unstable releases are released before their respective - // stable release and would not be matched by the constraints, - // but they will likely also contain the same vulnerabilities; - // so we strip off any non-numeric version modifiers from the end - preg_match('/^([0-9.]+)/', $this->currentVersion, $matches); - $currentVersion = $matches[1]; - - $vulnerabilities = $this->filterArrayByVersion( - $this->data['incidents'] ?? [], - ['affected' => $currentVersion], - 'while filtering incidents' - ); - - // sort the vulnerabilities by severity (with critical first) - $severities = array_map( - fn ($vulnerability) => match ($vulnerability['severity'] ?? null) { - 'critical' => 4, - 'high' => 3, - 'medium' => 2, - 'low' => 1, - default => 0 - }, - $vulnerabilities - ); - array_multisort($severities, SORT_DESC, $vulnerabilities); - - return $this->vulnerabilities = $vulnerabilities; - } - - /** - * Compares a version against a Composer version constraint - * and returns whether the constraint is satisfied - * - * @param string $reason Suffix for error messages - */ - protected function checkConstraint(string $version, string $constraint, string $reason): bool - { - try { - return Semver::satisfies($version, $constraint); - } catch (Exception $e) { - $package = $this->packageName(); - $message = 'Error comparing version constraint for ' . $package . ' ' . $reason . ': ' . $e->getMessage(); - - $exception = new KirbyException([ - 'fallback' => $message, - 'previous' => $e - ]); - $this->exceptions[] = $exception; - - return false; - } - } - - /** - * Filters a two-level array with one or multiple version constraints - * for each value by one or multiple version filters; - * values that don't contain the filter keys are removed - * - * @param array $array Array that contains associative arrays - * @param array $filters Associative array `field => version` - * @param string $reason Suffix for error messages - */ - protected function filterArrayByVersion(array $array, array $filters, string $reason): array - { - return array_filter($array, function ($item) use ($filters, $reason): bool { - foreach ($filters as $key => $version) { - if (isset($item[$key]) !== true) { - $package = $this->packageName(); - $this->exceptions[] = new KirbyException('Missing constraint ' . $key . ' for ' . $package . ' ' . $reason); - - return false; - } - - if ($this->checkConstraint($version, $item[$key], $reason) !== true) { - return false; - } - } - - return true; - }); - } - - /** - * Finds the maximum possible major update - * that is included with the current license - * - * @return string|null Version number of the update or - * `null` if no free update is possible - */ - protected function findMaximumFreeUpdate(): string|null - { - // get the timestamp of included updates - $renewal = $this->app->system()->license()->renewal(); - - if ($renewal === null || $this->data === null) { - return null; - } - - foreach ($this->data['versions'] ?? [] as $entry) { - $initialRelease = $entry['initialRelease'] ?? null; - $latest = $entry['latest'] ?? ''; - - // skip entries of irrelevant releases - if ( - is_string($initialRelease) !== true || - version_compare($latest, $this->currentVersion, '<=') === true - ) { - continue; - } - - $timestamp = strtotime($initialRelease); - - // update is free if the initial release was before the - // license renewal date - if (is_int($timestamp) === true && $timestamp < $renewal) { - return $latest; - } - } - - return null; - } - - /** - * Finds the minimum possible security update - * to fix all known vulnerabilities - * - * @return string|null Version number of the update or - * `null` if no free update is possible - */ - protected function findMinimumSecurityUpdate(): string|null - { - $versionEntry = $this->versionEntry(); - if ($versionEntry === null || isset($versionEntry['latest']) !== true) { - return null; // @codeCoverageIgnore - } - - $affected = $this->vulnerabilities(); - $incidents = $this->data['incidents'] ?? []; - $maxVersion = $versionEntry['latest']; - - // increase the target version number until there are no vulnerabilities - $version = $this->currentVersion; - $iterations = 0; - while (empty($affected) === false) { - // protect against infinite loops if the - // input data is contradicting itself - $iterations++; - if ($iterations > 10) { - return null; - } - - // if we arrived at the `$maxVersion` but still haven't found - // a version without vulnerabilities, we cannot suggest a version - if ($version === $maxVersion) { - return null; - } - - // find the minimum version that fixes all affected vulnerabilities - foreach ($affected as $incident) { - $incidentVersion = null; - foreach (Str::split($incident['fixed'], ',') as $fixed) { - // skip versions of other major releases - if ( - version_compare($fixed, $this->currentVersion, '<') === true || - version_compare($fixed, $maxVersion, '>') === true - ) { - continue; - } - - // find the minimum version that fixes this specific vulnerability - if ( - $incidentVersion === null || - version_compare($fixed, $incidentVersion, '<') === true - ) { - $incidentVersion = $fixed; - } - } - - // verify that we found at least one possible version; - // otherwise try the `$maxVersion` as a last chance before - // concluding at the top that we cannot solve the task - $incidentVersion ??= $maxVersion; - - // we need a version that fixes all vulnerabilities, so use the - // "largest of the smallest" fixed versions - if (version_compare($incidentVersion, $version, '>') === true) { - $version = $incidentVersion; - } - } - - // run another loop to verify that the suggested version - // doesn't have any known vulnerabilities on its own - $affected = $this->filterArrayByVersion( - $incidents, - ['affected' => $version], - 'while filtering incidents' - ); - } - - return $version; - } - - /** - * Loads the getkirby.com update data - * from cache or via HTTP - */ - protected function loadData(): array|null - { - // try to get the data from cache - $cache = $this->app->cache('updates'); - $key = ( - $this->pluginName ? - 'plugins/' . $this->pluginName : - 'security' - ); - - // try to return from cache; - // invalidate the cache after updates - $data = $cache->get($key); - if ( - is_array($data) === true && - $data['_version'] === $this->currentVersion - ) { - return $data; - } - - // exception message (on previous request error) - if (is_string($data) === true) { - // restore the exception to make it visible when debugging - $this->exceptions[] = new KirbyException($data); - - return null; - } - - // before we request the data, ensure we have a writable cache; - // this reduces strain on the CDN from repeated requests - if ($cache->enabled() === false) { - $this->exceptions[] = new KirbyException('Cannot check for updates without a working "updates" cache'); - - return null; - } - - // first catch every exception; - // we collect it below for debugging - try { - if (static::$timedOut === true) { - throw new Exception('Previous remote request timed out'); // @codeCoverageIgnore - } - - $response = Remote::get( - static::$host . '/' . $key . '.json', - ['timeout' => 2] - ); - - // allow status code HTTP 200 or 0 (e.g. for the file:// protocol) - if (in_array($response->code(), [0, 200], true) !== true) { - throw new Exception('HTTP error ' . $response->code()); // @codeCoverageIgnore - } - - $data = $response->json(); - - if (is_array($data) !== true) { - throw new Exception('Invalid JSON data'); - } - } catch (Exception $e) { - $package = $this->packageName(); - $message = 'Could not load update data for ' . $package . ': ' . $e->getMessage(); - - $exception = new KirbyException([ - 'fallback' => $message, - 'previous' => $e - ]); - $this->exceptions[] = $exception; - - // if the request timed out, prevent additional - // requests for other packages (e.g. plugins) - // to avoid long Panel hangs - if ($e->getCode() === 28) { - static::$timedOut = true; // @codeCoverageIgnore - } elseif (static::$timedOut === false) { - // different error than timeout; - // prevent additional requests in the - // next three days (e.g. if a plugin - // does not have a page on getkirby.com) - // by caching the exception message - // instead of the data array - $cache->set($key, $exception->getMessage(), 3 * 24 * 60); - } - - return null; - } - - // also cache the current version to - // invalidate the cache after updates - // (ensures that the update status is - // fresh directly after the update to - // avoid confusion with outdated info) - $data['_version'] = $this->currentVersion; - - // cache the retrieved data for three days - $cache->set($key, $data, 3 * 24 * 60); - - return $data; - } - - /** - * Returns the human-readable package name for error messages - */ - protected function packageName(): string - { - return $this->pluginName ? 'plugin ' . $this->pluginName : 'Kirby'; - } - - /** - * Performs the update check and returns data for the - * target version (with fallback and error handling) - */ - protected function targetData(): array - { - if (isset($this->targetData) === true) { - return $this->targetData; - } - - // check if we have valid data to compare to - $versionEntry = $this->versionEntry(); - if ($versionEntry === null) { - $version = $this->currentVersion ?? $this->data['latest'] ?? null; - - return $this->targetData = [ - 'status' => 'error', - 'url' => $version ? $this->urlFor($version, 'changes') : null, - 'version' => null - ]; - } - - // check if the current version is the latest available - if (($versionEntry['status'] ?? null) === 'latest') { - return $this->targetData = [ - 'status' => 'up-to-date', - 'url' => $this->urlFor($this->currentVersion, 'changes'), - 'version' => null - ]; - } - - // check if the current version is unreleased - if (($versionEntry['status'] ?? null) === 'unreleased') { - return $this->targetData = [ - 'status' => 'unreleased', - 'url' => null, - 'version' => null - ]; - } - - // check if the installation is vulnerable; - // minimum possible security fixes are preferred - // over all other updates and upgrades - if (count($this->vulnerabilities()) > 0) { - $update = $this->findMinimumSecurityUpdate(); - - if ($update !== null) { - // a free security update was found - return $this->targetData = [ - 'status' => 'security-update', - 'url' => $this->urlFor($update, 'changes'), - 'version' => $update - ]; - } - - // only a paid security upgrade is possible - return $this->targetData = [ - 'status' => 'security-upgrade', - 'url' => $this->urlFor($this->currentVersion, 'upgrade'), - 'version' => $this->data['latest'] ?? null - ]; - } - - // check if the user limited update checking to security updates - if ($this->securityOnly === true) { - return $this->targetData = [ - 'status' => 'not-vulnerable', - 'url' => $this->urlFor($this->currentVersion, 'changes'), - 'version' => null - ]; - } - - // check if updates within the same major version are possible - $latest = $versionEntry['latest'] ?? null; - if (is_string($latest) === true && $latest !== $this->currentVersion) { - return $this->targetData = [ - 'status' => 'update', - 'url' => $this->urlFor($latest, 'changes'), - 'version' => $latest - ]; - } - - // check if the license includes updates to a newer major version - if ($version = $this->findMaximumFreeUpdate()) { - // extract the part before the first dot - // to find the major release page URL - preg_match('/^(\w+)\./', $version, $matches); - - return $this->targetData = [ - 'status' => 'update', - 'url' => $this->urlFor($matches[1] . '.0', 'changes'), - 'version' => $version - ]; - } - - // no free update is possible, but we are not on the latest version, - // so the overall latest version must be an upgrade - return $this->targetData = [ - 'status' => 'upgrade', - 'url' => $this->urlFor($this->currentVersion, 'upgrade'), - 'version' => $this->data['latest'] ?? null - ]; - } - - /** - * Returns the URL for a specific version and purpose - */ - protected function urlFor(string $version, string $purpose): string|null - { - if ($this->data === null) { - return null; - } - - // find the first matching entry - $url = null; - foreach ($this->data['urls'] ?? [] as $constraint => $entry) { - // filter out every entry that does not match the version - if ($this->checkConstraint($version, $constraint, 'while finding URL') !== true) { - continue; - } - - // we found a result - $url = $entry[$purpose] ?? null; - if ($url !== null) { - break; - } - } - - if ($url === null) { - $package = $this->packageName(); - $message = 'No matching URL found for ' . $package . '@' . $version; - - $this->exceptions[] = new KirbyException($message); - - return null; - } - - // insert the URL template placeholders - return Str::template($url, [ - 'current' => $this->currentVersion, - 'version' => $version - ]); - } - - /** - * Extracts the first matching version entry from - * the data array unless no data is available - */ - protected function versionEntry(): array|null - { - if (isset($this->versionEntry) === true) { - // no version entry found on last call - if ($this->versionEntry === false) { - return null; - } - - return $this->versionEntry; - } - - if ( - $this->data === null || - $this->currentVersion === null || - $this->currentVersion === '' - ) { - return null; - } - - // special check for unreleased versions - $latest = $this->data['latest'] ?? null; - if ( - $latest !== null && - version_compare($this->currentVersion, $latest, '>') === true - ) { - return [ - 'status' => 'unreleased' - ]; - } - - $versionEntry = null; - foreach ($this->data['versions'] ?? [] as $constraint => $entry) { - // filter out every entry that does not match the current version - if ($this->checkConstraint($this->currentVersion, $constraint, 'while finding version entry') !== true) { - continue; - } - - if (($entry['status'] ?? null) === 'no-vulnerabilities') { - $this->noVulns = true; - - // use the next matching version entry with - // more specific update information - continue; - } - - if (($entry['status'] ?? null) === 'latest') { - $this->noVulns = true; - } - - // we found a result - $versionEntry = $entry; - break; - } - - if ($versionEntry === null) { - $package = $this->packageName(); - $message = 'No matching version entry found for ' . $package . '@' . $this->currentVersion; - - $this->exceptions[] = new KirbyException($message); - } - - $this->versionEntry = $versionEntry ?? false; - return $versionEntry; - } -} diff --git a/kirby/src/Cms/Template.php b/kirby/src/Cms/Template.php new file mode 100644 index 0000000..e3e7e07 --- /dev/null +++ b/kirby/src/Cms/Template.php @@ -0,0 +1,205 @@ + + * @link https://getkirby.com + * @copyright Bastian Allgeier + * @license https://getkirby.com/license + */ +class Template +{ + /** + * Global template data + * + * @var array + */ + public static $data = []; + + /** + * The name of the template + * + * @var string + */ + protected $name; + + /** + * Template type (html, json, etc.) + * + * @var string + */ + protected $type; + + /** + * Default template type if no specific type is set + * + * @var string + */ + protected $defaultType; + + /** + * Creates a new template object + * + * @param string $name + * @param string $type + * @param string $defaultType + */ + public function __construct(string $name, string $type = 'html', string $defaultType = 'html') + { + $this->name = strtolower($name); + $this->type = $type; + $this->defaultType = $defaultType; + } + + /** + * Converts the object to a simple string + * This is used in template filters for example + * + * @return string + */ + public function __toString(): string + { + return $this->name; + } + + /** + * Checks if the template exists + * + * @return bool + */ + public function exists(): bool + { + if ($file = $this->file()) { + return file_exists($file); + } + + return false; + } + + /** + * Returns the expected template file extension + * + * @return string + */ + public function extension(): string + { + return 'php'; + } + + /** + * Returns the default template type + * + * @return string + */ + public function defaultType(): string + { + return $this->defaultType; + } + + /** + * Returns the place where templates are located + * in the site folder and and can be found in extensions + * + * @return string + */ + public function store(): string + { + return 'templates'; + } + + /** + * Detects the location of the template file + * if it exists. + * + * @return string|null + */ + public function file(): ?string + { + if ($this->hasDefaultType() === true) { + try { + // Try the default template in the default template directory. + return F::realpath($this->root() . '/' . $this->name() . '.' . $this->extension(), $this->root()); + } catch (Exception $e) { + // ignore errors, continue searching + } + + // Look for the default template provided by an extension. + $path = App::instance()->extension($this->store(), $this->name()); + + if ($path !== null) { + return $path; + } + } + + $name = $this->name() . '.' . $this->type(); + + try { + // Try the template with type extension in the default template directory. + return F::realpath($this->root() . '/' . $name . '.' . $this->extension(), $this->root()); + } catch (Exception $e) { + // Look for the template with type extension provided by an extension. + // This might be null if the template does not exist. + return App::instance()->extension($this->store(), $name); + } + } + + /** + * Returns the template name + * + * @return string + */ + public function name(): string + { + return $this->name; + } + + /** + * @param array $data + * @return string + */ + public function render(array $data = []): string + { + return Tpl::load($this->file(), $data); + } + + /** + * Returns the root to the templates directory + * + * @return string + */ + public function root(): string + { + return App::instance()->root($this->store()); + } + + /** + * Returns the template type + * + * @return string + */ + public function type(): string + { + return $this->type; + } + + /** + * Checks if the template uses the default type + * + * @return bool + */ + public function hasDefaultType(): bool + { + $type = $this->type(); + + return $type === null || $type === $this->defaultType(); + } +} diff --git a/kirby/src/Cms/Translation.php b/kirby/src/Cms/Translation.php index 680f212..b297ba4 100644 --- a/kirby/src/Cms/Translation.php +++ b/kirby/src/Cms/Translation.php @@ -18,15 +18,30 @@ use Kirby\Toolkit\Str; */ class Translation { - public function __construct( - protected string $code, - protected array $data - ) { + /** + * @var string + */ + protected $code; + + /** + * @var array + */ + protected $data = []; + + /** + * @param string $code + * @param array $data + */ + public function __construct(string $code, array $data) + { + $this->code = $code; + $this->data = $data; } /** * Improved `var_dump` output - * @codeCoverageIgnore + * + * @return array */ public function __debugInfo(): array { @@ -35,6 +50,8 @@ class Translation /** * Returns the translation author + * + * @return string */ public function author(): string { @@ -43,6 +60,8 @@ class Translation /** * Returns the official translation code + * + * @return string */ public function code(): string { @@ -52,6 +71,8 @@ class Translation /** * Returns an array with all * translation strings + * + * @return array */ public function data(): array { @@ -61,6 +82,8 @@ class Translation /** * Returns the translation data and merges * it with the data from the default translation + * + * @return array */ public function dataWithFallback(): array { @@ -77,6 +100,8 @@ class Translation /** * Returns the writing direction * (ltr or rtl) + * + * @return string */ public function direction(): string { @@ -86,8 +111,12 @@ class Translation /** * Returns a single translation * string by key + * + * @param string $key + * @param string|null $default + * @return string|null */ - public function get(string $key, string $default = null): string|null + public function get(string $key, string $default = null): ?string { return $this->data[$key] ?? $default; } @@ -95,6 +124,8 @@ class Translation /** * Returns the translation id, * which is also the code + * + * @return string */ public function id(): string { @@ -104,15 +135,17 @@ class Translation /** * Loads the translation from the * json file in Kirby's translations folder + * + * @param string $code + * @param string $root + * @param array $inject + * @return static */ - public static function load( - string $code, - string $root, - array $inject = [] - ): static { + public static function load(string $code, string $root, array $inject = []) + { try { $data = array_merge(Data::read($root), $inject); - } catch (Exception) { + } catch (Exception $e) { $data = []; } @@ -121,6 +154,8 @@ class Translation /** * Returns the PHP locale of the translation + * + * @return string */ public function locale(): string { @@ -134,6 +169,8 @@ class Translation /** * Returns the human-readable translation name. + * + * @return string */ public function name(): string { @@ -143,6 +180,8 @@ class Translation /** * Converts the most important * properties to an array + * + * @return array */ public function toArray(): array { diff --git a/kirby/src/Cms/Translations.php b/kirby/src/Cms/Translations.php index 40c0b55..c45dd40 100644 --- a/kirby/src/Cms/Translations.php +++ b/kirby/src/Cms/Translations.php @@ -20,11 +20,28 @@ use Kirby\Filesystem\F; class Translations extends Collection { /** - * All registered translations methods + * @param string $code + * @return void */ - public static array $methods = []; + public function start(string $code): void + { + F::move($this->parent->contentFile('', true), $this->parent->contentFile($code, true)); + } - public static function factory(array $translations): static + /** + * @param string $code + * @return void + */ + public function stop(string $code): void + { + F::move($this->parent->contentFile($code, true), $this->parent->contentFile('', true)); + } + + /** + * @param array $translations + * @return static + */ + public static function factory(array $translations) { $collection = new static(); @@ -36,7 +53,12 @@ class Translations extends Collection return $collection; } - public static function load(string $root, array $inject = []): static + /** + * @param string $root + * @param array $inject + * @return static + */ + public static function load(string $root, array $inject = []) { $collection = new static(); diff --git a/kirby/src/Cms/Url.php b/kirby/src/Cms/Url.php index bb44139..9111b09 100644 --- a/kirby/src/Cms/Url.php +++ b/kirby/src/Cms/Url.php @@ -21,10 +21,12 @@ use Kirby\Http\Url as BaseUrl; */ class Url extends BaseUrl { - public static string|null $home = null; + public static $home = null; /** * Returns the Url to the homepage + * + * @return string */ public static function home(): string { @@ -32,13 +34,14 @@ class Url extends BaseUrl } /** - * Creates an absolute Url to a template asset if it exists. - * This is used in the `css()` and `js()` helpers + * Creates an absolute Url to a template asset if it exists. This is used in the `css()` and `js()` helpers + * + * @param string $assetPath + * @param string $extension + * @return string|null */ - public static function toTemplateAsset( - string $assetPath, - string $extension - ): string|null { + public static function toTemplateAsset(string $assetPath, string $extension) + { $kirby = App::instance(); $page = $kirby->site()->page(); $path = $assetPath . '/' . $page->template() . '.' . $extension; @@ -51,12 +54,12 @@ class Url extends BaseUrl /** * Smart resolver for internal and external urls * + * @param string|null $path * @param array|string|null $options Either an array of options for the Uri class or a language string + * @return string */ - public static function to( - string|null $path = null, - array|string|null $options = null - ): string { + public static function to(string $path = null, $options = null): string + { $kirby = App::instance(); return ($kirby->component('url'))($kirby, $path, $options); } diff --git a/kirby/src/Cms/User.php b/kirby/src/Cms/User.php index ce5fbb0..c872289 100644 --- a/kirby/src/Cms/User.php +++ b/kirby/src/Cms/User.php @@ -2,18 +2,13 @@ namespace Kirby\Cms; -use Closure; use Exception; -use Kirby\Content\Field; use Kirby\Exception\InvalidArgumentException; use Kirby\Exception\NotFoundException; -use Kirby\Exception\PermissionException; use Kirby\Filesystem\Dir; use Kirby\Filesystem\F; use Kirby\Panel\User as Panel; -use Kirby\Session\Session; use Kirby\Toolkit\Str; -use SensitiveParameter; /** * The `$user` object represents a @@ -35,65 +30,80 @@ class User extends ModelWithContent public const CLASS_ALIAS = 'user'; /** - * All registered user methods - * @todo Remove when support for PHP 8.2 is dropped + * @var UserBlueprint */ - public static array $methods = []; + protected $blueprint; + + /** + * @var array + */ + protected $credentials; + + /** + * @var string + */ + protected $email; + + /** + * @var string + */ + protected $hash; + + /** + * @var string + */ + protected $id; + + /** + * @var array|null + */ + protected $inventory; + + /** + * @var string + */ + protected $language; + + /** + * All registered user methods + * + * @var array + */ + public static $methods = []; /** * Registry with all User models + * + * @var array */ - public static array $models = []; - - protected UserBlueprint|null $blueprint = null; - protected array $credentials; - protected string|null $email; - protected string $hash; - protected string $id; - protected array|null $inventory = null; - protected string|null $language; - protected Field|string|null $name; - protected string|null $password; - protected Role|string|null $role; + public static $models = []; /** - * Creates a new User object + * @var \Kirby\Cms\Field */ - public function __construct(array $props) - { - // helper function to easily edit values (if not null) - // before assigning them to their properties - $set = function (string $key, Closure $callback) use ($props) { - if ($value = $props[$key] ?? null) { - $value = $callback($value); - } + protected $name; - return $value; - }; + /** + * @var string + */ + protected $password; - // if no ID passed, generate one; - // do so before calling parent constructor - // so it also gets stored in propertyData prop - $props['id'] ??= $this->createId(); - - parent::__construct($props); - - $this->id = $props['id']; - $this->email = $set('email', fn ($email) => Str::lower(trim($email))); - $this->language = $set('language', fn ($language) => trim($language)); - $this->name = $set('name', fn ($name) => trim(strip_tags($name))); - $this->password = $props['password'] ?? null; - $this->role = $set('role', fn ($role) => Str::lower(trim($role))); - - $this->setBlueprint($props['blueprint'] ?? null); - $this->setFiles($props['files'] ?? null); - } + /** + * The user role + * + * @var string + */ + protected $role; /** * Modified getter to also return fields * from the content + * + * @param string $method + * @param array $arguments + * @return mixed */ - public function __call(string $method, array $arguments = []): mixed + public function __call(string $method, array $arguments = []) { // public property access if (isset($this->$method) === true) { @@ -109,9 +119,22 @@ class User extends ModelWithContent return $this->content()->get($method); } + /** + * Creates a new User object + * + * @param array $props + */ + public function __construct(array $props) + { + // TODO: refactor later to avoid redundant prop setting + $this->setProperty('id', $props['id'] ?? $this->createId(), true); + $this->setProperties($props); + } + /** * Improved `var_dump` output - * @codeCoverageIgnore + * + * @return array */ public function __debugInfo(): array { @@ -124,34 +147,45 @@ class User extends ModelWithContent /** * Returns the url to the api endpoint + * * @internal + * @param bool $relative + * @return string */ public function apiUrl(bool $relative = false): string { if ($relative === true) { return 'users/' . $this->id(); + } else { + return $this->kirby()->url('api') . '/users/' . $this->id(); } - - return $this->kirby()->url('api') . '/users/' . $this->id(); } /** * Returns the File object for the avatar or null + * + * @return \Kirby\Cms\File|null */ - public function avatar(): File|null + public function avatar() { return $this->files()->template('avatar')->first(); } /** * Returns the UserBlueprint object + * + * @return \Kirby\Cms\Blueprint */ - public function blueprint(): UserBlueprint + public function blueprint() { + if (is_a($this->blueprint, 'Kirby\Cms\Blueprint') === true) { + return $this->blueprint; + } + try { - return $this->blueprint ??= UserBlueprint::factory('users/' . $this->role(), 'users/default', $this); - } catch (Exception) { - return $this->blueprint ??= new UserBlueprint([ + return $this->blueprint = UserBlueprint::factory('users/' . $this->role(), 'users/default', $this); + } catch (Exception $e) { + return $this->blueprint = new UserBlueprint([ 'model' => $this, 'name' => 'default', 'title' => 'Default', @@ -161,13 +195,14 @@ class User extends ModelWithContent /** * Prepares the content for the write method + * * @internal + * @param array $data * @param string $languageCode|null Not used so far + * @return array */ - public function contentFileData( - array $data, - string|null $languageCode = null - ): array { + public function contentFileData(array $data, string $languageCode = null): array + { // remove stuff that has nothing to do in the text files unset( $data['email'], @@ -184,13 +219,10 @@ class User extends ModelWithContent * Filename for the content file * * @internal - * @deprecated 4.0.0 - * @todo Remove in v5 - * @codeCoverageIgnore + * @return string */ public function contentFileName(): string { - Helpers::deprecated('The internal $model->contentFileName() method has been deprecated. Please let us know via a GitHub issue if you need this method and tell us your use case.', 'model-content-file'); return 'user'; } @@ -201,29 +233,33 @@ class User extends ModelWithContent /** * Returns the user email address + * + * @return string */ - public function email(): string|null + public function email(): ?string { return $this->email ??= $this->credentials()['email'] ?? null; } /** * Checks if the user exists + * + * @return bool */ public function exists(): bool { - return $this->storage()->exists( - 'published', - 'default' - ); + return is_file($this->contentFile('default')) === true; } /** * Constructs a User object and also * takes User models into account. + * * @internal + * @param mixed $props + * @return static */ - public static function factory(mixed $props): static + public static function factory($props) { if (empty($props['model']) === false) { return static::model($props['model'], $props); @@ -235,12 +271,13 @@ class User extends ModelWithContent /** * Hashes the user's password unless it is `null`, * which will leave it as `null` + * * @internal + * @param string|null $password + * @return string|null */ - public static function hashPassword( - #[SensitiveParameter] - string $password = null - ): string|null { + public static function hashPassword($password): ?string + { if ($password !== null) { $password = password_hash($password, PASSWORD_DEFAULT); } @@ -250,6 +287,8 @@ class User extends ModelWithContent /** * Returns the user id + * + * @return string */ public function id(): string { @@ -259,6 +298,8 @@ class User extends ModelWithContent /** * Returns the inventory of files * children and content files + * + * @return array */ public function inventory(): array { @@ -278,6 +319,9 @@ class User extends ModelWithContent /** * Compares the current object with the given user object + * + * @param \Kirby\Cms\User|null $user + * @return bool */ public function is(User $user = null): bool { @@ -290,6 +334,8 @@ class User extends ModelWithContent /** * Checks if this user has the admin role + * + * @return bool */ public function isAdmin(): bool { @@ -299,14 +345,18 @@ class User extends ModelWithContent /** * Checks if the current user is the virtual * Kirby user + * + * @return bool */ public function isKirby(): bool { - return $this->isAdmin() && $this->id() === 'kirby'; + return $this->email() === 'kirby@getkirby.com'; } /** * Checks if the current user is this user + * + * @return bool */ public function isLoggedIn(): bool { @@ -316,16 +366,19 @@ class User extends ModelWithContent /** * Checks if the user is the last one * with the admin role + * + * @return bool */ public function isLastAdmin(): bool { - return - $this->role()->isAdmin() === true && - $this->kirby()->users()->filter('role', 'admin')->count() <= 1; + return $this->role()->isAdmin() === true && + $this->kirby()->users()->filter('role', 'admin')->count() <= 1; } /** * Checks if the user is the last user + * + * @return bool */ public function isLastUser(): bool { @@ -335,32 +388,33 @@ class User extends ModelWithContent /** * Checks if the current user is the virtual * Nobody user + * + * @return bool */ public function isNobody(): bool { - return $this->role()->id() === 'nobody' && $this->id() === 'nobody'; + return $this->email() === 'nobody@getkirby.com'; } /** * Returns the user language + * + * @return string */ public function language(): string { - return $this->language ??= - $this->credentials()['language'] ?? - $this->kirby()->panelLanguage(); + return $this->language ??= $this->credentials()['language'] ?? $this->kirby()->panelLanguage(); } /** * Logs the user in * + * @param string $password * @param \Kirby\Session\Session|array|null $session Session options or session object to set the user in + * @return bool */ - public function login( - #[SensitiveParameter] - string $password, - $session = null - ): bool { + public function login(string $password, $session = null): bool + { $this->validatePassword($password); $this->loginPasswordless($session); @@ -371,43 +425,33 @@ class User extends ModelWithContent * Logs the user in without checking the password * * @param \Kirby\Session\Session|array|null $session Session options or session object to set the user in + * @return void */ - public function loginPasswordless( - Session|array|null $session = null - ): void { - if ($this->id() === 'kirby') { - throw new PermissionException('The almighty user "kirby" cannot be used for login, only for raising permissions in code via `$kirby->impersonate()`'); - } + public function loginPasswordless($session = null): void + { + $kirby = $this->kirby(); - $kirby = $this->kirby(); $session = $this->sessionFromOptions($session); - $kirby->trigger( - 'user.login:before', - ['user' => $this, 'session' => $session] - ); + $kirby->trigger('user.login:before', ['user' => $this, 'session' => $session]); $session->regenerateToken(); // privilege change $session->data()->set('kirby.userId', $this->id()); - if ($this->passwordTimestamp() !== null) { $session->data()->set('kirby.loginTimestamp', time()); } + $this->kirby()->auth()->setUser($this); - $kirby->auth()->setUser($this); - - $kirby->trigger( - 'user.login:after', - ['user' => $this, 'session' => $session] - ); + $kirby->trigger('user.login:after', ['user' => $this, 'session' => $session]); } /** * Logs the user out * * @param \Kirby\Session\Session|array|null $session Session options or session object to unset the user in + * @return void */ - public function logout(Session|array|null $session = null): void + public function logout($session = null): void { $kirby = $this->kirby(); $session = $this->sessionFromOptions($session); @@ -436,7 +480,9 @@ class User extends ModelWithContent /** * Returns the root to the media folder for the user + * * @internal + * @return string */ public function mediaRoot(): string { @@ -445,7 +491,9 @@ class User extends ModelWithContent /** * Returns the media url for the user object + * * @internal + * @return string */ public function mediaUrl(): string { @@ -454,14 +502,18 @@ class User extends ModelWithContent /** * Creates a user model if it has been registered + * * @internal + * @param string $name + * @param array $props + * @return \Kirby\Cms\User */ - public static function model(string $name, array $props = []): static + public static function model(string $name, array $props = []) { if ($class = (static::$models[$name] ?? null)) { $object = new $class($props); - if ($object instanceof self) { + if (is_a($object, 'Kirby\Cms\User') === true) { return $object; } } @@ -471,36 +523,47 @@ class User extends ModelWithContent /** * Returns the last modification date of the user + * + * @param string $format + * @param string|null $handler + * @param string|null $languageCode + * @return int|string */ - public function modified( - string $format = 'U', - string|null $handler = null, - string|null $languageCode = null - ): int|string|false { - $modifiedContent = $this->storage()->modified('published', $languageCode); + public function modified(string $format = 'U', string $handler = null, string $languageCode = null) + { + $modifiedContent = F::modified($this->contentFile($languageCode)); $modifiedIndex = F::modified($this->root() . '/index.php'); $modifiedTotal = max([$modifiedContent, $modifiedIndex]); + $handler ??= $this->kirby()->option('date.handler', 'date'); return Str::date($modifiedTotal, $format, $handler); } /** * Returns the user's name + * + * @return \Kirby\Cms\Field */ - public function name(): Field + public function name() { if (is_string($this->name) === true) { return new Field($this, 'name', $this->name); } - return $this->name ??= new Field($this, 'name', $this->credentials()['name'] ?? null); + if ($this->name !== null) { + return $this->name; + } + + return $this->name = new Field($this, 'name', $this->credentials()['name'] ?? null); } /** * Returns the user's name or, * if empty, the email address + * + * @return \Kirby\Cms\Field */ - public function nameOrEmail(): Field + public function nameOrEmail() { $name = $this->name(); return $name->isNotEmpty() ? $name : new Field($this, 'email', $this->email()); @@ -508,9 +571,11 @@ class User extends ModelWithContent /** * Create a dummy nobody + * * @internal + * @return static */ - public static function nobody(): static + public static function nobody() { return new static([ 'email' => 'nobody@getkirby.com', @@ -520,27 +585,35 @@ class User extends ModelWithContent /** * Returns the panel info object + * + * @return \Kirby\Panel\User */ - public function panel(): Panel + public function panel() { return new Panel($this); } /** * Returns the encrypted user password + * + * @return string|null */ - public function password(): string|null + public function password(): ?string { - return $this->password ??= $this->readPassword(); + if ($this->password !== null) { + return $this->password; + } + + return $this->password = $this->readPassword(); } /** * Returns the timestamp when the password * was last changed */ - public function passwordTimestamp(): int|null + public function passwordTimestamp(): ?int { - $file = $this->secretsFile(); + $file = $this->passwordFile(); // ensure we have the latest information // to prevent cache attacks @@ -554,31 +627,42 @@ class User extends ModelWithContent return filemtime($file); } - public function permissions(): UserPermissions + /** + * @return \Kirby\Cms\UserPermissions + */ + public function permissions() { return new UserPermissions($this); } /** * Returns the user role + * + * @return \Kirby\Cms\Role */ - public function role(): Role + public function role() { - if ($this->role instanceof Role) { + if (is_a($this->role, 'Kirby\Cms\Role') === true) { return $this->role; } - $name = $this->role ?? $this->credentials()['role'] ?? 'visitor'; + $roleName = $this->role ?? $this->credentials()['role'] ?? 'visitor'; - return $this->role = $this->kirby()->roles()->find($name) ?? Role::nobody(); + if ($role = $this->kirby()->roles()->find($roleName)) { + return $this->role = $role; + } + + return $this->role = Role::nobody(); } /** * Returns all available roles * for this user, that can be selected * by the authenticated user + * + * @return \Kirby\Cms\Roles */ - public function roles(): Roles + public function roles() { $kirby = $this->kirby(); $roles = $kirby->roles(); @@ -587,16 +671,18 @@ class User extends ModelWithContent $myRole = $roles->filter('id', $this->role()->id()); // if there's an authenticated user … - // admin users can select pretty much any role - if ($kirby->user()?->isAdmin() === true) { - // except if the user is the last admin - if ($this->isLastAdmin() === true) { - // in which case they have to stay admin - return $myRole; - } + if ($user = $kirby->user()) { + // admin users can select pretty much any role + if ($user->isAdmin() === true) { + // except if the user is the last admin + if ($this->isLastAdmin() === true) { + // in which case they have to stay admin + return $myRole; + } - // return all roles for mighty admins - return $roles; + // return all roles for mighty admins + return $roles; + } } // any other user can only keep their role @@ -605,6 +691,8 @@ class User extends ModelWithContent /** * The absolute path to the user directory + * + * @return string */ public function root(): string { @@ -614,27 +702,21 @@ class User extends ModelWithContent /** * Returns the UserRules class to * validate any important action. + * + * @return \Kirby\Cms\UserRules */ - protected function rules(): UserRules + protected function rules() { return new UserRules(); } - /** - * Reads a specific secret from the user secrets file on disk - * @since 4.0.0 - */ - public function secret(string $key): mixed - { - return $this->readSecrets()[$key] ?? null; - } - /** * Sets the Blueprint object * + * @param array|null $blueprint * @return $this */ - protected function setBlueprint(array $blueprint = null): static + protected function setBlueprint(array $blueprint = null) { if ($blueprint !== null) { $blueprint['model'] = $this; @@ -644,17 +726,92 @@ class User extends ModelWithContent return $this; } + /** + * Sets the user email + * + * @param string $email|null + * @return $this + */ + protected function setEmail(string $email = null) + { + if ($email !== null) { + $this->email = Str::lower(trim($email)); + } + return $this; + } + + /** + * Sets the user id + * + * @param string $id|null + * @return $this + */ + protected function setId(string $id = null) + { + $this->id = $id; + return $this; + } + + /** + * Sets the user language + * + * @param string $language|null + * @return $this + */ + protected function setLanguage(string $language = null) + { + $this->language = $language !== null ? trim($language) : null; + return $this; + } + + /** + * Sets the user name + * + * @param string $name|null + * @return $this + */ + protected function setName(string $name = null) + { + $this->name = $name !== null ? trim(strip_tags($name)) : null; + return $this; + } + + /** + * Sets the user's password hash + * + * @param string $password|null + * @return $this + */ + protected function setPassword(string $password = null) + { + $this->password = $password; + return $this; + } + + /** + * Sets the user role + * + * @param string $role|null + * @return $this + */ + protected function setRole(string $role = null) + { + $this->role = $role !== null ? Str::lower(trim($role)) : null; + return $this; + } + /** * Converts session options into a session object * * @param \Kirby\Session\Session|array $session Session options or session object to unset the user in + * @return \Kirby\Session\Session */ - protected function sessionFromOptions(Session|array|null $session): Session + protected function sessionFromOptions($session) { // use passed session options or session object if set if (is_array($session) === true) { $session = $this->kirby()->session($session); - } elseif ($session instanceof Session === false) { + } elseif (is_a($session, 'Kirby\Session\Session') === false) { $session = $this->kirby()->session(['detect' => true]); } @@ -663,8 +820,10 @@ class User extends ModelWithContent /** * Returns the parent Users collection + * + * @return \Kirby\Cms\Users */ - protected function siblingsCollection(): Users + protected function siblingsCollection() { return $this->kirby()->users(); } @@ -672,32 +831,36 @@ class User extends ModelWithContent /** * Converts the most important user properties * to an array + * + * @return array */ public function toArray(): array { - return array_merge(parent::toArray(), [ - 'avatar' => $this->avatar()?->toArray(), + return [ + 'avatar' => $this->avatar() ? $this->avatar()->toArray() : null, + 'content' => $this->content()->toArray(), 'email' => $this->email(), 'id' => $this->id(), 'language' => $this->language(), 'role' => $this->role()->name(), 'username' => $this->username() - ]); + ]; } /** * String template builder * - * @param string|null $fallback Fallback for tokens in the template that cannot be replaced - * (`null` to keep the original token) + * @param string|null $template + * @param array|null $data + * @param string $fallback Fallback for tokens in the template that cannot be replaced + * @return string */ - public function toString( - string $template = null, - array $data = [], - string|null $fallback = '', - string $handler = 'template' - ): string { - $template ??= $this->email(); + public function toString(string $template = null, array $data = [], string $fallback = '', string $handler = 'template'): string + { + if ($template === null) { + $template = $this->email(); + } + return parent::toString($template, $data, $fallback, $handler); } @@ -705,8 +868,10 @@ class User extends ModelWithContent * Returns the username * which is the given name or the email * as a fallback + * + * @return string|null */ - public function username(): string|null + public function username(): ?string { return $this->name()->or($this->email())->value(); } @@ -714,14 +879,15 @@ class User extends ModelWithContent /** * Compares the given password with the stored one * + * @param string $password|null + * @return bool + * * @throws \Kirby\Exception\NotFoundException If the user has no password * @throws \Kirby\Exception\InvalidArgumentException If the entered password is not valid * or does not match the user password */ - public function validatePassword( - #[SensitiveParameter] - string $password = null - ): bool { + public function validatePassword(string $password = null): bool + { if (empty($this->password()) === true) { throw new NotFoundException(['key' => 'user.password.undefined']); } @@ -745,21 +911,61 @@ class User extends ModelWithContent } /** - * @deprecated 4.0.0 Use `->secretsFile()` instead - * @codeCoverageIgnore + * Returns the path to the password file */ protected function passwordFile(): string { - return $this->secretsFile(); + return $this->root() . '/.htpasswd'; } /** - * Returns the path to the file containing - * all user secrets, including the password - * @since 4.0.0 + * Deprecated! */ - protected function secretsFile(): string + + /** + * Returns the full path without leading slash + * + * @todo Remove in 3.8.0 + * + * @internal + * @return string + * @codeCoverageIgnore + */ + public function panelPath(): string { - return $this->root() . '/.htpasswd'; + Helpers::deprecated('Cms\User::panelPath() has been deprecated and will be removed in Kirby 3.8.0. Use $user->panel()->path() instead.'); + return $this->panel()->path(); + } + + /** + * Returns prepared data for the panel user picker + * + * @todo Remove in 3.8.0 + * + * @param array|null $params + * @return array + * @codeCoverageIgnore + */ + public function panelPickerData(array $params = null): array + { + Helpers::deprecated('Cms\User::panelPickerData() has been deprecated and will be removed in Kirby 3.8.0. Use $user->panel()->pickerData() instead.'); + return $this->panel()->pickerData($params); + } + + /** + * Returns the url to the editing view + * in the panel + * + * @todo Remove in 3.8.0 + * + * @internal + * @param bool $relative + * @return string + * @codeCoverageIgnore + */ + public function panelUrl(bool $relative = false): string + { + Helpers::deprecated('Cms\User::panelUrl() has been deprecated and will be removed in Kirby 3.8.0. Use $user->panel()->url() instead.'); + return $this->panel()->url($relative); } } diff --git a/kirby/src/Cms/UserActions.php b/kirby/src/Cms/UserActions.php index 728acc1..24278a6 100644 --- a/kirby/src/Cms/UserActions.php +++ b/kirby/src/Cms/UserActions.php @@ -4,16 +4,13 @@ namespace Kirby\Cms; use Closure; use Kirby\Data\Data; -use Kirby\Data\Json; use Kirby\Exception\LogicException; use Kirby\Exception\PermissionException; use Kirby\Filesystem\Dir; use Kirby\Filesystem\F; use Kirby\Form\Form; use Kirby\Http\Idn; -use Kirby\Toolkit\A; use Kirby\Toolkit\Str; -use SensitiveParameter; use Throwable; /** @@ -29,8 +26,11 @@ trait UserActions { /** * Changes the user email address + * + * @param string $email + * @return static */ - public function changeEmail(string $email): static + public function changeEmail(string $email) { $email = trim($email); @@ -52,8 +52,11 @@ trait UserActions /** * Changes the user language + * + * @param string $language + * @return static */ - public function changeLanguage(string $language): static + public function changeLanguage(string $language) { return $this->commit('changeLanguage', ['user' => $this, 'language' => $language], function ($user, $language) { $user = $user->clone([ @@ -73,8 +76,11 @@ trait UserActions /** * Changes the screen name of the user + * + * @param string $name + * @return static */ - public function changeName(string $name): static + public function changeName(string $name) { $name = trim($name); @@ -96,11 +102,12 @@ trait UserActions /** * Changes the user password + * + * @param string $password + * @return static */ - public function changePassword( - #[SensitiveParameter] - string $password - ): static { + public function changePassword(string $password) + { return $this->commit('changePassword', ['user' => $this, 'password' => $password], function ($user, $password) { $user = $user->clone([ 'password' => $password = User::hashPassword($password) @@ -124,8 +131,11 @@ trait UserActions /** * Changes the user role + * + * @param string $role + * @return static */ - public function changeRole(string $role): static + public function changeRole(string $role) { return $this->commit('changeRole', ['user' => $this, 'role' => $role], function ($user, $role) { $user = $user->clone([ @@ -143,28 +153,6 @@ trait UserActions }); } - /** - * Changes the user's TOTP secret - * @since 4.0.0 - */ - public function changeTotp( - #[SensitiveParameter] - string|null $secret - ): static { - return $this->commit('changeTotp', ['user' => $this, 'secret' => $secret], function ($user, $secret) { - $this->writeSecret('totp', $secret); - - // keep the user logged in to the current browser - // if they changed their own TOTP secret - // (regenerate the session token, update the login timestamp) - if ($user->isLoggedIn() === true) { - $user->loginPasswordless(); - } - - return $user; - }); - } - /** * Commits a user action, by following these steps * @@ -174,13 +162,14 @@ trait UserActions * 4. sends the after hook * 5. returns the result * + * @param string $action + * @param array $arguments + * @param \Closure $callback + * @return mixed * @throws \Kirby\Exception\PermissionException */ - protected function commit( - string $action, - array $arguments, - Closure $callback - ): mixed { + protected function commit(string $action, array $arguments, Closure $callback) + { if ($this->isKirby() === true) { throw new PermissionException('The Kirby user cannot be changed'); } @@ -194,12 +183,13 @@ trait UserActions $result = $callback(...$argumentValues); - $argumentsAfter = match ($action) { - 'create' => ['user' => $result], - 'delete' => ['status' => $result, 'user' => $old], - default => ['newUser' => $result, 'oldUser' => $old] - }; - + if ($action === 'create') { + $argumentsAfter = ['user' => $result]; + } elseif ($action === 'delete') { + $argumentsAfter = ['status' => $result, 'user' => $old]; + } else { + $argumentsAfter = ['newUser' => $result, 'oldUser' => $old]; + } $kirby->trigger('user.' . $action . ':after', $argumentsAfter); $kirby->cache('pages')->flush(); @@ -208,8 +198,11 @@ trait UserActions /** * Creates a new User from the given props and returns a new User object + * + * @param array|null $props + * @return static */ - public static function create(array $props = null): User + public static function create(array $props = null) { $data = $props; @@ -261,6 +254,8 @@ trait UserActions /** * Returns a random user id + * + * @return string */ public function createId(): string { @@ -275,7 +270,7 @@ trait UserActions // we can't really test for a random match // @codeCoverageIgnoreStart - } catch (Throwable) { + } catch (Throwable $e) { $length++; } } while (true); @@ -285,6 +280,7 @@ trait UserActions /** * Deletes the user * + * @return bool * @throws \Kirby\Exception\LogicException */ public function delete(): bool @@ -311,63 +307,42 @@ trait UserActions /** * Read the account information from disk + * + * @return array */ protected function readCredentials(): array { $path = $this->root() . '/index.php'; if (is_file($path) === true) { - $credentials = F::load($path, allowOutput: false); + $credentials = F::load($path); return is_array($credentials) === false ? [] : $credentials; + } else { + return []; } - - return []; } /** * Reads the user password from disk + * + * @return string|false */ - protected function readPassword(): string|false + protected function readPassword() { - return $this->secret('password') ?? false; - } - - /** - * Reads the secrets from the user secrets file on disk - * @since 4.0.0 - */ - protected function readSecrets(): array - { - $file = $this->secretsFile(); - $secrets = []; - - if (is_file($file) === true) { - $lines = explode("\n", file_get_contents($file)); - - if (isset($lines[1]) === true) { - $secrets = Json::decode($lines[1]); - } - - $secrets['password'] = $lines[0]; - } - - // an empty password hash means that no password was set - if (($secrets['password'] ?? null) === '') { - unset($secrets['password']); - } - - return $secrets; + return F::read($this->passwordFile()); } /** * Updates the user data + * + * @param array|null $input + * @param string|null $languageCode + * @param bool $validate + * @return static */ - public function update( - array $input = null, - string $languageCode = null, - bool $validate = false - ): static { + public function update(array $input = null, string $languageCode = null, bool $validate = false) + { $user = parent::update($input, $languageCode, $validate); // set auth user data only if the current user is this user @@ -384,6 +359,9 @@ trait UserActions /** * This always merges the existing credentials * with the given input. + * + * @param array $credentials + * @return bool */ protected function updateCredentials(array $credentials): bool { @@ -397,6 +375,9 @@ trait UserActions /** * Writes the account information to disk + * + * @param array $credentials + * @return bool */ protected function writeCredentials(array $credentials): bool { @@ -405,44 +386,12 @@ trait UserActions /** * Writes the password to disk + * + * @param string|null $password + * @return bool */ - protected function writePassword( - #[SensitiveParameter] - string $password = null - ): bool { - return $this->writeSecret('password', $password); - } - - /** - * Writes a specific secret to the user secrets file on disk; - * `password` is the first line, the rest is stored as JSON - * @since 4.0.0 - */ - protected function writeSecret( - string $key, - #[SensitiveParameter] - mixed $secret - ): bool { - $secrets = $this->readSecrets(); - - if ($secret === null) { - unset($secrets[$key]); - } else { - $secrets[$key] = $secret; - } - - // first line is always the password - $lines = $secrets['password'] ?? ''; - - // everything else is for the second line - $secondLine = Json::encode( - A::without($secrets, 'password') - ); - - if ($secondLine !== '[]') { - $lines .= "\n" . $secondLine; - } - - return F::write($this->secretsFile(), $lines); + protected function writePassword(string $password = null): bool + { + return F::write($this->passwordFile(), $password); } } diff --git a/kirby/src/Cms/UserBlueprint.php b/kirby/src/Cms/UserBlueprint.php index d44d852..0f86fe1 100644 --- a/kirby/src/Cms/UserBlueprint.php +++ b/kirby/src/Cms/UserBlueprint.php @@ -17,6 +17,7 @@ class UserBlueprint extends Blueprint /** * UserBlueprint constructor. * + * @param array $props * @throws \Kirby\Exception\InvalidArgumentException */ public function __construct(array $props) diff --git a/kirby/src/Cms/UserPermissions.php b/kirby/src/Cms/UserPermissions.php index 62cd662..bc91161 100644 --- a/kirby/src/Cms/UserPermissions.php +++ b/kirby/src/Cms/UserPermissions.php @@ -13,22 +13,35 @@ namespace Kirby\Cms; */ class UserPermissions extends ModelPermissions { - protected string $category = 'users'; + /** + * @var string + */ + protected $category = 'users'; - public function __construct(User $model) + /** + * UserPermissions constructor + * + * @param \Kirby\Cms\Model $model + */ + public function __construct(Model $model) { parent::__construct($model); - // change the scope of the permissions, - // when the current user is this user - $this->category = $this->user?->is($model) ? 'user' : 'users'; + // change the scope of the permissions, when the current user is this user + $this->category = $this->user && $this->user->is($model) ? 'user' : 'users'; } + /** + * @return bool + */ protected function canChangeRole(): bool { return $this->model->roles()->count() > 1; } + /** + * @return bool + */ protected function canCreate(): bool { // the admin can always create new users @@ -44,6 +57,9 @@ class UserPermissions extends ModelPermissions return true; } + /** + * @return bool + */ protected function canDelete(): bool { return $this->model->isLastAdmin() !== true; diff --git a/kirby/src/Cms/UserPicker.php b/kirby/src/Cms/UserPicker.php index 0e9ab3e..46da3dc 100644 --- a/kirby/src/Cms/UserPicker.php +++ b/kirby/src/Cms/UserPicker.php @@ -19,6 +19,8 @@ class UserPicker extends Picker { /** * Extends the basic defaults + * + * @return array */ public function defaults(): array { @@ -31,27 +33,27 @@ class UserPicker extends Picker /** * Search all users for the picker * + * @return \Kirby\Cms\Users|null * @throws \Kirby\Exception\InvalidArgumentException */ - public function items(): Users|null + public function items() { $model = $this->options['model']; // find the right default query - $query = match (true) { - empty($this->options['query']) === false - => $this->options['query'], - $model instanceof User - => 'user.siblings', - default - => 'kirby.users' - }; + if (empty($this->options['query']) === false) { + $query = $this->options['query']; + } elseif (is_a($model, 'Kirby\Cms\User') === true) { + $query = 'user.siblings'; + } else { + $query = 'kirby.users'; + } // fetch all users for the picker $users = $model->query($query); // catch invalid data - if ($users instanceof Users === false) { + if (is_a($users, 'Kirby\Cms\Users') === false) { throw new InvalidArgumentException('Your query must return a set of users'); } diff --git a/kirby/src/Cms/UserRules.php b/kirby/src/Cms/UserRules.php index cf32665..2a6d0c6 100644 --- a/kirby/src/Cms/UserRules.php +++ b/kirby/src/Cms/UserRules.php @@ -7,9 +7,7 @@ use Kirby\Exception\InvalidArgumentException; use Kirby\Exception\LogicException; use Kirby\Exception\PermissionException; use Kirby\Toolkit\Str; -use Kirby\Toolkit\Totp; use Kirby\Toolkit\V; -use SensitiveParameter; /** * Validators for all user actions @@ -25,6 +23,9 @@ class UserRules /** * Validates if the email address can be changed * + * @param \Kirby\Cms\User $user + * @param string $email + * @return bool * @throws \Kirby\Exception\PermissionException If the user is not allowed to change the address */ public static function changeEmail(User $user, string $email): bool @@ -42,6 +43,9 @@ class UserRules /** * Validates if the language can be changed * + * @param \Kirby\Cms\User $user + * @param string $language + * @return bool * @throws \Kirby\Exception\PermissionException If the user is not allowed to change the language */ public static function changeLanguage(User $user, string $language): bool @@ -59,6 +63,9 @@ class UserRules /** * Validates if the name can be changed * + * @param \Kirby\Cms\User $user + * @param string $name + * @return bool * @throws \Kirby\Exception\PermissionException If the user is not allowed to change the name */ public static function changeName(User $user, string $name): bool @@ -76,13 +83,13 @@ class UserRules /** * Validates if the password can be changed * + * @param \Kirby\Cms\User $user + * @param string $password + * @return bool * @throws \Kirby\Exception\PermissionException If the user is not allowed to change the password */ - public static function changePassword( - User $user, - #[SensitiveParameter] - string $password - ): bool { + public static function changePassword(User $user, string $password): bool + { if ($user->permissions()->changePassword() !== true) { throw new PermissionException([ 'key' => 'user.changePassword.permission', @@ -96,6 +103,9 @@ class UserRules /** * Validates if the role can be changed * + * @param \Kirby\Cms\User $user + * @param string $role + * @return bool * @throws \Kirby\Exception\LogicException If the user is the last admin * @throws \Kirby\Exception\PermissionException If the user is not allowed to change the role */ @@ -141,38 +151,12 @@ class UserRules return true; } - /** - * Validates if the TOTP can be changed - * @since 4.0.0 - * - * @throws \Kirby\Exception\PermissionException If the user is not allowed to change the password - */ - public static function changeTotp( - User $user, - #[SensitiveParameter] - string|null $secret - ): bool { - $currentUser = $user->kirby()->user(); - - if ( - $currentUser->is($user) === false && - $currentUser->isAdmin() === false - ) { - throw new PermissionException('You cannot change the time-based code for ' . $user->email()); - } - - // safety check to avoid accidental insecure secrets; - // throws an exception for secrets of the wrong length - if ($secret !== null) { - new Totp($secret); - } - - return true; - } - /** * Validates if the user can be created * + * @param \Kirby\Cms\User $user + * @param array $props + * @return bool * @throws \Kirby\Exception\PermissionException If the user is not allowed to create a new user */ public static function create(User $user, array $props = []): bool @@ -195,27 +179,26 @@ class UserRules $currentUser = $user->kirby()->user(); // admins are allowed everything - if ($currentUser?->isAdmin() === true) { + if ($currentUser && $currentUser->isAdmin() === true) { return true; } // only admins are allowed to add admins $role = $props['role'] ?? null; - if ($role === 'admin' && $currentUser?->isAdmin() === false) { + if ($role === 'admin' && $currentUser && $currentUser->isAdmin() === false) { throw new PermissionException([ 'key' => 'user.create.permission' ]); } // check user permissions (if not on install) - if ( - $user->kirby()->users()->count() > 0 && - $user->permissions()->create() !== true - ) { - throw new PermissionException([ - 'key' => 'user.create.permission' - ]); + if ($user->kirby()->users()->count() > 0) { + if ($user->permissions()->create() !== true) { + throw new PermissionException([ + 'key' => 'user.create.permission' + ]); + } } return true; @@ -224,6 +207,8 @@ class UserRules /** * Validates if the user can be deleted * + * @param \Kirby\Cms\User $user + * @return bool * @throws \Kirby\Exception\LogicException If this is the last user or last admin, which cannot be deleted * @throws \Kirby\Exception\PermissionException If the user is not allowed to delete this user */ @@ -252,13 +237,14 @@ class UserRules /** * Validates if the user can be updated * + * @param \Kirby\Cms\User $user + * @param array $values + * @param array $strings + * @return bool * @throws \Kirby\Exception\PermissionException If the user it not allowed to update this user */ - public static function update( - User $user, - array $values = [], - array $strings = [] - ): bool { + public static function update(User $user, array $values = [], array $strings = []): bool + { if ($user->permissions()->update() !== true) { throw new PermissionException([ 'key' => 'user.update.permission', @@ -272,14 +258,15 @@ class UserRules /** * Validates an email address * + * @param \Kirby\Cms\User $user + * @param string $email + * @param bool $strict + * @return bool * @throws \Kirby\Exception\DuplicateException If the email address already exists * @throws \Kirby\Exception\InvalidArgumentException If the email address is invalid */ - public static function validEmail( - User $user, - string $email, - bool $strict = false - ): bool { + public static function validEmail(User $user, string $email, bool $strict = false): bool + { if (V::email($email ?? null) === false) { throw new InvalidArgumentException([ 'key' => 'user.email.invalid', @@ -305,12 +292,15 @@ class UserRules /** * Validates a user id * + * @param \Kirby\Cms\User $user + * @param string $id + * @return bool * @throws \Kirby\Exception\DuplicateException If the user already exists */ public static function validId(User $user, string $id): bool { - if (in_array($id, ['account', 'kirby', 'nobody']) === true) { - throw new InvalidArgumentException('"' . $id . '" is a reserved word and cannot be used as user id'); + if ($id === 'account') { + throw new InvalidArgumentException('"account" is a reserved word and cannot be used as user id'); } if ($user->kirby()->users()->find($id)) { @@ -323,6 +313,9 @@ class UserRules /** * Validates a user language code * + * @param \Kirby\Cms\User $user + * @param string $language + * @return bool * @throws \Kirby\Exception\InvalidArgumentException If the language does not exist */ public static function validLanguage(User $user, string $language): bool @@ -339,13 +332,13 @@ class UserRules /** * Validates a password * + * @param \Kirby\Cms\User $user + * @param string $password + * @return bool * @throws \Kirby\Exception\InvalidArgumentException If the password is too short */ - public static function validPassword( - User $user, - #[SensitiveParameter] - string $password - ): bool { + public static function validPassword(User $user, string $password): bool + { // too short passwords are ineffective if (Str::length($password ?? null) < 8) { throw new InvalidArgumentException([ @@ -369,11 +362,14 @@ class UserRules /** * Validates a user role * + * @param \Kirby\Cms\User $user + * @param string $role + * @return bool * @throws \Kirby\Exception\InvalidArgumentException If the user role does not exist */ public static function validRole(User $user, string $role): bool { - if ($user->kirby()->roles()->find($role) instanceof Role) { + if (is_a($user->kirby()->roles()->find($role), 'Kirby\Cms\Role') === true) { return true; } diff --git a/kirby/src/Cms/Users.php b/kirby/src/Cms/Users.php index df2f6c3..055863c 100644 --- a/kirby/src/Cms/Users.php +++ b/kirby/src/Cms/Users.php @@ -6,7 +6,6 @@ use Kirby\Exception\InvalidArgumentException; use Kirby\Filesystem\Dir; use Kirby\Filesystem\F; use Kirby\Toolkit\Str; -use Kirby\Uuid\HasUuids; /** * The `$users` object refers to a collection @@ -22,14 +21,14 @@ use Kirby\Uuid\HasUuids; */ class Users extends Collection { - use HasUuids; - /** * All registered users methods + * + * @var array */ - public static array $methods = []; + public static $methods = []; - public function create(array $data): User + public function create(array $data) { return User::create($data); } @@ -43,21 +42,18 @@ class Users extends Collection * @return $this * @throws \Kirby\Exception\InvalidArgumentException When no `User` or `Users` object or an ID of an existing user is passed */ - public function add($object): static + public function add($object) { // add a users collection - if ($object instanceof self) { + if (is_a($object, self::class) === true) { $this->data = array_merge($this->data, $object->data); // add a user by id - } elseif ( - is_string($object) === true && - $user = App::instance()->user($object) - ) { + } elseif (is_string($object) === true && $user = App::instance()->user($object)) { $this->__set($user->id(), $user); // add a user object - } elseif ($object instanceof User) { + } elseif (is_a($object, 'Kirby\Cms\User') === true) { $this->__set($object->id(), $object); // give a useful error message on invalid input; @@ -70,10 +66,13 @@ class Users extends Collection } /** - * Takes an array of user props and creates a nice - * and clean user collection from it + * Takes an array of user props and creates a nice and clean user collection from it + * + * @param array $users + * @param array $inject + * @return static */ - public static function factory(array $users, array $inject = []): static + public static function factory(array $users, array $inject = []) { $collection = new static(); @@ -86,32 +85,15 @@ class Users extends Collection return $collection; } - /** - * Returns all files of all users - */ - public function files(): Files - { - $files = new Files([], $this->parent); - - foreach ($this->data as $user) { - foreach ($user->files() as $fileKey => $file) { - $files->data[$fileKey] = $file; - } - } - - return $files; - } - /** * Finds a user in the collection by ID or email address * @internal Use `$users->find()` instead + * + * @param string $key + * @return \Kirby\Cms\User|null */ - public function findByKey(string $key): User|null + public function findByKey(string $key) { - if ($user = $this->findByUuid($key, 'user')) { - return $user; - } - if (Str::contains($key, '@') === true) { return parent::findBy('email', Str::lower($key)); } @@ -121,8 +103,12 @@ class Users extends Collection /** * Loads a user from disk by passing the absolute path (root) + * + * @param string $root + * @param array $inject + * @return static */ - public static function load(string $root, array $inject = []): static + public static function load(string $root, array $inject = []) { $users = new static(); @@ -134,7 +120,7 @@ class Users extends Collection // get role information $path = $root . '/' . $userDirectory . '/index.php'; if (is_file($path) === true) { - $credentials = F::load($path, allowOutput: false); + $credentials = F::load($path); } // create user model based on role @@ -151,8 +137,11 @@ class Users extends Collection /** * Shortcut for `$users->filter('role', 'admin')` + * + * @param string $role + * @return static */ - public function role(string $role): static + public function role(string $role) { return $this->filter('role', $role); } diff --git a/kirby/src/Cms/Visitor.php b/kirby/src/Cms/Visitor.php index 511eb8e..eae9f3a 100644 --- a/kirby/src/Cms/Visitor.php +++ b/kirby/src/Cms/Visitor.php @@ -2,7 +2,6 @@ namespace Kirby\Cms; -use Kirby\Http\Visitor as BaseVisitor; use Kirby\Toolkit\Facade; /** @@ -16,7 +15,10 @@ use Kirby\Toolkit\Facade; */ class Visitor extends Facade { - public static function instance(): BaseVisitor + /** + * @return \Kirby\Http\Visitor + */ + public static function instance() { return App::instance()->visitor(); } diff --git a/kirby/src/Content/ContentStorage.php b/kirby/src/Content/ContentStorage.php deleted file mode 100644 index 23eab40..0000000 --- a/kirby/src/Content/ContentStorage.php +++ /dev/null @@ -1,314 +0,0 @@ - - * @author Nico Hoffmann - * @link https://getkirby.com - * @copyright Bastian Allgeier - * @license https://getkirby.com/license - */ -class ContentStorage -{ - protected ContentStorageHandler $handler; - - public function __construct( - protected ModelWithContent $model, - string $handler = PlainTextContentStorageHandler::class - ) { - $this->handler = new $handler($model); - } - - /** - * Magic caller for handler methods - */ - public function __call(string $name, array $args): mixed - { - return $this->handler->$name(...$args); - } - - /** - * Returns generator for all existing versions-languages combinations - * - * @return Generator - * @todo 4.0.0 consider more descpritive name - */ - public function all(): Generator - { - foreach ($this->model->kirby()->languages()->codes() as $lang) { - foreach ($this->dynamicVersions() as $version) { - if ($this->exists($version, $lang) === true) { - yield $version => $lang; - } - } - } - } - - /** - * Returns the absolute path to the content file - * @internal eventually should only exists in PlainTextContentStorage, - * when not relying anymore on language helper - * - * @param string $lang Code `'default'` in a single-lang installation - * - * @throws \Kirby\Exception\LogicException If the model type doesn't have a known content filename - */ - public function contentFile( - string $version, - string $lang, - bool $force = false - ): string { - $lang = $this->language($lang, $force); - return $this->handler->contentFile($version, $lang); - } - - /** - * Adapts all versions when converting languages - * @internal - */ - public function convertLanguage(string $from, string $to): void - { - $from = $this->language($from, true); - $to = $this->language($to, true); - - foreach ($this->dynamicVersions() as $version) { - $this->handler->move($version, $from, $version, $to); - } - } - - /** - * Creates a new version - * - * @param string|null $lang Code `'default'` in a single-lang installation - * @param array $fields Content fields - */ - public function create( - string $versionType, - string|null $lang, - array $fields - ): void { - $lang = $this->language($lang); - $this->handler->create($versionType, $lang, $fields); - } - - /** - * Returns the default version identifier for the model - * @internal - */ - public function defaultVersion(): string - { - if ( - $this->model instanceof Page === true && - $this->model->isDraft() === true - ) { - return 'changes'; - } - - return 'published'; - } - - /** - * Deletes an existing version in an idempotent way if it was already deleted - * - * @param string $lang Code `'default'` in a single-lang installation - */ - public function delete( - string $version, - string|null $lang = null, - bool $force = false - ): void { - $lang = $this->language($lang, $force); - $this->handler->delete($version, $lang); - } - - /** - * Deletes all versions when deleting a language - * @internal - */ - public function deleteLanguage(string|null $lang): void - { - $lang = $this->language($lang, true); - - foreach ($this->dynamicVersions() as $version) { - $this->handler->delete($version, $lang); - } - } - - /** - * Returns all versions availalbe for the model that can be updated - * @internal - */ - public function dynamicVersions(): array - { - $versions = ['changes']; - - if ( - $this->model instanceof Page === false || - $this->model->isDraft() === false - ) { - $versions[] = 'published'; - } - - return $versions; - } - - /** - * Checks if a version exists - * - * @param string|null $lang Code `'default'` in a single-lang installation; - * checks for "any language" if not provided - */ - public function exists( - string $version, - string|null $lang - ): bool { - if ($lang !== null) { - $lang = $this->language($lang); - } - - return $this->handler->exists($version, $lang); - } - - /** - * Returns the modification timestamp of a version - * if it exists - * - * @param string $lang Code `'default'` in a single-lang installation - */ - public function modified( - string $version, - string|null $lang = null - ): int|null { - $lang = $this->language($lang); - return $this->handler->modified($version, $lang); - } - - /** - * Returns the stored content fields - * - * @param string $lang Code `'default'` in a single-lang installation - * @return array - * - * @throws \Kirby\Exception\NotFoundException If the version does not exist - */ - public function read( - string $version, - string|null $lang = null - ): array { - $lang = $this->language($lang); - $this->ensureExistingVersion($version, $lang); - return $this->handler->read($version, $lang); - } - - /** - * Updates the modification timestamp of an existing version - * - * @param string $lang Code `'default'` in a single-lang installation - * - * @throws \Kirby\Exception\NotFoundException If the version does not exist - */ - public function touch( - string $version, - string|null $lang = null - ): void { - $lang = $this->language($lang); - $this->ensureExistingVersion($version, $lang); - $this->handler->touch($version, $lang); - } - - /** - * Touches all versions of a language - * @internal - */ - public function touchLanguage(string|null $lang): void - { - $lang = $this->language($lang, true); - - foreach ($this->dynamicVersions() as $version) { - if ($this->exists($version, $lang) === true) { - $this->handler->touch($version, $lang); - } - } - } - - /** - * Updates the content fields of an existing version - * - * @param string $lang Code `'default'` in a single-lang installation - * @param array $fields Content fields - * - * @throws \Kirby\Exception\NotFoundException If the version does not exist - */ - public function update( - string $version, - string|null $lang = null, - array $fields = [] - ): void { - $lang = $this->language($lang); - $this->ensureExistingVersion($version, $lang); - $this->handler->update($version, $lang, $fields); - } - - /** - * @throws \Kirby\Exception\NotFoundException If the version does not exist - */ - protected function ensureExistingVersion( - string $version, - string $lang - ): void { - if ($this->exists($version, $lang) !== true) { - throw new NotFoundException('Version "' . $version . ' (' . $lang . ')" does not already exist'); - } - } - - /** - * Converts a "user-facing" language code to a "raw" language code to be - * used for storage - * - * @param bool $force If set to `true`, the language code is not validated - * @return string Language code - */ - protected function language( - string|null $languageCode = null, - bool $force = false - ): string { - // in force mode, use the provided language code even in single-lang for - // compatibility with the previous behavior in `$model->contentFile()` - if ($force === true) { - return $languageCode ?? 'default'; - } - - // in multi-lang, … - if ($this->model->kirby()->multilang() === true) { - // look up the actual language object if possible - $language = $this->model->kirby()->language($languageCode); - - // validate the language code - if ($language === null) { - throw new InvalidArgumentException('Invalid language: ' . $languageCode); - } - - return $language->code(); - } - - // otherwise use hardcoded "default" code for single lang - return 'default'; - } -} diff --git a/kirby/src/Content/ContentStorageHandler.php b/kirby/src/Content/ContentStorageHandler.php deleted file mode 100644 index 6f39d11..0000000 --- a/kirby/src/Content/ContentStorageHandler.php +++ /dev/null @@ -1,96 +0,0 @@ - - * @link https://getkirby.com - * @copyright Bastian Allgeier - * @license https://getkirby.com/license - */ -interface ContentStorageHandler -{ - public function __construct(ModelWithContent $model); - - /** - * Creates a new version - * - * @param string $lang Code `'default'` in a single-lang installation - * @param array $fields Content fields - */ - public function create(string $versionType, string $lang, array $fields): void; - - /** - * Deletes an existing version in an idempotent way if it was already deleted - * - * @param string $lang Code `'default'` in a single-lang installation - */ - public function delete(string $version, string $lang): void; - - /** - * Checks if a version exists - * - * @param string|null $lang Code `'default'` in a single-lang installation; - * checks for "any language" if not provided - */ - public function exists(string $version, string|null $lang): bool; - - /** - * Returns the modification timestamp of a version if it exists - * - * @param string $lang Code `'default'` in a single-lang installation - */ - public function modified(string $version, string $lang): int|null; - - /** - * Moves content from one version-language combination to another - * - * @param string $fromLang Code `'default'` in a single-lang installation - * @param string $toLang Code `'default'` in a single-lang installation - */ - public function move( - string $fromVersion, - string $fromLang, - string $toVersion, - string $toLang - ): void; - - /** - * Returns the stored content fields - * - * @param string $lang Code `'default'` in a single-lang installation - * @return array - * - * @throws \Kirby\Exception\NotFoundException If the version does not exist - */ - public function read(string $version, string $lang): array; - - /** - * Updates the modification timestamp of an existing version - * - * @param string $lang Code `'default'` in a single-lang installation - * - * @throws \Kirby\Exception\NotFoundException If the version does not exist - */ - public function touch(string $version, string $lang): void; - - /** - * Updates the content fields of an existing version - * - * @param string $lang Code `'default'` in a single-lang installation - * @param array $fields Content fields - * - * @throws \Kirby\Exception\NotFoundException If the version does not exist - */ - public function update(string $version, string $lang, array $fields): void; -} diff --git a/kirby/src/Content/ContentTranslation.php b/kirby/src/Content/ContentTranslation.php deleted file mode 100644 index c04ec32..0000000 --- a/kirby/src/Content/ContentTranslation.php +++ /dev/null @@ -1,173 +0,0 @@ - - * @link https://getkirby.com - * @copyright Bastian Allgeier - * @license https://getkirby.com/license - */ -class ContentTranslation -{ - protected string $code; - protected array|null $content; - protected string $contentFile; - protected ModelWithContent $parent; - protected string|null $slug; - - /** - * Creates a new translation object - */ - public function __construct(array $props) - { - $this->code = $props['code']; - $this->parent = $props['parent']; - $this->slug = $props['slug'] ?? null; - - if ($content = $props['content'] ?? null) { - $this->content = array_change_key_case($content); - } else { - $this->content = null; - } - } - - /** - * Improve `var_dump` output - * @codeCoverageIgnore - */ - public function __debugInfo(): array - { - return $this->toArray(); - } - - /** - * Returns the language code of the - * translation - */ - public function code(): string - { - return $this->code; - } - - /** - * Returns the translation content - * as plain array - */ - public function content(): array - { - $parent = $this->parent(); - $content = $this->content ??= $parent->readContent($this->code()); - - // merge with the default content - if ( - $this->isDefault() === false && - $defaultLanguage = $parent->kirby()->defaultLanguage() - ) { - $content = array_merge( - $parent->translation($defaultLanguage->code())?->content() ?? [], - $content - ); - } - - return $content; - } - - /** - * Absolute path to the translation content file - */ - public function contentFile(): string - { - // temporary compatibility change (TODO: take this from the parent `ModelVersion` object) - $identifier = $this->parent::CLASS_ALIAS === 'page' && $this->parent->isDraft() === true ? - 'changes' : - 'published'; - - return $this->contentFile = $this->parent->storage()->contentFile( - $identifier, - $this->code, - true - ); - } - - /** - * Checks if the translation file exists - */ - public function exists(): bool - { - return - empty($this->content) === false || - file_exists($this->contentFile()) === true; - } - - /** - * Returns the translation code as id - */ - public function id(): string - { - return $this->code(); - } - - /** - * Checks if the this is the default translation - * of the model - */ - public function isDefault(): bool - { - return $this->code() === $this->parent->kirby()->defaultLanguage()?->code(); - } - - /** - * Returns the parent page, file or site object - */ - public function parent(): ModelWithContent - { - return $this->parent; - } - - /** - * Returns the custom translation slug - */ - public function slug(): string|null - { - return $this->slug ??= ($this->content()['slug'] ?? null); - } - - /** - * Merge the old and new data - * - * @return $this - */ - public function update(array $data = null, bool $overwrite = false): static - { - $data = array_change_key_case((array)$data); - - $this->content = match ($overwrite) { - true => $data, - default => array_merge($this->content(), $data) - }; - - return $this; - } - - /** - * Converts the most important translation - * props to an array - */ - public function toArray(): array - { - return [ - 'code' => $this->code(), - 'content' => $this->content(), - 'exists' => $this->exists(), - 'slug' => $this->slug(), - ]; - } -} diff --git a/kirby/src/Content/PlainTextContentStorageHandler.php b/kirby/src/Content/PlainTextContentStorageHandler.php deleted file mode 100644 index 756816a..0000000 --- a/kirby/src/Content/PlainTextContentStorageHandler.php +++ /dev/null @@ -1,253 +0,0 @@ - - * @link https://getkirby.com - * @copyright Bastian Allgeier - * @license https://getkirby.com/license - */ -class PlainTextContentStorageHandler implements ContentStorageHandler -{ - public function __construct(protected ModelWithContent $model) - { - } - - /** - * Creates a new version - * - * @param string $lang Code `'default'` in a single-lang installation - * @param array $fields Content fields - */ - public function create(string $versionType, string $lang, array $fields): void - { - $success = Data::write($this->contentFile($versionType, $lang), $fields); - - // @codeCoverageIgnoreStart - if ($success !== true) { - throw new Exception('Could not write new content file'); - } - // @codeCoverageIgnoreEnd - } - - /** - * Deletes an existing version in an idempotent way if it was already deleted - * - * @param string $lang Code `'default'` in a single-lang installation - */ - public function delete(string $version, string $lang): void - { - $contentFile = $this->contentFile($version, $lang); - $success = F::unlink($contentFile); - - // @codeCoverageIgnoreStart - if ($success !== true) { - throw new Exception('Could not delete content file'); - } - // @codeCoverageIgnoreEnd - - // clean up empty directories - $contentDir = dirname($contentFile); - if ( - Dir::exists($contentDir) === true && - Dir::isEmpty($contentDir) === true - ) { - $success = rmdir($contentDir); - - // @codeCoverageIgnoreStart - if ($success !== true) { - throw new Exception('Could not delete empty content directory'); - } - // @codeCoverageIgnoreEnd - } - } - - /** - * Checks if a version exists - * - * @param string|null $lang Code `'default'` in a single-lang installation; - * checks for "any language" if not provided - */ - public function exists(string $version, string|null $lang): bool - { - if ($lang === null) { - foreach ($this->contentFiles($version) as $file) { - if (is_file($file) === true) { - return true; - } - } - - return false; - } - - return is_file($this->contentFile($version, $lang)) === true; - } - - /** - * Returns the modification timestamp of a version - * if it exists - * - * @param string $lang Code `'default'` in a single-lang installation - */ - public function modified(string $version, string $lang): int|null - { - $modified = F::modified($this->contentFile($version, $lang)); - - if (is_int($modified) === true) { - return $modified; - } - - return null; - } - - /** - * Returns the stored content fields - * - * @param string $lang Code `'default'` in a single-lang installation - * @return array - * - * @throws \Kirby\Exception\NotFoundException If the version does not exist - */ - public function read(string $version, string $lang): array - { - return Data::read($this->contentFile($version, $lang)); - } - - /** - * Updates the modification timestamp of an existing version - * - * @param string $lang Code `'default'` in a single-lang installation - * - * @throws \Kirby\Exception\NotFoundException If the version does not exist - */ - public function touch(string $version, string $lang): void - { - $success = touch($this->contentFile($version, $lang)); - - // @codeCoverageIgnoreStart - if ($success !== true) { - throw new Exception('Could not touch existing content file'); - } - // @codeCoverageIgnoreEnd - } - - /** - * Updates the content fields of an existing version - * - * @param string $lang Code `'default'` in a single-lang installation - * @param array $fields Content fields - * - * @throws \Kirby\Exception\NotFoundException If the version does not exist - */ - public function update(string $version, string $lang, array $fields): void - { - $success = Data::write($this->contentFile($version, $lang), $fields); - - // @codeCoverageIgnoreStart - if ($success !== true) { - throw new Exception('Could not write existing content file'); - } - // @codeCoverageIgnoreEnd - } - - /** - * Returns the absolute path to the content file - * @internal To be made `protected` when the CMS core no longer relies on it - * - * @param string $lang Code `'default'` in a single-lang installation - * - * @throws \Kirby\Exception\LogicException If the model type doesn't have a known content filename - */ - public function contentFile(string $version, string $lang): string - { - if (in_array($version, ['published', 'changes']) !== true) { - throw new InvalidArgumentException('Invalid version identifier "' . $version . '"'); - } - - $extension = $this->model->kirby()->contentExtension(); - $directory = $this->model->root(); - - $directory = match ($this->model::CLASS_ALIAS) { - 'file' => dirname($this->model->root()), - default => $this->model->root() - }; - - $filename = match ($this->model::CLASS_ALIAS) { - 'file' => $this->model->filename(), - 'page' => $this->model->intendedTemplate()->name(), - 'site', - 'user' => $this->model::CLASS_ALIAS, - // @codeCoverageIgnoreStart - default => throw new LogicException('Cannot determine content filename for model type "' . $this->model::CLASS_ALIAS . '"') - // @codeCoverageIgnoreEnd - }; - - if ($this->model::CLASS_ALIAS === 'page' && $this->model->isDraft() === true) { - // changes versions don't need anything extra - // (drafts already have the `_drafts` prefix in their root), - // but a published version is not possible - if ($version === 'published') { - throw new LogicException('Drafts cannot have a published content file'); - } - } elseif ($version === 'changes') { - // other model type or published page that has a changes subfolder - $directory .= '/_changes'; - } - - if ($lang !== 'default') { - return $directory . '/' . $filename . '.' . $lang . '.' . $extension; - } - - return $directory . '/' . $filename . '.' . $extension; - } - - /** - * Returns an array with content files of all languages - * @internal To be made `protected` when the CMS core no longer relies on it - */ - public function contentFiles(string $version): array - { - if ($this->model->kirby()->multilang() === true) { - return $this->model->kirby()->languages()->values( - fn ($lang) => $this->contentFile($version, $lang) - ); - } - - return [ - $this->contentFile($version, 'default') - ]; - } - - /** - * Moves content from one version-language combination to another - * - * @param string $fromLang Code `'default'` in a single-lang installation - * @param string $toLang Code `'default'` in a single-lang installation - */ - public function move( - string $fromVersion, - string $fromLang, - string $toVersion, - string $toLang - ): void { - F::move( - $this->contentFile($fromVersion, $fromLang), - $this->contentFile($toVersion, $toLang) - ); - } -} diff --git a/kirby/src/Data/Data.php b/kirby/src/Data/Data.php index b6a1cb6..3c69e32 100644 --- a/kirby/src/Data/Data.php +++ b/kirby/src/Data/Data.php @@ -26,8 +26,10 @@ class Data { /** * Handler Type Aliases + * + * @var array */ - public static array $aliases = [ + public static $aliases = [ 'md' => 'txt', 'mdown' => 'txt', 'rss' => 'xml', @@ -36,45 +38,46 @@ class Data /** * All registered handlers + * + * @var array */ - public static array $handlers = [ - 'json' => Json::class, - 'php' => PHP::class, - 'txt' => Txt::class, - 'xml' => Xml::class, - 'yaml' => Yaml::class + public static $handlers = [ + 'json' => 'Kirby\Data\Json', + 'php' => 'Kirby\Data\PHP', + 'txt' => 'Kirby\Data\Txt', + 'xml' => 'Kirby\Data\Xml', + 'yaml' => 'Kirby\Data\Yaml', ]; /** * Handler getter + * + * @param string $type + * @return \Kirby\Data\Handler */ - public static function handler(string $type): Handler + public static function handler(string $type) { // normalize the type $type = strtolower($type); // find a handler or alias - $handler = static::$handlers[$type] ?? null; + $handler = static::$handlers[$type] ?? + static::$handlers[static::$aliases[$type] ?? null] ?? + null; - if ($alias = static::$aliases[$type] ?? null) { - $handler ??= static::$handlers[$alias] ?? null; + if ($handler !== null && class_exists($handler)) { + return new $handler(); } - if ($handler === null || class_exists($handler) === false) { - throw new Exception('Missing handler for type: "' . $type . '"'); - } - - $handler = new $handler(); - - if ($handler instanceof Handler === false) { - throw new Exception('Handler for type: "' . $type . '" needs to extend Kirby\\Data\\Handler'); - } - - return $handler; + throw new Exception('Missing handler for type: "' . $type . '"'); } /** * Decodes data with the specified handler + * + * @param mixed $string + * @param string $type + * @return array */ public static function decode($string, string $type): array { @@ -83,6 +86,10 @@ class Data /** * Encodes data with the specified handler + * + * @param mixed $data + * @param string $type + * @return string */ public static function encode($data, string $type): string { @@ -93,26 +100,28 @@ class Data * Reads data from a file; * the data handler is automatically chosen by * the extension if not specified + * + * @param string $file + * @param string $type + * @return array */ - public static function read(string $file, string|null $type = null): array + public static function read(string $file, string $type = null): array { - $type ??= F::extension($file); - $handler = static::handler($type); - return $handler->read($file); + return static::handler($type ?? F::extension($file))->read($file); } /** * Writes data to a file; * the data handler is automatically chosen by * the extension if not specified + * + * @param string $file + * @param mixed $data + * @param string $type + * @return bool */ - public static function write( - string $file, - $data = [], - string|null $type = null - ): bool { - $type ??= F::extension($file); - $handler = static::handler($type); - return $handler->write($file, $data); + public static function write(string $file = null, $data = [], string $type = null): bool + { + return static::handler($type ?? F::extension($file))->write($file, $data); } } diff --git a/kirby/src/Data/Handler.php b/kirby/src/Data/Handler.php index 95dbad3..9c511f8 100644 --- a/kirby/src/Data/Handler.php +++ b/kirby/src/Data/Handler.php @@ -21,24 +21,32 @@ abstract class Handler /** * Parses an encoded string and returns a multi-dimensional array * - * @throws \Exception if the file can't be parsed + * Needs to throw an Exception if the file can't be parsed. + * + * @param mixed $string + * @return array */ abstract public static function decode($string): array; /** * Converts an array to an encoded string + * + * @param mixed $data + * @return string */ abstract public static function encode($data): string; /** * Reads data from a file + * + * @param string $file + * @return array */ public static function read(string $file): array { $contents = F::read($file); - if ($contents === false) { - throw new Exception('The file "' . $file . '" does not exist or cannot be read'); + throw new Exception('The file "' . $file . '" does not exist'); } return static::decode($contents); @@ -46,8 +54,12 @@ abstract class Handler /** * Writes data to a file + * + * @param string $file + * @param mixed $data + * @return bool */ - public static function write(string $file, $data = []): bool + public static function write(string $file = null, $data = []): bool { return F::write($file, static::encode($data)); } diff --git a/kirby/src/Data/Json.php b/kirby/src/Data/Json.php index 35fa867..622636b 100644 --- a/kirby/src/Data/Json.php +++ b/kirby/src/Data/Json.php @@ -17,17 +17,20 @@ class Json extends Handler { /** * Converts an array to an encoded JSON string + * + * @param mixed $data + * @return string */ public static function encode($data): string { - return json_encode( - $data, - JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE - ); + return json_encode($data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE); } /** * Parses an encoded JSON string and returns a multi-dimensional array + * + * @param mixed $string + * @return array */ public static function decode($string): array { @@ -47,8 +50,8 @@ class Json extends Handler if (is_array($result) === true) { return $result; + } else { + throw new InvalidArgumentException('JSON string is invalid'); } - - throw new InvalidArgumentException('JSON string is invalid'); } } diff --git a/kirby/src/Data/PHP.php b/kirby/src/Data/PHP.php index b22d38a..ff3106c 100644 --- a/kirby/src/Data/PHP.php +++ b/kirby/src/Data/PHP.php @@ -20,7 +20,9 @@ class PHP extends Handler /** * Converts an array to PHP file content * + * @param mixed $data * @param string $indent For internal use only + * @return string */ public static function encode($data, string $indent = ''): string { @@ -38,7 +40,7 @@ class PHP extends Handler return $data ? 'true' : 'false'; case 'integer': case 'double': - return (string)$data; + return $data; default: return var_export($data, true); } @@ -46,6 +48,9 @@ class PHP extends Handler /** * PHP strings shouldn't be decoded manually + * + * @param mixed $string + * @return array */ public static function decode($string): array { @@ -54,6 +59,9 @@ class PHP extends Handler /** * Reads data from a file + * + * @param string $file + * @return array */ public static function read(string $file): array { @@ -61,13 +69,17 @@ class PHP extends Handler throw new Exception('The file "' . $file . '" does not exist'); } - return (array)F::load($file, [], allowOutput: false); + return (array)F::load($file, []); } /** * Creates a PHP file with the given data + * + * @param string $file + * @param mixed $data + * @return bool */ - public static function write(string $file, $data = []): bool + public static function write(string $file = null, $data = []): bool { $php = static::encode($data); $php = " "\n\n", - default => ' ', - }; + if (preg_match('!\R!', $value) === 1) { + $result .= "\n\n"; + } else { + $result .= ' '; + } $result .= $value; @@ -77,6 +88,9 @@ class Txt extends Handler /** * Parses a Kirby txt string and returns a multi-dimensional array + * + * @param mixed $string + * @return array */ public static function decode($string): array { @@ -105,24 +119,18 @@ class Txt extends Handler // loop through all fields and add them to the content foreach ($fields as $field) { - if ($pos = strpos($field, ':')) { - $key = strtolower(trim(substr($field, 0, $pos))); - $key = str_replace(['-', ' '], '_', $key); + $pos = strpos($field, ':'); + $key = str_replace(['-', ' '], '_', strtolower(trim(substr($field, 0, $pos)))); - // Don't add fields with empty keys - if (empty($key) === true) { - continue; - } - - $value = trim(substr($field, $pos + 1)); - - // unescape escaped dividers within a field - $data[$key] = preg_replace( - '!(?<=\n|^)\\\\----!', - '----', - $value - ); + // Don't add fields with empty keys + if (empty($key) === true) { + continue; } + + $value = trim(substr($field, $pos + 1)); + + // unescape escaped dividers within a field + $data[$key] = preg_replace('!(?<=\n|^)\\\\----!', '----', $value); } return $data; diff --git a/kirby/src/Data/Xml.php b/kirby/src/Data/Xml.php index 68fa511..ccbd171 100644 --- a/kirby/src/Data/Xml.php +++ b/kirby/src/Data/Xml.php @@ -18,6 +18,9 @@ class Xml extends Handler { /** * Converts an array to an encoded XML string + * + * @param mixed $data + * @return string */ public static function encode($data): string { @@ -26,6 +29,9 @@ class Xml extends Handler /** * Parses an encoded XML string and returns a multi-dimensional array + * + * @param mixed $string + * @return array */ public static function decode($string): array { @@ -51,8 +57,8 @@ class Xml extends Handler } return $result; + } else { + throw new InvalidArgumentException('XML string is invalid'); } - - throw new InvalidArgumentException('XML string is invalid'); } } diff --git a/kirby/src/Data/Yaml.php b/kirby/src/Data/Yaml.php index efa9c9c..56c1349 100644 --- a/kirby/src/Data/Yaml.php +++ b/kirby/src/Data/Yaml.php @@ -2,11 +2,11 @@ namespace Kirby\Data; -use Kirby\Cms\App; use Kirby\Exception\InvalidArgumentException; +use Spyc; /** - * Simple Wrapper around the Symfony or Spyc YAML class + * Simple Wrapper around the Spyc YAML class * * @package Kirby Data * @author Bastian Allgeier @@ -18,17 +18,35 @@ class Yaml extends Handler { /** * Converts an array to an encoded YAML string + * + * @param mixed $data + * @return string */ public static function encode($data): string { - return match (static::handler()) { - 'symfony' => YamlSymfony::encode($data), - default => YamlSpyc::encode($data), - }; + // TODO: The locale magic should no longer be + // necessary when support for PHP 7.x is dropped + + // fetch the current locale setting for numbers + $locale = setlocale(LC_NUMERIC, 0); + + // change to english numerics to avoid issues with floats + setlocale(LC_NUMERIC, 'C'); + + // $data, $indent, $wordwrap, $no_opening_dashes + $yaml = Spyc::YAMLDump($data, false, false, true); + + // restore the previous locale settings + setlocale(LC_NUMERIC, $locale); + + return $yaml; } /** * Parses an encoded YAML string and returns a multi-dimensional array + * + * @param mixed $string + * @return array */ public static function decode($string): array { @@ -44,19 +62,16 @@ class Yaml extends Handler throw new InvalidArgumentException('Invalid YAML data; please pass a string'); } - return match (static::handler()) { - 'symfony' => YamlSymfony::decode($string), - default => YamlSpyc::decode($string) - }; - } + // remove BOM + $string = str_replace("\xEF\xBB\xBF", '', $string); + $result = Spyc::YAMLLoadString($string); - /** - * Returns which YAML parser (`spyc` or `symfony`) - * is configured to be used - * @internal - */ - public static function handler(): string - { - return App::instance(null, true)?->option('yaml.handler') ?? 'spyc'; + if (is_array($result)) { + return $result; + } else { + // apparently Spyc always returns an array, even for invalid YAML syntax + // so this Exception should currently never be thrown + throw new InvalidArgumentException('The YAML data cannot be parsed'); // @codeCoverageIgnore + } } } diff --git a/kirby/src/Data/YamlSpyc.php b/kirby/src/Data/YamlSpyc.php deleted file mode 100644 index a00e92d..0000000 --- a/kirby/src/Data/YamlSpyc.php +++ /dev/null @@ -1,43 +0,0 @@ - - * @link https://getkirby.com - * @copyright Bastian Allgeier - * @license https://opensource.org/licenses/MIT - */ -class YamlSpyc -{ - /** - * Converts an array to an encoded YAML string - */ - public static function encode($data): string - { - // $data, $indent, $wordwrap, $no_opening_dashes - return Spyc::YAMLDump($data, false, false, true); - } - - /** - * Parses an encoded YAML string and returns a multi-dimensional array - */ - public static function decode($string): array - { - $result = Spyc::YAMLLoadString($string); - - if (is_array($result) === true) { - return $result; - } - - // apparently Spyc always returns an array, even for invalid YAML syntax - // so this Exception should currently never be thrown - throw new InvalidArgumentException('The YAML data cannot be parsed'); // @codeCoverageIgnore - } -} diff --git a/kirby/src/Data/YamlSymfony.php b/kirby/src/Data/YamlSymfony.php deleted file mode 100644 index 013a0d0..0000000 --- a/kirby/src/Data/YamlSymfony.php +++ /dev/null @@ -1,44 +0,0 @@ - - * @link https://getkirby.com - * @copyright Bastian Allgeier - * @license https://opensource.org/licenses/MIT - */ -class YamlSymfony -{ - /** - * Converts an array to an encoded YAML string - */ - public static function encode($data): string - { - $kirby = App::instance(null, true); - - return Symfony::dump( - $data, - $kirby?->option('yaml.params.inline') ?? 9999, - $kirby?->option('yaml.params.indent') ?? 2, - Symfony::DUMP_MULTI_LINE_LITERAL_BLOCK | Symfony::DUMP_EMPTY_ARRAY_AS_SEQUENCE - ); - } - - /** - * Parses an encoded YAML string and returns a multi-dimensional array - */ - public static function decode($string): array - { - $result = Symfony::parse($string); - $result = A::wrap($result); - return $result; - } -} diff --git a/kirby/src/Database/Database.php b/kirby/src/Database/Database.php index 9db17ae..99260e4 100644 --- a/kirby/src/Database/Database.php +++ b/kirby/src/Database/Database.php @@ -3,15 +3,10 @@ namespace Kirby\Database; use Closure; -use Kirby\Database\Sql\Mysql; -use Kirby\Database\Sql\Sqlite; use Kirby\Exception\InvalidArgumentException; use Kirby\Toolkit\A; -use Kirby\Toolkit\Collection; -use Kirby\Toolkit\Obj; use Kirby\Toolkit\Str; use PDO; -use PDOStatement; use Throwable; /** @@ -27,90 +22,131 @@ class Database { /** * The number of affected rows for the last query + * + * @var int|null */ - protected int|null $affected = null; + protected $affected; /** * Whitelist for column names + * + * @var array */ - protected array $columnWhitelist = []; + protected $columnWhitelist = []; /** * The established connection + * + * @var \PDO|null */ - protected PDO|null $connection = null; + protected $connection; /** * A global array of started connections + * + * @var array */ - public static array $connections = []; + public static $connections = []; /** * Database name + * + * @var string */ - protected string $database; + protected $database; - protected string $dsn; + /** + * @var string + */ + protected $dsn; /** * Set to true to throw exceptions on failed queries + * + * @var bool */ - protected bool $fail = false; + protected $fail = false; /** * The connection id + * + * @var string */ - protected string $id; + protected $id; /** * The last error + * + * @var \Exception|null */ - protected Throwable|null $lastError = null; + protected $lastError; /** * The last insert id + * + * @var int|null */ - protected int|null $lastId = null; + protected $lastId; /** * The last query + * + * @var string */ - protected string $lastQuery; + protected $lastQuery; /** * The last result set + * + * @var mixed */ protected $lastResult; /** * Optional prefix for table names + * + * @var string */ - protected string|null $prefix = null; + protected $prefix; /** * The PDO query statement + * + * @var \PDOStatement|null */ - protected PDOStatement|null $statement = null; + protected $statement; /** * List of existing tables in the database + * + * @var array|null */ - protected array|null $tables = null; + protected $tables; /** * An array with all queries which are being made + * + * @var array */ - protected array $trace = []; + protected $trace = []; /** * The database type (mysql, sqlite) + * + * @var string */ - protected string $type; + protected $type; - public static array $types = []; + /** + * @var array + */ + public static $types = []; /** * Creates a new Database instance + * + * @param array $params + * @return void */ public function __construct(array $params = []) { @@ -119,18 +155,19 @@ class Database /** * Returns one of the started instances + * + * @param string|null $id + * @return static|null */ - public static function instance(string|null $id = null): static|null + public static function instance(string $id = null) { - if ($id === null) { - return A::last(static::$connections); - } - - return static::$connections[$id] ?? null; + return $id === null ? A::last(static::$connections) : static::$connections[$id] ?? null; } /** * Returns all started instances + * + * @return array */ public static function instances(): array { @@ -141,9 +178,10 @@ class Database * Connects to a database * * @param array|null $params This can either be a config key or an array of parameters for the connection + * @return \PDO|null * @throws \Kirby\Exception\InvalidArgumentException */ - public function connect(array|null $params = null): PDO|null + public function connect(array $params = null) { $defaults = [ 'database' => null, @@ -189,8 +227,10 @@ class Database /** * Returns the currently active connection + * + * @return \PDO|null */ - public function connection(): PDO|null + public function connection(): ?PDO { return $this->connection; } @@ -198,9 +238,10 @@ class Database /** * Sets the exception mode * - * @return $this + * @param bool $fail + * @return \Kirby\Database\Database */ - public function fail(bool $fail = true): static + public function fail(bool $fail = true) { $this->fail = $fail; return $this; @@ -208,6 +249,8 @@ class Database /** * Returns the used database type + * + * @return string */ public function type(): string { @@ -216,8 +259,10 @@ class Database /** * Returns the used table name prefix + * + * @return string|null */ - public function prefix(): string|null + public function prefix(): ?string { return $this->prefix; } @@ -225,6 +270,9 @@ class Database /** * Escapes a value to be used for a safe query * NOTE: Prepared statements using bound parameters are more secure and solid + * + * @param string $value + * @return string */ public function escape(string $value): string { @@ -232,10 +280,12 @@ class Database } /** - * Adds a value to the db trace and also - * returns the entire trace if nothing is specified + * Adds a value to the db trace and also returns the entire trace if nothing is specified + * + * @param array|null $data + * @return array */ - public function trace(array|null $data = null): array + public function trace(array $data = null): array { // return the full trace if ($data === null) { @@ -250,30 +300,38 @@ class Database /** * Returns the number of affected rows for the last query + * + * @return int|null */ - public function affected(): int|null + public function affected(): ?int { return $this->affected; } /** * Returns the last id if available + * + * @return int|null */ - public function lastId(): int|null + public function lastId(): ?int { return $this->lastId; } /** * Returns the last query + * + * @return string|null */ - public function lastQuery(): string|null + public function lastQuery(): ?string { return $this->lastQuery; } /** * Returns the last set of results + * + * @return mixed */ public function lastResult() { @@ -282,16 +340,20 @@ class Database /** * Returns the last db error + * + * @return \Throwable */ - public function lastError(): Throwable|null + public function lastError() { return $this->lastError; } /** * Returns the name of the database + * + * @return string|null */ - public function name(): string|null + public function name(): ?string { return $this->database; } @@ -299,29 +361,17 @@ class Database /** * Private method to execute database queries. * This is used by the query() and execute() methods + * + * @param string $query + * @param array $bindings + * @return bool */ protected function hit(string $query, array $bindings = []): bool { // try to prepare and execute the sql try { $this->statement = $this->connection->prepare($query); - // bind parameters to statement - foreach ($bindings as $parameter => $value) { - // positional parameters start at 1 - if (is_int($parameter)) { - $parameter++; - } - - $type = match (gettype($value)) { - 'integer' => PDO::PARAM_INT, - 'boolean' => PDO::PARAM_BOOL, - 'NULL' => PDO::PARAM_NULL, - default => PDO::PARAM_STR - }; - - $this->statement->bindValue($parameter, $value, $type); - } - $this->statement->execute(); + $this->statement->execute($bindings); $this->affected = $this->statement->rowCount(); $this->lastId = Str::startsWith($query, 'insert ', true) ? $this->connection->lastInsertId() : null; @@ -355,17 +405,19 @@ class Database /** * Executes a sql query, which is expected to return a set of results + * + * @param string $query + * @param array $bindings + * @param array $params + * @return mixed */ - public function query( - string $query, - array $bindings = [], - array $params = [] - ) { + public function query(string $query, array $bindings = [], array $params = []) + { $defaults = [ 'flag' => null, 'method' => 'fetchAll', - 'fetch' => Obj::class, - 'iterator' => Collection::class, + 'fetch' => 'Kirby\Toolkit\Obj', + 'iterator' => 'Kirby\Toolkit\Collection', ]; $options = array_merge($defaults, $params); @@ -375,13 +427,10 @@ class Database } // define the default flag for the fetch method - if ( - $options['fetch'] instanceof Closure || - $options['fetch'] === 'array' - ) { + if ($options['fetch'] instanceof Closure || $options['fetch'] === 'array') { $flags = PDO::FETCH_ASSOC; } else { - $flags = PDO::FETCH_CLASS | PDO::FETCH_PROPS_LATE; + $flags = PDO::FETCH_CLASS|PDO::FETCH_PROPS_LATE; } // add optional flags @@ -390,10 +439,7 @@ class Database } // set the fetch mode - if ( - $options['fetch'] instanceof Closure || - $options['fetch'] === 'array' - ) { + if ($options['fetch'] instanceof Closure || $options['fetch'] === 'array') { $this->statement->setFetchMode($flags); } else { $this->statement->setFetchMode($flags, $options['fetch']); @@ -404,14 +450,8 @@ class Database // apply the fetch closure to all results if given if ($options['fetch'] instanceof Closure) { - if ($options['method'] === 'fetchAll') { - // fetching multiple records - foreach ($results as $key => $result) { - $results[$key] = $options['fetch']($result, $key); - } - } elseif ($options['method'] === 'fetch' && $results !== false) { - // fetching a single record - $results = $options['fetch']($results, null); + foreach ($results as $key => $result) { + $results[$key] = $options['fetch']($result, $key); } } @@ -423,8 +463,11 @@ class Database } /** - * Executes a sql query, which is expected - * to not return a set of results + * Executes a sql query, which is expected to not return a set of results + * + * @param string $query + * @param array $bindings + * @return bool */ public function execute(string $query, array $bindings = []): bool { @@ -434,8 +477,10 @@ class Database /** * Returns the correct Sql generator instance * for the type of database + * + * @return \Kirby\Database\Sql */ - public function sql(): Sql + public function sql() { $className = static::$types[$this->type]['sql'] ?? 'Sql'; return new $className($this); @@ -445,14 +490,20 @@ class Database * Sets the current table, which should be queried. Returns a * Query object, which can be used to build a full query * for that table + * + * @param string $table + * @return \Kirby\Database\Query */ - public function table(string $table): Query + public function table(string $table) { return new Query($this, $this->prefix() . $table); } /** * Checks if a table exists in the current database + * + * @param string $table + * @return bool */ public function validateTable(string $table): bool { @@ -473,6 +524,10 @@ class Database /** * Checks if a column exists in a specified table + * + * @param string $table + * @param string $column + * @return bool */ public function validateColumn(string $table, string $column): bool { @@ -498,8 +553,12 @@ class Database /** * Creates a new table + * + * @param string $table + * @param array $columns + * @return bool */ - public function createTable(string $table, array $columns = []): bool + public function createTable($table, $columns = []): bool { $sql = $this->sql()->createTable($table, $columns); $queries = Str::split($sql['query'], ';'); @@ -522,6 +581,9 @@ class Database /** * Drops a table + * + * @param string $table + * @return bool */ public function dropTable(string $table): bool { @@ -543,8 +605,12 @@ class Database * Magic way to start queries for tables by * using a method named like the table. * I.e. $db->users()->all() + * + * @param mixed $method + * @param mixed $arguments + * @return \Kirby\Database\Query */ - public function __call(string $method, mixed $arguments = null): Query + public function __call($method, $arguments = null) { return $this->table($method); } @@ -554,8 +620,8 @@ class Database * MySQL database connector */ Database::$types['mysql'] = [ - 'sql' => Mysql::class, - 'dsn' => function (array $params): string { + 'sql' => 'Kirby\Database\Sql\Mysql', + 'dsn' => function (array $params) { if (isset($params['host']) === false && isset($params['socket']) === false) { throw new InvalidArgumentException('The mysql connection requires either a "host" or a "socket" parameter'); } @@ -582,7 +648,7 @@ Database::$types['mysql'] = [ $parts[] = 'dbname=' . $params['database']; } - $parts[] = 'charset=' . ($params['charset'] ?? 'utf8mb4'); + $parts[] = 'charset=' . ($params['charset'] ?? 'utf8'); return 'mysql:' . implode(';', $parts); } @@ -592,8 +658,8 @@ Database::$types['mysql'] = [ * SQLite database connector */ Database::$types['sqlite'] = [ - 'sql' => Sqlite::class, - 'dsn' => function (array $params): string { + 'sql' => 'Kirby\Database\Sql\Sqlite', + 'dsn' => function (array $params) { if (isset($params['database']) === false) { throw new InvalidArgumentException('The sqlite connection requires a "database" parameter'); } diff --git a/kirby/src/Database/Db.php b/kirby/src/Database/Db.php index 82d07b5..e57562f 100644 --- a/kirby/src/Database/Db.php +++ b/kirby/src/Database/Db.php @@ -18,21 +18,26 @@ class Db { /** * Query shortcuts + * + * @var array */ - public static array $queries = []; + public static $queries = []; /** * The singleton Database object + * + * @var \Kirby\Database\Database */ - public static Database|null $connection = null; + public static $connection = null; /** * (Re)connect the database * * @param array|null $params Pass `[]` to use the default params from the config, * don't pass any argument to get the current connection + * @return \Kirby\Database\Database */ - public static function connect(array|null $params = null): Database + public static function connect(?array $params = null) { if ($params === null && static::$connection !== null) { return static::$connection; @@ -47,8 +52,7 @@ class Db 'password' => Config::get('db.password', ''), 'database' => Config::get('db.database', ''), 'prefix' => Config::get('db.prefix', ''), - 'port' => Config::get('db.port', ''), - 'charset' => Config::get('db.charset') + 'port' => Config::get('db.port', '') ]; return static::$connection = new Database($params); @@ -56,8 +60,10 @@ class Db /** * Returns the current database connection + * + * @return \Kirby\Database\Database|null */ - public static function connection(): Database|null + public static function connection() { return static::$connection; } @@ -66,8 +72,11 @@ class Db * Sets the current table which should be queried. Returns a * Query object, which can be used to build a full query for * that table. + * + * @param string $table + * @return \Kirby\Database\Query */ - public static function table(string $table): Query + public static function table(string $table) { $db = static::connect(); return $db->table($table); @@ -75,6 +84,11 @@ class Db /** * Executes a raw SQL query which expects a set of results + * + * @param string $query + * @param array $bindings + * @param array $params + * @return mixed */ public static function query(string $query, array $bindings = [], array $params = []) { @@ -83,8 +97,11 @@ class Db } /** - * Executes a raw SQL query which expects - * no set of results (i.e. update, insert, delete) + * Executes a raw SQL query which expects no set of results (i.e. update, insert, delete) + * + * @param string $query + * @param array $bindings + * @return bool */ public static function execute(string $query, array $bindings = []): bool { @@ -97,6 +114,9 @@ class Db * redirected to either a predefined query or * the respective method of the Database object * + * @param string $method + * @param mixed $arguments + * @return mixed * @throws \Kirby\Exception\InvalidArgumentException */ public static function __callStatic(string $method, $arguments) @@ -105,10 +125,7 @@ class Db return (static::$queries[$method])(...$arguments); } - if ( - static::$connection !== null && - method_exists(static::$connection, $method) === true - ) { + if (static::$connection !== null && method_exists(static::$connection, $method) === true) { return call_user_func_array([static::$connection, $method], $arguments); } @@ -124,22 +141,13 @@ class Db * @param string $table The name of the table which should be queried * @param mixed $columns Either a string with columns or an array of column names * @param mixed $where The WHERE clause; can be a string or an array + * @param string $order + * @param int $offset + * @param int $limit + * @return mixed */ -Db::$queries['select'] = function ( - string $table, - $columns = '*', - $where = null, - string|null $order = null, - int $offset = 0, - int|null $limit = null -) { - return Db::table($table) - ->select($columns) - ->where($where) - ->order($order) - ->offset($offset) - ->limit($limit) - ->all(); +Db::$queries['select'] = function (string $table, $columns = '*', $where = null, string $order = null, int $offset = 0, int $limit = null) { + return Db::table($table)->select($columns)->where($where)->order($order)->offset($offset)->limit($limit)->all(); }; /** @@ -148,18 +156,13 @@ Db::$queries['select'] = function ( * @param string $table The name of the table which should be queried * @param mixed $columns Either a string with columns or an array of column names * @param mixed $where The WHERE clause; can be a string or an array + * @param string $order + * @param int $offset + * @param int $limit + * @return mixed */ -Db::$queries['first'] = Db::$queries['row'] = Db::$queries['one'] = function ( - string $table, - $columns = '*', - $where = null, - string|null $order = null -) { - return Db::table($table) - ->select($columns) - ->where($where) - ->order($order) - ->first(); +Db::$queries['first'] = Db::$queries['row'] = Db::$queries['one'] = function (string $table, $columns = '*', $where = null, string $order = null) { + return Db::table($table)->select($columns)->where($where)->order($order)->first(); }; /** @@ -168,21 +171,13 @@ Db::$queries['first'] = Db::$queries['row'] = Db::$queries['one'] = function ( * @param string $table The name of the table which should be queried * @param string $column The name of the column to select from * @param mixed $where The WHERE clause; can be a string or an array + * @param string $order + * @param int $offset + * @param int $limit + * @return mixed */ -Db::$queries['column'] = function ( - string $table, - string $column, - $where = null, - string|null $order = null, - int $offset = 0, - int|null $limit = null -) { - return Db::table($table) - ->where($where) - ->order($order) - ->offset($offset) - ->limit($limit) - ->column($column); +Db::$queries['column'] = function (string $table, string $column, $where = null, string $order = null, int $offset = 0, int $limit = null) { + return Db::table($table)->where($where)->order($order)->offset($offset)->limit($limit)->column($column); }; /** @@ -192,7 +187,7 @@ Db::$queries['column'] = function ( * @param array $values An array of values which should be inserted * @return mixed Returns the last inserted id on success or false */ -Db::$queries['insert'] = function (string $table, array $values): mixed { +Db::$queries['insert'] = function (string $table, array $values) { return Db::table($table)->insert($values); }; @@ -202,12 +197,9 @@ Db::$queries['insert'] = function (string $table, array $values): mixed { * @param string $table The name of the table which should be queried * @param array $values An array of values which should be inserted * @param mixed $where An optional WHERE clause + * @return bool */ -Db::$queries['update'] = function ( - string $table, - array $values, - $where = null -): bool { +Db::$queries['update'] = function (string $table, array $values, $where = null): bool { return Db::table($table)->where($where)->update($values); }; @@ -216,6 +208,7 @@ Db::$queries['update'] = function ( * * @param string $table The name of the table which should be queried * @param mixed $where An optional WHERE clause + * @return bool */ Db::$queries['delete'] = function (string $table, $where = null): bool { return Db::table($table)->where($where)->delete(); @@ -226,8 +219,9 @@ Db::$queries['delete'] = function (string $table, $where = null): bool { * * @param string $table The name of the table which should be queried * @param mixed $where An optional WHERE clause + * @return int */ -Db::$queries['count'] = function (string $table, mixed $where = null): int { +Db::$queries['count'] = function (string $table, $where = null): int { return Db::table($table)->where($where)->count(); }; @@ -237,12 +231,9 @@ Db::$queries['count'] = function (string $table, mixed $where = null): int { * @param string $table The name of the table which should be queried * @param string $column The name of the column of which the minimum should be calculated * @param mixed $where An optional WHERE clause + * @return float */ -Db::$queries['min'] = function ( - string $table, - string $column, - $where = null -): float { +Db::$queries['min'] = function (string $table, string $column, $where = null): float { return Db::table($table)->where($where)->min($column); }; @@ -252,12 +243,9 @@ Db::$queries['min'] = function ( * @param string $table The name of the table which should be queried * @param string $column The name of the column of which the maximum should be calculated * @param mixed $where An optional WHERE clause + * @return float */ -Db::$queries['max'] = function ( - string $table, - string $column, - $where = null -): float { +Db::$queries['max'] = function (string $table, string $column, $where = null): float { return Db::table($table)->where($where)->max($column); }; @@ -267,12 +255,9 @@ Db::$queries['max'] = function ( * @param string $table The name of the table which should be queried * @param string $column The name of the column of which the average should be calculated * @param mixed $where An optional WHERE clause + * @return float */ -Db::$queries['avg'] = function ( - string $table, - string $column, - $where = null -): float { +Db::$queries['avg'] = function (string $table, string $column, $where = null): float { return Db::table($table)->where($where)->avg($column); }; @@ -282,12 +267,9 @@ Db::$queries['avg'] = function ( * @param string $table The name of the table which should be queried * @param string $column The name of the column of which the sum should be calculated * @param mixed $where An optional WHERE clause + * @return float */ -Db::$queries['sum'] = function ( - string $table, - string $column, - $where = null -): float { +Db::$queries['sum'] = function (string $table, string $column, $where = null): float { return Db::table($table)->where($where)->sum($column); }; diff --git a/kirby/src/Database/Query.php b/kirby/src/Database/Query.php index 1181b98..9354892 100644 --- a/kirby/src/Database/Query.php +++ b/kirby/src/Database/Query.php @@ -2,10 +2,8 @@ namespace Kirby\Database; -use Closure; use InvalidArgumentException; -use Kirby\Toolkit\Collection; -use Kirby\Toolkit\Obj; +use Kirby\Toolkit\A; use Kirby\Toolkit\Pagination; use Kirby\Toolkit\Str; @@ -25,94 +23,130 @@ class Query /** * Parent Database object + * + * @var \Kirby\Database\Database */ - protected Database|null $database = null; + protected $database = null; /** * The object which should be fetched for each row * or function to call for each row + * + * @var string|\Closure */ - protected string|Closure $fetch = Obj::class; + protected $fetch = 'Kirby\Toolkit\Obj'; /** * The iterator class, which should be used for result sets + * + * @var string */ - protected string $iterator = Collection::class; + protected $iterator = 'Kirby\Toolkit\Collection'; /** * An array of bindings for the final query + * + * @var array */ - protected array $bindings = []; + protected $bindings = []; /** * The table name + * + * @var string */ - protected string $table; + protected $table; /** * The name of the primary key column + * + * @var string */ - protected string $primaryKeyName = 'id'; + protected $primaryKeyName = 'id'; /** * An array with additional join parameters + * + * @var array */ - protected array|null $join = null; + protected $join; /** * A list of columns, which should be selected + * + * @var array|string */ - protected array|string|null $select = null; + protected $select; /** * Boolean for distinct select clauses + * + * @var bool */ - protected bool|null $distinct = null; + protected $distinct; /** * Boolean for if exceptions should be thrown on failing queries + * + * @var bool */ - protected bool $fail = false; + protected $fail = false; /** * A list of values for update and insert clauses + * + * @var array */ - protected array|null $values = null; + protected $values; /** * WHERE clause + * + * @var mixed */ - protected $where = null; + protected $where; /** * GROUP BY clause + * + * @var mixed */ - protected string|null $group = null; + protected $group; /** * HAVING clause + * + * @var mixed */ - protected $having = null; + protected $having; /** * ORDER BY clause + * + * @var mixed */ - protected $order = null; + protected $order; /** * The offset, which should be applied to the select query + * + * @var int */ - protected int $offset = 0; + protected $offset = 0; /** * The limit, which should be applied to the select query + * + * @var int */ - protected int|null $limit = null; + protected $limit; /** * Boolean to enable query debugging + * + * @var bool */ - protected bool $debug = false; + protected $debug = false; /** * Constructor @@ -129,7 +163,7 @@ class Query /** * Reset the query class after each db hit */ - protected function reset(): void + protected function reset() { $this->bindings = []; $this->join = null; @@ -151,9 +185,10 @@ class Query * If enabled, the query will return an array with all important info about * the query instead of actually executing the query and returning results * - * @return $this + * @param bool $debug + * @return \Kirby\Database\Query */ - public function debug(bool $debug = true): static + public function debug(bool $debug = true) { $this->debug = $debug; return $this; @@ -162,9 +197,10 @@ class Query /** * Enables distinct select clauses. * - * @return $this + * @param bool $distinct + * @return \Kirby\Database\Query */ - public function distinct(bool $distinct = true): static + public function distinct(bool $distinct = true) { $this->distinct = $distinct; return $this; @@ -174,9 +210,10 @@ class Query * Enables failing queries. * If enabled queries will no longer fail silently but throw an exception * - * @return $this + * @param bool $fail + * @return \Kirby\Database\Query */ - public function fail(bool $fail = true): static + public function fail(bool $fail = true) { $this->fail = $fail; return $this; @@ -187,14 +224,11 @@ class Query * set this to `'array'` to get a simple array instead of an object; * pass a function that receives the `$data` and the `$key` to generate arbitrary data structures * - * @return $this + * @param string|\Closure $fetch + * @return \Kirby\Database\Query */ - public function fetch(string|callable|Closure $fetch): static + public function fetch($fetch) { - if (is_callable($fetch) === true) { - $fetch = Closure::fromCallable($fetch); - } - $this->fetch = $fetch; return $this; } @@ -203,9 +237,10 @@ class Query * Sets the iterator class, which should be used for multiple results * Set this to array to get a simple array instead of an iterator object * - * @return $this + * @param string $iterator + * @return \Kirby\Database\Query */ - public function iterator(string $iterator): static + public function iterator(string $iterator) { $this->iterator = $iterator; return $this; @@ -214,10 +249,11 @@ class Query /** * Sets the name of the table, which should be queried * - * @return $this + * @param string $table + * @return \Kirby\Database\Query * @throws \Kirby\Exception\InvalidArgumentException if the table does not exist */ - public function table(string $table): static + public function table(string $table) { if ($this->database->validateTable($table) === false) { throw new InvalidArgumentException('Invalid table: ' . $table); @@ -230,9 +266,10 @@ class Query /** * Sets the name of the primary key column * - * @return $this + * @param string $primaryKeyName + * @return \Kirby\Database\Query */ - public function primaryKeyName(string $primaryKeyName): static + public function primaryKeyName(string $primaryKeyName) { $this->primaryKeyName = $primaryKeyName; return $this; @@ -242,10 +279,10 @@ class Query * Sets the columns, which should be selected from the table * By default all columns will be selected * - * @param array|string|null $select Pass either a string of columns or an array - * @return $this + * @param mixed $select Pass either a string of columns or an array + * @return \Kirby\Database\Query */ - public function select(array|string|null $select): static + public function select($select) { $this->select = $select; return $this; @@ -259,11 +296,8 @@ class Query * @param string $type The join type. Uses an inner join by default * @return $this */ - public function join( - string $table, - string $on, - string $type = 'JOIN' - ): static { + public function join(string $table, string $on, string $type = 'JOIN') + { $join = [ 'table' => $table, 'on' => $on, @@ -279,11 +313,11 @@ class Query * * @param string $table Name of the table, which should be joined * @param string $on The on clause for this join - * @return $this + * @return \Kirby\Database\Query */ - public function leftJoin(string $table, string $on): static + public function leftJoin(string $table, string $on) { - return $this->join($table, $on, 'left join'); + return $this->join($table, $on, 'left'); } /** @@ -291,11 +325,11 @@ class Query * * @param string $table Name of the table, which should be joined * @param string $on The on clause for this join - * @return $this + * @return \Kirby\Database\Query */ - public function rightJoin(string $table, string $on): static + public function rightJoin(string $table, string $on) { - return $this->join($table, $on, 'right join'); + return $this->join($table, $on, 'right'); } /** @@ -303,9 +337,9 @@ class Query * * @param string $table Name of the table, which should be joined * @param string $on The on clause for this join - * @return $this + * @return \Kirby\Database\Query */ - public function innerJoin($table, $on): static + public function innerJoin($table, $on) { return $this->join($table, $on, 'inner join'); } @@ -314,9 +348,9 @@ class Query * Sets the values which should be used for the update or insert clause * * @param mixed $values Can either be a string or an array of values - * @return $this + * @return \Kirby\Database\Query */ - public function values($values = []): static + public function values($values = []) { if ($values !== null) { $this->values = $values; @@ -326,13 +360,12 @@ class Query /** * Attaches additional bindings to the query. - * Also can be used as getter for all attached bindings - * by not passing an argument. + * Also can be used as getter for all attached bindings by not passing an argument. * - * @return array|$this - * @psalm-return ($bindings is array ? $this : array) + * @param mixed $bindings Array of bindings or null to use this method as getter + * @return array|\Kirby\Database\Query */ - public function bindings(array|null $bindings = null): array|static + public function bindings(array $bindings = null) { if (is_array($bindings) === true) { $this->bindings = array_merge($this->bindings, $bindings); @@ -353,9 +386,10 @@ class Query * ->where('username like ?', 'myuser') (args: 2) * ->where('username', 'like', 'myuser'); (args: 3) * - * @return $this + * @param mixed ...$args + * @return \Kirby\Database\Query */ - public function where(...$args): static + public function where(...$args) { $this->where = $this->filterQuery($args, $this->where); return $this; @@ -365,11 +399,23 @@ class Query * Shortcut to attach a where clause with an OR operator. * Check out the where() method docs for additional info. * - * @return $this + * @param mixed ...$args + * @return \Kirby\Database\Query */ - public function orWhere(...$args): static + public function orWhere(...$args) { - $this->where = $this->filterQuery($args, $this->where, 'OR'); + $mode = A::last($args); + + // if there's a where clause mode attribute attached… + if (in_array($mode, ['AND', 'OR'], true) === true) { + // remove that from the list of arguments + array_pop($args); + } + + // make sure to always attach the OR mode indicator + $args[] = 'OR'; + + $this->where(...$args); return $this; } @@ -377,20 +423,33 @@ class Query * Shortcut to attach a where clause with an AND operator. * Check out the where() method docs for additional info. * - * @return $this + * @param mixed ...$args + * @return \Kirby\Database\Query */ - public function andWhere(...$args): static + public function andWhere(...$args) { - $this->where = $this->filterQuery($args, $this->where, 'AND'); + $mode = A::last($args); + + // if there's a where clause mode attribute attached… + if (in_array($mode, ['AND', 'OR'], true) === true) { + // remove that from the list of arguments + array_pop($args); + } + + // make sure to always attach the AND mode indicator + $args[] = 'AND'; + + $this->where(...$args); return $this; } /** * Attaches a group by clause * - * @return $this + * @param string|null $group + * @return \Kirby\Database\Query */ - public function group(string|null $group = null): static + public function group(string $group = null) { $this->group = $group; return $this; @@ -407,9 +466,10 @@ class Query * ->having('username like ?', 'myuser') (args: 2) * ->having('username', 'like', 'myuser'); (args: 3) * - * @return $this + * @param mixed ...$args + * @return \Kirby\Database\Query */ - public function having(...$args): static + public function having(...$args) { $this->having = $this->filterQuery($args, $this->having); return $this; @@ -419,7 +479,7 @@ class Query * Attaches an order clause * * @param string|null $order - * @return $this + * @return \Kirby\Database\Query */ public function order(string $order = null) { @@ -430,9 +490,10 @@ class Query /** * Sets the offset for select clauses * - * @return $this + * @param int|null $offset + * @return \Kirby\Database\Query */ - public function offset(int $offset): static + public function offset(int $offset = null) { $this->offset = $offset; return $this; @@ -441,9 +502,10 @@ class Query /** * Sets the limit for select clauses * - * @return $this + * @param int|null $limit + * @return \Kirby\Database\Query */ - public function limit(int|null $limit = null): static + public function limit(int $limit = null) { $this->limit = $limit; return $this; @@ -456,46 +518,51 @@ class Query * @param string $type (select, update, insert) * @return array The final query */ - public function build(string $type): array + public function build(string $type) { $sql = $this->database->sql(); - return match ($type) { - 'select' => $sql->select([ - 'table' => $this->table, - 'columns' => $this->select, - 'join' => $this->join, - 'distinct' => $this->distinct, - 'where' => $this->where, - 'group' => $this->group, - 'having' => $this->having, - 'order' => $this->order, - 'offset' => $this->offset, - 'limit' => $this->limit, - 'bindings' => $this->bindings - ]), - 'update' => $sql->update([ - 'table' => $this->table, - 'where' => $this->where, - 'values' => $this->values, - 'bindings' => $this->bindings - ]), - 'insert' => $sql->insert([ - 'table' => $this->table, - 'values' => $this->values, - 'bindings' => $this->bindings - ]), - 'delete' => $sql->delete([ - 'table' => $this->table, - 'where' => $this->where, - 'bindings' => $this->bindings - ]), - default => null - }; + switch ($type) { + case 'select': + return $sql->select([ + 'table' => $this->table, + 'columns' => $this->select, + 'join' => $this->join, + 'distinct' => $this->distinct, + 'where' => $this->where, + 'group' => $this->group, + 'having' => $this->having, + 'order' => $this->order, + 'offset' => $this->offset, + 'limit' => $this->limit, + 'bindings' => $this->bindings + ]); + case 'update': + return $sql->update([ + 'table' => $this->table, + 'where' => $this->where, + 'values' => $this->values, + 'bindings' => $this->bindings + ]); + case 'insert': + return $sql->insert([ + 'table' => $this->table, + 'values' => $this->values, + 'bindings' => $this->bindings + ]); + case 'delete': + return $sql->delete([ + 'table' => $this->table, + 'where' => $this->where, + 'bindings' => $this->bindings + ]); + } } /** * Builds a count query + * + * @return int */ public function count(): int { @@ -504,6 +571,9 @@ class Query /** * Builds a max query + * + * @param string $column + * @return float */ public function max(string $column): float { @@ -512,6 +582,9 @@ class Query /** * Builds a min query + * + * @param string $column + * @return float */ public function min(string $column): float { @@ -520,6 +593,9 @@ class Query /** * Builds a sum query + * + * @param string $column + * @return float */ public function sum(string $column): float { @@ -528,6 +604,9 @@ class Query /** * Builds an average query + * + * @param string $column + * @return float */ public function avg(string $column): float { @@ -538,9 +617,12 @@ class Query * Builds an aggregation query. * This is used by all the aggregation methods above * + * @param string $method + * @param string $column * @param int $default An optional default value, which should be returned if the query fails + * @return mixed */ - public function aggregate(string $method, string $column = '*', int $default = 0) + public function aggregate(string $method, string $column = '*', $default = 0) { // reset the sorting to avoid counting issues $this->order = null; @@ -552,13 +634,13 @@ class Query } $fetch = $this->fetch; - $row = $this->select($method . '(' . $column . ') as aggregation')->fetch(Obj::class)->first(); + $row = $this->select($method . '(' . $column . ') as aggregation')->fetch('Obj')->first(); if ($this->debug === true) { return $row; } - $result = $row?->get('aggregation') ?? $default; + $result = $row ? $row->get('aggregation') : $default; $this->fetch($fetch); @@ -567,8 +649,12 @@ class Query /** * Used as an internal shortcut for firing a db query + * + * @param string|array $sql + * @param array $params + * @return mixed */ - protected function query(string|array $sql, array $params = []) + protected function query($sql, array $params = []) { if (is_string($sql) === true) { $sql = [ @@ -598,8 +684,12 @@ class Query /** * Used as an internal shortcut for executing a db query + * + * @param string|array $sql + * @param array $params + * @return mixed */ - protected function execute(string|array $sql, array $params = []) + protected function execute($sql, array $params = []) { if (is_string($sql) === true) { $sql = [ @@ -629,8 +719,10 @@ class Query /** * Selects only one row from a table + * + * @return object */ - public function first(): mixed + public function first() { return $this->query($this->offset(0)->limit(1)->build('select'), [ 'fetch' => $this->fetch, @@ -641,16 +733,20 @@ class Query /** * Selects only one row from a table + * + * @return object */ - public function row(): mixed + public function row() { return $this->first(); } /** * Selects only one row from a table + * + * @return object */ - public function one(): mixed + public function one() { return $this->first(); } @@ -658,10 +754,11 @@ class Query /** * Automatically adds pagination to a query * + * @param int $page * @param int $limit The number of rows, which should be returned for each page * @return object Collection iterator with attached pagination object */ - public function page(int $page, int $limit): object + public function page(int $page, int $limit) { // clone this to create a counter query $counter = clone $this; @@ -681,7 +778,7 @@ class Query $collection = $this ->offset($pagination->offset()) ->limit($pagination->limit()) - ->iterator(Collection::class) + ->iterator('Kirby\Toolkit\Collection') ->all(); $this->iterator($iterator); @@ -703,6 +800,8 @@ class Query /** * Returns all matching rows from a table + * + * @return mixed */ public function all() { @@ -714,6 +813,9 @@ class Query /** * Returns only values from a single column + * + * @param string $column + * @return mixed */ public function column(string $column) { @@ -748,6 +850,10 @@ class Query /** * Find a single row by column and value + * + * @param string $column + * @param mixed $value + * @return mixed */ public function findBy(string $column, $value) { @@ -756,6 +862,9 @@ class Query /** * Find a single row by its primary key + * + * @param mixed $id + * @return mixed */ public function find($id) { @@ -784,8 +893,9 @@ class Query * * @param mixed $values You can pass values here or set them with ->values() before * @param mixed $where You can pass a where clause here or set it with ->where() before + * @return bool */ - public function update($values = null, $where = null): bool + public function update($values = null, $where = null) { return $this->execute($this->values($values)->where($where)->build('update')); } @@ -794,22 +904,28 @@ class Query * Fires a delete query * * @param mixed $where You can pass a where clause here or set it with ->where() before + * @return bool */ - public function delete($where = null): bool + public function delete($where = null) { return $this->execute($this->where($where)->build('delete')); } /** * Enables magic queries like findByUsername or findByEmail + * + * @param string $method + * @param array $arguments + * @return mixed */ public function __call(string $method, array $arguments = []) { if (preg_match('!^findBy([a-z]+)!i', $method, $match)) { $column = Str::lower($match[1]); return $this->findBy($column, $arguments[0]); + } else { + throw new InvalidArgumentException('Invalid query method: ' . $method, static::ERROR_INVALID_QUERY_METHOD); } - throw new InvalidArgumentException('Invalid query method: ' . $method, static::ERROR_INVALID_QUERY_METHOD); } /** @@ -817,11 +933,21 @@ class Query * * @param array $args Arguments, see where() description * @param mixed $current Current value (like $this->where) + * @return string */ - protected function filterQuery(array $args, $current, string $mode = 'AND') + protected function filterQuery(array $args, $current) { + $mode = A::last($args); $result = ''; + // if there's a where clause mode attribute attached… + if (in_array($mode, ['AND', 'OR'], true) === true) { + // remove that from the list of arguments + array_pop($args); + } else { + $mode = 'AND'; + } + switch (count($args)) { case 1: @@ -869,7 +995,7 @@ class Query $this->bindings($args[1]); // ->where('username like ?', 'myuser') - } elseif (is_string($args[0]) === true && is_scalar($args[1]) === true) { + } elseif (is_string($args[0]) === true && is_string($args[1]) === true) { // prepared where clause $result = $args[0]; @@ -887,10 +1013,9 @@ class Query $key = $sql->columnName($this->table, $args[0]); // ->where('username', 'in', ['myuser', 'myotheruser']); - // ->where('quantity', 'between', [10, 50]); $predicate = trim(strtoupper($args[1])); if (is_array($args[2]) === true) { - if (in_array($predicate, ['IN', 'NOT IN', 'BETWEEN', 'NOT BETWEEN']) === false) { + if (in_array($predicate, ['IN', 'NOT IN']) === false) { throw new InvalidArgumentException('Invalid predicate ' . $predicate); } @@ -904,20 +1029,15 @@ class Query $values[] = $valueBinding; } - // add that to the where clause in parenthesis or seperated by AND - $values = match ($predicate) { - 'IN', - 'NOT IN' => '(' . implode(', ', $values) . ')', - 'BETWEEN', - 'NOT BETWEEN' => $values[0] . ' AND ' . $values[1] - }; - $result = $key . ' ' . $predicate . ' ' . $values; + // add that to the where clause in parenthesis + $result = $key . ' ' . $predicate . ' (' . implode(', ', $values) . ')'; // ->where('username', 'like', 'myuser'); } else { $predicates = [ '=', '>=', '>', '<=', '<', '<>', '!=', '<=>', 'IS', 'IS NOT', + 'BETWEEN', 'NOT BETWEEN', 'LIKE', 'NOT LIKE', 'SOUNDS LIKE', 'REGEXP', 'NOT REGEXP' @@ -941,8 +1061,8 @@ class Query // attach the where clause if (empty($current) === false) { return $current . ' ' . $mode . ' ' . $result; + } else { + return $result; } - - return $result; } } diff --git a/kirby/src/Database/Sql.php b/kirby/src/Database/Sql.php index 16349af..e3cff62 100644 --- a/kirby/src/Database/Sql.php +++ b/kirby/src/Database/Sql.php @@ -19,25 +19,33 @@ abstract class Sql { /** * List of literals which should not be escaped in queries + * + * @var array */ - public static array $literals = ['NOW()', null]; + public static $literals = ['NOW()', null]; /** * The parent database connection + * + * @var \Kirby\Database\Database */ - protected Database $database; + protected $database; /** * List of used bindings; used to avoid * duplicate binding names + * + * @var array */ - protected array $bindings = []; + protected $bindings = []; /** * Constructor * @codeCoverageIgnore + * + * @param \Kirby\Database\Database $database */ - public function __construct(Database $database) + public function __construct($database) { $this->database = $database; } @@ -72,6 +80,7 @@ abstract class Sql * the query needs to return rows with a column `name` * * @param string $table Table name + * @return array */ abstract public function columns(string $table): array; @@ -109,10 +118,10 @@ abstract class Sql * @param bool $enforceQualified If true, a qualified identifier is returned in all cases * @return string|null Identifier or null if the table or column is invalid */ - public function columnName(string $table, string $column, bool $enforceQualified = false): string|null + public function columnName(string $table, string $column, bool $enforceQualified = false): ?string { // ensure we have clean $table and $column values without qualified identifiers - [$table, $column] = $this->splitIdentifier($table, $column); + list($table, $column) = $this->splitIdentifier($table, $column); // combine the identifiers again if ($this->database->validateColumn($table, $column) === true) { @@ -127,26 +136,29 @@ abstract class Sql * Abstracted column types to simplify table * creation for multiple database drivers * @codeCoverageIgnore + * + * @return array */ public function columnTypes(): array { return [ 'id' => '{{ name }} INT(11) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY', - 'varchar' => '{{ name }} varchar({{ size }}) {{ null }} {{ default }} {{ unique }}', + 'varchar' => '{{ name }} varchar(255) {{ null }} {{ default }} {{ unique }}', 'text' => '{{ name }} TEXT {{ unique }}', - 'int' => '{{ name }} INT(11) {{ unsigned }} {{ null }} {{ default }} {{ unique }}', + 'int' => '{{ name }} INT(11) UNSIGNED {{ null }} {{ default }} {{ unique }}', 'timestamp' => '{{ name }} TIMESTAMP {{ null }} {{ default }} {{ unique }}', - 'bool' => '{{ name }} TINYINT(1) {{ null }} {{ default }} {{ unique }}', - 'float' => '{{ name }} DOUBLE {{ null }} {{ default }} {{ unique }}', - 'decimal' => '{{ name }} DECIMAL({{ precision }}, {{ decimalPlaces }}) {{ null }} {{ default }} {{ unique }}' + 'bool' => '{{ name }} TINYINT(1) {{ null }} {{ default }} {{ unique }}' ]; } /** * Combines an identifier (table and column) * + * @param $table string + * @param $column string * @param $values bool Whether the identifier is going to be used for a VALUES clause; - * only relevant for SQLite + * only relevant for SQLite + * @return string */ public function combineIdentifier(string $table, string $column, bool $values = false): string { @@ -159,10 +171,6 @@ abstract class Sql * @param string $name Column name * @param array $column Column definition array; valid keys: * - `type` (required): Column template to use - * - `unsigned`: Whether an int column is signed or unsigned (boolean) - * - `size`: The size of varchar (int) - * - `precision`: The precision of a decimal type - * - `decimalPlaces`: The number of decimal places for a decimal type * - `null`: Whether the column may be NULL (boolean) * - `key`: Index this column is part of; special values `'primary'` for PRIMARY KEY and `true` for automatic naming * - `unique`: Whether the index (or if not set the column itself) has a UNIQUE constraint @@ -197,13 +205,6 @@ abstract class Sql } } - // unsigned (defaults to true for backwards compatibility) - if (isset($column['unsigned']) === true && $column['unsigned'] === false) { - $unsigned = ''; - } else { - $unsigned = 'UNSIGNED'; - } - // unique $uniqueKey = false; $uniqueColumn = null; @@ -221,15 +222,11 @@ abstract class Sql $columnDefault = $this->columnDefault($name, $column); $query = trim(Str::template($template, [ - 'name' => $this->quoteIdentifier($name), - 'unsigned' => $unsigned, - 'size' => $column['size'] ?? 255, - 'precision' => $column['precision'] ?? 14, - 'decimalPlaces' => $column['decimalPlaces'] ?? 4, - 'null' => $null, - 'default' => $columnDefault['query'], - 'unique' => $uniqueColumn - ], ['fallback' => ''])); + 'name' => $this->quoteIdentifier($name), + 'null' => $null, + 'default' => $columnDefault['query'], + 'unique' => $uniqueColumn + ], ['fallback' => ''])); return [ 'query' => $query, @@ -319,6 +316,7 @@ abstract class Sql * Builds a DELETE clause * * @param array $params List of parameters for the DELETE clause. See defaults for more info. + * @return array */ public function delete(array $params = []): array { @@ -346,6 +344,9 @@ abstract class Sql /** * Creates the sql for dropping a single table + * + * @param string $table + * @return array */ public function dropTable(string $table): array { @@ -358,8 +359,13 @@ abstract class Sql /** * Extends a given query and bindings * by reference + * + * @param array $query + * @param array $bindings + * @param array $input + * @return void */ - public function extend(array &$query, array &$bindings, array $input): void + public function extend(&$query, array &$bindings, $input) { if (empty($input['query']) === false) { $query[] = $input['query']; @@ -369,6 +375,9 @@ abstract class Sql /** * Creates the from syntax + * + * @param string $table + * @return array */ public function from(string $table): array { @@ -380,36 +389,51 @@ abstract class Sql /** * Creates the group by syntax + * + * @param string $group + * @return array */ - public function group(string|null $group = null): array + public function group(string $group = null): array { - if (empty($group) === false) { - $query = 'GROUP BY ' . $group; + if (empty($group) === true) { + return [ + 'query' => null, + 'bindings' => [] + ]; } return [ - 'query' => $query ?? null, + 'query' => 'GROUP BY ' . $group, 'bindings' => [] ]; } /** * Creates the having syntax + * + * @param string|null $having + * @return array */ - public function having(string|null $having = null): array + public function having(string $having = null): array { - if (empty($having) === false) { - $query = 'HAVING ' . $having; + if (empty($having) === true) { + return [ + 'query' => null, + 'bindings' => [] + ]; } return [ - 'query' => $query ?? null, + 'query' => 'HAVING ' . $having, 'bindings' => [] ]; } /** * Creates an insert query + * + * @param array $params + * @return array */ public function insert(array $params = []): array { @@ -430,6 +454,10 @@ abstract class Sql /** * Creates a join query * + * @param string $table + * @param string $type + * @param string $on + * @return array * @throws \Kirby\Exception\InvalidArgumentException if an invalid join type is given */ public function join(string $type, string $table, string $on): array @@ -464,8 +492,11 @@ abstract class Sql /** * Create the syntax for multiple joins + * + * @param array|null $joins + * @return array */ - public function joins(array|null $joins = null): array + public function joins(array $joins = null): array { $query = []; $bindings = []; @@ -482,8 +513,12 @@ abstract class Sql /** * Creates a limit and offset query instruction + * + * @param int $offset + * @param int|null $limit + * @return array */ - public function limit(int $offset = 0, int|null $limit = null): array + public function limit(int $offset = 0, int $limit = null): array { // no need to add it to the query if ($offset === 0 && $limit === null) { @@ -509,29 +544,42 @@ abstract class Sql /** * Creates the order by syntax + * + * @param string $order + * @return array */ - public function order(string|null $order = null): array + public function order(string $order = null): array { - if (empty($order) === false) { - $query = 'ORDER BY ' . $order; + if (empty($order) === true) { + return [ + 'query' => null, + 'bindings' => [] + ]; } return [ - 'query' => $query ?? null, + 'query' => 'ORDER BY ' . $order, 'bindings' => [] ]; } /** * Converts a query array into a final string + * + * @param array $query + * @param string $separator + * @return string */ - public function query(array $query, string $separator = ' '): string + public function query(array $query, string $separator = ' ') { return implode($separator, array_filter($query)); } /** * Quotes an identifier (table *or* column) + * + * @param $identifier string + * @return string */ public function quoteIdentifier(string $identifier): string { @@ -610,8 +658,12 @@ abstract class Sql /** * Creates a columns definition from string or array + * + * @param string $table + * @param array|string|null $columns + * @return string */ - public function selected(string $table, array|string|null $columns = null): string + public function selected($table, $columns = null): string { // all columns if (empty($columns) === true) { @@ -624,7 +676,7 @@ abstract class Sql $result = []; foreach ($columns as $column) { - [$table, $columnPart] = $this->splitIdentifier($table, $column); + list($table, $columnPart) = $this->splitIdentifier($table, $column); if ($this->validateColumn($table, $columnPart) === true) { $result[] = $this->combineIdentifier($table, $columnPart); @@ -632,46 +684,52 @@ abstract class Sql } return implode(', ', $result); + } else { + return $columns; } - - return $columns; } /** * Splits a (qualified) identifier into table and column * - * @param string $table Default table if the identifier is not qualified + * @param $table string Default table if the identifier is not qualified + * @param $identifier string + * @return array * @throws \Kirby\Exception\InvalidArgumentException if an invalid identifier is given */ - public function splitIdentifier(string $table, string $identifier): array + public function splitIdentifier($table, $identifier): array { // split by dot, but only outside of quotes $parts = preg_split('/(?:`[^`]*`|"[^"]*")(*SKIP)(*F)|\./', $identifier); - return match (count($parts)) { - // non-qualified identifier - 1 => [$table, $this->unquoteIdentifier($parts[0])], + switch (count($parts)) { + case 1: + // non-qualified identifier + return [$table, $this->unquoteIdentifier($parts[0])]; - // qualified identifier - 2 => [ - $this->unquoteIdentifier($parts[0]), - $this->unquoteIdentifier($parts[1]) - ], + case 2: + // qualified identifier + return [$this->unquoteIdentifier($parts[0]), $this->unquoteIdentifier($parts[1])]; - // every other number is an error - default => throw new InvalidArgumentException('Invalid identifier ' . $identifier) - }; + default: + // every other number is an error + throw new InvalidArgumentException('Invalid identifier ' . $identifier); + } } /** * Returns a query to list the tables of the current database; * the query needs to return rows with a column `name` + * + * @return array */ abstract public function tables(): array; /** * Validates and quotes a table name * + * @param string $table + * @return string * @throws \Kirby\Exception\InvalidArgumentException if an invalid table name is given */ public function tableName(string $table): string @@ -686,6 +744,9 @@ abstract class Sql /** * Unquotes an identifier (table *or* column) + * + * @param $identifier string + * @return string */ public function unquoteIdentifier(string $identifier): string { @@ -706,6 +767,7 @@ abstract class Sql * Builds an update clause * * @param array $params List of parameters for the update clause. See defaults for more info. + * @return array */ public function update(array $params = []): array { @@ -737,6 +799,9 @@ abstract class Sql /** * Validates a given column name in a table * + * @param string $table + * @param string $column + * @return bool * @throws \Kirby\Exception\InvalidArgumentException If the column is invalid */ public function validateColumn(string $table, string $column): bool @@ -757,13 +822,8 @@ abstract class Sql * @param bool $set If true builds a set list of values for update clauses * @param bool $enforceQualified Always use fully qualified column names */ - public function values( - string $table, - $values, - string $separator = ', ', - bool $set = true, - bool $enforceQualified = false - ): array { + public function values(string $table, $values, string $separator = ', ', bool $set = true, bool $enforceQualified = false): array + { if (is_array($values) === false) { return [ 'query' => $values, @@ -773,20 +833,22 @@ abstract class Sql if ($set === true) { return $this->valueSet($table, $values, $separator, $enforceQualified); + } else { + return $this->valueList($table, $values, $separator, $enforceQualified); } - - return $this->valueList($table, $values, $separator, $enforceQualified); } /** * Creates a list of fields and values + * + * @param string $table + * @param string|array $values + * @param string $separator + * @param bool $enforceQualified + * @param array */ - public function valueList( - string $table, - string|array $values, - string $separator = ',', - bool $enforceQualified = false - ): array { + public function valueList(string $table, $values, string $separator = ',', bool $enforceQualified = false): array + { $fields = []; $query = []; $bindings = []; @@ -824,13 +886,16 @@ abstract class Sql /** * Creates a set of values + * + * @param string $table + * @param string|array $values + * @param string $separator + * @param bool $enforceQualified + * @param array + * @return array */ - public function valueSet( - string $table, - string|array $values, - string $separator = ',', - bool $enforceQualified = false - ): array { + public function valueSet(string $table, $values, string $separator = ',', bool $enforceQualified = false): array + { $query = []; $bindings = []; @@ -863,7 +928,12 @@ abstract class Sql ]; } - public function where(string|array|null $where, array $bindings = []): array + /** + * @param string|array|null $where + * @param array $bindings + * @return array + */ + public function where($where, array $bindings = []): array { if (empty($where) === true) { return [ diff --git a/kirby/src/Database/Sql/Mysql.php b/kirby/src/Database/Sql/Mysql.php index 02c3939..f8fc9d3 100644 --- a/kirby/src/Database/Sql/Mysql.php +++ b/kirby/src/Database/Sql/Mysql.php @@ -20,6 +20,7 @@ class Mysql extends Sql * the query needs to return rows with a column `name` * * @param string $table Table name + * @return array */ public function columns(string $table): array { @@ -41,6 +42,8 @@ class Mysql extends Sql /** * Returns a query to list the tables of the current database; * the query needs to return rows with a column `name` + * + * @return array */ public function tables(): array { diff --git a/kirby/src/Database/Sql/Sqlite.php b/kirby/src/Database/Sql/Sqlite.php index fcb36b5..c064522 100644 --- a/kirby/src/Database/Sql/Sqlite.php +++ b/kirby/src/Database/Sql/Sqlite.php @@ -20,6 +20,7 @@ class Sqlite extends Sql * the query needs to return rows with a column `name` * * @param string $table Table name + * @return array */ public function columns(string $table): array { @@ -33,6 +34,8 @@ class Sqlite extends Sql * Abstracted column types to simplify table * creation for multiple database drivers * @codeCoverageIgnore + * + * @return array */ public function columnTypes(): array { @@ -42,18 +45,18 @@ class Sqlite extends Sql 'text' => '{{ name }} TEXT {{ null }} {{ default }} {{ unique }}', 'int' => '{{ name }} INTEGER {{ null }} {{ default }} {{ unique }}', 'timestamp' => '{{ name }} INTEGER {{ null }} {{ default }} {{ unique }}', - 'bool' => '{{ name }} INTEGER {{ null }} {{ default }} {{ unique }}', - 'float' => '{{ name }} REAL {{ null }} {{ default }} {{ unique }}', - 'decimal' => '{{ name }} REAL {{ null }} {{ default }} {{ unique }}' + 'bool' => '{{ name }} INTEGER {{ null }} {{ default }} {{ unique }}' ]; } /** * Combines an identifier (table and column) * - * @param bool $values Whether the identifier is going to be - * used for a VALUES clause; only relevant - * for SQLite + * @param $table string + * @param $column string + * @param $values bool Whether the identifier is going to be used for a VALUES clause; + * only relevant for SQLite + * @return string */ public function combineIdentifier(string $table, string $column, bool $values = false): string { @@ -108,6 +111,9 @@ class Sqlite extends Sql /** * Quotes an identifier (table *or* column) + * + * @param $identifier string + * @return string */ public function quoteIdentifier(string $identifier): string { @@ -126,6 +132,8 @@ class Sqlite extends Sql /** * Returns a query to list the tables of the current database; * the query needs to return rows with a column `name` + * + * @return string */ public function tables(): array { diff --git a/kirby/src/Email/Body.php b/kirby/src/Email/Body.php index a25904a..716dfd5 100644 --- a/kirby/src/Email/Body.php +++ b/kirby/src/Email/Body.php @@ -17,55 +17,69 @@ use Kirby\Toolkit\Properties; */ class Body { - protected string|null $html; - protected string|null $text; + use Properties; + + /** + * @var string + */ + protected $html; + + /** + * @var string + */ + protected $text; /** * Email body constructor + * + * @param array $props */ public function __construct(array $props = []) { - $this->html = $props['html'] ?? null; - $this->text = $props['text'] ?? null; - } - - /** - * Creates a new instance while - * merging initial and new properties - * @deprecated 4.0.0 - */ - public function clone(array $props = []): static - { - return new static(array_merge_recursive([ - 'html' => $this->html, - 'text' => $this->text - ], $props)); + $this->setProperties($props); } /** * Returns the HTML content of the email body + * + * @return string */ - public function html(): string + public function html() { return $this->html ?? ''; } /** * Returns the plain text content of the email body + * + * @return string */ - public function text(): string + public function text() { return $this->text ?? ''; } /** - * @since 4.0.0 + * Sets the HTML content for the email body + * + * @param string|null $html + * @return $this */ - public function toArray(): array + protected function setHtml(string $html = null) { - return [ - 'html' => $this->html(), - 'text' => $this->text() - ]; + $this->html = $html; + return $this; + } + + /** + * Sets the plain text content for the email body + * + * @param string|null $text + * @return $this + */ + protected function setText(string $text = null) + { + $this->text = $text; + return $this; } } diff --git a/kirby/src/Email/Email.php b/kirby/src/Email/Email.php index 2f1b15f..5cacbb7 100644 --- a/kirby/src/Email/Email.php +++ b/kirby/src/Email/Email.php @@ -4,7 +4,7 @@ namespace Kirby\Email; use Closure; use Exception; -use Kirby\Exception\InvalidArgumentException; +use Kirby\Toolkit\Properties; use Kirby\Toolkit\V; /** @@ -19,60 +19,98 @@ use Kirby\Toolkit\V; */ class Email { + use Properties; + /** * If set to `true`, the debug mode is enabled * for all emails + * + * @var bool */ - public static bool $debug = false; + public static $debug = false; /** * Store for sent emails when `Email::$debug` * is set to `true` + * + * @var array */ - public static array $emails = []; + public static $emails = []; - protected bool $isSent = false; + /** + * @var array|null + */ + protected $attachments; - protected array $attachments; - protected Body $body; - protected array $bcc; - protected Closure|null $beforeSend; - protected array $cc; - protected string $from; - protected string|null $fromName; - protected string $replyTo; - protected string|null $replyToName; - protected string $subject; - protected array $to; - protected array|null $transport; + /** + * @var \Kirby\Email\Body|null + */ + protected $body; + + /** + * @var array|null + */ + protected $bcc; + + /** + * @var \Closure|null + */ + protected $beforeSend; + + /** + * @var array|null + */ + protected $cc; + + /** + * @var string|null + */ + protected $from; + + /** + * @var string|null + */ + protected $fromName; + + /** + * @var string|null + */ + protected $replyTo; + + /** + * @var string|null + */ + protected $replyToName; + + /** + * @var bool + */ + protected $isSent = false; + + /** + * @var string|null + */ + protected $subject; + + /** + * @var array|null + */ + protected $to; + + /** + * @var array|null + */ + protected $transport; /** * Email constructor + * + * @param array $props + * @param bool $debug */ public function __construct(array $props = [], bool $debug = false) { - foreach (['body', 'from', 'to', 'subject'] as $required) { - if (isset($props[$required]) === false) { - throw new InvalidArgumentException('The property "' . $required . '" is required'); - } - } - - if (is_string($props['body']) === true) { - $props['body'] = ['text' => $props['body']]; - } - - $this->attachments = $props['attachments'] ?? []; - $this->bcc = $this->resolveEmail($props['bcc'] ?? null); - $this->beforeSend = $props['beforeSend'] ?? null; - $this->body = new Body($props['body']); - $this->cc = $this->resolveEmail($props['cc'] ?? null); - $this->from = $this->resolveEmail($props['from'], false); - $this->fromName = $props['fromName'] ?? null; - $this->replyTo = $this->resolveEmail($props['replyTo'] ?? null, false); - $this->replyToName = $props['replyToName'] ?? null; - $this->subject = $props['subject']; - $this->to = $this->resolveEmail($props['to']); - $this->transport = $props['transport'] ?? null; + $this->setProperties($props); // @codeCoverageIgnoreStart if (static::$debug === false && $debug === false) { @@ -85,6 +123,8 @@ class Email /** * Returns the email attachments + * + * @return array */ public function attachments(): array { @@ -93,14 +133,18 @@ class Email /** * Returns the email body + * + * @return \Kirby\Email\Body|null */ - public function body(): Body|null + public function body() { return $this->body; } /** * Returns "bcc" recipients + * + * @return array */ public function bcc(): array { @@ -110,45 +154,28 @@ class Email /** * Returns the beforeSend callback closure, * which has access to the PHPMailer instance + * + * @return \Closure|null */ - public function beforeSend(): Closure|null + public function beforeSend(): ?Closure { return $this->beforeSend; } /** * Returns "cc" recipients + * + * @return array */ public function cc(): array { return $this->cc; } - /** - * Creates a new instance while - * merging initial and new properties - * @deprecated 4.0.0 - */ - public function clone(array $props = []): static - { - return new static(array_merge_recursive([ - 'attachments' => $this->attachments, - 'bcc' => $this->bcc, - 'beforeSend' => $this->beforeSend, - 'body' => $this->body->toArray(), - 'cc' => $this->cc, - 'from' => $this->from, - 'fromName' => $this->fromName, - 'replyTo' => $this->replyTo, - 'replyToName' => $this->replyToName, - 'subject' => $this->subject, - 'to' => $this->to, - 'transport' => $this->transport - ], $props)); - } - /** * Returns default transport settings + * + * @return array */ protected function defaultTransport(): array { @@ -159,6 +186,8 @@ class Email /** * Returns the "from" email address + * + * @return string */ public function from(): string { @@ -167,22 +196,28 @@ class Email /** * Returns the "from" name + * + * @return string|null */ - public function fromName(): string|null + public function fromName(): ?string { return $this->fromName; } /** * Checks if the email has an HTML body + * + * @return bool */ - public function isHtml(): bool + public function isHtml() { return empty($this->body()->html()) === false; } /** * Checks if the email has been sent successfully + * + * @return bool */ public function isSent(): bool { @@ -191,6 +226,8 @@ class Email /** * Returns the "reply to" email address + * + * @return string */ public function replyTo(): string { @@ -199,8 +236,10 @@ class Email /** * Returns the "reply to" name + * + * @return string|null */ - public function replyToName(): string|null + public function replyToName(): ?string { return $this->replyToName; } @@ -208,12 +247,13 @@ class Email /** * Converts single or multiple email addresses to a sanitized format * + * @param string|array|null $email + * @param bool $multiple + * @return array|mixed|string * @throws \Exception */ - protected function resolveEmail( - string|array|null $email = null, - bool $multiple = true - ): array|string { + protected function resolveEmail($email = null, bool $multiple = true) + { if ($email === null) { return $multiple === true ? [] : ''; } @@ -244,14 +284,166 @@ class Email /** * Sends the email + * + * @return bool */ public function send(): bool { return $this->isSent = true; } + /** + * Sets the email attachments + * + * @param array|null $attachments + * @return $this + */ + protected function setAttachments($attachments = null) + { + $this->attachments = $attachments ?? []; + return $this; + } + + /** + * Sets the email body + * + * @param string|array $body + * @return $this + */ + protected function setBody($body) + { + if (is_string($body) === true) { + $body = ['text' => $body]; + } + + $this->body = new Body($body); + return $this; + } + + /** + * Sets "bcc" recipients + * + * @param string|array|null $bcc + * @return $this + */ + protected function setBcc($bcc = null) + { + $this->bcc = $this->resolveEmail($bcc); + return $this; + } + + /** + * Sets the "beforeSend" callback + * + * @param \Closure|null $beforeSend + * @return $this + */ + protected function setBeforeSend(?Closure $beforeSend = null) + { + $this->beforeSend = $beforeSend; + return $this; + } + + /** + * Sets "cc" recipients + * + * @param string|array|null $cc + * @return $this + */ + protected function setCc($cc = null) + { + $this->cc = $this->resolveEmail($cc); + return $this; + } + + /** + * Sets the "from" email address + * + * @param string $from + * @return $this + */ + protected function setFrom(string $from) + { + $this->from = $this->resolveEmail($from, false); + return $this; + } + + /** + * Sets the "from" name + * + * @param string|null $fromName + * @return $this + */ + protected function setFromName(string $fromName = null) + { + $this->fromName = $fromName; + return $this; + } + + /** + * Sets the "reply to" email address + * + * @param string|null $replyTo + * @return $this + */ + protected function setReplyTo(string $replyTo = null) + { + $this->replyTo = $this->resolveEmail($replyTo, false); + return $this; + } + + /** + * Sets the "reply to" name + * + * @param string|null $replyToName + * @return $this + */ + protected function setReplyToName(string $replyToName = null) + { + $this->replyToName = $replyToName; + return $this; + } + + /** + * Sets the email subject + * + * @param string $subject + * @return $this + */ + protected function setSubject(string $subject) + { + $this->subject = $subject; + return $this; + } + + /** + * Sets the recipients of the email + * + * @param string|array $to + * @return $this + */ + protected function setTo($to) + { + $this->to = $this->resolveEmail($to); + return $this; + } + + /** + * Sets the email transport settings + * + * @param array|null $transport + * @return $this + */ + protected function setTransport($transport = null) + { + $this->transport = $transport; + return $this; + } + /** * Returns the email subject + * + * @return string */ public function subject(): string { @@ -260,6 +452,8 @@ class Email /** * Returns the email recipients + * + * @return array */ public function to(): array { @@ -268,29 +462,11 @@ class Email /** * Returns the email transports settings + * + * @return array */ public function transport(): array { return $this->transport ?? $this->defaultTransport(); } - - /** - * @since 4.0.0 - */ - public function toArray(): array - { - return [ - 'attachments' => $this->attachments(), - 'bcc' => $this->bcc(), - 'body' => $this->body()->toArray(), - 'cc' => $this->cc(), - 'from' => $this->from(), - 'fromName' => $this->fromName(), - 'replyTo' => $this->replyTo(), - 'replyToName' => $this->replyToName(), - 'subject' => $this->subject(), - 'to' => $this->to(), - 'transport' => $this->transport() - ]; - } } diff --git a/kirby/src/Email/PHPMailer.php b/kirby/src/Email/PHPMailer.php index ee84a40..17f89cf 100644 --- a/kirby/src/Email/PHPMailer.php +++ b/kirby/src/Email/PHPMailer.php @@ -2,7 +2,6 @@ namespace Kirby\Email; -use Closure; use Kirby\Exception\InvalidArgumentException; use PHPMailer\PHPMailer\PHPMailer as Mailer; @@ -21,6 +20,8 @@ class PHPMailer extends Email /** * Sends email via PHPMailer library * + * @param bool $debug + * @return bool * @throws \Kirby\Exception\InvalidArgumentException */ public function send(bool $debug = false): bool @@ -95,10 +96,10 @@ class PHPMailer extends Email // accessible phpMailer instance $beforeSend = $this->beforeSend(); - if ($beforeSend instanceof Closure) { + if (empty($beforeSend) === false && is_a($beforeSend, 'Closure') === true) { $mailer = $beforeSend->call($this, $mailer) ?? $mailer; - if ($mailer instanceof Mailer === false) { + if (is_a($mailer, 'PHPMailer\PHPMailer\PHPMailer') === false) { throw new InvalidArgumentException('"beforeSend" option return should be instance of PHPMailer\PHPMailer\PHPMailer class'); } } diff --git a/kirby/src/Exception/AuthException.php b/kirby/src/Exception/AuthException.php deleted file mode 100644 index 1ea6203..0000000 --- a/kirby/src/Exception/AuthException.php +++ /dev/null @@ -1,21 +0,0 @@ - - * @link https://getkirby.com - * @copyright Bastian Allgeier - * @license https://opensource.org/licenses/MIT - */ -class AuthException extends Exception -{ - protected static string $defaultKey = 'auth'; - protected static string $defaultFallback = 'Unauthenticated'; - protected static int $defaultHttpCode = 401; -} diff --git a/kirby/src/Exception/BadMethodCallException.php b/kirby/src/Exception/BadMethodCallException.php index f8a1d1b..68c1f05 100644 --- a/kirby/src/Exception/BadMethodCallException.php +++ b/kirby/src/Exception/BadMethodCallException.php @@ -14,8 +14,8 @@ namespace Kirby\Exception; */ class BadMethodCallException extends Exception { - protected static string $defaultKey = 'invalidMethod'; - protected static string $defaultFallback = 'The method "{ method }" does not exist'; - protected static int $defaultHttpCode = 400; - protected static array $defaultData = ['method' => null]; + protected static $defaultKey = 'invalidMethod'; + protected static $defaultFallback = 'The method "{ method }" does not exist'; + protected static $defaultHttpCode = 400; + protected static $defaultData = ['method' => null]; } diff --git a/kirby/src/Exception/DuplicateException.php b/kirby/src/Exception/DuplicateException.php index 1bea2bf..74bc859 100644 --- a/kirby/src/Exception/DuplicateException.php +++ b/kirby/src/Exception/DuplicateException.php @@ -15,7 +15,7 @@ namespace Kirby\Exception; */ class DuplicateException extends Exception { - protected static string $defaultKey = 'duplicate'; - protected static string $defaultFallback = 'The entry exists'; - protected static int $defaultHttpCode = 400; + protected static $defaultKey = 'duplicate'; + protected static $defaultFallback = 'The entry exists'; + protected static $defaultHttpCode = 400; } diff --git a/kirby/src/Exception/ErrorPageException.php b/kirby/src/Exception/ErrorPageException.php index bd26c6f..7e9ed69 100644 --- a/kirby/src/Exception/ErrorPageException.php +++ b/kirby/src/Exception/ErrorPageException.php @@ -15,7 +15,7 @@ namespace Kirby\Exception; */ class ErrorPageException extends Exception { - protected static string $defaultKey = 'errorPage'; - protected static string $defaultFallback = 'Triggered error page'; - protected static int $defaultHttpCode = 404; + protected static $defaultKey = 'errorPage'; + protected static $defaultFallback = 'Triggered error page'; + protected static $defaultHttpCode = 404; } diff --git a/kirby/src/Exception/Exception.php b/kirby/src/Exception/Exception.php index ae16686..d3a0ba9 100644 --- a/kirby/src/Exception/Exception.php +++ b/kirby/src/Exception/Exception.php @@ -2,7 +2,6 @@ namespace Kirby\Exception; -use Kirby\Cms\App; use Kirby\Http\Environment; use Kirby\Toolkit\I18n; use Kirby\Toolkit\Str; @@ -22,39 +21,48 @@ class Exception extends \Exception { /** * Data variables that can be used inside the exception message + * + * @var array */ - protected array $data; + protected $data; /** * HTTP code that corresponds with the exception + * + * @var int */ - protected int $httpCode; + protected $httpCode; /** * Additional details that are not included in the exception message + * + * @var array */ - protected array $details; + protected $details; /** - * Whether the exception message could be translated - * into the user's language + * Whether the exception message could be translated into the user's language + * + * @var bool */ - protected bool $isTranslated = true; + protected $isTranslated = true; /** * Defaults that can be overridden by specific * exception classes */ - protected static string $defaultKey = 'general'; - protected static string $defaultFallback = 'An error occurred'; - protected static array $defaultData = []; - protected static int $defaultHttpCode = 500; - protected static array $defaultDetails = []; + protected static $defaultKey = 'general'; + protected static $defaultFallback = 'An error occurred'; + protected static $defaultData = []; + protected static $defaultHttpCode = 500; + protected static $defaultDetails = []; /** * Prefix for the exception key (e.g. 'error.general') + * + * @var string */ - private static string $prefix = 'error'; + private static $prefix = 'error'; /** * Class constructor @@ -63,7 +71,7 @@ class Exception extends \Exception * 'data', 'httpCode', 'details' and 'previous') or * just the message string */ - public function __construct(array|string $args = []) + public function __construct($args = []) { // set data and httpCode from provided arguments or defaults $this->data = $args['data'] ?? static::$defaultData; @@ -71,25 +79,19 @@ class Exception extends \Exception $this->details = $args['details'] ?? static::$defaultDetails; // define the Exception key - $key = $args['key'] ?? static::$defaultKey; - - if (Str::startsWith($key, self::$prefix . '.') === false) { - $key = self::$prefix . '.' . $key; - } + $key = self::$prefix . '.' . ($args['key'] ?? static::$defaultKey); if (is_string($args) === true) { $this->isTranslated = false; parent::__construct($args); } else { // define whether message can/should be translated - $translate = - ($args['translate'] ?? true) === true && - class_exists(App::class) === true; + $translate = ($args['translate'] ?? true) === true && class_exists('Kirby\Cms\App') === true; // fallback waterfall for message string $message = null; - if ($translate === true) { + if ($translate) { // 1. translation for provided key in current language // 2. translation for provided key in default language if (isset($args['key']) === true) { @@ -104,7 +106,7 @@ class Exception extends \Exception $this->isTranslated = false; } - if ($translate === true) { + if ($translate) { // 4. translation for default key in current language // 5. translation for default key in default language if ($message === null) { @@ -120,7 +122,11 @@ class Exception extends \Exception } // format message with passed data - $message = Str::template($message, $this->data, ['fallback' => '-']); + $message = Str::template($message, $this->data, [ + 'fallback' => '-', + 'start' => '{', + 'end' => '}' + ]); // handover to Exception parent class constructor parent::__construct($message, 0, $args['previous'] ?? null); @@ -133,6 +139,8 @@ class Exception extends \Exception /** * Returns the file in which the Exception was created * relative to the document root + * + * @return string */ final public function getFileRelative(): string { @@ -148,6 +156,8 @@ class Exception extends \Exception /** * Returns the data variables from the message + * + * @return array */ final public function getData(): array { @@ -157,6 +167,8 @@ class Exception extends \Exception /** * Returns the additional details that are * not included in the message + * + * @return array */ final public function getDetails(): array { @@ -165,6 +177,8 @@ class Exception extends \Exception /** * Returns the exception key (error type) + * + * @return string */ final public function getKey(): string { @@ -174,6 +188,8 @@ class Exception extends \Exception /** * Returns the HTTP code that corresponds * with the exception + * + * @return array */ final public function getHttpCode(): int { @@ -183,6 +199,8 @@ class Exception extends \Exception /** * Returns whether the exception message could * be translated into the user's language + * + * @return bool */ final public function isTranslated(): bool { @@ -191,6 +209,8 @@ class Exception extends \Exception /** * Converts the object to an array + * + * @return array */ public function toArray(): array { diff --git a/kirby/src/Exception/InvalidArgumentException.php b/kirby/src/Exception/InvalidArgumentException.php index 25603b7..d6cef17 100644 --- a/kirby/src/Exception/InvalidArgumentException.php +++ b/kirby/src/Exception/InvalidArgumentException.php @@ -14,8 +14,8 @@ namespace Kirby\Exception; */ class InvalidArgumentException extends Exception { - protected static string $defaultKey = 'invalidArgument'; - protected static string $defaultFallback = 'Invalid argument "{ argument }" in method "{ method }"'; - protected static int $defaultHttpCode = 400; - protected static array $defaultData = ['argument' => null, 'method' => null]; + protected static $defaultKey = 'invalidArgument'; + protected static $defaultFallback = 'Invalid argument "{ argument }" in method "{ method }"'; + protected static $defaultHttpCode = 400; + protected static $defaultData = ['argument' => null, 'method' => null]; } diff --git a/kirby/src/Exception/LogicException.php b/kirby/src/Exception/LogicException.php index 8fac228..d1fbc55 100644 --- a/kirby/src/Exception/LogicException.php +++ b/kirby/src/Exception/LogicException.php @@ -14,7 +14,7 @@ namespace Kirby\Exception; */ class LogicException extends Exception { - protected static string $defaultKey = 'logic'; - protected static string $defaultFallback = 'This task cannot be finished'; - protected static int $defaultHttpCode = 400; + protected static $defaultKey = 'logic'; + protected static $defaultFallback = 'This task cannot be finished'; + protected static $defaultHttpCode = 400; } diff --git a/kirby/src/Exception/NotFoundException.php b/kirby/src/Exception/NotFoundException.php index 5c7e284..1f48c4b 100644 --- a/kirby/src/Exception/NotFoundException.php +++ b/kirby/src/Exception/NotFoundException.php @@ -14,7 +14,7 @@ namespace Kirby\Exception; */ class NotFoundException extends Exception { - protected static string $defaultKey = 'notFound'; - protected static string $defaultFallback = 'Not found'; - protected static int $defaultHttpCode = 404; + protected static $defaultKey = 'notFound'; + protected static $defaultFallback = 'Not found'; + protected static $defaultHttpCode = 404; } diff --git a/kirby/src/Exception/PermissionException.php b/kirby/src/Exception/PermissionException.php index ae82a66..4863f66 100644 --- a/kirby/src/Exception/PermissionException.php +++ b/kirby/src/Exception/PermissionException.php @@ -15,7 +15,7 @@ namespace Kirby\Exception; */ class PermissionException extends Exception { - protected static string $defaultKey = 'permission'; - protected static string $defaultFallback = 'You are not allowed to do this'; - protected static int $defaultHttpCode = 403; + protected static $defaultKey = 'permission'; + protected static $defaultFallback = 'You are not allowed to do this'; + protected static $defaultHttpCode = 403; } diff --git a/kirby/src/Field/FieldOptions.php b/kirby/src/Field/FieldOptions.php deleted file mode 100644 index fb98070..0000000 --- a/kirby/src/Field/FieldOptions.php +++ /dev/null @@ -1,108 +0,0 @@ - - * @link https://getkirby.com - * @copyright Bastian Allgeier - * @license https://opensource.org/licenses/MIT - */ -class FieldOptions extends Node -{ - public function __construct( - /** - * The option source, either a fixed collection or - * a dynamic provider - */ - public Options|OptionsProvider|null $options = null, - - /** - * Whether to escape special HTML characters in - * the option text for safe output in the Panel; - * only set to `false` if the text is later escaped! - */ - public bool $safeMode = true - ) { - } - - public function defaults(): static - { - $this->options ??= new Options(); - - return parent::defaults(); - } - - public static function factory(array $props, bool $safeMode = true): static - { - $options = match ($props['type']) { - 'api' => OptionsApi::factory($props), - 'query' => OptionsQuery::factory($props), - default => Options::factory($props['options'] ?? []) - }; - - return new static($options, $safeMode); - } - - public static function polyfill(array $props = []): array - { - if (is_string($props['options'] ?? null) === true) { - $props['options'] = match ($props['options']) { - 'api' => - ['type' => 'api'] + - OptionsApi::polyfill($props['api'] ?? null), - - 'query' => - ['type' => 'query'] + - OptionsQuery::polyfill($props['query'] ?? null), - - default => - [ 'type' => 'query', 'query' => $props['options']] - }; - } - - unset($props['api'], $props['query']); - - if (($props['options']['type'] ?? null) !== null) { - return $props; - } - - if (($props['options'] ?? null) !== null) { - $props['options'] = [ - 'type' => 'array', - 'options' => $props['options'] - ]; - } - - return $props; - } - - public function resolve(ModelWithContent $model): Options - { - // apply default values - $this->defaults(); - - // already Options, return - if (is_a($this->options, Options::class) === true) { - return $this->options; - } - - // resolve OptionsProvider (OptionsApi or OptionsQuery) to Options - return $this->options = $this->options->resolve($model, $this->safeMode); - } - - public function render(ModelWithContent $model): array - { - return $this->resolve($model)->render($model); - } -} diff --git a/kirby/src/Filesystem/Asset.php b/kirby/src/Filesystem/Asset.php index 021d6c8..cd6488b 100644 --- a/kirby/src/Filesystem/Asset.php +++ b/kirby/src/Filesystem/Asset.php @@ -3,8 +3,6 @@ namespace Kirby\Filesystem; use Kirby\Cms\FileModifications; -use Kirby\Cms\HasMethods; -use Kirby\Exception\BadMethodCallException; /** * Anything in your public path can be converted @@ -22,53 +20,32 @@ class Asset { use IsFile; use FileModifications; - use HasMethods; /** * Relative file path + * + * @var string */ - protected string|null $path; - + protected $path; /** * Creates a new Asset object for the given path. + * + * @param string $path */ public function __construct(string $path) { - $this->root = $this->kirby()->root('index') . '/' . $path; - $this->url = $this->kirby()->url('base') . '/' . $path; - - $path = dirname($path); - $this->path = $path === '.' ? '' : $path; - } - - /** - * Magic caller for asset methods - * - * @throws \Kirby\Exception\BadMethodCallException - */ - public function __call(string $method, array $arguments = []): mixed - { - // public property access - if (isset($this->$method) === true) { - return $this->$method; - } - - // asset method proxy - if (method_exists($this->asset(), $method)) { - return $this->asset()->$method(...$arguments); - } - - // asset methods - if ($this->hasMethod($method)) { - return $this->callMethod($method, $arguments); - } - - throw new BadMethodCallException('The method: "' . $method . '" does not exist'); + $this->setProperties([ + 'path' => dirname($path), + 'root' => $this->kirby()->root('index') . '/' . $path, + 'url' => $this->kirby()->url('base') . '/' . $path + ]); } /** * Returns a unique id for the asset + * + * @return string */ public function id(): string { @@ -77,6 +54,8 @@ class Asset /** * Create a unique media hash + * + * @return string */ public function mediaHash(): string { @@ -85,6 +64,8 @@ class Asset /** * Returns the relative path starting at the media folder + * + * @return string */ public function mediaPath(): string { @@ -93,6 +74,8 @@ class Asset /** * Returns the absolute path to the file in the public media folder + * + * @return string */ public function mediaRoot(): string { @@ -101,6 +84,8 @@ class Asset /** * Returns the absolute Url to the file in the public media folder + * + * @return string */ public function mediaUrl(): string { @@ -110,9 +95,23 @@ class Asset /** * Returns the path of the file from the web root, * excluding the filename + * + * @return string */ public function path(): string { return $this->path; } + + /** + * Setter for the path + * + * @param string $path + * @return $this + */ + protected function setPath(string $path) + { + $this->path = $path === '.' ? '' : $path; + return $this; + } } diff --git a/kirby/src/Filesystem/Dir.php b/kirby/src/Filesystem/Dir.php index 680789b..8207efc 100644 --- a/kirby/src/Filesystem/Dir.php +++ b/kirby/src/Filesystem/Dir.php @@ -4,7 +4,6 @@ namespace Kirby\Filesystem; use Exception; use Kirby\Cms\App; -use Kirby\Cms\Helpers; use Kirby\Cms\Page; use Kirby\Toolkit\Str; use Throwable; @@ -31,8 +30,10 @@ class Dir { /** * Ignore when scanning directories + * + * @var array */ - public static array $ignore = [ + public static $ignore = [ '.', '..', '.DS_Store', @@ -44,21 +45,19 @@ class Dir '@eaDir' ]; - public static string $numSeparator = '_'; + public static $numSeparator = '_'; /** * Copy the directory to a new destination * - * @param array|false $ignore List of full paths to skip during copying - * or `false` to copy all files, including - * those listed in `Dir::$ignore` + * @param string $dir + * @param string $target + * @param bool $recursive + * @param array $ignore + * @return bool */ - public static function copy( - string $dir, - string $target, - bool $recursive = true, - array|false $ignore = [] - ): bool { + public static function copy(string $dir, string $target, bool $recursive = true, array $ignore = []): bool + { if (is_dir($dir) === false) { throw new Exception('The directory "' . $dir . '" does not exist'); } @@ -71,13 +70,10 @@ class Dir throw new Exception('The target directory "' . $target . '" could not be created'); } - foreach (static::read($dir, $ignore === false ? [] : null) as $name) { + foreach (static::read($dir) as $name) { $root = $dir . '/' . $name; - if ( - is_array($ignore) === true && - in_array($root, $ignore) === true - ) { + if (in_array($root, $ignore) === true) { continue; } @@ -95,14 +91,15 @@ class Dir /** * Get all subdirectories + * + * @param string $dir + * @param array $ignore + * @param bool $absolute + * @return array */ - public static function dirs( - string $dir, - array|null $ignore = null, - bool $absolute = false - ): array { - $scan = static::read($dir, $ignore, true); - $result = array_values(array_filter($scan, 'is_dir')); + public static function dirs(string $dir, array $ignore = null, bool $absolute = false): array + { + $result = array_values(array_filter(static::read($dir, $ignore, true), 'is_dir')); if ($absolute !== true) { $result = array_map('basename', $result); @@ -113,6 +110,9 @@ class Dir /** * Checks if the directory exists on disk + * + * @param string $dir + * @return bool */ public static function exists(string $dir): bool { @@ -121,14 +121,15 @@ class Dir /** * Get all files + * + * @param string $dir + * @param array $ignore + * @param bool $absolute + * @return array */ - public static function files( - string $dir, - array|null $ignore = null, - bool $absolute = false - ): array { - $scan = static::read($dir, $ignore, true); - $result = array_values(array_filter($scan, 'is_file')); + public static function files(string $dir, array $ignore = null, bool $absolute = false): array + { + $result = array_values(array_filter(static::read($dir, $ignore, true), 'is_file')); if ($absolute !== true) { $result = array_map('basename', $result); @@ -140,39 +141,25 @@ class Dir /** * Read the directory and all subdirectories * - * @todo Remove support for `$ignore = null` in a major release - * @param array|false|null $ignore Array of absolut file paths; - * `false` to disable `Dir::$ignore` list - * (passing null is deprecated) + * @param string $dir + * @param bool $recursive + * @param array $ignore + * @param string $path + * @return array */ - public static function index( - string $dir, - bool $recursive = false, - array|false|null $ignore = [], - string $path = null - ): array { + public static function index(string $dir, bool $recursive = false, array $ignore = null, string $path = null) + { $result = []; $dir = realpath($dir); - $items = static::read($dir, $ignore === false ? [] : null); + $items = static::read($dir); foreach ($items as $item) { - $root = $dir . '/' . $item; - - if ( - is_array($ignore) === true && - in_array($root, $ignore) === true - ) { - continue; - } - + $root = $dir . '/' . $item; $entry = $path !== null ? $path . '/' . $item : $item; $result[] = $entry; if ($recursive === true && is_dir($root) === true) { - $result = [ - ...$result, - ...static::index($root, true, $ignore, $entry) - ]; + $result = array_merge($result, static::index($root, true, $ignore, $entry)); } } @@ -181,6 +168,9 @@ class Dir /** * Checks if the folder has any contents + * + * @param string $dir + * @return bool */ public static function isEmpty(string $dir): bool { @@ -189,6 +179,9 @@ class Dir /** * Checks if the directory is readable + * + * @param string $dir + * @return bool */ public static function isReadable(string $dir): bool { @@ -197,6 +190,9 @@ class Dir /** * Checks if the directory is writable + * + * @param string $dir + * @return bool */ public static function isWritable(string $dir): bool { @@ -213,156 +209,163 @@ class Dir * Don't use outside the Cms context. * * @internal + * + * @param string $dir + * @param string $contentExtension + * @param array|null $contentIgnore + * @param bool $multilang + * @return array */ - public static function inventory( - string $dir, - string $contentExtension = 'txt', - array|null $contentIgnore = null, - bool $multilang = false - ): array { + public static function inventory(string $dir, string $contentExtension = 'txt', array $contentIgnore = null, bool $multilang = false): array + { + $dir = realpath($dir); + $inventory = [ 'children' => [], 'files' => [], 'template' => 'default', ]; - $dir = realpath($dir); - if ($dir === false) { return $inventory; } + $items = static::read($dir, $contentIgnore); + // a temporary store for all content files $content = []; - // read and sort all items naturally to avoid sorting issues later - $items = static::read($dir, $contentIgnore); + // sort all items naturally to avoid sorting issues later natsort($items); - // loop through all directory items and collect all relevant information foreach ($items as $item) { - // ignore all items with a leading dot or underscore + // ignore all items with a leading dot if (in_array(substr($item, 0, 1), ['.', '_']) === true) { continue; } $root = $dir . '/' . $item; - // collect all directories as children if (is_dir($root) === true) { - $inventory['children'][] = static::inventoryChild( - $item, - $root, - $contentExtension, - $multilang - ); - continue; - } - - $extension = pathinfo($item, PATHINFO_EXTENSION); - - // don't track files with these extensions - if (in_array($extension, ['htm', 'html', 'php']) === true) { - continue; - } - - // collect all content files separately, - // not as inventory entries - if ($extension === $contentExtension) { - $filename = pathinfo($item, PATHINFO_FILENAME); - - // remove the language codes from all content filenames - if ($multilang === true) { - $filename = pathinfo($filename, PATHINFO_FILENAME); + // extract the slug and num of the directory + if (preg_match('/^([0-9]+)' . static::$numSeparator . '(.*)$/', $item, $match)) { + $num = (int)$match[1]; + $slug = $match[2]; + } else { + $num = null; + $slug = $item; } - $content[] = $filename; - continue; - } + $inventory['children'][] = [ + 'dirname' => $item, + 'model' => null, + 'num' => $num, + 'root' => $root, + 'slug' => $slug, + ]; + } else { + $extension = pathinfo($item, PATHINFO_EXTENSION); - // collect all other files - $inventory['files'][$item] = [ - 'filename' => $item, - 'extension' => $extension, - 'root' => $root, - ]; + switch ($extension) { + case 'htm': + case 'html': + case 'php': + // don't track those files + break; + case $contentExtension: + $content[] = pathinfo($item, PATHINFO_FILENAME); + break; + default: + $inventory['files'][$item] = [ + 'filename' => $item, + 'extension' => $extension, + 'root' => $root, + ]; + } + } } - $content = array_unique($content); + // remove the language codes from all content filenames + if ($multilang === true) { + foreach ($content as $key => $filename) { + $content[$key] = pathinfo($filename, PATHINFO_FILENAME); + } - $inventory['template'] = static::inventoryTemplate( - $content, - $inventory['files'] - ); + $content = array_unique($content); + } + + $inventory = static::inventoryContent($inventory, $content); + $inventory = static::inventoryModels($inventory, $contentExtension, $multilang); return $inventory; } /** - * Collect information for a child for the inventory + * Take all content files, + * remove those who are meta files and + * detect the main content file + * + * @param array $inventory + * @param array $content + * @return array */ - protected static function inventoryChild( - string $item, - string $root, - string $contentExtension = 'txt', - bool $multilang = false - ): array { - // extract the slug and num of the directory - if ($separator = strpos($item, static::$numSeparator)) { - $num = (int)substr($item, 0, $separator); - $slug = substr($item, $separator + 1); + protected static function inventoryContent(array $inventory, array $content): array + { + // filter meta files from the content file + if (empty($content) === true) { + $inventory['template'] = 'default'; + return $inventory; } - // determine the model - if (empty(Page::$models) === false) { - if ($multilang === true) { - $code = App::instance()->defaultLanguage()->code(); - $contentExtension = $code . '.' . $contentExtension; - } - - // look if a content file can be found - // for any of the available models - foreach (Page::$models as $modelName => $modelClass) { - if (is_file($root . '/' . $modelName . '.' . $contentExtension) === true) { - $model = $modelName; - break; - } - } - } - - return [ - 'dirname' => $item, - 'model' => $model ?? null, - 'num' => $num ?? null, - 'root' => $root, - 'slug' => $slug ?? $item, - ]; - } - - /** - * Determines the main template for the inventory - * from all collected content files, ignore file meta files - */ - protected static function inventoryTemplate( - array $content, - array $files, - ): string { - foreach ($content as $name) { - // is a meta file corresponding to an actual file, i.e. cover.jpg - if (isset($files[$name]) === true) { + foreach ($content as $contentName) { + // could be a meta file. i.e. cover.jpg + if (isset($inventory['files'][$contentName]) === true) { continue; } // it's most likely the template - // (will overwrite and use the last match for historic reasons) - $template = $name; + $inventory['template'] = $contentName; } - return $template ?? 'default'; + return $inventory; + } + + /** + * Go through all inventory children + * and inject a model for each + * + * @param array $inventory + * @param string $contentExtension + * @param bool $multilang + * @return array + */ + protected static function inventoryModels(array $inventory, string $contentExtension, bool $multilang = false): array + { + // inject models + if (empty($inventory['children']) === false && empty(Page::$models) === false) { + if ($multilang === true) { + $contentExtension = App::instance()->defaultLanguage()->code() . '.' . $contentExtension; + } + + foreach ($inventory['children'] as $key => $child) { + foreach (Page::$models as $modelName => $modelClass) { + if (file_exists($child['root'] . '/' . $modelName . '.' . $contentExtension) === true) { + $inventory['children'][$key]['model'] = $modelName; + break; + } + } + } + } + + return $inventory; } /** * Create a (symbolic) link to a directory + * + * @param string $source + * @param string $link + * @return bool */ public static function link(string $source, string $link): bool { @@ -378,7 +381,7 @@ class Dir try { return symlink($source, $link) === true; - } catch (Throwable) { + } catch (Throwable $e) { return false; } } @@ -407,21 +410,17 @@ class Dir $parent = dirname($dir); - if ($recursive === true && is_dir($parent) === false) { - static::make($parent, true); + if ($recursive === true) { + if (is_dir($parent) === false) { + static::make($parent, true); + } } if (is_writable($parent) === false) { throw new Exception(sprintf('The directory "%s" cannot be created', $dir)); } - return Helpers::handleErrors( - fn (): bool => mkdir($dir), - // if the dir was already created (race condition), - fn (int $errno, string $errstr): bool => Str::endsWith($errstr, 'File exists'), - // consider it a success - true - ); + return mkdir($dir); } /** @@ -429,22 +428,22 @@ class Dir * subfolders have been modified for the last time. * * @param string $dir The path of the directory - * @param 'date'|'intl'|'strftime'|null $handler Custom date handler or `null` - * for the globally configured one + * @param string $format + * @param string $handler + * @return int|string */ - public static function modified( - string $dir, - string $format = null, - string|null $handler = null - ): int|string { + public static function modified(string $dir, string $format = null, string $handler = 'date') + { $modified = filemtime($dir); $items = static::read($dir); foreach ($items as $item) { - $newModified = match (is_file($dir . '/' . $item)) { - true => filemtime($dir . '/' . $item), - false => static::modified($dir . '/' . $item) - }; + if (is_file($dir . '/' . $item) === true) { + $newModified = filemtime($dir . '/' . $item); + } else { + $newModified = static::modified($dir . '/' . $item); + } + $modified = ($newModified > $modified) ? $newModified : $modified; } @@ -479,14 +478,13 @@ class Dir * Returns a nicely formatted size of all the contents of the folder * * @param string $dir The path of the directory - * @param string|false|null $locale Locale for number formatting, + * @param string|null|false $locale Locale for number formatting, * `null` for the current locale, * `false` to disable number formatting + * @return mixed */ - public static function niceSize( - string $dir, - string|false|null $locale = null - ): string { + public static function niceSize(string $dir, $locale = null) + { return F::niceSize(static::size($dir), $locale); } @@ -499,11 +497,8 @@ class Dir * @param bool $absolute If true, the full path for each item will be returned * @return array An array of filenames */ - public static function read( - string $dir, - array|null $ignore = null, - bool $absolute = false - ): array { + public static function read(string $dir, array $ignore = null, bool $absolute = false): array + { if (is_dir($dir) === false) { return []; } @@ -525,6 +520,9 @@ class Dir /** * Removes a folder including all containing files and folders + * + * @param string $dir + * @return bool */ public static function remove(string $dir): bool { @@ -560,8 +558,9 @@ class Dir * * @param string $dir The path of the directory * @param bool $recursive Include all subfolders and their files + * @return mixed */ - public static function size(string $dir, bool $recursive = true): int|false + public static function size(string $dir, bool $recursive = true) { if (is_dir($dir) === false) { return false; @@ -583,6 +582,10 @@ class Dir /** * Checks if the directory or any subdirectory has been * modified after the given timestamp + * + * @param string $dir + * @param int $time + * @return bool */ public static function wasModifiedAfter(string $dir, int $time): bool { @@ -599,10 +602,7 @@ class Dir return true; } - if ( - is_dir($subdir) === true && - static::wasModifiedAfter($subdir, $time) === true - ) { + if (is_dir($subdir) === true && static::wasModifiedAfter($subdir, $time) === true) { return true; } } diff --git a/kirby/src/Filesystem/F.php b/kirby/src/Filesystem/F.php index 2f7e6e6..5481242 100644 --- a/kirby/src/Filesystem/F.php +++ b/kirby/src/Filesystem/F.php @@ -3,9 +3,7 @@ namespace Kirby\Filesystem; use Exception; -use IntlDateFormatter; use Kirby\Cms\Helpers; -use Kirby\Http\Response; use Kirby\Toolkit\I18n; use Kirby\Toolkit\Str; use Throwable; @@ -25,7 +23,10 @@ use ZipArchive; */ class F { - public static array $types = [ + /** + * @var array + */ + public static $types = [ 'archive' => [ 'gz', 'gzip', @@ -110,23 +111,17 @@ class F ], ]; - public static array $units = [ - 'B', - 'KB', - 'MB', - 'GB', - 'TB', - 'PB', - 'EB', - 'ZB', - 'YB' - ]; + /** + * @var array + */ + public static $units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']; /** * Appends new content to an existing file * * @param string $file The path for the file * @param mixed $content Either a string or an array. Arrays will be converted to JSON. + * @return bool */ public static function append(string $file, $content): bool { @@ -137,6 +132,7 @@ class F * Returns the file content as base64 encoded string * * @param string $file The path for the file + * @return string */ public static function base64(string $file): string { @@ -145,6 +141,11 @@ class F /** * Copy a file to a new location. + * + * @param string $source + * @param string $target + * @param bool $force + * @return bool */ public static function copy(string $source, string $target, bool $force = false): bool { @@ -173,6 +174,7 @@ class F * * * @param string $file The path + * @return string */ public static function dirname(string $file): string { @@ -181,13 +183,17 @@ class F /** * Checks if the file exists on disk + * + * @param string $file + * @param string $in + * @return bool */ - public static function exists(string $file, string|null $in = null): bool + public static function exists(string $file, string $in = null): bool { try { static::realpath($file, $in); return true; - } catch (Exception) { + } catch (Exception $e) { return false; } } @@ -195,13 +201,12 @@ class F /** * Gets the extension of a file * - * @param string|null $file The filename or path - * @param string|null $extension Set an optional extension to overwrite the current one + * @param string $file The filename or path + * @param string $extension Set an optional extension to overwrite the current one + * @return string */ - public static function extension( - string|null $file = null, - string|null $extension = null - ): string { + public static function extension(string $file = null, string $extension = null): string + { // overwrite the current extension if ($extension !== null) { return static::name($file) . '.' . $extension; @@ -213,16 +218,22 @@ class F /** * Converts a file extension to a mime type + * + * @param string $extension + * @return string|false */ - public static function extensionToMime(string $extension): string|null + public static function extensionToMime(string $extension) { return Mime::fromExtension($extension); } /** * Returns the file type for a passed extension + * + * @param string $extension + * @return string|false */ - public static function extensionToType(string $extension): string|false + public static function extensionToType(string $extension) { foreach (static::$types as $type => $extensions) { if (in_array($extension, $extensions) === true) { @@ -235,8 +246,11 @@ class F /** * Returns all extensions for a certain file type + * + * @param string $type + * @return array */ - public static function extensions(string|null $type = null): array + public static function extensions(string $type = null) { if ($type === null) { return array_keys(Mime::types()); @@ -256,6 +270,7 @@ class F * * * @param string $name The path + * @return string */ public static function filename(string $name): string { @@ -266,17 +281,15 @@ class F * Invalidate opcode cache for file. * * @param string $file The path of the file + * @return bool */ public static function invalidateOpcodeCache(string $file): bool { - if ( - function_exists('opcache_invalidate') && - strlen(ini_get('opcache.restrict_api')) === 0 - ) { + if (function_exists('opcache_invalidate') && strlen(ini_get('opcache.restrict_api')) === 0) { return opcache_invalidate($file, true); + } else { + return false; } - - return false; } /** @@ -284,6 +297,7 @@ class F * * @param string $file Full path to the file * @param string $value An extension or mime type + * @return bool */ public static function is(string $file, string $value): bool { @@ -302,6 +316,9 @@ class F /** * Checks if the file is readable + * + * @param string $file + * @return bool */ public static function isReadable(string $file): bool { @@ -310,6 +327,9 @@ class F /** * Checks if the file is writable + * + * @param string $file + * @return bool */ public static function isWritable(string $file): bool { @@ -322,6 +342,11 @@ class F /** * Create a (symbolic) link to a file + * + * @param string $source + * @param string $link + * @param string $method + * @return bool */ public static function link(string $source, string $link, string $method = 'link'): bool { @@ -337,7 +362,7 @@ class F try { return $method($source, $link) === true; - } catch (Throwable) { + } catch (Throwable $e) { return false; } } @@ -346,14 +371,13 @@ class F * Loads a file and returns the result or `false` if the * file to load does not exist * + * @param string $file + * @param mixed $fallback * @param array $data Optional array of variables to extract in the variable scope + * @return mixed */ - public static function load( - string $file, - mixed $fallback = null, - array $data = [], - bool $allowOutput = true - ) { + public static function load(string $file, $fallback = null, array $data = []) + { if (is_file($file) === false) { return $fallback; } @@ -361,21 +385,9 @@ class F // we use the loadIsolated() method here to prevent the included // file from overwriting our $fallback in this variable scope; see // https://www.php.net/manual/en/function.include.php#example-124 - $callback = fn () => static::loadIsolated($file, $data); + $result = static::loadIsolated($file, $data); - // if the loaded file should not produce any output, - // call the loaidIsolated method from the Response class - // which checks for unintended ouput and throws an error if detected - if ($allowOutput === false) { - $result = Response::guardAgainstOutput($callback); - } else { - $result = $callback(); - } - - if ( - $fallback !== null && - gettype($result) !== gettype($fallback) - ) { + if ($fallback !== null && gettype($result) !== gettype($fallback)) { return $fallback; } @@ -385,35 +397,37 @@ class F /** * A super simple class autoloader * @since 3.7.0 + * + * @param array $classmap + * @param string|null $base + * @return void */ - public static function loadClasses( - array $classmap, - string|null $base = null - ): void { + public static function loadClasses(array $classmap, ?string $base = null): void + { // convert all classnames to lowercase $classmap = array_change_key_case($classmap); - spl_autoload_register( - fn ($class) => Response::guardAgainstOutput(function () use ($class, $classmap, $base) { - $class = strtolower($class); + spl_autoload_register(function ($class) use ($classmap, $base) { + $class = strtolower($class); - if (isset($classmap[$class]) === false) { - return false; - } + if (!isset($classmap[$class])) { + return false; + } - if ($base) { - include $base . '/' . $classmap[$class]; - } else { - include $classmap[$class]; - } - }) - ); + if ($base) { + include $base . '/' . $classmap[$class]; + } else { + include $classmap[$class]; + } + }); } /** * Loads a file with as little as possible in the variable scope * + * @param string $file * @param array $data Optional array of variables to extract in the variable scope + * @return mixed */ protected static function loadIsolated(string $file, array $data = []) { @@ -426,48 +440,50 @@ class F } /** - * Loads a file using `include_once()` and - * returns whether loading was successful + * Loads a file using `include_once()` and returns whether loading was successful + * + * @param string $file + * @return bool */ - public static function loadOnce( - string $file, - bool $allowOutput = true - ): bool { + public static function loadOnce(string $file): bool + { if (is_file($file) === false) { return false; } - $callback = fn () => include_once $file; - - if ($allowOutput === false) { - Response::guardAgainstOutput($callback); - } else { - $callback(); - } - + include_once $file; return true; } /** * Returns the mime type of a file + * + * @param string $file + * @return string|false */ - public static function mime(string $file): string|null + public static function mime(string $file) { return Mime::type($file); } /** * Converts a mime type to a file extension + * + * @param string $mime + * @return string|false */ - public static function mimeToExtension(string|null $mime = null): string|false + public static function mimeToExtension(string $mime = null) { return Mime::toExtension($mime); } /** * Returns the type for a given mime + * + * @param string $mime + * @return string|false */ - public static function mimeToType(string $mime): string|false + public static function mimeToType(string $mime) { return static::extensionToType(Mime::toExtension($mime)); } @@ -475,14 +491,13 @@ class F /** * Get the file's last modification time. * - * @param 'date'|'intl'|'strftime'|null $handler Custom date handler or `null` - * for the globally configured one + * @param string $file + * @param string|\IntlDateFormatter|null $format + * @param string $handler date, intl or strftime + * @return mixed */ - public static function modified( - string $file, - string|IntlDateFormatter|null $format = null, - string|null $handler = null - ): string|int|false { + public static function modified(string $file, $format = null, string $handler = 'date') + { if (file_exists($file) !== true) { return false; } @@ -498,6 +513,7 @@ class F * @param string $oldRoot The current path for the file * @param string $newRoot The path to the new location * @param bool $force Force move if the target file exists + * @return bool */ public static function move(string $oldRoot, string $newRoot, bool $force = false): bool { @@ -515,39 +531,19 @@ class F static::remove($newRoot); } - $directory = dirname($newRoot); - - // create the parent directory if it does not exist - if (is_dir($directory) === false) { - Dir::make($directory, true); + // actually move the file if it exists + if (rename($oldRoot, $newRoot) !== true) { + return false; } - // atomically moving the file will only work if - // source and target are on the same filesystem - if (stat($oldRoot)['dev'] === stat($directory)['dev']) { - // same filesystem, we can move the file - return rename($oldRoot, $newRoot) === true; - } - - // @codeCoverageIgnoreStart - // not the same filesystem; we need to copy - // the file and unlink the source afterwards - if (copy($oldRoot, $newRoot) === true) { - return unlink($oldRoot) === true; - } - - // copying failed, ensure the new root isn't there - // (e.g. if the file could be created but there's no - // more remaining disk space to write its contents) - static::remove($newRoot); - return false; - // @codeCoverageIgnoreEnd + return true; } /** * Extracts the name from a file path or filename without extension * * @param string $name The path or filename + * @return string */ public static function name(string $name): string { @@ -557,15 +553,14 @@ class F /** * Converts an integer size into a human readable format * - * @param int|string|array $size The file size, a file path or array of paths - * @param string|false|null $locale Locale for number formatting, + * @param mixed $size The file size, a file path or array of paths + * @param string|null|false $locale Locale for number formatting, * `null` for the current locale, * `false` to disable number formatting + * @return string */ - public static function niceSize( - int|string|array $size, - string|false|null $locale = null - ): string { + public static function niceSize($size, $locale = null): string + { // file mode if (is_string($size) === true || is_array($size) === true) { $size = static::size($size); @@ -580,7 +575,7 @@ class F } // the math magic - $size = round($size / 1024 ** ($unit = floor(log($size, 1024))), 2); + $size = round($size / pow(1024, ($unit = floor(log($size, 1024)))), 2); // format the number if requested if ($locale !== false) { @@ -595,27 +590,31 @@ class F * contents of a remote HTTP or HTTPS URL * * @param string $file The path for the file or an absolute URL + * @return string|false */ - public static function read(string $file): string|false + public static function read(string $file) { if ( - is_readable($file) !== true && + is_file($file) !== true && Str::startsWith($file, 'https://') !== true && Str::startsWith($file, 'http://') !== true ) { return false; } - return file_get_contents($file); + return @file_get_contents($file); } /** * Changes the name of the file without * touching the extension * + * @param string $file + * @param string $newName * @param bool $overwrite Force overwrite existing files + * @return string|false */ - public static function rename(string $file, string $newName, bool $overwrite = false): string|false + public static function rename(string $file, string $newName, bool $overwrite = false) { // create the new name $name = static::safeName(basename($newName)); @@ -637,8 +636,12 @@ class F /** * Returns the absolute path to the file if the file can be found. + * + * @param string $file + * @param string $in + * @return string|null */ - public static function realpath(string $file, string|null $in = null): string + public static function realpath(string $file, string $in = null) { $realpath = realpath($file); @@ -666,8 +669,12 @@ class F * starting after $in * * @SuppressWarnings(PHPMD.CountInLoopExpression) + * + * @param string $file + * @param string $in + * @return string */ - public static function relativepath(string $file, string|null $in = null): string + public static function relativepath(string $file, string $in = null): string { if (empty($in) === true) { return basename($file); @@ -708,6 +715,7 @@ class F * * * @param string $file The path for the file + * @return bool */ public static function remove(string $file): bool { @@ -728,8 +736,7 @@ class F } /** - * Sanitize a file's full name (filename and extension) - * to strip unwanted special characters + * Sanitize a filename to strip unwanted special characters * * * @@ -739,54 +746,25 @@ class F * * * @param string $string The file name + * @return string */ public static function safeName(string $string): string { - $basename = static::safeBasename($string); - $extension = static::safeExtension($string); + $name = static::name($string); + $extension = static::extension($string); + $safeName = Str::slug($name, '-', 'a-z0-9@._-'); + $safeExtension = empty($extension) === false ? '.' . Str::slug($extension) : ''; - if (empty($extension) === false) { - $extension = '.' . $extension; - } - - return $basename . $extension; - } - - /** - * Sanitize a file's name (without extension) - * @since 4.0.0 - */ - public static function safeBasename( - string $string, - bool $extract = true - ): string { - // extract only the name part from whole filename string - if ($extract === true) { - $string = static::name($string); - } - - return Str::slug($string, '-', 'a-z0-9@._-'); - } - - /** - * Sanitize a file's extension - * @since 4.0.0 - */ - public static function safeExtension( - string $string, - bool $extract = true - ): string { - // extract only the extension part from whole filename string - if ($extract === true) { - $string = static::extension($string); - } - - return Str::slug($string); + return $safeName . $safeExtension; } /** * Tries to find similar or the same file by * building a glob based on the path + * + * @param string $path + * @param string $pattern + * @return array */ public static function similar(string $path, string $pattern = '*'): array { @@ -801,8 +779,9 @@ class F * Returns the size of a file or an array of files. * * @param string|array $file file path or array of paths + * @return int */ - public static function size(string|array $file): int + public static function size($file): int { if (is_array($file) === true) { return array_reduce( @@ -812,19 +791,20 @@ class F ); } - if ($size = @filesize($file)) { - return $size; + try { + return filesize($file); + } catch (Throwable $e) { + return 0; } - - return 0; } /** * Categorize the file * * @param string $file Either the file path or extension + * @return string|null */ - public static function type(string $file): string|null + public static function type(string $file) { $length = strlen($file); @@ -857,8 +837,11 @@ class F /** * Returns all extensions of a given file type * or `null` if the file type is unknown + * + * @param string $type + * @return array|null */ - public static function typeToExtensions(string $type): array|null + public static function typeToExtensions(string $type): ?array { return static::$types[$type] ?? null; } @@ -871,15 +854,28 @@ class F { return Helpers::handleErrors( fn (): bool => unlink($file), - // if the file or link was already deleted (race condition), - fn (int $errno, string $errstr): bool => Str::endsWith($errstr, 'No such file or directory'), - // consider it a success - true + function (&$override, int $errno, string $errstr): bool { + // if the file or link was already deleted (race condition), + // consider it a success + if (Str::endsWith($errstr, 'No such file or directory') === true) { + $override = true; + + // drop the warning + return true; + } + + // handle every other warning normally + return false; + } ); } /** * Unzips a zip file + * + * @param string $file + * @param string $to + * @return bool */ public static function unzip(string $file, string $to): bool { @@ -902,8 +898,9 @@ class F * Returns the file as data uri * * @param string $file The path for the file + * @return string|false */ - public static function uri(string $file): string|false + public static function uri(string $file) { if ($mime = static::mime($file)) { return 'data:' . $mime . ';base64,' . static::base64($file); @@ -918,6 +915,7 @@ class F * @param string $file The path for the new file * @param mixed $content Either a string, an object or an array. Arrays and objects will be serialized. * @param bool $append true: append the content to an existing file if available. false: overwrite. + * @return bool */ public static function write(string $file, $content, bool $append = false): bool { diff --git a/kirby/src/Filesystem/File.php b/kirby/src/Filesystem/File.php index 035c25c..89cffbb 100644 --- a/kirby/src/Filesystem/File.php +++ b/kirby/src/Filesystem/File.php @@ -2,14 +2,13 @@ namespace Kirby\Filesystem; -use IntlDateFormatter; use Kirby\Cms\App; use Kirby\Exception\Exception; -use Kirby\Exception\InvalidArgumentException; use Kirby\Http\Response; use Kirby\Sane\Sane; use Kirby\Toolkit\Escape; use Kirby\Toolkit\Html; +use Kirby\Toolkit\Properties; use Kirby\Toolkit\V; /** @@ -26,26 +25,28 @@ use Kirby\Toolkit\V; */ class File { - /** - * Parent file model - * The model object must use the `\Kirby\Filesystem\IsFile` trait - */ - protected object|null $model; + use Properties; /** * Absolute file path + * + * @var string */ - protected string|null $root; + protected $root; /** * Absolute file URL + * + * @var string|null */ - protected string|null $url; + protected $url; /** * Validation rules to be used for `::match()` + * + * @var array */ - public static array $validations = [ + public static $validations = [ 'maxsize' => ['size', 'max'], 'minsize' => ['size', 'min'] ]; @@ -55,15 +56,12 @@ class File * * @param array|string|null $props Properties or deprecated `$root` string * @param string|null $url Deprecated argument, use `$props['url']` instead - * - * @throws \Kirby\Exception\InvalidArgumentException When the model does not use the `Kirby\Filesystem\IsFile` trait */ - public function __construct( - array|string $props = null, - string $url = null - ) { + public function __construct($props = null, string $url = null) + { // Legacy support for old constructor of // the `Kirby\Image\Image` class + // @todo 4.0.0 remove if (is_array($props) === false) { $props = [ 'root' => $props, @@ -71,21 +69,13 @@ class File ]; } - $this->root = $props['root'] ?? null; - $this->url = $props['url'] ?? null; - $this->model = $props['model'] ?? null; - - if ( - $this->model !== null && - method_exists($this->model, 'hasIsFileTrait') !== true - ) { - throw new InvalidArgumentException('The model object must use the "Kirby\Filesystem\IsFile" trait'); - } + $this->setProperties($props); } /** * Improved `var_dump` output - * @codeCoverageIgnore + * + * @return array */ public function __debugInfo(): array { @@ -94,6 +84,8 @@ class File /** * Returns the URL for the file object + * + * @return string */ public function __toString(): string { @@ -102,6 +94,8 @@ class File /** * Returns the file content as base64 encoded string + * + * @return string */ public function base64(): string { @@ -110,11 +104,15 @@ class File /** * Copy a file to a new location. + * + * @param string $target + * @param bool $force + * @return static */ - public function copy(string $target, bool $force = false): static + public function copy(string $target, bool $force = false) { - if (F::copy($this->root(), $target, $force) !== true) { - throw new Exception('The file "' . $this->root() . '" could not be copied'); + if (F::copy($this->root, $target, $force) !== true) { + throw new Exception('The file "' . $this->root . '" could not be copied'); } return new static($target); @@ -124,6 +122,7 @@ class File * Returns the file as data uri * * @param bool $base64 Whether the data should be base64 encoded or not + * @return string */ public function dataUri(bool $base64 = true): string { @@ -136,64 +135,77 @@ class File /** * Deletes the file + * + * @return bool */ public function delete(): bool { - if (F::remove($this->root()) !== true) { - throw new Exception('The file "' . $this->root() . '" could not be deleted'); + if (F::remove($this->root) !== true) { + throw new Exception('The file "' . $this->root . '" could not be deleted'); } return true; } /* - * Automatically sends all needed headers - * for the file to be downloaded and - * echos the file's content + * Automatically sends all needed headers for the file to be downloaded + * and echos the file's content * * @param string|null $filename Optional filename for the download + * @return string */ - public function download(string|null $filename = null): string + public function download($filename = null): string { - return Response::download($this->root(), $filename ?? $this->filename()); + return Response::download($this->root, $filename ?? $this->filename()); } /** * Checks if the file actually exists + * + * @return bool */ public function exists(): bool { - return file_exists($this->root()) === true; + return file_exists($this->root) === true; } /** * Returns the current lowercase extension (without .) + * + * @return string */ public function extension(): string { - return F::extension($this->root()); + return F::extension($this->root); } /** * Returns the filename + * + * @return string */ public function filename(): string { - return basename($this->root()); + return basename($this->root); } /** * Returns a md5 hash of the root + * + * @return string */ public function hash(): string { - return md5($this->root()); + return md5($this->root); } /** * Sends an appropriate header for the asset + * + * @param bool $send + * @return \Kirby\Http\Response|void */ - public function header(bool $send = true): Response|null + public function header(bool $send = true) { $response = new Response('', $this->mime()); @@ -202,11 +214,13 @@ class File } $response->send(); - return null; } /** * Converts the file to html + * + * @param array $attr + * @return string */ public function html(array $attr = []): string { @@ -217,22 +231,27 @@ class File * Checks if a file is of a certain type * * @param string $value An extension or mime type + * @return bool */ public function is(string $value): bool { - return F::is($this->root(), $value); + return F::is($this->root, $value); } /** * Checks if the file is readable + * + * @return bool */ public function isReadable(): bool { - return is_readable($this->root()) === true; + return is_readable($this->root) === true; } /** * Checks if the file is a resizable image + * + * @return bool */ public function isResizable(): bool { @@ -242,6 +261,8 @@ class File /** * Checks if a preview can be displayed for the file * in the panel or in the frontend + * + * @return bool */ public function isViewable(): bool { @@ -250,16 +271,20 @@ class File /** * Checks if the file is writable + * + * @return bool */ public function isWritable(): bool { - return F::isWritable($this->root()); + return F::isWritable($this->root); } /** * Returns the app instance if it exists + * + * @return \Kirby\Cms\App|null */ - public function kirby(): App|null + public function kirby() { return App::instance(null, true); } @@ -268,6 +293,8 @@ class File * Runs a set of validations on the file object * (mainly for images). * + * @param array $rules + * @return bool * @throws \Kirby\Exception\Exception */ public function match(array $rules): bool @@ -277,15 +304,6 @@ class File if (is_array($rules['mime'] ?? null) === true) { $mime = $this->mime(); - // the MIME type could not be determined, but matching - // to it was requested explicitly - if ($mime === null) { - throw new Exception([ - 'key' => 'file.mime.missing', - 'data' => ['filename' => $this->filename()] - ]); - } - // determine if any pattern matches the MIME type; // once any pattern matches, `$carry` is `true` and the rest is skipped $matches = array_reduce( @@ -343,42 +361,43 @@ class File /** * Detects the mime type of the file + * + * @return string|null */ - public function mime(): string|null + public function mime() { - return Mime::type($this->root()); - } - - /** - * Returns the parent file model, which uses this instance as proxied file asset - */ - public function model(): object|null - { - return $this->model; + return Mime::type($this->root); } /** * Returns the file's last modification time * - * @param 'date'|'intl'|'strftime'|null $handler Custom date handler or `null` - * for the globally configured one + * @param string|\IntlDateFormatter|null $format + * @param string|null $handler date, intl or strftime + * @return mixed */ - public function modified( - string|IntlDateFormatter|null $format = null, - string|null $handler = null - ): string|int|false { - return F::modified($this->root(), $format, $handler); + public function modified($format = null, ?string $handler = null) + { + $kirby = $this->kirby(); + + return F::modified( + $this->root, + $format, + $handler ?? ($kirby ? $kirby->option('date.handler', 'date') : 'date') + ); } /** * Move the file to a new location * + * @param string $newRoot * @param bool $overwrite Force overwriting any existing files + * @return static */ - public function move(string $newRoot, bool $overwrite = false): static + public function move(string $newRoot, bool $overwrite = false) { - if (F::move($this->root(), $newRoot, $overwrite) !== true) { - throw new Exception('The file: "' . $this->root() . '" could not be moved to: "' . $newRoot . '"'); + if (F::move($this->root, $newRoot, $overwrite) !== true) { + throw new Exception('The file: "' . $this->root . '" could not be moved to: "' . $newRoot . '"'); } return new static($newRoot); @@ -387,53 +406,62 @@ class File /** * Getter for the name of the file * without the extension + * + * @return string */ public function name(): string { - return pathinfo($this->root(), PATHINFO_FILENAME); + return pathinfo($this->root, PATHINFO_FILENAME); } /** * Returns the file size in a * human-readable format * - * @param string|false|null $locale Locale for number formatting, + * @param string|null|false $locale Locale for number formatting, * `null` for the current locale, * `false` to disable number formatting + * @return string */ - public function niceSize(string|false|null $locale = null): string + public function niceSize($locale = null): string { - return F::niceSize($this->root(), $locale); + return F::niceSize($this->root, $locale); } /** * Reads the file content and returns it. + * + * @return string|false */ - public function read(): string|false + public function read() { - return F::read($this->root()); + return F::read($this->root); } /** * Returns the absolute path to the file + * + * @return string */ public function realpath(): string { - return realpath($this->root()); + return realpath($this->root); } /** * Changes the name of the file without * touching the extension * + * @param string $newName * @param bool $overwrite Force overwrite existing files + * @return static */ - public function rename(string $newName, bool $overwrite = false): static + public function rename(string $newName, bool $overwrite = false) { - $newRoot = F::rename($this->root(), $newName, $overwrite); + $newRoot = F::rename($this->root, $newName, $overwrite); if ($newRoot === false) { - throw new Exception('The file: "' . $this->root() . '" could not be renamed to: "' . $newName . '"'); + throw new Exception('The file: "' . $this->root . '" could not be renamed to: "' . $newName . '"'); } return new static($newRoot); @@ -441,21 +469,46 @@ class File /** * Returns the given file path + * + * @return string|null */ - public function root(): string|null + public function root(): ?string { - return $this->root ??= $this->model?->root(); + return $this->root; + } + + /** + * Setter for the root + * + * @param string|null $root + * @return $this + */ + protected function setRoot(?string $root = null) + { + $this->root = $root; + return $this; + } + + /** + * Setter for the file url + * + * @param string|null $url + * @return $this + */ + protected function setUrl(?string $url = null) + { + $this->url = $url; + return $this; } /** * Returns the absolute url for the file + * + * @return string|null */ - public function url(): string|null + public function url(): ?string { - // lazily determine the URL from the model object - // only if it's needed to avoid breaking custom file::url - // components that rely on `$cmsFile->asset()` methods - return $this->url ??= $this->model?->url(); + return $this->url; } /** @@ -466,13 +519,14 @@ class File * @param string|bool $typeLazy Explicit sane handler type string, * `true` for lazy autodetection or * `false` for normal autodetection + * @return void * * @throws \Kirby\Exception\InvalidArgumentException If the file didn't pass validation * @throws \Kirby\Exception\LogicException If more than one handler applies * @throws \Kirby\Exception\NotFoundException If the handler was not found * @throws \Kirby\Exception\Exception On other errors */ - public function sanitizeContents(string|bool $typeLazy = false): void + public function sanitizeContents($typeLazy = false): void { Sane::sanitizeFile($this->root(), $typeLazy); } @@ -480,23 +534,29 @@ class File /** * Returns the sha1 hash of the file * @since 3.6.0 + * + * @return string */ public function sha1(): string { - return sha1_file($this->root()); + return sha1_file($this->root); } /** * Returns the raw size of the file + * + * @return int */ public function size(): int { - return F::size($this->root()); + return F::size($this->root); } /** * Converts the media object to a * plain PHP array + * + * @return array */ public function toArray(): array { @@ -522,6 +582,8 @@ class File /** * Converts the entire file array into * a json string + * + * @return string */ public function toJson(): string { @@ -530,10 +592,12 @@ class File /** * Returns the file type. + * + * @return string|null */ - public function type(): string|null + public function type(): ?string { - return F::type($this->root()); + return F::type($this->root); } /** @@ -542,23 +606,27 @@ class File * @param string|bool $typeLazy Explicit sane handler type string, * `true` for lazy autodetection or * `false` for normal autodetection + * @return void * * @throws \Kirby\Exception\InvalidArgumentException If the file didn't pass validation * @throws \Kirby\Exception\NotFoundException If the handler was not found * @throws \Kirby\Exception\Exception On other errors */ - public function validateContents(string|bool $typeLazy = false): void + public function validateContents($typeLazy = false): void { Sane::validateFile($this->root(), $typeLazy); } /** * Writes content to the file + * + * @param string $content + * @return bool */ - public function write(string $content): bool + public function write($content): bool { - if (F::write($this->root(), $content) !== true) { - throw new Exception('The file "' . $this->root() . '" could not be written'); + if (F::write($this->root, $content) !== true) { + throw new Exception('The file "' . $this->root . '" could not be written'); } return true; diff --git a/kirby/src/Filesystem/Filename.php b/kirby/src/Filesystem/Filename.php index a73891e..f97de71 100644 --- a/kirby/src/Filesystem/Filename.php +++ b/kirby/src/Filesystem/Filename.php @@ -30,31 +30,45 @@ class Filename { /** * List of all applicable attributes + * + * @var array */ - protected array $attributes; + protected $attributes; /** * The sanitized file extension + * + * @var string */ - protected string $extension; + protected $extension; /** * The source original filename + * + * @var string */ - protected string $filename; + protected $filename; /** * The sanitized file name + * + * @var string */ - protected string $name; + protected $name; /** * The template for the final name + * + * @var string */ - protected string $template; + protected $template; /** * Creates a new Filename object + * + * @param string $filename + * @param string $template + * @param array $attributes */ public function __construct(string $filename, string $template, array $attributes = []) { @@ -65,11 +79,13 @@ class Filename $attributes['format'] ?? pathinfo($filename, PATHINFO_EXTENSION) ); - $this->name = $this->sanitizeName($filename); + $this->name = $this->sanitizeName(pathinfo($filename, PATHINFO_FILENAME)); } /** * Converts the entire object to a string + * + * @return string */ public function __toString(): string { @@ -80,6 +96,8 @@ class Filename * Converts all processed attributes * to an array. The array keys are already * the shortened versions for the filename + * + * @return array */ public function attributesToArray(): array { @@ -89,7 +107,6 @@ class Filename 'blur' => $this->blur(), 'bw' => $this->grayscale(), 'q' => $this->quality(), - 'sharpen' => $this->sharpen(), ]; $array = array_filter( @@ -106,8 +123,9 @@ class Filename * new filename * * @param string|null $prefix The prefix will be used in the filename creation + * @return string */ - public function attributesToString(string|null $prefix = null): string + public function attributesToString(string $prefix = null): string { $array = $this->attributesToArray(); $result = []; @@ -117,11 +135,16 @@ class Filename $value = ''; } - $result[] = match ($key) { - 'dimensions' => $value, - 'crop' => ($value === 'center') ? 'crop' : $key . '-' . $value, - default => $key . $value - }; + switch ($key) { + case 'dimensions': + $result[] = $value; + break; + case 'crop': + $result[] = ($value === 'center') ? 'crop' : $key . '-' . $value; + break; + default: + $result[] = $key . $value; + } } $result = array_filter($result); @@ -136,8 +159,10 @@ class Filename /** * Normalizes the blur option value + * + * @return false|int */ - public function blur(): int|false + public function blur() { $value = $this->attributes['blur'] ?? false; @@ -150,8 +175,10 @@ class Filename /** * Normalizes the crop option value + * + * @return false|string */ - public function crop(): string|false + public function crop() { // get the crop value $crop = $this->attributes['crop'] ?? false; @@ -167,8 +194,10 @@ class Filename * Returns a normalized array * with width and height values * if available + * + * @return array */ - public function dimensions(): array + public function dimensions() { if (empty($this->attributes['width']) === true && empty($this->attributes['height']) === true) { return []; @@ -182,6 +211,8 @@ class Filename /** * Returns the sanitized extension + * + * @return string */ public function extension(): string { @@ -194,6 +225,8 @@ class Filename * the option. You can use `grayscale`, * `greyscale` or simply `bw`. The function * will always return `grayscale` + * + * @return bool */ public function grayscale(): bool { @@ -206,6 +239,8 @@ class Filename /** * Returns the filename without extension + * + * @return string */ public function name(): string { @@ -214,8 +249,10 @@ class Filename /** * Normalizes the quality option value + * + * @return false|int */ - public function quality(): int|false + public function quality() { $value = $this->attributes['quality'] ?? false; @@ -228,37 +265,36 @@ class Filename /** * Sanitizes the file extension. - * It also replaces `jpeg` with `jpg`. + * The extension will be converted + * to lowercase and `jpeg` will be + * replaced with `jpg` + * + * @param string $extension + * @return string */ protected function sanitizeExtension(string $extension): string { - $extension = F::safeExtension('test.' . $extension); + $extension = strtolower($extension); $extension = str_replace('jpeg', 'jpg', $extension); return $extension; } /** - * Sanitizes the file name + * Sanitizes the name with Kirby's + * Str::slug function + * + * @param string $name + * @return string */ protected function sanitizeName(string $name): string { - return F::safeBasename($name); - } - - /** - * Normalizes the sharpen option value - */ - public function sharpen(): int|false - { - return match ($this->attributes['sharpen'] ?? false) { - false => false, - true => 50, - default => (int)$this->attributes['sharpen'] - }; + return Str::slug($name); } /** * Returns the converted filename as string + * + * @return string */ public function toString(): string { diff --git a/kirby/src/Filesystem/IsFile.php b/kirby/src/Filesystem/IsFile.php index e5b1ab1..7e69799 100644 --- a/kirby/src/Filesystem/IsFile.php +++ b/kirby/src/Filesystem/IsFile.php @@ -5,6 +5,7 @@ namespace Kirby\Filesystem; use Kirby\Cms\App; use Kirby\Exception\BadMethodCallException; use Kirby\Image\Image; +use Kirby\Toolkit\Properties; /** * Trait for all objects that represent an asset file. @@ -21,36 +22,48 @@ use Kirby\Image\Image; */ trait IsFile { + use Properties; + /** * File asset object + * + * @var \Kirby\Filesystem\File */ - protected File|null $asset = null; + protected $asset; /** * Absolute file path + * + * @var string|null */ - protected string|null $root; + protected $root; /** * Absolute file URL + * + * @var string|null */ - protected string|null $url; + protected $url; /** * Constructor sets all file properties + * + * @param array $props */ public function __construct(array $props) { - $this->root = $props['root'] ?? null; - $this->url = $props['url'] ?? null; + $this->setProperties($props); } /** * Magic caller for asset methods * + * @param string $method + * @param array $arguments + * @return mixed * @throws \Kirby\Exception\BadMethodCallException */ - public function __call(string $method, array $arguments = []): mixed + public function __call(string $method, array $arguments = []) { // public property access if (isset($this->$method) === true) { @@ -67,6 +80,8 @@ trait IsFile /** * Converts the asset to a string + * + * @return string */ public function __toString(): string { @@ -75,29 +90,33 @@ trait IsFile /** * Returns the file asset object + * + * @param array|string|null $props + * @return \Kirby\Filesystem\File */ - public function asset(array|string|null $props = null): File + public function asset($props = null) { if ($this->asset !== null) { return $this->asset; } - $props ??= []; + $props = $props ?? [ + 'root' => $this->root(), + 'url' => $this->url() + ]; - if (is_string($props) === true) { - $props = ['root' => $props]; + switch ($this->type()) { + case 'image': + return $this->asset = new Image($props); + default: + return $this->asset = new File($props); } - - $props['model'] ??= $this; - - return $this->asset = match ($this->type()) { - 'image' => new Image($props), - default => new File($props) - }; } /** * Checks if the file exists on disk + * + * @return bool */ public function exists(): bool { @@ -107,37 +126,57 @@ trait IsFile return file_exists($this->root()) === true; } - /** - * To check the existence of the IsFile trait - * - * @todo Switch to class constant in traits when min PHP version 8.2 required - * @codeCoverageIgnore - */ - protected function hasIsFileTrait(): bool - { - return true; - } /** * Returns the app instance + * + * @return \Kirby\Cms\App */ - public function kirby(): App + public function kirby() { return App::instance(); } /** * Returns the given file path + * + * @return string|null */ - public function root(): string|null + public function root(): ?string { return $this->root; } /** - * Returns the file type + * Setter for the root + * + * @param string|null $root + * @return $this */ - public function type(): string|null + protected function setRoot(?string $root = null) + { + $this->root = $root; + return $this; + } + + /** + * Setter for the file url + * + * @param string|null $url + * @return $this + */ + protected function setUrl(?string $url = null) + { + $this->url = $url; + return $this; + } + + /** + * Returns the file type + * + * @return string|null + */ + public function type(): ?string { // Important to include this in the trait // to avoid infinite loops when trying @@ -147,8 +186,10 @@ trait IsFile /** * Returns the absolute url for the file + * + * @return string|null */ - public function url(): string|null + public function url(): ?string { return $this->url; } diff --git a/kirby/src/Filesystem/Mime.php b/kirby/src/Filesystem/Mime.php index 5b83918..ca8b63f 100644 --- a/kirby/src/Filesystem/Mime.php +++ b/kirby/src/Filesystem/Mime.php @@ -2,7 +2,6 @@ namespace Kirby\Filesystem; -use Kirby\Toolkit\A; use Kirby\Toolkit\Str; use SimpleXMLElement; @@ -31,7 +30,7 @@ class Mime 'aifc' => 'audio/x-aiff', 'aiff' => 'audio/x-aiff', 'avi' => 'video/x-msvideo', - 'avif' => 'image/avif', + 'avif' => 'image/avif', 'bmp' => 'image/bmp', 'css' => 'text/css', 'csv' => ['text/csv', 'text/x-comma-separated-values', 'text/comma-separated-values', 'application/octet-stream'], @@ -79,7 +78,6 @@ class Mime 'php' => ['text/php', 'text/x-php', 'application/x-httpd-php', 'application/php', 'application/x-php', 'application/x-httpd-php-source'], 'php3' => ['text/php', 'text/x-php', 'application/x-httpd-php', 'application/php', 'application/x-php', 'application/x-httpd-php-source'], 'phps' => ['text/php', 'text/x-php', 'application/x-httpd-php', 'application/php', 'application/x-php', 'application/x-httpd-php-source'], - 'pht' => ['text/php', 'text/x-php', 'application/x-httpd-php', 'application/php', 'application/x-php', 'application/x-httpd-php-source'], 'phtml' => ['text/php', 'text/x-php', 'application/x-httpd-php', 'application/php', 'application/x-php', 'application/x-httpd-php-source'], 'png' => 'image/png', 'ppt' => ['application/powerpoint', 'application/vnd.ms-powerpoint'], @@ -120,22 +118,24 @@ class Mime /** * Fixes an invalid MIME type guess for the given file + * + * @param string $file + * @param string $mime + * @param string $extension + * @return string|null */ - public static function fix( - string $file, - string|null $mime = null, - string|null $extension = null - ): string|null { + public static function fix(string $file, string $mime = null, string $extension = null) + { // fixing map $map = [ 'text/html' => [ - 'svg' => [Mime::class, 'fromSvg'], + 'svg' => ['Kirby\Filesystem\Mime', 'fromSvg'], ], 'text/plain' => [ 'css' => 'text/css', 'json' => 'application/json', 'mjs' => 'text/javascript', - 'svg' => [Mime::class, 'fromSvg'], + 'svg' => ['Kirby\Filesystem\Mime', 'fromSvg'], ], 'text/x-asm' => [ 'css' => 'text/css' @@ -166,8 +166,11 @@ class Mime /** * Guesses a MIME type by extension + * + * @param string $extension + * @return string|null */ - public static function fromExtension(string $extension): string|null + public static function fromExtension(string $extension): ?string { $mime = static::$types[$extension] ?? null; return is_array($mime) === true ? array_shift($mime) : $mime; @@ -175,8 +178,11 @@ class Mime /** * Returns the MIME type of a file + * + * @param string $file + * @return string|false */ - public static function fromFileInfo(string $file): string|false + public static function fromFileInfo(string $file) { if (function_exists('finfo_file') === true && file_exists($file) === true) { $finfo = finfo_open(FILEINFO_MIME_TYPE); @@ -190,13 +196,13 @@ class Mime /** * Returns the MIME type of a file + * + * @param string $file + * @return string|false */ - public static function fromMimeContentType(string $file): string|false + public static function fromMimeContentType(string $file) { - if ( - function_exists('mime_content_type') === true && - file_exists($file) === true - ) { + if (function_exists('mime_content_type') === true && file_exists($file) === true) { return mime_content_type($file); } @@ -205,8 +211,11 @@ class Mime /** * Tries to detect a valid SVG and returns the MIME type accordingly + * + * @param string $file + * @return string|false */ - public static function fromSvg(string $file): string|false + public static function fromSvg(string $file) { if (file_exists($file) === true) { libxml_use_internal_errors(true); @@ -224,6 +233,10 @@ class Mime /** * Tests if a given MIME type is matched by an `Accept` header * pattern; returns true if the MIME type is contained at all + * + * @param string $mime + * @param string $pattern + * @return bool */ public static function isAccepted(string $mime, string $pattern): bool { @@ -242,6 +255,10 @@ class Mime * Tests if a MIME wildcard pattern from an `Accept` header * matches a given type * @since 3.3.0 + * + * @param string $test + * @param string $wildcard + * @return bool */ public static function matches(string $test, string $wildcard): bool { @@ -250,8 +267,11 @@ class Mime /** * Returns the extension for a given MIME type + * + * @param string|null $mime + * @return string|false */ - public static function toExtension(string $mime = null): string|false + public static function toExtension(string $mime = null) { foreach (static::$types as $key => $value) { if (is_array($value) === true && in_array($mime, $value) === true) { @@ -268,33 +288,22 @@ class Mime /** * Returns all available extensions for a given MIME type + * + * @param string|null $mime + * @return array */ - public static function toExtensions(string $mime = null, bool $matchWildcards = false): array + public static function toExtensions(string $mime = null): array { $extensions = []; - $testMime = fn (string $v) => static::matches($v, $mime); foreach (static::$types as $key => $value) { - if (is_array($value) === true) { - if ($matchWildcards === true) { - if (A::some($value, $testMime)) { - $extensions[] = $key; - } - } else { - if (in_array($mime, $value) === true) { - $extensions[] = $key; - } - } - } else { - if ($matchWildcards === true) { - if ($testMime($value) === true) { - $extensions[] = $key; - } - } else { - if ($value === $mime) { - $extensions[] = $key; - } - } + if (is_array($value) === true && in_array($mime, $value) === true) { + $extensions[] = $key; + continue; + } + + if ($value === $mime) { + $extensions[] = $key; } } @@ -303,11 +312,13 @@ class Mime /** * Returns the MIME type of a file + * + * @param string $file + * @param string $extension + * @return string|false */ - public static function type( - string $file, - string|null $extension = null - ): string|null { + public static function type(string $file, string $extension = null) + { // use the standard finfo extension $mime = static::fromFileInfo($file); @@ -330,6 +341,8 @@ class Mime /** * Returns all detectable MIME types + * + * @return array */ public static function types(): array { diff --git a/kirby/src/Form/Field.php b/kirby/src/Form/Field.php index cb95fd4..34f4a62 100644 --- a/kirby/src/Form/Field.php +++ b/kirby/src/Form/Field.php @@ -2,9 +2,7 @@ namespace Kirby\Form; -use Closure; use Exception; -use Kirby\Cms\App; use Kirby\Exception\InvalidArgumentException; use Kirby\Toolkit\A; use Kirby\Toolkit\Component; @@ -26,37 +24,44 @@ class Field extends Component { /** * An array of all found errors + * + * @var array|null */ - protected array|null $errors = null; + protected $errors; /** * Parent collection with all fields of the current form + * + * @var \Kirby\Form\Fields|null */ - protected Fields|null $formFields; + protected $formFields; /** * Registry for all component mixins + * + * @var array */ - public static array $mixins = []; + public static $mixins = []; /** * Registry for all component types + * + * @var array */ - public static array $types = []; + public static $types = []; /** + * Field constructor + * + * @param string $type + * @param array $attrs + * @param \Kirby\Form\Fields|null $formFields * @throws \Kirby\Exception\InvalidArgumentException */ - public function __construct( - string $type, - array $attrs = [], - Fields|null $formFields = null - ) { + public function __construct(string $type, array $attrs = [], ?Fields $formFields = null) + { if (isset(static::$types[$type]) === false) { - throw new InvalidArgumentException([ - 'key' => 'field.type.missing', - 'data' => ['name' => $attrs['name'] ?? '-', 'type' => $type] - ]); + throw new InvalidArgumentException('The field type "' . $type . '" does not exist'); } if (isset($attrs['model']) === false) { @@ -74,23 +79,26 @@ class Field extends Component /** * Returns field api call + * + * @return mixed */ - public function api(): mixed + public function api() { if ( isset($this->options['api']) === true && - $this->options['api'] instanceof Closure + is_a($this->options['api'], 'Closure') === true ) { return $this->options['api']->call($this); } - - return null; } /** * Returns field data + * + * @param bool $default + * @return mixed */ - public function data(bool $default = false): mixed + public function data(bool $default = false) { $save = $this->options['save'] ?? true; @@ -104,7 +112,7 @@ class Field extends Component return null; } - if ($save instanceof Closure) { + if (is_a($save, 'Closure') === true) { return $save->call($this, $value); } @@ -113,6 +121,8 @@ class Field extends Component /** * Default props and computed of the field + * + * @return array */ public static function defaults(): array { @@ -249,44 +259,16 @@ class Field extends Component ]; } - /** - * Returns optional dialog routes for the field - */ - public function dialogs(): array - { - if ( - isset($this->options['dialogs']) === true && - $this->options['dialogs'] instanceof Closure - ) { - return $this->options['dialogs']->call($this); - } - - return []; - } - - /** - * Returns optional drawer routes for the field - */ - public function drawers(): array - { - if ( - isset($this->options['drawers']) === true && - $this->options['drawers'] instanceof Closure - ) { - return $this->options['drawers']->call($this); - } - - return []; - } - /** * Creates a new field instance + * + * @param string $type + * @param array $attrs + * @param Fields|null $formFields + * @return static */ - public static function factory( - string $type, - array $attrs = [], - Fields|null $formFields = null - ): static|FieldClass { + public static function factory(string $type, array $attrs = [], ?Fields $formFields = null) + { $field = static::$types[$type] ?? null; if (is_string($field) && class_exists($field) === true) { @@ -299,14 +281,18 @@ class Field extends Component /** * Parent collection with all fields of the current form + * + * @return \Kirby\Form\Fields|null */ - public function formFields(): Fields|null + public function formFields(): ?Fields { return $this->formFields; } /** * Validates when run for the first time and returns any errors + * + * @return array */ public function errors(): array { @@ -319,31 +305,29 @@ class Field extends Component /** * Checks if the field is empty + * + * @param mixed ...$args + * @return bool */ - public function isEmpty(mixed ...$args): bool + public function isEmpty(...$args): bool { - $value = match (count($args)) { - 0 => $this->value(), - default => $args[0] - }; + if (count($args) === 0) { + $value = $this->value(); + } else { + $value = $args[0]; + } - if ($empty = $this->options['isEmpty'] ?? null) { - return $empty->call($this, $value); + if (isset($this->options['isEmpty']) === true) { + return $this->options['isEmpty']->call($this, $value); } return in_array($value, [null, '', []], true); } - /** - * Checks if the field is hidden - */ - public function isHidden(): bool - { - return ($this->options['hidden'] ?? false) === true; - } - /** * Checks if the field is invalid + * + * @return bool */ public function isInvalid(): bool { @@ -352,6 +336,8 @@ class Field extends Component /** * Checks if the field is required + * + * @return bool */ public function isRequired(): bool { @@ -360,6 +346,8 @@ class Field extends Component /** * Checks if the field is valid + * + * @return bool */ public function isValid(): bool { @@ -368,16 +356,20 @@ class Field extends Component /** * Returns the Kirby instance + * + * @return \Kirby\Cms\App */ - public function kirby(): App + public function kirby() { return $this->model()->kirby(); } /** * Returns the parent model + * + * @return mixed */ - public function model(): mixed + public function model() { return $this->model; } @@ -389,33 +381,31 @@ class Field extends Component * - The field is required * - The field is currently empty * - The field is not currently inactive because of a `when` rule + * + * @return bool */ protected function needsValue(): bool { // check simple conditions first - if ( - $this->save() === false || - $this->isRequired() === false || - $this->isEmpty() === false - ) { + if ($this->save() === false || $this->isRequired() === false || $this->isEmpty() === false) { return false; } // check the data of the relevant fields if there is a `when` option - if ( - empty($this->when) === false && - is_array($this->when) === true && - $formFields = $this->formFields() - ) { - foreach ($this->when as $field => $value) { - $field = $formFields->get($field); - $inputValue = $field?->value() ?? ''; + if (empty($this->when) === false && is_array($this->when) === true) { + $formFields = $this->formFields(); - // if the input data doesn't match the requested `when` value, - // that means that this field is not required and can be saved - // (*all* `when` conditions must be met for this field to be required) - if ($inputValue !== $value) { - return false; + if ($formFields !== null) { + foreach ($this->when as $field => $value) { + $field = $formFields->get($field); + $inputValue = $field !== null ? $field->value() : ''; + + // if the input data doesn't match the requested `when` value, + // that means that this field is not required and can be saved + // (*all* `when` conditions must be met for this field to be required) + if ($inputValue !== $value) { + return false; + } } } } @@ -426,6 +416,8 @@ class Field extends Component /** * Checks if the field is saveable + * + * @return bool */ public function save(): bool { @@ -434,6 +426,8 @@ class Field extends Component /** * Converts the field to a plain array + * + * @return array */ public function toArray(): array { @@ -441,7 +435,6 @@ class Field extends Component unset($array['model']); - $array['hidden'] = $this->isHidden(); $array['saveable'] = $this->save(); $array['signature'] = md5(json_encode($array)); @@ -455,6 +448,8 @@ class Field extends Component /** * Runs the validations defined for the field + * + * @return void */ protected function validate(): void { @@ -477,7 +472,7 @@ class Field extends Component continue; } - if ($validation instanceof Closure) { + if (is_a($validation, 'Closure') === true) { try { $validation->call($this, $this->value()); } catch (Exception $e) { @@ -502,8 +497,10 @@ class Field extends Component /** * Returns the value of the field if saveable * otherwise it returns null + * + * @return mixed */ - public function value(): mixed + public function value() { return $this->save() ? $this->value : null; } diff --git a/kirby/src/Form/Field/BlocksField.php b/kirby/src/Form/Field/BlocksField.php index e37d373..6479b8a 100644 --- a/kirby/src/Form/Field/BlocksField.php +++ b/kirby/src/Form/Field/BlocksField.php @@ -5,9 +5,7 @@ namespace Kirby\Form\Field; use Kirby\Cms\App; use Kirby\Cms\Block; use Kirby\Cms\Blocks as BlocksCollection; -use Kirby\Cms\Fieldset; use Kirby\Cms\Fieldsets; -use Kirby\Cms\ModelWithContent; use Kirby\Exception\InvalidArgumentException; use Kirby\Exception\NotFoundException; use Kirby\Form\FieldClass; @@ -24,17 +22,15 @@ class BlocksField extends FieldClass use Max; use Min; - protected Fieldsets $fieldsets; - protected string|null $group; - protected bool $pretty; - protected mixed $value = []; + protected $blocks; + protected $fieldsets; + protected $group; + protected $pretty; + protected $value = []; public function __construct(array $params = []) { - $this->setFieldsets( - $params['fieldsets'] ?? null, - $params['model'] ?? App::instance()->site() - ); + $this->setFieldsets($params['fieldsets'] ?? null, $params['model'] ?? App::instance()->site()); parent::__construct($params); @@ -45,10 +41,8 @@ class BlocksField extends FieldClass $this->setPretty($params['pretty'] ?? false); } - public function blocksToValues( - array $blocks, - string $to = 'values' - ): array { + public function blocksToValues($blocks, $to = 'values'): array + { $result = []; $fields = []; @@ -60,58 +54,53 @@ class BlocksField extends FieldClass $fields[$type] ??= $this->fields($block['type']); // overwrite the block content with form values - $block['content'] = $this->form( - $fields[$type], - $block['content'] - )->$to(); + $block['content'] = $this->form($fields[$type], $block['content'])->$to(); - // create id if not exists - $block['id'] ??= Str::uuid(); - } catch (Throwable) { - // skip invalid blocks - } finally { $result[] = $block; + } catch (Throwable $e) { + $result[] = $block; + + // skip invalid blocks + continue; } } return $result; } - public function fields(string $type): array + public function fields(string $type) { return $this->fieldset($type)->fields(); } - public function fieldset(string $type): Fieldset + public function fieldset(string $type) { if ($fieldset = $this->fieldsets->find($type)) { return $fieldset; } - throw new NotFoundException( - 'The fieldset ' . $type . ' could not be found' - ); + throw new NotFoundException('The fieldset ' . $type . ' could not be found'); } - public function fieldsets(): Fieldsets + public function fieldsets() { return $this->fieldsets; } - public function fieldsetGroups(): array|null + public function fieldsetGroups(): ?array { - $groups = $this->fieldsets()->groups(); - return empty($groups) === true ? null : $groups; + $fieldsetGroups = $this->fieldsets()->groups(); + return empty($fieldsetGroups) === true ? null : $fieldsetGroups; } - public function fill(mixed $value = null): void + public function fill($value = null) { $value = BlocksCollection::parse($value); - $blocks = BlocksCollection::factory($value)->toArray(); - $this->value = $this->blocksToValues($blocks); + $blocks = BlocksCollection::factory($value); + $this->value = $this->blocksToValues($blocks->toArray()); } - public function form(array $fields, array $input = []): Form + public function form(array $fields, array $input = []) { return new Form([ 'fields' => $fields, @@ -136,30 +125,6 @@ class BlocksField extends FieldClass return $this->pretty; } - /** - * Paste action for blocks: - * - generates new uuids for the blocks - * - filters only supported fieldsets - * - applies max limit if defined - */ - public function pasteBlocks(array $blocks): array - { - $blocks = $this->blocksToValues($blocks); - - foreach ($blocks as $index => &$block) { - $block['id'] = Str::uuid(); - - // remove the block if it's not available - try { - $this->fieldset($block['type']); - } catch (Throwable) { - unset($blocks[$index]); - } - } - - return array_values($blocks); - } - public function props(): array { return [ @@ -179,25 +144,23 @@ class BlocksField extends FieldClass return [ [ 'pattern' => 'uuid', - 'action' => fn (): array => ['uuid' => Str::uuid()] + 'action' => fn () => ['uuid' => Str::uuid()] ], [ 'pattern' => 'paste', 'method' => 'POST', - 'action' => function () use ($field): array { + 'action' => function () use ($field) { $request = App::instance()->request(); - $value = BlocksCollection::parse($request->get('html')); - $blocks = BlocksCollection::factory($value); - return $field->pasteBlocks($blocks->toArray()); + $value = BlocksCollection::parse($request->get('html')); + $blocks = BlocksCollection::factory($value); + return $field->blocksToValues($blocks->toArray()); } ], [ 'pattern' => 'fieldsets/(:any)', 'method' => 'GET', - 'action' => function ( - string $fieldsetType - ) use ($field): array { + 'action' => function ($fieldsetType) use ($field) { $fields = $field->fields($fieldsetType); $defaults = $field->form($fields, [])->data(true); $content = $field->form($fields, $defaults)->values(); @@ -211,33 +174,22 @@ class BlocksField extends FieldClass [ 'pattern' => 'fieldsets/(:any)/fields/(:any)/(:all?)', 'method' => 'ALL', - 'action' => function ( - string $fieldsetType, - string $fieldName, - string $path = null - ) use ($field) { + 'action' => function (string $fieldsetType, string $fieldName, string $path = null) use ($field) { $fields = $field->fields($fieldsetType); $field = $field->form($fields)->field($fieldName); $fieldApi = $this->clone([ 'routes' => $field->api(), - 'data' => array_merge( - $this->data(), - ['field' => $field] - ) + 'data' => array_merge($this->data(), ['field' => $field]) ]); - return $fieldApi->call( - $path, - $this->requestMethod(), - $this->requestData() - ); + return $fieldApi->call($path, $this->requestMethod(), $this->requestData()); } ], ]; } - public function store(mixed $value): mixed + public function store($value) { $blocks = $this->blocksToValues((array)$value, 'content'); @@ -250,38 +202,23 @@ class BlocksField extends FieldClass return $this->valueToJson($blocks, $this->pretty()); } - protected function setDefault(mixed $default = null): void + protected function setFieldsets($fieldsets, $model) { - // set id for blocks if not exists - if (is_array($default) === true) { - array_walk($default, function (&$block) { - $block['id'] ??= Str::uuid(); - }); - } - - parent::setDefault($default); - } - - protected function setFieldsets( - string|array|null $fieldsets, - ModelWithContent $model - ): void { if (is_string($fieldsets) === true) { $fieldsets = []; } - $this->fieldsets = Fieldsets::factory( - $fieldsets, - ['parent' => $model] - ); + $this->fieldsets = Fieldsets::factory($fieldsets, [ + 'parent' => $model + ]); } - protected function setGroup(string $group = null): void + protected function setGroup(string $group = null) { $this->group = $group; } - protected function setPretty(bool $pretty = false): void + protected function setPretty(bool $pretty = false) { $this->pretty = $pretty; } @@ -313,22 +250,20 @@ class BlocksField extends FieldClass foreach ($value as $block) { $index++; - $type = $block['type']; + $blockType = $block['type']; try { - $fieldset = $this->fieldset($type); - $blockFields = $fields[$type] ?? $fieldset->fields() ?? []; - } catch (Throwable) { + $blockFields = $fields[$blockType] ?? $this->fields($blockType) ?? []; + } catch (Throwable $e) { // skip invalid blocks continue; } // store the fields for the next round - $fields[$type] = $blockFields; + $fields[$blockType] = $blockFields; // overwrite the content with the serialized form - $form = $this->form($blockFields, $block['content']); - foreach ($form->fields() as $field) { + foreach ($this->form($blockFields, $block['content'])->fields() as $field) { $errors = $field->errors(); // rough first validation @@ -336,9 +271,7 @@ class BlocksField extends FieldClass throw new InvalidArgumentException([ 'key' => 'blocks.validation', 'data' => [ - 'field' => $field->label(), - 'fieldset' => $fieldset->name(), - 'index' => $index + 'index' => $index, ] ]); } diff --git a/kirby/src/Form/Field/LayoutField.php b/kirby/src/Form/Field/LayoutField.php index 2e595c0..640d095 100644 --- a/kirby/src/Form/Field/LayoutField.php +++ b/kirby/src/Form/Field/LayoutField.php @@ -14,21 +14,19 @@ use Throwable; class LayoutField extends BlocksField { - protected array|null $layouts; - protected array|null $selector; - protected Fieldset|null $settings; + protected $layouts; + protected $settings; public function __construct(array $params) { $this->setModel($params['model'] ?? App::instance()->site()); $this->setLayouts($params['layouts'] ?? ['1/1']); - $this->setSelector($params['selector'] ?? null); $this->setSettings($params['settings'] ?? null); parent::__construct($params); } - public function fill(mixed $value = null): void + public function fill($value = null) { $value = $this->valueFromJson($value); $layouts = Layouts::factory($value, ['parent' => $this->model])->toArray(); @@ -46,88 +44,30 @@ class LayoutField extends BlocksField $this->value = $layouts; } - public function attrsForm(array $input = []): Form + public function attrsForm(array $input = []) { $settings = $this->settings(); return new Form([ - 'fields' => $settings?->fields() ?? [], + 'fields' => $settings ? $settings->fields() : [], 'model' => $this->model, 'strict' => true, 'values' => $input, ]); } - public function layouts(): array|null + public function layouts(): ?array { return $this->layouts; } - /** - * Creates form values for each layout - */ - public function layoutsToValues(array $layouts): array - { - foreach ($layouts as &$layout) { - $layout['id'] ??= Str::uuid(); - $layout['columns'] ??= []; - - array_walk($layout['columns'], function (&$column) { - $column['id'] ??= Str::uuid(); - $column['blocks'] = $this->blocksToValues($column['blocks'] ?? []); - }); - } - - return $layouts; - } - - /** - * Paste action for layouts: - * - generates new uuids for layout, column and blocks - * - filters only supported layouts - * - filters only supported fieldsets - */ - public function pasteLayouts(array $layouts): array - { - $layouts = $this->layoutsToValues($layouts); - - foreach ($layouts as $layoutIndex => &$layout) { - $layout['id'] = Str::uuid(); - - // remove the row if layout not available for the pasted layout field - $columns = array_column($layout['columns'], 'width'); - if (in_array($columns, $this->layouts()) === false) { - unset($layouts[$layoutIndex]); - continue; - } - - array_walk($layout['columns'], function (&$column) { - $column['id'] = Str::uuid(); - - array_walk($column['blocks'], function (&$block, $index) use ($column) { - $block['id'] = Str::uuid(); - - // remove the block if it's not available - try { - $this->fieldset($block['type']); - } catch (Throwable) { - unset($column['blocks'][$index]); - } - }); - }); - } - - return $layouts; - } - public function props(): array { $settings = $this->settings(); return array_merge(parent::props(), [ - 'layouts' => $this->layouts(), - 'selector' => $this->selector(), - 'settings' => $settings?->toArray() + 'settings' => $settings !== null ? $settings->toArray() : null, + 'layouts' => $this->layouts() ]); } @@ -135,15 +75,13 @@ class LayoutField extends BlocksField { $field = $this; $routes = parent::routes(); - $routes[] = [ 'pattern' => 'layout', 'method' => 'POST', - 'action' => function () use ($field): array { + 'action' => function () use ($field) { $request = App::instance()->request(); - $input = $request->get('attrs') ?? []; - $defaults = $field->attrsForm($input)->data(true); + $defaults = $field->attrsForm([])->data(true); $attrs = $field->attrsForm($defaults)->values(); $columns = $request->get('columns') ?? ['1/1']; @@ -158,79 +96,26 @@ class LayoutField extends BlocksField }, ]; - $routes[] = [ - 'pattern' => 'layout/paste', - 'method' => 'POST', - 'action' => function () use ($field): array { - $request = App::instance()->request(); - $value = Layouts::parse($request->get('json')); - $layouts = Layouts::factory($value); - - return $field->pasteLayouts($layouts->toArray()); - } - ]; - $routes[] = [ 'pattern' => 'fields/(:any)/(:all?)', 'method' => 'ALL', - 'action' => function ( - string $fieldName, - string $path = null - ) use ($field): array { + 'action' => function (string $fieldName, string $path = null) use ($field) { $form = $field->attrsForm(); $field = $form->field($fieldName); $fieldApi = $this->clone([ 'routes' => $field->api(), - 'data' => array_merge( - $this->data(), - ['field' => $field] - ) + 'data' => array_merge($this->data(), ['field' => $field]) ]); - return $fieldApi->call( - $path, - $this->requestMethod(), - $this->requestData() - ); + return $fieldApi->call($path, $this->requestMethod(), $this->requestData()); } ]; return $routes; } - public function selector(): array|null - { - return $this->selector; - } - - protected function setDefault(mixed $default = null): void - { - // set id for layouts, columns and blocks within layout if not exists - if (is_array($default) === true) { - array_walk($default, function (&$layout) { - $layout['id'] ??= Str::uuid(); - - // set columns id within layout - if (isset($layout['columns']) === true) { - array_walk($layout['columns'], function (&$column) { - $column['id'] ??= Str::uuid(); - - // set blocks id within column - if (isset($column['blocks']) === true) { - array_walk($column['blocks'], function (&$block) { - $block['id'] ??= Str::uuid(); - }); - } - }); - } - }); - } - - parent::setDefault($default); - } - - protected function setLayouts(array $layouts = []): void + protected function setLayouts(array $layouts = []) { $this->layouts = array_map( fn ($layout) => Str::split($layout), @@ -238,15 +123,7 @@ class LayoutField extends BlocksField ); } - /** - * Layout selector's styles such as size (`small`, `medium`, `large` or `huge`) and columns - */ - protected function setSelector(array|null $selector = null): void - { - $this->selector = $selector; - } - - protected function setSettings(array|string|null $settings = null): void + protected function setSettings($settings = null) { if (empty($settings) === true) { $this->settings = null; @@ -262,12 +139,12 @@ class LayoutField extends BlocksField $this->settings = Fieldset::factory($settings); } - public function settings(): Fieldset|null + public function settings() { return $this->settings; } - public function store(mixed $value): mixed + public function store($value) { $value = Layouts::factory($value, ['parent' => $this->model])->toArray(); @@ -301,9 +178,7 @@ class LayoutField extends BlocksField $layoutIndex++; // validate settings form - $form = $this->attrsForm($layout['attrs'] ?? []); - - foreach ($form->fields() as $field) { + foreach ($this->attrsForm($layout['attrs'] ?? [])->fields() as $field) { $errors = $field->errors(); if (empty($errors) === false) { @@ -325,9 +200,8 @@ class LayoutField extends BlocksField $blockType = $block['type']; try { - $fieldset = $this->fieldset($blockType); $blockFields = $fields[$blockType] ?? $this->fields($blockType) ?? []; - } catch (Throwable) { + } catch (Throwable $e) { // skip invalid blocks continue; } @@ -336,9 +210,7 @@ class LayoutField extends BlocksField $fields[$blockType] = $blockFields; // overwrite the content with the serialized form - $form = $this->form($blockFields, $block['content']); - - foreach ($form->fields() as $field) { + foreach ($this->form($blockFields, $block['content'])->fields() as $field) { $errors = $field->errors(); // rough first validation @@ -347,8 +219,6 @@ class LayoutField extends BlocksField 'key' => 'layout.validation.block', 'data' => [ 'blockIndex' => $blockIndex, - 'field' => $field->label(), - 'fieldset' => $fieldset->name(), 'layoutIndex' => $layoutIndex ] ]); diff --git a/kirby/src/Form/FieldClass.php b/kirby/src/Form/FieldClass.php index cc4115e..ed3804b 100644 --- a/kirby/src/Form/FieldClass.php +++ b/kirby/src/Form/FieldClass.php @@ -2,7 +2,6 @@ namespace Kirby\Form; -use Closure; use Exception; use Kirby\Cms\App; use Kirby\Cms\HasSiblings; @@ -27,27 +26,117 @@ abstract class FieldClass { use HasSiblings; - protected string|null $after; - protected bool $autofocus; - protected string|null $before; - protected mixed $default; - protected bool $disabled; - protected string|null $help; - protected string|null $icon; - protected string|null $label; - protected ModelWithContent $model; - protected string|null $name; - protected string|null $placeholder; - protected bool $required; - protected Fields $siblings; - protected bool $translate; - protected mixed $value = null; - protected array|null $when; - protected string|null $width; + /** + * @var string|null + */ + protected $after; + + /** + * @var bool + */ + protected $autofocus; + + /** + * @var string|null + */ + protected $before; + + /** + * @var mixed + */ + protected $default; + + /** + * @var bool + */ + protected $disabled; + + /** + * @var string|null + */ + protected $help; + + /** + * @var string|null + */ + protected $icon; + + /** + * @var string|null + */ + protected $label; + + /** + * @var \Kirby\Cms\ModelWithContent + */ + protected $model; + + /** + * @var string + */ + protected $name; + + /** + * @var array + */ + protected $params; + + /** + * @var string|null + */ + protected $placeholder; + + /** + * @var bool + */ + protected $required; + + /** + * @var \Kirby\Form\Fields + */ + protected $siblings; + + /** + * @var bool + */ + protected $translate; + + /** + * @var mixed + */ + protected $value; + + /** + * @var array|null + */ + protected $when; + + /** + * @var string|null + */ + protected $width; + + /** + * @param string $param + * @param array $args + * @return mixed + */ + public function __call(string $param, array $args) + { + if (isset($this->$param) === true) { + return $this->$param; + } + + return $this->params[$param] ?? null; + } + + /** + * @param array $params + */ + public function __construct(array $params = []) + { + $this->params = $params; - public function __construct( - protected array $params = [] - ) { $this->setAfter($params['after'] ?? null); $this->setAutofocus($params['autofocus'] ?? false); $this->setBefore($params['before'] ?? null); @@ -70,31 +159,34 @@ abstract class FieldClass } } - public function __call(string $param, array $args): mixed - { - if (isset($this->$param) === true) { - return $this->$param; - } - - return $this->params[$param] ?? null; - } - - public function after(): string|null + /** + * @return string|null + */ + public function after(): ?string { return $this->stringTemplate($this->after); } + /** + * @return array + */ public function api(): array { return $this->routes(); } + /** + * @return bool + */ public function autofocus(): bool { return $this->autofocus; } - public function before(): string|null + /** + * @return string|null + */ + public function before(): ?string { return $this->stringTemplate($this->before); } @@ -106,8 +198,11 @@ abstract class FieldClass * Returns the field data * in a format to be stored * in Kirby's content fields + * + * @param bool $default + * @return mixed */ - public function data(bool $default = false): mixed + public function data(bool $default = false) { return $this->store($this->value($default)); } @@ -115,8 +210,10 @@ abstract class FieldClass /** * Returns the default value for the field, * which will be used when a page/file/user is created + * + * @return mixed */ - public function default(): mixed + public function default() { if (is_string($this->default) === false) { return $this->default; @@ -125,33 +222,21 @@ abstract class FieldClass return $this->stringTemplate($this->default); } - /** - * Returns optional dialog routes for the field - */ - public function dialogs(): array - { - return []; - } - /** * If `true`, the field is no longer editable and will not be saved + * + * @return bool */ public function disabled(): bool { return $this->disabled; } - /** - * Returns optional drawer routes for the field - */ - public function drawers(): array - { - return []; - } - /** * Runs all validations and returns an array of * error messages + * + * @return array */ public function errors(): array { @@ -160,16 +245,21 @@ abstract class FieldClass /** * Setter for the value + * + * @param mixed $value + * @return void */ - public function fill(mixed $value = null): void + public function fill($value = null) { $this->value = $value; } /** * Optional help text below the field + * + * @return string|null */ - public function help(): string|null + public function help(): ?string { if (empty($this->help) === false) { $help = $this->stringTemplate($this->help); @@ -180,57 +270,79 @@ abstract class FieldClass return null; } - protected function i18n(string|array|null $param = null): string|null + /** + * @param string|array|null $param + * @return string|null + */ + protected function i18n($param = null): ?string { return empty($param) === false ? I18n::translate($param, $param) : null; } /** * Optional icon that will be shown at the end of the field + * + * @return string|null */ - public function icon(): string|null + public function icon(): ?string { return $this->icon; } + /** + * @return string + */ public function id(): string { return $this->name(); } + /** + * @return bool + */ public function isDisabled(): bool { return $this->disabled; } + /** + * @return bool + */ public function isEmpty(): bool { return $this->isEmptyValue($this->value()); } - public function isEmptyValue(mixed $value = null): bool + /** + * @param mixed $value + * @return bool + */ + public function isEmptyValue($value = null): bool { return in_array($value, [null, '', []], true); } - public function isHidden(): bool - { - return false; - } - /** * Checks if the field is invalid + * + * @return bool */ public function isInvalid(): bool { return $this->isValid() === false; } + /** + * @return bool + */ public function isRequired(): bool { return $this->required; } + /** + * @return bool + */ public function isSaveable(): bool { return true; @@ -238,6 +350,8 @@ abstract class FieldClass /** * Checks if the field is valid + * + * @return bool */ public function isValid(): bool { @@ -246,32 +360,38 @@ abstract class FieldClass /** * Returns the Kirby instance + * + * @return \Kirby\Cms\App */ - public function kirby(): App + public function kirby() { return $this->model->kirby(); } /** * The field label can be set as string or associative array with translations + * + * @return string */ public function label(): string { - return $this->stringTemplate( - $this->label ?? Str::ucfirst($this->name()) - ); + return $this->stringTemplate($this->label ?? Str::ucfirst($this->name())); } /** * Returns the parent model + * + * @return mixed */ - public function model(): ModelWithContent + public function model() { return $this->model; } /** * Returns the field name + * + * @return string */ public function name(): string { @@ -285,6 +405,8 @@ abstract class FieldClass * - The field is required * - The field is currently empty * - The field is not currently inactive because of a `when` rule + * + * @return bool */ protected function needsValue(): bool { @@ -298,20 +420,20 @@ abstract class FieldClass } // check the data of the relevant fields if there is a `when` option - if ( - empty($this->when) === false && - is_array($this->when) === true && - $formFields = $this->siblings() - ) { - foreach ($this->when as $field => $value) { - $field = $formFields->get($field); - $inputValue = $field?->value() ?? ''; + if (empty($this->when) === false && is_array($this->when) === true) { + $formFields = $this->siblings(); - // if the input data doesn't match the requested `when` value, - // that means that this field is not required and can be saved - // (*all* `when` conditions must be met for this field to be required) - if ($inputValue !== $value) { - return false; + if ($formFields !== null) { + foreach ($this->when as $field => $value) { + $field = $formFields->get($field); + $inputValue = $field !== null ? $field->value() : ''; + + // if the input data doesn't match the requested `when` value, + // that means that this field is not required and can be saved + // (*all* `when` conditions must be met for this field to be required) + if ($inputValue !== $value) { + return false; + } } } } @@ -322,6 +444,8 @@ abstract class FieldClass /** * Returns all original params for the field + * + * @return array */ public function params(): array { @@ -330,8 +454,10 @@ abstract class FieldClass /** * Optional placeholder value that will be shown when the field is empty + * + * @return string|null */ - public function placeholder(): string|null + public function placeholder(): ?string { return $this->stringTemplate($this->placeholder); } @@ -339,6 +465,8 @@ abstract class FieldClass /** * Define the props that will be sent to * the Vue component + * + * @return array */ public function props(): array { @@ -349,7 +477,6 @@ abstract class FieldClass 'default' => $this->default(), 'disabled' => $this->isDisabled(), 'help' => $this->help(), - 'hidden' => $this->isHidden(), 'icon' => $this->icon(), 'label' => $this->label(), 'name' => $this->name(), @@ -365,6 +492,8 @@ abstract class FieldClass /** * If `true`, the field has to be filled in correctly to be saved. + * + * @return bool */ public function required(): bool { @@ -373,6 +502,8 @@ abstract class FieldClass /** * Routes for the field API + * + * @return array */ public function routes(): array { @@ -382,110 +513,178 @@ abstract class FieldClass /** * @deprecated 3.5.0 * @todo remove when the general field class setup has been refactored + * @return bool */ - public function save(): bool + public function save() { return $this->isSaveable(); } - protected function setAfter(array|string|null $after = null): void + /** + * @param array|string|null $after + * @return void + */ + protected function setAfter($after = null) { $this->after = $this->i18n($after); } - protected function setAutofocus(bool $autofocus = false): void + /** + * @param bool $autofocus + * @return void + */ + protected function setAutofocus(bool $autofocus = false) { $this->autofocus = $autofocus; } - protected function setBefore(array|string|null $before = null): void + /** + * @param array|string|null $before + * @return void + */ + protected function setBefore($before = null) { $this->before = $this->i18n($before); } - protected function setDefault(mixed $default = null): void + /** + * @param mixed $default + * @return void + */ + protected function setDefault($default = null) { $this->default = $default; } - protected function setDisabled(bool $disabled = false): void + /** + * @param bool $disabled + * @return void + */ + protected function setDisabled(bool $disabled = false) { $this->disabled = $disabled; } - protected function setHelp(array|string|null $help = null): void + /** + * @param array|string|null $help + * @return void + */ + protected function setHelp($help = null) { $this->help = $this->i18n($help); } - protected function setIcon(string|null $icon = null): void + /** + * @param string|null $icon + * @return void + */ + protected function setIcon(?string $icon = null) { $this->icon = $icon; } - protected function setLabel(array|string|null $label = null): void + /** + * @param array|string|null $label + * @return void + */ + protected function setLabel($label = null) { $this->label = $this->i18n($label); } - protected function setModel(ModelWithContent $model): void + /** + * @param \Kirby\Cms\ModelWithContent $model + * @return void + */ + protected function setModel(ModelWithContent $model) { $this->model = $model; } - protected function setName(string|null $name = null): void + /** + * @param string|null $name + * @return void + */ + protected function setName(string $name = null) { $this->name = $name; } - protected function setPlaceholder(array|string|null $placeholder = null): void + /** + * @param array|string|null $placeholder + * @return void + */ + protected function setPlaceholder($placeholder = null) { $this->placeholder = $this->i18n($placeholder); } - protected function setRequired(bool $required = false): void + /** + * @param bool $required + * @return void + */ + protected function setRequired(bool $required = false) { $this->required = $required; } - protected function setSiblings(Fields|null $siblings = null): void + /** + * @param \Kirby\Form\Fields|null $siblings + * @return void + */ + protected function setSiblings(?Fields $siblings = null) { $this->siblings = $siblings ?? new Fields([$this]); } - protected function setTranslate(bool $translate = true): void + /** + * @param bool $translate + * @return void + */ + protected function setTranslate(bool $translate = true) { $this->translate = $translate; } /** * Setter for the when condition + * + * @param mixed $when + * @return void */ - protected function setWhen(array|null $when = null): void + protected function setWhen($when = null) { $this->when = $when; } /** * Setter for the field width + * + * @param string|null $width + * @return void */ - protected function setWidth(string|null $width = null): void + protected function setWidth(string $width = null) { $this->width = $width; } /** * Returns all sibling fields + * + * @return \Kirby\Form\Fields */ - protected function siblingsCollection(): Fields + protected function siblingsCollection() { return $this->siblings; } /** * Parses a string template in the given value + * + * @param string|null $string + * @return string|null */ - protected function stringTemplate(string|null $string = null): string|null + protected function stringTemplate(?string $string = null): ?string { if ($string !== null) { return $this->model->toString($string); @@ -497,14 +696,19 @@ abstract class FieldClass /** * Converts the given value to a value * that can be stored in the text file + * + * @param mixed $value + * @return mixed */ - public function store(mixed $value): mixed + public function store($value) { return $value; } /** * Should the field be translatable? + * + * @return bool */ public function translate(): bool { @@ -513,6 +717,8 @@ abstract class FieldClass /** * Converts the field to a plain array + * + * @return array */ public function toArray(): array { @@ -526,6 +732,8 @@ abstract class FieldClass /** * Returns the field type + * + * @return string */ public function type(): string { @@ -534,6 +742,8 @@ abstract class FieldClass /** * Runs the validations defined for the field + * + * @return array */ protected function validate(): array { @@ -557,7 +767,7 @@ abstract class FieldClass continue; } - if ($validation instanceof Closure) { + if (is_a($validation, 'Closure') === true) { try { $validation->call($this, $value); } catch (Exception $e) { @@ -571,7 +781,8 @@ abstract class FieldClass /** * Defines all validation rules - * @codeCoverageIgnore + * + * @return array */ protected function validations(): array { @@ -581,8 +792,10 @@ abstract class FieldClass /** * Returns the value of the field if saveable * otherwise it returns null + * + * @return mixed */ - public function value(bool $default = false): mixed + public function value(bool $default = false) { if ($this->isSaveable() === false) { return null; @@ -595,33 +808,46 @@ abstract class FieldClass return $this->value; } - protected function valueFromJson(mixed $value): array + /** + * @param mixed $value + * @return array + */ + protected function valueFromJson($value): array { try { return Data::decode($value, 'json'); - } catch (Throwable) { + } catch (Throwable $e) { return []; } } - protected function valueFromYaml(mixed $value): array + /** + * @param mixed $value + * @return array + */ + protected function valueFromYaml($value): array { return Data::decode($value, 'yaml'); } - protected function valueToJson( - array $value = null, - bool $pretty = false - ): string { - $constants = JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE; - + /** + * @param array|null $value + * @param bool $pretty + * @return string + */ + protected function valueToJson(array $value = null, bool $pretty = false): string + { if ($pretty === true) { - $constants |= JSON_PRETTY_PRINT; + return json_encode($value, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE); } - return json_encode($value, $constants); + return json_encode($value); } + /** + * @param array|null $value + * @return string + */ protected function valueToYaml(array $value = null): string { return Data::encode($value, 'yaml'); @@ -629,8 +855,10 @@ abstract class FieldClass /** * Conditions when the field will be shown + * + * @return array|null */ - public function when(): array|null + public function when(): ?array { return $this->when; } @@ -638,6 +866,8 @@ abstract class FieldClass /** * Returns the width of the field in * the Panel grid + * + * @return string */ public function width(): string { diff --git a/kirby/src/Form/Fields.php b/kirby/src/Form/Fields.php index ef46f2e..9abd199 100644 --- a/kirby/src/Form/Fields.php +++ b/kirby/src/Form/Fields.php @@ -21,7 +21,9 @@ class Fields extends Collection * This takes care of validation and of setting * the collection prop on each object correctly. * + * @param string $name * @param object|array $field + * @return void */ public function __set(string $name, $field): void { @@ -38,6 +40,9 @@ class Fields extends Collection * Converts the fields collection to an * array and also does that for every * included field. + * + * @param \Closure|null $map + * @return array */ public function toArray(Closure $map = null): array { diff --git a/kirby/src/Form/Form.php b/kirby/src/Form/Form.php index adec4f3..5935ced 100644 --- a/kirby/src/Form/Form.php +++ b/kirby/src/Form/Form.php @@ -2,13 +2,10 @@ namespace Kirby\Form; -use Closure; use Kirby\Cms\App; -use Kirby\Cms\File; -use Kirby\Cms\ModelWithContent; +use Kirby\Cms\Model; use Kirby\Data\Data; use Kirby\Exception\NotFoundException; -use Kirby\Toolkit\A; use Kirby\Toolkit\Str; use Throwable; @@ -28,21 +25,29 @@ class Form { /** * An array of all found errors + * + * @var array|null */ - protected array|null $errors = null; + protected $errors; /** * Fields in the form + * + * @var \Kirby\Form\Fields|null */ - protected Fields|null $fields; + protected $fields; /** * All values of form + * + * @var array */ - protected array $values = []; + protected $values = []; /** * Form constructor + * + * @param array $props */ public function __construct(array $props) { @@ -74,12 +79,15 @@ class Form // inject the name $props['name'] = $name = strtolower($name); - // check if the field is disabled and + // check if the field is disabled + $disabled = $props['disabled'] ?? false; + // overwrite the field value if not set - $props['value'] = match ($props['disabled'] ?? false) { - true => $values[$name] ?? null, - default => $input[$name] ?? $values[$name] ?? null - }; + if ($disabled === true) { + $props['value'] = $values[$name] ?? null; + } else { + $props['value'] = $input[$name] ?? $values[$name] ?? null; + } try { $field = Field::factory($props['type'], $props, $this->fields); @@ -100,7 +108,9 @@ class Form $input = array_merge($values, $input); foreach ($input as $key => $value) { - $this->values[$key] ??= $value; + if (isset($this->values[$key]) === false) { + $this->values[$key] = $value; + } } } } @@ -108,6 +118,8 @@ class Form /** * Returns the data required to write to the content file * Doesn't include default and null values + * + * @return array */ public function content(): array { @@ -118,6 +130,8 @@ class Form * Returns data for all fields in the form * * @param false $defaults + * @param bool $includeNulls + * @return array */ public function data($defaults = false, bool $includeNulls = true): array { @@ -140,6 +154,8 @@ class Form /** * An array of all found errors + * + * @return array */ public function errors(): array { @@ -163,16 +179,17 @@ class Form /** * Shows the error with the field + * + * @param \Throwable $exception + * @param array $props + * @return \Kirby\Form\Field */ - public static function exceptionField( - Throwable $exception, - array $props = [] - ): Field { + public static function exceptionField(Throwable $exception, array $props = []) + { $message = $exception->getMessage(); if (App::instance()->option('debug') === true) { - $message .= ' in file: ' . $exception->getFile(); - $message .= ' line: ' . $exception->getLine(); + $message .= ' in file: ' . $exception->getFile() . ' line: ' . $exception->getLine(); } $props = array_merge($props, [ @@ -188,9 +205,11 @@ class Form * Get the field object by name * and handle nested fields correctly * + * @param string $name * @throws \Kirby\Exception\NotFoundException + * @return \Kirby\Form\Field */ - public function field(string $name): Field|FieldClass + public function field(string $name) { $form = $this; $fieldNames = Str::split($name, '+'); @@ -205,11 +224,9 @@ class Form if ($count !== $index) { $form = $field->form(); } - - continue; + } else { + throw new NotFoundException('The field "' . $fieldName . '" could not be found'); } - - throw new NotFoundException('The field "' . $fieldName . '" could not be found'); } // it can get this error only if $name is an empty string as $name = '' @@ -222,23 +239,28 @@ class Form /** * Returns form fields + * + * @return \Kirby\Form\Fields|null */ - public function fields(): Fields|null + public function fields() { return $this->fields; } - public static function for( - ModelWithContent $model, - array $props = [] - ): static { + /** + * @param \Kirby\Cms\Model $model + * @param array $props + * @return static + */ + public static function for(Model $model, array $props = []) + { // get the original model data $original = $model->content($props['language'] ?? null)->toArray(); $values = $props['values'] ?? []; // convert closures to values foreach ($values as $key => $value) { - if ($value instanceof Closure) { + if (is_a($value, 'Closure') === true) { $values[$key] = $value($original[$key] ?? null); } } @@ -249,10 +271,7 @@ class Form $props['model'] = $model; // search for the blueprint - if ( - method_exists($model, 'blueprint') === true && - $blueprint = $model->blueprint() - ) { + if (method_exists($model, 'blueprint') === true && $blueprint = $model->blueprint()) { $props['fields'] = $blueprint->fields(); } @@ -271,14 +290,18 @@ class Form /** * Checks if the form is invalid + * + * @return bool */ public function isInvalid(): bool { - return $this->isValid() === false; + return empty($this->errors()) === false; } /** * Checks if the form is valid + * + * @return bool */ public function isValid(): bool { @@ -288,19 +311,23 @@ class Form /** * Disables fields in secondary languages when * they are configured to be untranslatable + * + * @param array $fields + * @param string|null $language + * @return array */ - protected static function prepareFieldsForLanguage( - array $fields, - string|null $language = null - ): array { + protected static function prepareFieldsForLanguage(array $fields, ?string $language = null): array + { $kirby = App::instance(null, true); // only modify the fields if we have a valid Kirby multilang instance - if ($kirby?->multilang() !== true) { + if (!$kirby || $kirby->multilang() === false) { return $fields; } - $language ??= $kirby->language()->code(); + if ($language === null) { + $language = $kirby->language()->code(); + } if ($language !== $kirby->defaultLanguage()->code()) { foreach ($fields as $fieldName => $fieldProps) { @@ -319,20 +346,29 @@ class Form * Converts the data of fields to strings * * @param false $defaults + * @return array */ public function strings($defaults = false): array { - return A::map( - $this->data($defaults), - fn ($value) => match (true) { - is_array($value) => Data::encode($value, 'yaml'), - default => $value + $strings = []; + + foreach ($this->data($defaults) as $key => $value) { + if ($value === null) { + $strings[$key] = null; + } elseif (is_array($value) === true) { + $strings[$key] = Data::encode($value, 'yaml'); + } else { + $strings[$key] = $value; } - ); + } + + return $strings; } /** * Converts the form to a plain array + * + * @return array */ public function toArray(): array { @@ -347,6 +383,8 @@ class Form /** * Returns form values + * + * @return array */ public function values(): array { diff --git a/kirby/src/Form/Mixin/EmptyState.php b/kirby/src/Form/Mixin/EmptyState.php index 6f7d72a..782acaa 100644 --- a/kirby/src/Form/Mixin/EmptyState.php +++ b/kirby/src/Form/Mixin/EmptyState.php @@ -4,14 +4,14 @@ namespace Kirby\Form\Mixin; trait EmptyState { - protected string|null $empty; + protected $empty; - protected function setEmpty(string|array|null $empty = null): void + protected function setEmpty($empty = null) { $this->empty = $this->i18n($empty); } - public function empty(): string|null + public function empty(): ?string { return $this->stringTemplate($this->empty); } diff --git a/kirby/src/Form/Mixin/Max.php b/kirby/src/Form/Mixin/Max.php index 3141bbe..b02825e 100644 --- a/kirby/src/Form/Mixin/Max.php +++ b/kirby/src/Form/Mixin/Max.php @@ -4,9 +4,9 @@ namespace Kirby\Form\Mixin; trait Max { - protected int|null $max; + protected $max; - public function max(): int|null + public function max(): ?int { return $this->max; } diff --git a/kirby/src/Form/Mixin/Min.php b/kirby/src/Form/Mixin/Min.php index 1b585e1..46a8d87 100644 --- a/kirby/src/Form/Mixin/Min.php +++ b/kirby/src/Form/Mixin/Min.php @@ -4,9 +4,9 @@ namespace Kirby\Form\Mixin; trait Min { - protected int|null $min; + protected $min; - public function min(): int|null + public function min(): ?int { return $this->min; } diff --git a/kirby/src/Form/Options.php b/kirby/src/Form/Options.php new file mode 100644 index 0000000..4873b88 --- /dev/null +++ b/kirby/src/Form/Options.php @@ -0,0 +1,210 @@ + + * @link https://getkirby.com + * @copyright Bastian Allgeier + * @license https://opensource.org/licenses/MIT + */ +class Options +{ + /** + * Returns the classes of predefined Kirby objects + * + * @return array + */ + protected static function aliases(): array + { + return [ + 'Kirby\Cms\File' => 'file', + 'Kirby\Toolkit\Obj' => 'arrayItem', + 'Kirby\Cms\Block' => 'block', + 'Kirby\Cms\Page' => 'page', + 'Kirby\Cms\StructureObject' => 'structureItem', + 'Kirby\Cms\User' => 'user', + ]; + } + + /** + * Brings options through api + * + * @param $api + * @param \Kirby\Cms\Model|null $model + * @return array + */ + public static function api($api, $model = null): array + { + $model ??= App::instance()->site(); + $fetch = null; + $text = null; + $value = null; + + if (is_array($api) === true) { + $fetch = $api['fetch'] ?? null; + $text = $api['text'] ?? null; + $value = $api['value'] ?? null; + $url = $api['url'] ?? null; + } else { + $url = $api; + } + + $optionsApi = new OptionsApi([ + 'data' => static::data($model), + 'fetch' => $fetch, + 'url' => $url, + 'text' => $text, + 'value' => $value + ]); + + return $optionsApi->options(); + } + + /** + * @param \Kirby\Cms\Model $model + * @return array + */ + protected static function data($model): array + { + $kirby = $model->kirby(); + + // default data setup + $data = [ + 'kirby' => $kirby, + 'site' => $kirby->site(), + 'users' => $kirby->users(), + ]; + + // add the model by the proper alias + foreach (static::aliases() as $className => $alias) { + if (is_a($model, $className) === true) { + $data[$alias] = $model; + } + } + + return $data; + } + + /** + * Brings options by supporting both api and query + * + * @param $options + * @param array $props + * @param \Kirby\Cms\Model|null $model + * @return array + */ + public static function factory($options, array $props = [], $model = null): array + { + switch ($options) { + case 'api': + $options = static::api($props['api'], $model); + break; + case 'query': + $options = static::query($props['query'], $model); + break; + case 'children': + case 'grandChildren': + case 'siblings': + case 'index': + case 'files': + case 'images': + case 'documents': + case 'videos': + case 'audio': + case 'code': + case 'archives': + $options = static::query('page.' . $options, $model); + break; + case 'pages': + $options = static::query('site.index', $model); + break; + } + + if (is_array($options) === false) { + return []; + } + + $result = []; + + foreach ($options as $key => $option) { + if (is_array($option) === false || isset($option['value']) === false) { + $option = [ + 'value' => is_int($key) ? $option : $key, + 'text' => $option + ]; + } + + // fallback for the text + $option['text'] ??= $option['value']; + + // translate the option text + if (is_array($option['text']) === true) { + $option['text'] = I18n::translate($option['text'], $option['text']); + } + + // add the option to the list + $result[] = $option; + } + + return $result; + } + + /** + * Brings options with query + * + * @param $query + * @param \Kirby\Cms\Model|null $model + * @return array + */ + public static function query($query, $model = null): array + { + $model ??= App::instance()->site(); + + // default text setup + $text = [ + 'arrayItem' => '{{ arrayItem.value }}', + 'block' => '{{ block.type }}: {{ block.id }}', + 'file' => '{{ file.filename }}', + 'page' => '{{ page.title }}', + 'structureItem' => '{{ structureItem.title }}', + 'user' => '{{ user.username }}', + ]; + + // default value setup + $value = [ + 'arrayItem' => '{{ arrayItem.value }}', + 'block' => '{{ block.id }}', + 'file' => '{{ file.id }}', + 'page' => '{{ page.id }}', + 'structureItem' => '{{ structureItem.id }}', + 'user' => '{{ user.email }}', + ]; + + // resolve array query setup + if (is_array($query) === true) { + $text = $query['text'] ?? $text; + $value = $query['value'] ?? $value; + $query = $query['fetch'] ?? null; + } + + $optionsQuery = new OptionsQuery([ + 'aliases' => static::aliases(), + 'data' => static::data($model), + 'query' => $query, + 'text' => $text, + 'value' => $value + ]); + + return $optionsQuery->options(); + } +} diff --git a/kirby/src/Form/OptionsApi.php b/kirby/src/Form/OptionsApi.php new file mode 100644 index 0000000..c4df0b4 --- /dev/null +++ b/kirby/src/Form/OptionsApi.php @@ -0,0 +1,242 @@ + + * @link https://getkirby.com + * @copyright Bastian Allgeier + * @license https://opensource.org/licenses/MIT + */ +class OptionsApi +{ + use Properties; + + /** + * @var array + */ + protected $data; + + /** + * @var string|null + */ + protected $fetch; + + /** + * @var array|string|null + */ + protected $options; + + /** + * @var string + */ + protected $text = '{{ item.value }}'; + + /** + * @var string + */ + protected $url; + + /** + * @var string + */ + protected $value = '{{ item.key }}'; + + /** + * OptionsApi constructor + * + * @param array $props + */ + public function __construct(array $props) + { + $this->setProperties($props); + } + + /** + * @return array + */ + public function data(): array + { + return $this->data; + } + + /** + * @return mixed + */ + public function fetch() + { + return $this->fetch; + } + + /** + * @param string $field + * @param array $data + * @return string + */ + protected function field(string $field, array $data): string + { + $value = $this->$field(); + return Str::safeTemplate($value, $data); + } + + /** + * @return array + * @throws \Exception + * @throws \Kirby\Exception\InvalidArgumentException + */ + public function options(): array + { + if (is_array($this->options) === true) { + return $this->options; + } + + if (Url::isAbsolute($this->url()) === true) { + // URL, request via cURL + $data = Remote::get($this->url())->json(); + } else { + // local file, get contents locally + + // ensure the file exists before trying to load it as the + // file_get_contents() warnings need to be suppressed + if (is_file($this->url()) !== true) { + throw new Exception('Local file ' . $this->url() . ' was not found'); + } + + $content = @file_get_contents($this->url()); + + if (is_string($content) !== true) { + throw new Exception('Unexpected read error'); // @codeCoverageIgnore + } + + if (empty($content) === true) { + return []; + } + + $data = json_decode($content, true); + } + + if (is_array($data) === false) { + throw new InvalidArgumentException('Invalid options format'); + } + + $result = (new Query($this->fetch(), Nest::create($data)))->result(); + $options = []; + + foreach ($result as $item) { + $data = array_merge($this->data(), ['item' => $item]); + + $options[] = [ + 'text' => $this->field('text', $data), + 'value' => $this->field('value', $data), + ]; + } + + return $options; + } + + /** + * @param array $data + * @return $this + */ + protected function setData(array $data) + { + $this->data = $data; + return $this; + } + + /** + * @param string|null $fetch + * @return $this + */ + protected function setFetch(?string $fetch = null) + { + $this->fetch = $fetch; + return $this; + } + + /** + * @param array|string|null $options + * @return $this + */ + protected function setOptions($options = null) + { + $this->options = $options; + return $this; + } + + /** + * @param string $text + * @return $this + */ + protected function setText(?string $text = null) + { + $this->text = $text; + return $this; + } + + /** + * @param string $url + * @return $this + */ + protected function setUrl(string $url) + { + $this->url = $url; + return $this; + } + + /** + * @param string|null $value + * @return $this + */ + protected function setValue(?string $value = null) + { + $this->value = $value; + return $this; + } + + /** + * @return string + */ + public function text(): string + { + return $this->text; + } + + /** + * @return array + * @throws \Kirby\Exception\InvalidArgumentException + */ + public function toArray(): array + { + return $this->options(); + } + + /** + * @return string + */ + public function url(): string + { + return Str::template($this->url, $this->data()); + } + + /** + * @return string + */ + public function value(): string + { + return $this->value; + } +} diff --git a/kirby/src/Form/OptionsQuery.php b/kirby/src/Form/OptionsQuery.php new file mode 100644 index 0000000..c91ac64 --- /dev/null +++ b/kirby/src/Form/OptionsQuery.php @@ -0,0 +1,271 @@ + + * @link https://getkirby.com + * @copyright Bastian Allgeier + * @license https://opensource.org/licenses/MIT + */ +class OptionsQuery +{ + use Properties; + + /** + * @var array + */ + protected $aliases = []; + + /** + * @var array + */ + protected $data; + + /** + * @var array|string|null + */ + protected $options; + + /** + * @var string + */ + protected $query; + + /** + * @var mixed + */ + protected $text; + + /** + * @var mixed + */ + protected $value; + + /** + * OptionsQuery constructor + * + * @param array $props + */ + public function __construct(array $props) + { + $this->setProperties($props); + } + + /** + * @return array + */ + public function aliases(): array + { + return $this->aliases; + } + + /** + * @return array + */ + public function data(): array + { + return $this->data; + } + + /** + * @param string $object + * @param string $field + * @param array $data + * @return string + * @throws \Kirby\Exception\NotFoundException + */ + protected function template(string $object, string $field, array $data) + { + $value = $this->$field(); + + if (is_array($value) === true) { + if (isset($value[$object]) === false) { + throw new NotFoundException('Missing "' . $field . '" definition'); + } + + $value = $value[$object]; + } + + return Str::safeTemplate($value, $data); + } + + /** + * @return array + */ + public function options(): array + { + if (is_array($this->options) === true) { + return $this->options; + } + + $data = $this->data(); + $query = new Query($this->query(), $data); + $result = $query->result(); + $result = $this->resultToCollection($result); + $options = []; + + foreach ($result as $item) { + $alias = $this->resolve($item); + $data = array_merge($data, [$alias => $item]); + + $options[] = [ + 'text' => $this->template($alias, 'text', $data), + 'value' => $this->template($alias, 'value', $data) + ]; + } + + return $this->options = $options; + } + + /** + * @return string + */ + public function query(): string + { + return $this->query; + } + + /** + * @param $object + * @return mixed|string|null + */ + public function resolve($object) + { + // fast access + if ($alias = ($this->aliases[get_class($object)] ?? null)) { + return $alias; + } + + // slow but precise resolving + foreach ($this->aliases as $className => $alias) { + if (is_a($object, $className) === true) { + return $alias; + } + } + + return 'item'; + } + + /** + * @param $result + * @throws \Kirby\Exception\InvalidArgumentException + */ + protected function resultToCollection($result) + { + if (is_array($result)) { + foreach ($result as $key => $item) { + if (is_scalar($item) === true) { + $result[$key] = new Obj([ + 'key' => new Field(null, 'key', $key), + 'value' => new Field(null, 'value', $item), + ]); + } + } + + $result = new Collection($result); + } + + if (is_a($result, 'Kirby\Toolkit\Collection') === false) { + throw new InvalidArgumentException('Invalid query result data'); + } + + return $result; + } + + /** + * @param array|null $aliases + * @return $this + */ + protected function setAliases(?array $aliases = null) + { + $this->aliases = $aliases; + return $this; + } + + /** + * @param array $data + * @return $this + */ + protected function setData(array $data) + { + $this->data = $data; + return $this; + } + + /** + * @param array|string|null $options + * @return $this + */ + protected function setOptions($options = null) + { + $this->options = $options; + return $this; + } + + /** + * @param string $query + * @return $this + */ + protected function setQuery(string $query) + { + $this->query = $query; + return $this; + } + + /** + * @param mixed $text + * @return $this + */ + protected function setText($text) + { + $this->text = $text; + return $this; + } + + /** + * @param mixed $value + * @return $this + */ + protected function setValue($value) + { + $this->value = $value; + return $this; + } + + /** + * @return mixed + */ + public function text() + { + return $this->text; + } + + public function toArray(): array + { + return $this->options(); + } + + /** + * @return mixed + */ + public function value() + { + return $this->value; + } +} diff --git a/kirby/src/Form/Validations.php b/kirby/src/Form/Validations.php index 7f0a539..5834624 100644 --- a/kirby/src/Form/Validations.php +++ b/kirby/src/Form/Validations.php @@ -20,6 +20,8 @@ class Validations * Validates if the field value is boolean * * @param \Kirby\Form\Field|\Kirby\Form\FieldClass $field + * @param $value + * @return bool * @throws \Kirby\Exception\InvalidArgumentException */ public static function boolean($field, $value): bool @@ -38,9 +40,12 @@ class Validations /** * Validates if the field value is valid date * + * @param \Kirby\Form\Field|\Kirby\Form\FieldClass $field + * @param $value + * @return bool * @throws \Kirby\Exception\InvalidArgumentException */ - public static function date(Field|FieldClass $field, mixed $value): bool + public static function date($field, $value): bool { if ($field->isEmpty($value) === false) { if (V::date($value) !== true) { @@ -56,9 +61,12 @@ class Validations /** * Validates if the field value is valid email * + * @param \Kirby\Form\Field|\Kirby\Form\FieldClass $field + * @param $value + * @return bool * @throws \Kirby\Exception\InvalidArgumentException */ - public static function email(Field|FieldClass $field, mixed $value): bool + public static function email($field, $value): bool { if ($field->isEmpty($value) === false) { if (V::email($value) === false) { @@ -74,14 +82,14 @@ class Validations /** * Validates if the field value is maximum * + * @param \Kirby\Form\Field|\Kirby\Form\FieldClass $field + * @param $value + * @return bool * @throws \Kirby\Exception\InvalidArgumentException */ - public static function max(Field|FieldClass $field, mixed $value): bool + public static function max($field, $value): bool { - if ( - $field->isEmpty($value) === false && - $field->max() !== null - ) { + if ($field->isEmpty($value) === false && $field->max() !== null) { if (V::max($value, $field->max()) === false) { throw new InvalidArgumentException( V::message('max', $value, $field->max()) @@ -95,14 +103,14 @@ class Validations /** * Validates if the field value is max length * + * @param \Kirby\Form\Field|\Kirby\Form\FieldClass $field + * @param $value + * @return bool * @throws \Kirby\Exception\InvalidArgumentException */ - public static function maxlength(Field|FieldClass $field, mixed $value): bool + public static function maxlength($field, $value): bool { - if ( - $field->isEmpty($value) === false && - $field->maxlength() !== null - ) { + if ($field->isEmpty($value) === false && $field->maxlength() !== null) { if (V::maxLength($value, $field->maxlength()) === false) { throw new InvalidArgumentException( V::message('maxlength', $value, $field->maxlength()) @@ -116,14 +124,14 @@ class Validations /** * Validates if the field value is minimum * + * @param \Kirby\Form\Field|\Kirby\Form\FieldClass $field + * @param $value + * @return bool * @throws \Kirby\Exception\InvalidArgumentException */ - public static function min(Field|FieldClass $field, mixed $value): bool + public static function min($field, $value): bool { - if ( - $field->isEmpty($value) === false && - $field->min() !== null - ) { + if ($field->isEmpty($value) === false && $field->min() !== null) { if (V::min($value, $field->min()) === false) { throw new InvalidArgumentException( V::message('min', $value, $field->min()) @@ -137,14 +145,14 @@ class Validations /** * Validates if the field value is min length * + * @param \Kirby\Form\Field|\Kirby\Form\FieldClass $field + * @param $value + * @return bool * @throws \Kirby\Exception\InvalidArgumentException */ - public static function minlength(Field|FieldClass $field, mixed $value): bool + public static function minlength($field, $value): bool { - if ( - $field->isEmpty($value) === false && - $field->minlength() !== null - ) { + if ($field->isEmpty($value) === false && $field->minlength() !== null) { if (V::minLength($value, $field->minlength()) === false) { throw new InvalidArgumentException( V::message('minlength', $value, $field->minlength()) @@ -158,9 +166,12 @@ class Validations /** * Validates if the field value matches defined pattern * + * @param \Kirby\Form\Field|\Kirby\Form\FieldClass $field + * @param $value + * @return bool * @throws \Kirby\Exception\InvalidArgumentException */ - public static function pattern(Field|FieldClass $field, mixed $value): bool + public static function pattern($field, $value): bool { if ($field->isEmpty($value) === false && $field->pattern() !== null) { if (V::match($value, '/' . $field->pattern() . '/i') === false) { @@ -176,15 +187,14 @@ class Validations /** * Validates if the field value is required * + * @param \Kirby\Form\Field|\Kirby\Form\FieldClass $field + * @param $value + * @return bool * @throws \Kirby\Exception\InvalidArgumentException */ - public static function required(Field|FieldClass $field, mixed $value): bool + public static function required($field, $value): bool { - if ( - $field->isRequired() === true && - $field->save() === true && - $field->isEmpty($value) === true - ) { + if ($field->isRequired() === true && $field->save() === true && $field->isEmpty($value) === true) { throw new InvalidArgumentException([ 'key' => 'validation.required' ]); @@ -196,9 +206,12 @@ class Validations /** * Validates if the field value is in defined options * + * @param \Kirby\Form\Field|\Kirby\Form\FieldClass $field + * @param $value + * @return bool * @throws \Kirby\Exception\InvalidArgumentException */ - public static function option(Field|FieldClass $field, mixed $value): bool + public static function option($field, $value): bool { if ($field->isEmpty($value) === false) { $values = array_column($field->options(), 'value'); @@ -216,9 +229,12 @@ class Validations /** * Validates if the field values is in defined options * + * @param \Kirby\Form\Field|\Kirby\Form\FieldClass $field + * @param $value + * @return bool * @throws \Kirby\Exception\InvalidArgumentException */ - public static function options(Field|FieldClass $field, mixed $value): bool + public static function options($field, $value): bool { if ($field->isEmpty($value) === false) { $values = array_column($field->options(), 'value'); @@ -237,9 +253,12 @@ class Validations /** * Validates if the field value is valid time * + * @param \Kirby\Form\Field|\Kirby\Form\FieldClass $field + * @param $value + * @return bool * @throws \Kirby\Exception\InvalidArgumentException */ - public static function time(Field|FieldClass $field, mixed $value): bool + public static function time($field, $value): bool { if ($field->isEmpty($value) === false) { if (V::time($value) !== true) { @@ -255,9 +274,12 @@ class Validations /** * Validates if the field value is valid url * + * @param \Kirby\Form\Field|\Kirby\Form\FieldClass $field + * @param $value + * @return bool * @throws \Kirby\Exception\InvalidArgumentException */ - public static function url(Field|FieldClass $field, mixed $value): bool + public static function url($field, $value): bool { if ($field->isEmpty($value) === false) { if (V::url($value) === false) { diff --git a/kirby/src/Http/Cookie.php b/kirby/src/Http/Cookie.php index a44b752..b63c606 100644 --- a/kirby/src/Http/Cookie.php +++ b/kirby/src/Http/Cookie.php @@ -19,8 +19,9 @@ class Cookie { /** * Key to use for cookie signing + * @var string */ - public static string $key = 'KirbyHttpCookieKey'; + public static $key = 'KirbyHttpCookieKey'; /** * Set a new cookie @@ -39,11 +40,8 @@ class Cookie * @return bool true: cookie was created, * false: cookie creation failed */ - public static function set( - string $key, - string $value, - array $options = [] - ): bool { + public static function set(string $key, string $value, array $options = []): bool + { // modify CMS caching behavior static::trackUsage($key); @@ -62,31 +60,27 @@ class Cookie $_COOKIE[$key] = $value; // store the cookie - return setcookie( - $key, - $value, - compact('expires', 'path', 'domain', 'secure', 'httponly', 'samesite') - ); + $options = compact('expires', 'path', 'domain', 'secure', 'httponly', 'samesite'); + return setcookie($key, $value, $options); } /** * Calculates the lifetime for a cookie * * @param int $minutes Number of minutes or timestamp + * @return int */ public static function lifetime(int $minutes): int { - // absolute timestamp if ($minutes > 1000000000) { + // absolute timestamp return $minutes; - } - - // minutes from now - if ($minutes > 0) { + } elseif ($minutes > 0) { + // minutes from now return time() + ($minutes * 60); + } else { + return 0; } - - return 0; } /** @@ -106,11 +100,8 @@ class Cookie * @return bool true: cookie was created, * false: cookie creation failed */ - public static function forever( - string $key, - string $value, - array $options = [] - ): bool { + public static function forever(string $key, string $value, array $options = []): bool + { // 9999-12-31 if supported (lower on 32-bit servers) $options['lifetime'] = min(253402214400, PHP_INT_MAX); return static::set($key, $value, $options); @@ -120,19 +111,19 @@ class Cookie * Get a cookie value * * + * * cookie::get('mycookie', 'peter'); * // sample output: 'hello' or if the cookie is not set 'peter' + * * * * @param string|null $key The name of the cookie * @param string|null $default The default value, which should be returned * if the cookie has not been found - * @return string|array|null The found value + * @return mixed The found value */ - public static function get( - string|null $key = null, - string|null $default = null - ): string|array|null { + public static function get(string $key = null, string $default = null) + { if ($key === null) { return $_COOKIE; } @@ -140,15 +131,15 @@ class Cookie // modify CMS caching behavior static::trackUsage($key); - if ($value = $_COOKIE[$key] ?? null) { - return static::parse($value); - } - - return $default; + $value = $_COOKIE[$key] ?? null; + return empty($value) ? $default : static::parse($value); } /** * Checks if a cookie exists + * + * @param string $key + * @return bool */ public static function exists(string $key): bool { @@ -158,6 +149,9 @@ class Cookie /** * Creates a HMAC for the cookie value * Used as a cookie signature to prevent easy tampering with cookie data + * + * @param string $value + * @return string */ protected static function hmac(string $value): string { @@ -167,8 +161,11 @@ class Cookie /** * Parses the hashed value from a cookie * and tries to extract the value + * + * @param string $string + * @return mixed */ - protected static function parse(string $string): string|null + protected static function parse(string $string) { // if no hash-value separator is present, we can't parse the value if (strpos($string, '+') === false) { @@ -181,7 +178,7 @@ class Cookie // if the hash or the value is missing at all return null // $value can be an empty string, $hash can't be! - if ($hash === '') { + if (!is_string($hash) || $hash === '' || !is_string($value)) { return null; } @@ -210,7 +207,7 @@ class Cookie */ public static function remove(string $key): bool { - if (isset($_COOKIE[$key]) === true) { + if (isset($_COOKIE[$key])) { unset($_COOKIE[$key]); return setcookie($key, '', 1, '/') && setcookie($key, false); } @@ -224,11 +221,17 @@ class Cookie * this ensures that the response is only cached for visitors who don't * have this cookie set; * https://github.com/getkirby/kirby/issues/4423#issuecomment-1166300526 + * + * @param string $key + * @return void */ protected static function trackUsage(string $key): void { // lazily request the instance for non-CMS use cases $kirby = App::instance(null, true); - $kirby?->response()->usesCookie($key); + + if ($kirby) { + $kirby->response()->usesCookie($key); + } } } diff --git a/kirby/src/Http/Environment.php b/kirby/src/Http/Environment.php index 413f07c..68aedd4 100644 --- a/kirby/src/Http/Environment.php +++ b/kirby/src/Http/Environment.php @@ -3,6 +3,7 @@ namespace Kirby\Http; use Kirby\Cms\App; +use Kirby\Cms\Helpers; use Kirby\Exception\InvalidArgumentException; use Kirby\Filesystem\F; use Kirby\Toolkit\A; @@ -25,110 +26,143 @@ class Environment { /** * Full base URL object + * + * @var \Kirby\Http\Uri */ - protected Uri $baseUri; + protected $baseUri; /** * Full base URL + * + * @var string */ - protected string $baseUrl; + protected $baseUrl; /** * Whether the request is being served by the CLI + * + * @var bool */ - protected bool $cli; + protected $cli; /** * Current host name + * + * @var string */ - protected string|null $host; + protected $host; /** * Whether the HTTPS protocol is used + * + * @var bool */ - protected bool $https; + protected $https; /** * Sanitized `$_SERVER` data + * + * @var array */ - protected array $info; + protected $info; /** * Current server's IP address + * + * @var string */ - protected string|null $ip; + protected $ip; /** * Whether the site is behind a reverse proxy; * `null` if not known (fixed allowed URL setup) + * + * @var bool|null */ - protected bool|null $isBehindProxy; + protected $isBehindProxy; /** * URI path to the base + * + * @var string */ - protected string $path; + protected $path; /** * Port number in the site URL + * + * @var int|null */ - protected int|null $port; + protected $port; /** * Intermediary value of the port * extracted from the host name + * + * @var int|null */ - protected int|null $portInHost = null; + protected $portInHost; /** * Uri object for the full request URI. * It is a combination of the base URL and `REQUEST_URI` + * + * @var \Kirby\Http\Uri */ - protected Uri $requestUri; + protected $requestUri; /** * Full request URL + * + * @var string */ - protected string $requestUrl; + protected $requestUrl; /** * Path to the php script within the * document root without the * filename of the script + * + * @var string */ - protected string $scriptPath; + protected $scriptPath; /** * Class constructor * + * @param array|null $options * @param array|null $info Optional override for `$_SERVER` */ - public function __construct( - array|null $options = null, - array|null $info = null - ) { + public function __construct(?array $options = null, ?array $info = null) + { $this->detect($options, $info); } /** * Returns the server's IP address - * @see ::ip + * + * @see static::ip + * @return string|null */ - public function address(): string|null + public function address(): ?string { return $this->ip(); } /** * Returns the full base URL object + * + * @return \Kirby\Http\Uri */ - public function baseUri(): Uri + public function baseUri() { return $this->baseUri; } /** * Returns the full base URL + * + * @return string */ public function baseUrl(): string { @@ -137,6 +171,8 @@ class Environment /** * Checks if the request is being served by the CLI + * + * @return bool */ public function cli(): bool { @@ -150,19 +186,17 @@ class Environment * the stored information and re-detect the * environment if necessary. * + * @param array|null $options * @param array|null $info Optional override for `$_SERVER` + * @return array */ - public function detect( - array $options = null, - array $info = null - ): array { - $defaults = [ + public function detect(array $options = null, array $info = null): array + { + $info ??= $_SERVER; + $options = array_merge([ 'cli' => null, 'allowed' => null - ]; - - $info ??= $_SERVER; - $options = array_merge($defaults, $options ?? []); + ], $options ?? []); $this->info = static::sanitize($info); $this->cli = $this->detectCli($options['cli']); @@ -174,6 +208,18 @@ class Environment $this->path = $this->detectPath($this->scriptPath); $this->port = null; + // keep Server flags compatible for now + // TODO: remove in 3.8.0 + // @codeCoverageIgnoreStart + if (is_int($options['allowed']) === true) { + Helpers::deprecated(' + Using `Server::` constants for the `allowed` option has been deprecated and support will be removed in 3.8.0. Use one of the following instead: a single fixed URL, an array of allowed URLs to match dynamically, `*` wildcard to match dynamically even from insecure headers, or `true` to match automtically from safe server variables. + '); + + $options['allowed'] = $this->detectAllowedFromFlag($options['allowed']); + } + // @codeCoverageIgnoreEnd + // insecure auto-detection if ($options['allowed'] === '*' || $options['allowed'] === ['*']) { $this->detectAuto(true); @@ -200,8 +246,11 @@ class Environment /** * Sets the host name, port, path and protocol from the * fixed list of allowed URLs + * + * @param array|string $allowed + * @return void */ - protected function detectAllowed(array|string $allowed): void + protected function detectAllowed($allowed): void { $allowed = A::wrap($allowed); @@ -241,9 +290,9 @@ class Environment $uri = new Uri($url, ['slash' => false]); - // the current environment is allowed, - // stop before the exception below is thrown if ($uri->toString() === $this->baseUrl) { + // the current environment is allowed, + // stop before the exception below is thrown return; } } @@ -251,10 +300,34 @@ class Environment throw new InvalidArgumentException('The environment is not allowed'); } + /** + * The URL option receives a set of Server constant flags + * + * Server::HOST_FROM_SERVER + * Server::HOST_FROM_SERVER | Server::HOST_ALLOW_EMPTY + * Server::HOST_FROM_HEADER + * Server::HOST_FROM_HEADER | Server::HOST_ALLOW_EMPTY + * @todo Remove in 3.8.0 + * + * @param int $flags + * @return string|null + */ + protected function detectAllowedFromFlag(int $flags): ?string + { + // allow host detection from host headers + if ($flags & Server::HOST_FROM_HEADER) { + return '*'; + } + + // detect host only from server name + return null; + } + /** * Sets the host name, port and protocol without configuration * * @param bool $insecure Include the `Host`, `Forwarded` and `X-Forwarded-*` headers in the search + * @return void */ protected function detectAuto(bool $insecure = false): void { @@ -291,8 +364,10 @@ class Environment /** * Builds the base URL based on the * given environment params + * + * @return \Kirby\Http\Uri */ - protected function detectBaseUri(): Uri + protected function detectBaseUri() { $this->baseUri = new Uri([ 'host' => $this->host, @@ -310,8 +385,9 @@ class Environment * Detects if the request is served by the CLI * * @param bool|null $override Set to a boolean to override detection (for testing) + * @return bool */ - protected function detectCli(bool|null $override = null): bool + protected function detectCli(?bool $override = null): bool { if (is_bool($override) === true) { return $override; @@ -322,18 +398,9 @@ class Environment } // @codeCoverageIgnoreStart - $sapi = php_sapi_name(); - if ($sapi === 'cli') { - return true; - } - $term = getenv('TERM'); - if ( - substr($sapi, 0, 3) === 'cgi' && - $term && - $term !== 'unknown' - ) { + if (substr(PHP_SAPI, 0, 3) === 'cgi' && $term && $term !== 'unknown') { return true; } @@ -344,6 +411,8 @@ class Environment /** * Detects the host, protocol, port and client IP * from the `Forwarded` and `X-Forwarded-*` headers + * + * @return array */ protected function detectForwarded(): array { @@ -355,7 +424,8 @@ class Environment ]; // prefer the standardized `Forwarded` header if defined - if ($forwarded = $this->get('HTTP_FORWARDED')) { + $forwarded = $this->get('HTTP_FORWARDED'); + if ($forwarded) { // only use the first (outermost) proxy by using the first set of values // before the first comma (but only a comma outside of quotes) if (Str::contains($forwarded, ',') === true) { @@ -391,8 +461,8 @@ class Environment $data['https'] = $this->detectHttpsProtocol($fields['proto']); } - if ($data['https'] === true) { - $data['port'] ??= 443; + if ($data['port'] === null && $data['https'] === true) { + $data['port'] = 443; } $data['for'] = $parts['for'] ?? null; @@ -412,8 +482,10 @@ class Environment /** * Detects the host name of the reverse proxy * from the `X-Forwarded-Host` header + * + * @return string|null */ - protected function detectForwardedHost(): string|null + protected function detectForwardedHost(): ?string { $host = $this->get('HTTP_X_FORWARDED_HOST'); $parts = $this->detectPortInHost($host); @@ -426,6 +498,8 @@ class Environment /** * Detects the protocol of the reverse proxy from the * `X-Forwarded-SSL` or `X-Forwarded-Proto` header + * + * @return bool */ protected function detectForwardedHttps(): bool { @@ -445,8 +519,9 @@ class Environment * `X-Forwarded-Host` or `X-Forwarded-Port` header * * @param bool $https Whether HTTPS was detected + * @return int|null */ - protected function detectForwardedPort(bool $https): int|null + protected function detectForwardedPort(bool $https): ?int { // based on forwarded port $port = $this->get('HTTP_X_FORWARDED_PORT'); @@ -472,11 +547,10 @@ class Environment * Detects the host name from various headers * * @param bool $insecure Include the `Host` header in the search + * @return string|null */ - protected function detectHost(bool $insecure = false): string|null + protected function detectHost(bool $insecure = false): ?string { - $hosts = []; - if ($insecure === true) { $hosts[] = $this->get('HTTP_HOST'); } @@ -497,6 +571,8 @@ class Environment /** * Detects the HTTPS status + * + * @return bool */ protected function detectHttps(): bool { @@ -509,8 +585,11 @@ class Environment /** * Normalizes the HTTPS status into a boolean + * + * @param string|bool|null|int $value + * @return bool */ - protected function detectHttpsOn(string|int|bool|null $value): bool + protected function detectHttpsOn($value): bool { // off can mean many things :) $off = ['off', null, '', 0, '0', false, 'false', -1, '-1']; @@ -520,30 +599,36 @@ class Environment /** * Detects the HTTPS status from a `X-Forwarded-Proto` string + * + * @param string|null $protocol + * @return bool */ - protected function detectHttpsProtocol(string|null $protocol = null): bool + protected function detectHttpsProtocol(?string $protocol = null): bool { if ($protocol === null) { return false; } - $protocols = ['https', 'https, http']; - - return in_array(strtolower($protocol), $protocols) === true; + return in_array(strtolower($protocol), ['https', 'https, http']) === true; } /** * Detects the server's IP address + * + * @return string|null */ - protected function detectIp(): string|null + protected function detectIp(): ?string { return $this->get('SERVER_ADDR'); } /** * Detects the URI path unless in CLI mode + * + * @param string|null $path + * @return string */ - protected function detectPath(string|null $path = null): string + protected function detectPath(?string $path = null): string { if ($this->cli === true) { return ''; @@ -554,8 +639,10 @@ class Environment /** * Detects the port from various sources + * + * @return int|null */ - protected function detectPort(): int|null + protected function detectPort(): ?int { // based on server port $port = $this->get('SERVER_PORT'); @@ -579,8 +666,11 @@ class Environment /** * Splits a hostname:port string into its components + * + * @param string|null $host + * @return array */ - protected function detectPortInHost(string|null $host = null): array + protected function detectPortInHost(?string $host = null): array { if (empty($host) === true) { return [ @@ -599,8 +689,11 @@ class Environment /** * Splits any URI into path and query + * + * @param string|null $requestUri + * @return \Kirby\Http\Uri */ - protected function detectRequestUri(string|null $requestUri = null): Uri + protected function detectRequestUri(?string $requestUri = null) { // make sure the URL parser works properly when there's a // colon in the request URI but the URI is relative @@ -627,8 +720,11 @@ class Environment /** * Returns the sanitized script path unless in CLI mode + * + * @param string|null $scriptPath + * @return string */ - protected function detectScriptPath(string|null $scriptPath = null): string + protected function detectScriptPath(?string $scriptPath = null): string { if ($this->cli === true) { return ''; @@ -652,8 +748,9 @@ class Environment * to return the entire server array. * @param mixed $default Optional default value, which should be * returned if no element has been found + * @return mixed */ - public function get(string|false|null $key = null, $default = null) + public function get($key = null, $default = null) { if (is_string($key) === false) { return $this->info; @@ -675,13 +772,13 @@ class Environment * to return the entire server array. * @param mixed $default Optional default value, which should be * returned if no element has been found + * @return mixed */ - public static function getGlobally( - string|false|null $key = null, - $default = null - ) { + public static function getGlobally($key = null, $default = null) + { // first try the global `Environment` object if the CMS is running - if ($app = App::instance(null, true)) { + $app = App::instance(null, true); + if ($app) { return $app->environment()->get($key, $default); } @@ -698,14 +795,18 @@ class Environment /** * Returns the current host name + * + * @return string|null */ - public function host(): string|null + public function host(): ?string { return $this->host; } /** * Returns whether the HTTPS protocol is used + * + * @return bool */ public function https(): bool { @@ -714,6 +815,8 @@ class Environment /** * Returns the sanitized `$_SERVER` array + * + * @return array */ public function info(): array { @@ -722,8 +825,10 @@ class Environment /** * Returns the server's IP address + * + * @return string|null */ - public function ip(): string|null + public function ip(): ?string { return $this->ip; } @@ -731,8 +836,10 @@ class Environment /** * Returns if the server is behind a * reverse proxy server + * + * @return bool|null */ - public function isBehindProxy(): bool|null + public function isBehindProxy(): ?bool { return $this->isBehindProxy; } @@ -740,6 +847,8 @@ class Environment /** * Checks if this is a local installation; * returns `false` if in doubt + * + * @return bool */ public function isLocal(): bool { @@ -758,10 +867,6 @@ class Environment return true; } - if (Str::endsWith($host, '.ddev.site') === true) { - return true; - } - // collect all possible visitor ips $ips = [ $this->get('REMOTE_ADDR'), @@ -793,69 +898,58 @@ class Environment /** * Loads and returns options from environment-specific - * PHP files (by host name and server IP address or CLI) + * PHP files (by host name and server IP address) * * @param string $root Root directory to load configs from + * @return array */ public function options(string $root): array { - $configCli = []; $configHost = []; $configAddr = []; $host = $this->host(); $addr = $this->ip(); - // load the config for the cli - if ($this->cli() === true) { - $configCli = F::load( - file: $root . '/config.cli.php', - fallback: [], - allowOutput: false - ); - } - // load the config for the host if (empty($host) === false) { - $configHost = F::load( - file: $root . '/config.' . $host . '.php', - fallback: [], - allowOutput: false - ); + $configHost = F::load($root . '/config.' . $host . '.php', []); } // load the config for the server IP if (empty($addr) === false) { - $configAddr = F::load( - file: $root . '/config.' . $addr . '.php', - fallback: [], - allowOutput: false - ); + $configAddr = F::load($root . '/config.' . $addr . '.php', []); } - return array_replace_recursive($configCli, $configHost, $configAddr); + return array_replace_recursive($configHost, $configAddr); } /** * Returns the detected path + * + * @return string|null */ - public function path(): string|null + public function path(): ?string { return $this->path; } /** * Returns the correct port number + * + * @return int|null */ - public function port(): int|null + public function port(): ?int { return $this->port; } /** * Returns an URI object for the requested URL + * + * @return \Kirby\Http\Uri */ - public function requestUri(): Uri + public function requestUri() { return $this->requestUri; } @@ -863,6 +957,8 @@ class Environment /** * Returns the current URL, including the request path * and query + * + * @return string */ public function requestUrl(): string { @@ -871,11 +967,13 @@ class Environment /** * Sanitizes some `$_SERVER` keys + * + * @param string|array $key + * @param mixed $value + * @return mixed */ - public static function sanitize( - string|array $key, - $value = null - ) { + public static function sanitize($key, $value = null) + { if (is_array($key) === true) { foreach ($key as $k => $v) { $key[$k] = static::sanitize($k, $v); @@ -884,25 +982,28 @@ class Environment return $key; } - return match ($key) { - 'SERVER_ADDR', - 'SERVER_NAME', - 'HTTP_HOST', - 'HTTP_X_FORWARDED_HOST' => static::sanitizeHost($value), - - 'SERVER_PORT', - 'HTTP_X_FORWARDED_PORT' => static::sanitizePort($value), - - default => $value - }; + switch ($key) { + case 'SERVER_ADDR': + case 'SERVER_NAME': + case 'HTTP_HOST': + case 'HTTP_X_FORWARDED_HOST': + return static::sanitizeHost($value); + case 'SERVER_PORT': + case 'HTTP_X_FORWARDED_PORT': + return static::sanitizePort($value); + default: + return $value; + } } /** * Sanitizes the given host name + * + * @param string|null $host + * @return string|null */ - protected static function sanitizeHost( - string|null $host = null - ): string|null { + protected static function sanitizeHost(?string $host = null): ?string + { if (empty($host) === true) { return null; } @@ -925,10 +1026,12 @@ class Environment /** * Sanitizes the given port number + * + * @param string|int|null $port + * @return int|null */ - protected static function sanitizePort( - string|int|false|null $port = null - ): int|null { + protected static function sanitizePort($port = null): ?int + { // already fine if (is_int($port) === true) { return $port; @@ -940,7 +1043,7 @@ class Environment } // remove any character that is not an integer - $port = preg_replace('![^0-9]+!', '', $port); + $port = preg_replace('![^0-9]+!', '', (string)($port ?? '')); // no port if ($port === '') { @@ -953,11 +1056,14 @@ class Environment /** * Sanitizes the given script path + * + * @param string|null $scriptPath + * @return string */ - protected function sanitizeScriptPath(string|null $scriptPath = null): string + protected function sanitizeScriptPath(?string $scriptPath = null): string { $scriptPath ??= ''; - $scriptPath = trim($scriptPath); + $scriptPath = trim($scriptPath); // skip all the sanitizing steps if the path is empty if ($scriptPath === '') { @@ -991,6 +1097,8 @@ class Environment * * This can be used to build the base baseUrl * for subfolder installations + * + * @return string */ public function scriptPath(): string { @@ -999,6 +1107,8 @@ class Environment /** * Returns all environment data as array + * + * @return array */ public function toArray(): array { diff --git a/kirby/src/Http/Header.php b/kirby/src/Http/Header.php index 857798c..5f3b5ee 100644 --- a/kirby/src/Http/Header.php +++ b/kirby/src/Http/Header.php @@ -17,7 +17,8 @@ use Kirby\Filesystem\F; class Header { // configuration - public static array $codes = [ + public static $codes = [ + // successful '_200' => 'OK', '_201' => 'Created', @@ -55,13 +56,13 @@ class Header /** * Sends a content type header * + * @param string $mime + * @param string $charset + * @param bool $send * @return string|void */ - public static function contentType( - string $mime, - string $charset = 'UTF-8', - bool $send = true - ) { + public static function contentType(string $mime, string $charset = 'UTF-8', bool $send = true) + { if ($found = F::extensionToMime($mime)) { $mime = $found; } @@ -81,11 +82,13 @@ class Header /** * Creates headers by key and value + * + * @param string|array $key + * @param string|null $value + * @return string */ - public static function create( - string|array $key, - string|null $value = null - ): string { + public static function create($key, string $value = null): string + { if (is_array($key) === true) { $headers = []; @@ -96,21 +99,20 @@ class Header return implode("\r\n", $headers); } - // prevent header injection by stripping - // any newline characters from single headers + // prevent header injection by stripping any newline characters from single headers return str_replace(["\r", "\n"], '', $key . ': ' . $value); } /** * Shortcut for static::contentType() * + * @param string $mime + * @param string $charset + * @param bool $send * @return string|void */ - public static function type( - string $mime, - string $charset = 'UTF-8', - bool $send = true - ) { + public static function type(string $mime, string $charset = 'UTF-8', bool $send = true) + { return static::contentType($mime, $charset, $send); } @@ -121,30 +123,21 @@ class Header * and send a custom status code and message, use a $code string formatted * as 3 digits followed by a space and a message, e.g. '999 Custom Status'. * - * @param int|string|null $code The HTTP status code + * @param int|string $code The HTTP status code * @param bool $send If set to false the header will be returned instead * @return string|void - * @psalm-return ($send is false ? string : void) */ - public static function status( - int|string|null $code = null, - bool $send = true - ) { + public static function status($code = null, bool $send = true) + { $codes = static::$codes; $protocol = Environment::getGlobally('SERVER_PROTOCOL', 'HTTP/1.1'); // allow full control over code and message - if ( - is_string($code) === true && - preg_match('/^\d{3} \w.+$/', $code) === 1 - ) { + if (is_string($code) === true && preg_match('/^\d{3} \w.+$/', $code) === 1) { $message = substr(rtrim($code), 4); $code = substr($code, 0, 3); } else { - if (array_key_exists('_' . $code, $codes) === false) { - $code = 500; - } - + $code = array_key_exists('_' . $code, $codes) === false ? 500 : $code; $message = $codes['_' . $code] ?? 'Something went wrong'; } @@ -161,6 +154,7 @@ class Header /** * Sends a 200 header * + * @param bool $send * @return string|void */ public static function success(bool $send = true) @@ -171,6 +165,7 @@ class Header /** * Sends a 201 header * + * @param bool $send * @return string|void */ public static function created(bool $send = true) @@ -181,6 +176,7 @@ class Header /** * Sends a 202 header * + * @param bool $send * @return string|void */ public static function accepted(bool $send = true) @@ -191,6 +187,7 @@ class Header /** * Sends a 400 header * + * @param bool $send * @return string|void */ public static function error(bool $send = true) @@ -201,6 +198,7 @@ class Header /** * Sends a 403 header * + * @param bool $send * @return string|void */ public static function forbidden(bool $send = true) @@ -211,6 +209,7 @@ class Header /** * Sends a 404 header * + * @param bool $send * @return string|void */ public static function notfound(bool $send = true) @@ -221,6 +220,7 @@ class Header /** * Sends a 404 header * + * @param bool $send * @return string|void */ public static function missing(bool $send = true) @@ -231,6 +231,7 @@ class Header /** * Sends a 410 header * + * @param bool $send * @return string|void */ public static function gone(bool $send = true) @@ -241,6 +242,7 @@ class Header /** * Sends a 500 header * + * @param bool $send * @return string|void */ public static function panic(bool $send = true) @@ -251,6 +253,7 @@ class Header /** * Sends a 503 header * + * @param bool $send * @return string|void */ public static function unavailable(bool $send = true) @@ -261,13 +264,13 @@ class Header /** * Sends a redirect header * + * @param string $url + * @param int $code + * @param bool $send * @return string|void */ - public static function redirect( - string $url, - int $code = 302, - bool $send = true - ) { + public static function redirect(string $url, int $code = 302, bool $send = true) + { $status = static::status($code, false); $location = 'Location:' . Url::unIdn($url); @@ -285,7 +288,7 @@ class Header * * @param array $params Check out the defaults array for available parameters */ - public static function download(array $params = []): void + public static function download(array $params = []) { $defaults = [ 'name' => 'download', diff --git a/kirby/src/Http/Idn.php b/kirby/src/Http/Idn.php index 2ede8b3..a9a538f 100644 --- a/kirby/src/Http/Idn.php +++ b/kirby/src/Http/Idn.php @@ -17,22 +17,31 @@ class Idn { /** * Convert domain name from IDNA ASCII to Unicode + * + * @param string $domain + * @return string|false */ - public static function decode(string $domain): string|false + public static function decode(string $domain) { return idn_to_utf8($domain); } /** * Convert domain name to IDNA ASCII form + * + * @param string $domain + * @return string|false */ - public static function encode(string $domain): string|false + public static function encode(string $domain) { return idn_to_ascii($domain); } /** * Decodes a email address to the Unicode format + * + * @param string $email + * @return string */ public static function decodeEmail(string $email): string { @@ -48,6 +57,9 @@ class Idn /** * Encodes a email address to the Punycode format + * + * @param string $email + * @return string */ public static function encodeEmail(string $email): string { diff --git a/kirby/src/Http/Params.php b/kirby/src/Http/Params.php index 4067a0f..f9c7e1a 100644 --- a/kirby/src/Http/Params.php +++ b/kirby/src/Http/Params.php @@ -2,7 +2,6 @@ namespace Kirby\Http; -use Kirby\Toolkit\Obj; use Kirby\Toolkit\Str; /** @@ -16,14 +15,19 @@ use Kirby\Toolkit\Str; * @copyright Bastian Allgeier * @license https://opensource.org/licenses/MIT */ -class Params extends Obj +class Params extends Query { - public static string|null $separator = null; + /** + * @var null|string + */ + public static $separator; /** * Creates a new params object + * + * @param array|string $params */ - public function __construct(array|string|null $params) + public function __construct($params) { if (is_string($params) === true) { $params = static::extract($params)['params']; @@ -34,8 +38,11 @@ class Params extends Obj /** * Extract the params from a string or array + * + * @param string|array|null $path + * @return array */ - public static function extract(string|array|null $path = null): array + public static function extract($path = null): array { if (empty($path) === true) { return [ @@ -66,7 +73,7 @@ class Params extends Obj $paramValue = $paramParts[1] ?? null; if ($paramKey !== null) { - $params[rawurldecode($paramKey)] = $paramValue !== null ? rawurldecode($paramValue) : null; + $params[rawurldecode($paramKey)] = $paramValue ? rawurldecode($paramValue) : null; } unset($path[$index]); @@ -86,22 +93,14 @@ class Params extends Obj ]; } - public function isEmpty(): bool - { - return empty((array)$this) === true; - } - - public function isNotEmpty(): bool - { - return $this->isEmpty() === false; - } - /** * Returns the param separator according * to the operating system. * * Unix = ':' * Windows = ';' + * + * @return string */ public static function separator(): string { @@ -111,19 +110,27 @@ class Params extends Obj if (DIRECTORY_SEPARATOR === '/') { return static::$separator = ':'; + } else { + return static::$separator = ';'; } - - return static::$separator = ';'; } /** * Converts the params object to a params string * which can then be used in the URL builder again + * + * @param bool $leadingSlash + * @param bool $trailingSlash + * @return string|null + * + * @todo The argument $leadingSlash is incompatible with + * Query::toString($questionMark = false); the Query class + * should be extracted into a common parent class for both + * Query and Params + * @psalm-suppress ParamNameMismatch */ - public function toString( - bool $leadingSlash = false, - bool $trailingSlash = false - ): string { + public function toString($leadingSlash = false, $trailingSlash = false): string + { if ($this->isEmpty() === true) { return ''; } @@ -148,9 +155,4 @@ class Params extends Obj return $leadingSlash . $params . $trailingSlash; } - - public function __toString(): string - { - return $this->toString(); - } } diff --git a/kirby/src/Http/Path.php b/kirby/src/Http/Path.php index 02d2b05..ca4a77d 100644 --- a/kirby/src/Http/Path.php +++ b/kirby/src/Http/Path.php @@ -17,7 +17,7 @@ use Kirby\Toolkit\Str; */ class Path extends Collection { - public function __construct(string|array|null $items) + public function __construct($items) { if (is_string($items) === true) { $items = Str::split($items, '/'); @@ -31,10 +31,8 @@ class Path extends Collection return $this->toString(); } - public function toString( - bool $leadingSlash = false, - bool $trailingSlash = false - ): string { + public function toString(bool $leadingSlash = false, bool $trailingSlash = false): string + { if (empty($this->data) === true) { return ''; } diff --git a/kirby/src/Http/Query.php b/kirby/src/Http/Query.php index 410e2f0..89e7f50 100644 --- a/kirby/src/Http/Query.php +++ b/kirby/src/Http/Query.php @@ -17,7 +17,7 @@ use Kirby\Toolkit\Obj; */ class Query extends Obj { - public function __construct(string|array|null $query) + public function __construct($query) { if (is_string($query) === true) { parse_str(ltrim($query, '?'), $query); @@ -33,10 +33,15 @@ class Query extends Obj public function isNotEmpty(): bool { - return $this->isEmpty() === false; + return empty((array)$this) === false; } - public function toString(bool $questionMark = false): string + public function __toString(): string + { + return $this->toString(); + } + + public function toString($questionMark = false): string { $query = http_build_query($this, '', '&', PHP_QUERY_RFC3986); @@ -50,10 +55,4 @@ class Query extends Obj return $query; } - - - public function __toString(): string - { - return $this->toString(); - } } diff --git a/kirby/src/Http/Remote.php b/kirby/src/Http/Remote.php index 2d596ff..8325e33 100644 --- a/kirby/src/Http/Remote.php +++ b/kirby/src/Http/Remote.php @@ -2,13 +2,11 @@ namespace Kirby\Http; -use CurlHandle; use Exception; use Kirby\Cms\App; use Kirby\Exception\InvalidArgumentException; use Kirby\Filesystem\F; use Kirby\Toolkit\Str; -use stdClass; /** * A handy little class to handle @@ -25,7 +23,10 @@ class Remote public const CA_INTERNAL = 1; public const CA_SYSTEM = 2; - public static array $defaults = [ + /** + * @var array + */ + public static $defaults = [ 'agent' => null, 'basicAuth' => null, 'body' => true, @@ -40,17 +41,64 @@ class Remote 'timeout' => 10, ]; - public string|null $content = null; - public CurlHandle|false $curl; - public array $curlopt = []; - public int $errorCode; - public string $errorMessage; - public array $headers = []; - public array $info = []; - public array $options = []; + /** + * @var string + */ + public $content; /** - * @throws \Exception when the curl request failed + * @var resource + */ + public $curl; + + /** + * @var array + */ + public $curlopt = []; + + /** + * @var int + */ + public $errorCode; + + /** + * @var string + */ + public $errorMessage; + + /** + * @var array + */ + public $headers = []; + + /** + * @var array + */ + public $info = []; + + /** + * @var array + */ + public $options = []; + + /** + * Magic getter for request info data + * + * @param string $method + * @param array $arguments + * @return mixed + */ + public function __call(string $method, array $arguments = []) + { + $method = str_replace('-', '_', Str::kebab($method)); + return $this->info[$method] ?? null; + } + + /** + * Constructor + * + * @param string $url + * @param array $options */ public function __construct(string $url, array $options = []) { @@ -59,15 +107,14 @@ class Remote // use the system CA store by default if // one has been configured in php.ini $cainfo = ini_get('curl.cainfo'); - - // Suppress warnings e.g. if system CA is outside of open_basedir (See: issue #6236) - if (empty($cainfo) === false && @is_file($cainfo) === true) { + if (empty($cainfo) === false && is_file($cainfo) === true) { $defaults['ca'] = self::CA_SYSTEM; } // update the defaults with App config if set; // request the App instance lazily - if ($app = App::instance(null, true)) { + $app = App::instance(null, true); + if ($app !== null) { $defaults = array_merge($defaults, $app->option('remote', [])); } @@ -81,40 +128,27 @@ class Remote $this->fetch(); } - /** - * Magic getter for request info data - */ - public function __call(string $method, array $arguments = []) + public static function __callStatic(string $method, array $arguments = []) { - $method = str_replace('-', '_', Str::kebab($method)); - return $this->info[$method] ?? null; - } - - public static function __callStatic( - string $method, - array $arguments = [] - ): static { - return new static( - url: $arguments[0], - options: array_merge( - ['method' => strtoupper($method)], - $arguments[1] ?? [] - ) - ); + return new static($arguments[0], array_merge(['method' => strtoupper($method)], $arguments[1] ?? [])); } /** * Returns the http status code + * + * @return int|null */ - public function code(): int|null + public function code(): ?int { return $this->info['http_code'] ?? null; } /** * Returns the response content + * + * @return mixed */ - public function content(): string|null + public function content() { return $this->content; } @@ -123,9 +157,8 @@ class Remote * Sets up all curl options and sends the request * * @return $this - * @throws \Exception when the curl request failed */ - public function fetch(): static + public function fetch() { // curl options $this->curlopt = [ @@ -138,7 +171,7 @@ class Remote CURLOPT_FOLLOWLOCATION => true, CURLOPT_MAXREDIRS => 10, CURLOPT_HEADER => false, - CURLOPT_HEADERFUNCTION => function ($curl, $header): int { + CURLOPT_HEADERFUNCTION => function ($curl, $header) { $parts = Str::split($header, ':'); if (empty($parts[0]) === false && empty($parts[1]) === false) { @@ -186,10 +219,10 @@ class Remote $headers = []; foreach ($this->options['headers'] as $key => $value) { if (is_string($key) === true) { - $value = $key . ': ' . $value; + $headers[] = $key . ': ' . $value; + } else { + $headers[] = $value; } - - $headers[] = $value; } $this->curlopt[CURLOPT_HTTPHEADER] = $headers; @@ -263,9 +296,11 @@ class Remote /** * Static method to send a GET request * - * @throws \Exception when the curl request failed + * @param string $url + * @param array $params + * @return static */ - public static function get(string $url, array $params = []): static + public static function get(string $url, array $params = []) { $defaults = [ 'method' => 'GET', @@ -276,10 +311,7 @@ class Remote $query = http_build_query($options['data']); if (empty($query) === false) { - $url = match (Url::hasQuery($url)) { - true => $url . '&' . $query, - default => $url . '?' . $query - }; + $url = Url::hasQuery($url) === true ? $url . '&' . $query : $url . '?' . $query; } // remove the data array from the options @@ -290,6 +322,8 @@ class Remote /** * Returns all received headers + * + * @return array */ public function headers(): array { @@ -298,6 +332,8 @@ class Remote /** * Returns the request info + * + * @return array */ public function info(): array { @@ -308,15 +344,17 @@ class Remote * Decode the response content * * @param bool $array decode as array or object - * @psalm-return ($array is true ? array|null : stdClass|null) + * @return array|\stdClass */ - public function json(bool $array = true): array|stdClass|null + public function json(bool $array = true) { return json_decode($this->content(), $array); } /** * Returns the request method + * + * @return string */ public function method(): string { @@ -326,6 +364,8 @@ class Remote /** * Returns all options which have been * set for the current request + * + * @return array */ public function options(): array { @@ -334,28 +374,35 @@ class Remote /** * Internal method to handle post field data + * + * @param mixed $data + * @return mixed */ protected function postfields($data) { if (is_object($data) || is_array($data)) { return http_build_query($data); + } else { + return $data; } - - return $data; } /** * Static method to init this class and send a request * - * @throws \Exception when the curl request failed + * @param string $url + * @param array $params + * @return static */ - public static function request(string $url, array $params = []): static + public static function request(string $url, array $params = []) { return new static($url, $params); } /** * Returns the request Url + * + * @return string */ public function url(): string { diff --git a/kirby/src/Http/Request.php b/kirby/src/Http/Request.php index 85178a9..0b6a897 100644 --- a/kirby/src/Http/Request.php +++ b/kirby/src/Http/Request.php @@ -3,10 +3,6 @@ namespace Kirby\Http; use Kirby\Cms\App; -use Kirby\Http\Request\Auth; -use Kirby\Http\Request\Auth\BasicAuth; -use Kirby\Http\Request\Auth\BearerAuth; -use Kirby\Http\Request\Auth\SessionAuth; use Kirby\Http\Request\Body; use Kirby\Http\Request\Files; use Kirby\Http\Request\Query; @@ -26,16 +22,18 @@ use Kirby\Toolkit\Str; */ class Request { - public static array $authTypes = [ - 'basic' => BasicAuth::class, - 'bearer' => BearerAuth::class, - 'session' => SessionAuth::class, + public static $authTypes = [ + 'basic' => 'Kirby\Http\Request\Auth\BasicAuth', + 'bearer' => 'Kirby\Http\Request\Auth\BearerAuth', + 'session' => 'Kirby\Http\Request\Auth\SessionAuth', ]; /** * The auth object if available + * + * @var \Kirby\Http\Request\Auth|false|null */ - protected Auth|false|null $auth = null; + protected $auth; /** * The Body object is a wrapper around @@ -46,8 +44,10 @@ class Request * Examples: * * `$request->body()->get('foo')` + * + * @var Body */ - protected Body|null $body = null; + protected $body; /** * The Files object is a wrapper around @@ -59,19 +59,25 @@ class Request * * `$request->files()->get('upload')['size']` * `$request->file('upload')['size']` + * + * @var Files */ - protected Files|null $files = null; + protected $files; /** * The Method type + * + * @var string */ - protected string $method; + protected $method; /** * All options that have been passed to * the request in the constructor + * + * @var array */ - protected array $options; + protected $options; /** * The Query object is a wrapper around @@ -82,19 +88,25 @@ class Request * Examples: * * `$request->query()->get('foo')` + * + * @var Query */ - protected Query $query; + protected $query; /** * Request URL object + * + * @var Uri */ - protected Uri $url; + protected $url; /** * Creates a new Request object * You can either pass your own request * data via the $options array or use * the data from the incoming request. + * + * @param array $options */ public function __construct(array $options = []) { @@ -102,37 +114,26 @@ class Request $this->method = $this->detectRequestMethod($options['method'] ?? null); if (isset($options['body']) === true) { - $this->body = - $options['body'] instanceof Body - ? $options['body'] - : new Body($options['body']); + $this->body = is_a($options['body'], Body::class) ? $options['body'] : new Body($options['body']); } if (isset($options['files']) === true) { - $this->files = - $options['files'] instanceof Files - ? $options['files'] - : new Files($options['files']); + $this->files = is_a($options['files'], Files::class) ? $options['files'] : new Files($options['files']); } if (isset($options['query']) === true) { - $this->query = - $options['query'] instanceof Query - ? $options['query'] - : new Query($options['query']); + $this->query = is_a($options['query'], Query::class) === true ? $options['query'] : new Query($options['query']); } if (isset($options['url']) === true) { - $this->url = - $options['url'] instanceof Uri - ? $options['url'] - : new Uri($options['url']); + $this->url = is_a($options['url'], Uri::class) === true ? $options['url'] : new Uri($options['url']); } } /** * Improved `var_dump` output - * @codeCoverageIgnore + * + * @return array */ public function __debugInfo(): array { @@ -147,8 +148,10 @@ class Request /** * Returns the Auth object if authentication is set + * + * @return \Kirby\Http\Request\Auth|null */ - public function auth(): Auth|false|null + public function auth() { if ($this->auth !== null) { return $this->auth; @@ -163,9 +166,11 @@ class Request // this ensures that the response is only cached for // unauthenticated visitors; // https://github.com/getkirby/kirby/issues/4423#issuecomment-1166300526 - $kirby?->response()->usesAuth(true); + if ($kirby) { + $kirby->response()->usesAuth(true); + } - if ($auth = $this->authString()) { + if ($auth = $this->options['auth'] ?? $this->header('authorization')) { $type = Str::lower(Str::before($auth, ' ')); $data = Str::after($auth, ' '); @@ -184,14 +189,18 @@ class Request /** * Returns the Body object + * + * @return \Kirby\Http\Request\Body */ - public function body(): Body + public function body() { return $this->body ??= new Body(); } /** * Checks if the request has been made from the command line + * + * @return bool */ public function cli(): bool { @@ -200,28 +209,32 @@ class Request /** * Returns a CSRF token if stored in a header or the query + * + * @return string|null */ - public function csrf(): string|null + public function csrf(): ?string { return $this->header('x-csrf') ?? $this->query()->get('csrf'); } /** * Returns the request input as array + * + * @return array */ public function data(): array { - return array_replace( - $this->body()->toArray(), - $this->query()->toArray() - ); + return array_merge($this->body()->toArray(), $this->query()->toArray()); } /** * Detect the request method from various * options: given method, query string, server vars + * + * @param string $method + * @return string */ - public function detectRequestMethod(string|null $method = null): string + public function detectRequestMethod(string $method = null): string { // all possible methods $methods = ['GET', 'HEAD', 'POST', 'PUT', 'DELETE', 'CONNECT', 'OPTIONS', 'TRACE', 'PATCH']; @@ -229,12 +242,12 @@ class Request // the request method can be overwritten with a header $methodOverride = strtoupper(Environment::getGlobally('HTTP_X_HTTP_METHOD_OVERRIDE', '')); - if (in_array($methodOverride, $methods) === true) { - $method ??= $methodOverride; + if ($method === null && in_array($methodOverride, $methods) === true) { + $method = $methodOverride; } // final chain of options to detect the method - $method ??= Environment::getGlobally('REQUEST_METHOD', 'GET'); + $method = $method ?? Environment::getGlobally('REQUEST_METHOD', 'GET'); // uppercase the shit out of it $method = strtoupper($method); @@ -249,6 +262,8 @@ class Request /** * Returns the domain + * + * @return string */ public function domain(): string { @@ -258,16 +273,21 @@ class Request /** * Fetches a single file array * from the Files object by key + * + * @param string $key + * @return array|null */ - public function file(string $key): array|null + public function file(string $key) { return $this->files()->get($key); } /** * Returns the Files object + * + * @return \Kirby\Cms\Files */ - public function files(): Files + public function files() { return $this->files ??= new Files(); } @@ -275,8 +295,12 @@ class Request /** * Returns any data field from the request * if it exists + * + * @param string|null|array $key + * @param mixed $fallback + * @return mixed */ - public function get(string|array|null $key = null, $fallback = null) + public function get($key = null, $fallback = null) { return A::get($this->data(), $key, $fallback); } @@ -285,14 +309,22 @@ class Request * Returns whether the request contains * the `Authorization` header * @since 3.7.0 + * + * @return bool */ public function hasAuth(): bool { - return $this->authString() !== null; + $header = $this->options['auth'] ?? $this->header('authorization'); + + return $header !== null; } /** * Returns a header by key if it exists + * + * @param string $key + * @param mixed $fallback + * @return mixed */ public function header(string $key, $fallback = null) { @@ -303,16 +335,15 @@ class Request /** * Return all headers with polyfill for * missing getallheaders function + * + * @return array */ public function headers(): array { $headers = []; foreach (Environment::getGlobally() as $key => $value) { - if ( - substr($key, 0, 5) !== 'HTTP_' && - substr($key, 0, 14) !== 'REDIRECT_HTTP_' - ) { + if (substr($key, 0, 5) !== 'HTTP_' && substr($key, 0, 14) !== 'REDIRECT_HTTP_') { continue; } @@ -340,6 +371,9 @@ class Request /** * Checks if the given method name * matches the name of the request method. + * + * @param string $method + * @return bool */ public function is(string $method): bool { @@ -348,6 +382,8 @@ class Request /** * Returns the request method + * + * @return string */ public function method(): string { @@ -357,7 +393,7 @@ class Request /** * Shortcut to the Params object */ - public function params(): Params + public function params() { return $this->url()->params(); } @@ -365,21 +401,25 @@ class Request /** * Shortcut to the Path object */ - public function path(): Path + public function path() { return $this->url()->path(); } /** * Returns the Query object + * + * @return \Kirby\Http\Request\Query */ - public function query(): Query + public function query() { return $this->query ??= new Query(); } /** * Checks for a valid SSL connection + * + * @return bool */ public function ssl(): bool { @@ -391,8 +431,11 @@ class Request * If you pass props you can safely modify * the Url with new parameters without destroying * the original object. + * + * @param array $props + * @return \Kirby\Http\Uri */ - public function url(array|null $props = null): Uri + public function url(array $props = null) { if ($props !== null) { return $this->url()->clone($props); @@ -400,27 +443,4 @@ class Request return $this->url ??= Uri::current(); } - - /** - * Returns the raw auth string from the `auth` option - * or `Authorization` header unless both are empty - */ - protected function authString(): string|null - { - // both variants need to be checked separately - // because empty strings are treated as invalid - // but the `??` operator wouldn't do the fallback - - $option = $this->options['auth'] ?? null; - if (empty($option) === false) { - return $option; - } - - $header = $this->header('authorization'); - if (empty($header) === false) { - return $header; - } - - return null; - } } diff --git a/kirby/src/Http/Request/Auth.php b/kirby/src/Http/Request/Auth.php index e73f4da..032ca11 100644 --- a/kirby/src/Http/Request/Auth.php +++ b/kirby/src/Http/Request/Auth.php @@ -2,8 +2,6 @@ namespace Kirby\Http\Request; -use SensitiveParameter; - /** * Base class for auth types * @@ -16,16 +14,27 @@ use SensitiveParameter; abstract class Auth { /** - * @param string $data Raw authentication data after the first space in the `Authorization` header + * Raw authentication data after the first space + * in the `Authorization` header + * + * @var string */ - public function __construct( - #[SensitiveParameter] - protected string $data - ) { + protected $data; + + /** + * Constructor + * + * @param string $data + */ + public function __construct(string $data) + { + $this->data = $data; } /** * Converts the object to a string + * + * @return string */ public function __toString(): string { @@ -35,6 +44,8 @@ abstract class Auth /** * Returns the raw authentication data after the * first space in the `Authorization` header + * + * @return string */ public function data(): string { @@ -43,6 +54,8 @@ abstract class Auth /** * Returns the name of the auth type (lowercase) + * + * @return string */ abstract public function type(): string; } diff --git a/kirby/src/Http/Request/Auth/BasicAuth.php b/kirby/src/Http/Request/Auth/BasicAuth.php index f0e80ce..3d6e70e 100644 --- a/kirby/src/Http/Request/Auth/BasicAuth.php +++ b/kirby/src/Http/Request/Auth/BasicAuth.php @@ -4,7 +4,6 @@ namespace Kirby\Http\Request\Auth; use Kirby\Http\Request\Auth; use Kirby\Toolkit\Str; -use SensitiveParameter; /** * HTTP basic authentication data @@ -17,14 +16,26 @@ use SensitiveParameter; */ class BasicAuth extends Auth { - protected string $credentials; - protected string|null $password; - protected string|null $username; + /** + * @var string + */ + protected $credentials; - public function __construct( - #[SensitiveParameter] - string $data - ) { + /** + * @var string + */ + protected $password; + + /** + * @var string + */ + protected $username; + + /** + * @param string $token + */ + public function __construct(string $data) + { parent::__construct($data); $this->credentials = base64_decode($data); @@ -34,6 +45,8 @@ class BasicAuth extends Auth /** * Returns the entire unencoded credentials string + * + * @return string */ public function credentials(): string { @@ -42,14 +55,18 @@ class BasicAuth extends Auth /** * Returns the password + * + * @return string|null */ - public function password(): string|null + public function password(): ?string { return $this->password; } /** * Returns the authentication type + * + * @return string */ public function type(): string { @@ -58,8 +75,10 @@ class BasicAuth extends Auth /** * Returns the username + * + * @return string|null */ - public function username(): string|null + public function username(): ?string { return $this->username; } diff --git a/kirby/src/Http/Request/Auth/BearerAuth.php b/kirby/src/Http/Request/Auth/BearerAuth.php index 81dc9a9..e287606 100644 --- a/kirby/src/Http/Request/Auth/BearerAuth.php +++ b/kirby/src/Http/Request/Auth/BearerAuth.php @@ -17,6 +17,8 @@ class BearerAuth extends Auth { /** * Returns the authentication token + * + * @return string */ public function token(): string { @@ -25,6 +27,8 @@ class BearerAuth extends Auth /** * Returns the auth type + * + * @return string */ public function type(): string { diff --git a/kirby/src/Http/Request/Auth/SessionAuth.php b/kirby/src/Http/Request/Auth/SessionAuth.php index ca10830..1ce29be 100644 --- a/kirby/src/Http/Request/Auth/SessionAuth.php +++ b/kirby/src/Http/Request/Auth/SessionAuth.php @@ -4,7 +4,6 @@ namespace Kirby\Http\Request\Auth; use Kirby\Cms\App; use Kirby\Http\Request\Auth; -use Kirby\Session\Session; /** * Authentication data using Kirby's session @@ -19,14 +18,18 @@ class SessionAuth extends Auth { /** * Tries to return the session object + * + * @return \Kirby\Session\Session */ - public function session(): Session + public function session() { return App::instance()->sessionHandler()->getManually($this->data); } /** * Returns the session token + * + * @return string */ public function token(): string { @@ -35,6 +38,8 @@ class SessionAuth extends Auth /** * Returns the authentication type + * + * @return string */ public function type(): string { diff --git a/kirby/src/Http/Request/Body.php b/kirby/src/Http/Request/Body.php index 53bcdd0..df6f330 100644 --- a/kirby/src/Http/Request/Body.php +++ b/kirby/src/Http/Request/Body.php @@ -20,13 +20,17 @@ class Body /** * The raw body content + * + * @var string|array */ - protected string|array|null $contents; + protected $contents; /** * The parsed content as array + * + * @var array */ - protected array|null $data = null; + protected $data; /** * Creates a new request body object. @@ -34,8 +38,10 @@ class Body * If null is being passed, the class will * fetch the body either from the $_POST global * or from php://input. + * + * @param array|string|null $contents */ - public function __construct(array|string|null $contents = null) + public function __construct($contents = null) { $this->contents = $contents; } @@ -43,18 +49,20 @@ class Body /** * Fetches the raw contents for the body * or uses the passed contents. + * + * @return string|array */ - public function contents(): string|array + public function contents() { - if ($this->contents !== null) { - return $this->contents; + if ($this->contents === null) { + if (empty($_POST) === false) { + $this->contents = $_POST; + } else { + $this->contents = file_get_contents('php://input'); + } } - if (empty($_POST) === false) { - return $this->contents = $_POST; - } - - return $this->contents = file_get_contents('php://input'); + return $this->contents; } /** @@ -63,6 +71,8 @@ class Body * the body with the json decoder first and * then run parse_str to get some results * if the json decoder failed. + * + * @return array */ public function data(): array { @@ -99,6 +109,8 @@ class Body /** * Converts the data array back * to a http query string + * + * @return string */ public function toString(): string { @@ -107,6 +119,8 @@ class Body /** * Magic string converter + * + * @return string */ public function __toString(): string { diff --git a/kirby/src/Http/Request/Data.php b/kirby/src/Http/Request/Data.php index d2f3d95..8826c90 100644 --- a/kirby/src/Http/Request/Data.php +++ b/kirby/src/Http/Request/Data.php @@ -20,7 +20,8 @@ trait Data { /** * Improved `var_dump` output - * @codeCoverageIgnore + * + * @return array */ public function __debugInfo(): array { @@ -32,6 +33,8 @@ trait Data * implemented by each class using this Trait * and has to return an associative array * for the get method + * + * @return array */ abstract public function data(): array; @@ -40,8 +43,12 @@ trait Data * Trait. You can use it to fetch a single value * of the data array by key or multiple values by * passing an array of keys. + * + * @param string|array $key + * @param mixed|null $default + * @return mixed */ - public function get(string|array $key, $default = null) + public function get($key, $default = null) { if (is_array($key) === true) { $result = []; @@ -57,6 +64,8 @@ trait Data /** * Returns the data array. * This is basically an alias for Data::data() + * + * @return array */ public function toArray(): array { @@ -65,6 +74,8 @@ trait Data /** * Converts the data array to json + * + * @return string */ public function toJson(): string { diff --git a/kirby/src/Http/Request/Files.php b/kirby/src/Http/Request/Files.php index 244028a..a23263a 100644 --- a/kirby/src/Http/Request/Files.php +++ b/kirby/src/Http/Request/Files.php @@ -21,17 +21,25 @@ class Files /** * Sanitized array of all received files + * + * @var array */ - protected array $files = []; + protected $files; /** * Creates a new Files object * Pass your own array to mock * uploads. + * + * @param array|null $files */ - public function __construct(array|null $files = null) + public function __construct($files = null) { - $files ??= $_FILES; + if ($files === null) { + $files = $_FILES; + } + + $this->files = []; foreach ($files as $key => $file) { if (is_array($file['name'])) { @@ -55,6 +63,8 @@ class Files * array. This is only needed to make * the Data trait work for the Files::get($key) * method. + * + * @return array */ public function data(): array { diff --git a/kirby/src/Http/Request/Query.php b/kirby/src/Http/Request/Query.php index 51b004a..315a683 100644 --- a/kirby/src/Http/Request/Query.php +++ b/kirby/src/Http/Request/Query.php @@ -19,8 +19,10 @@ class Query /** * The Query data array + * + * @var array|null */ - protected array|null $data = null; + protected $data; /** * Creates a new Query object. @@ -28,12 +30,14 @@ class Query * or a parsable query string. If * null is passed, the current Query * will be taken from $_GET + * + * @param array|string|null $data */ - public function __construct(array|string|null $data = null) + public function __construct($data = null) { if ($data === null) { $this->data = $_GET; - } elseif (is_array($data) === true) { + } elseif (is_array($data)) { $this->data = $data; } else { parse_str($data, $parsed); @@ -43,6 +47,8 @@ class Query /** * Returns the Query data as array + * + * @return array */ public function data(): array { @@ -51,6 +57,8 @@ class Query /** * Returns `true` if the request doesn't contain query variables + * + * @return bool */ public function isEmpty(): bool { @@ -59,6 +67,8 @@ class Query /** * Returns `true` if the request contains query variables + * + * @return bool */ public function isNotEmpty(): bool { @@ -68,6 +78,8 @@ class Query /** * Converts the query data array * back to a query string + * + * @return string */ public function toString(): string { @@ -76,6 +88,8 @@ class Query /** * Magic string converter + * + * @return string */ public function __toString(): string { diff --git a/kirby/src/Http/Response.php b/kirby/src/Http/Response.php index 53892d6..b88a5b1 100644 --- a/kirby/src/Http/Response.php +++ b/kirby/src/Http/Response.php @@ -2,10 +2,9 @@ namespace Kirby\Http; -use Closure; use Exception; -use Kirby\Exception\LogicException; use Kirby\Filesystem\F; +use Throwable; /** * Representation of an Http response, @@ -23,39 +22,50 @@ class Response /** * Store for all registered headers, * which will be sent with the response + * + * @var array */ - protected array $headers = []; + protected $headers = []; /** * The response body + * + * @var string */ - protected string $body; + protected $body; /** * The HTTP response code + * + * @var int */ - protected int $code; + protected $code; /** * The content type for the response + * + * @var string */ - protected string $type; + protected $type; /** * The content type charset + * + * @var string */ - protected string $charset = 'UTF-8'; + protected $charset = 'UTF-8'; /** * Creates a new response object + * + * @param string $body + * @param string $type + * @param int $code + * @param array $headers + * @param string $charset */ - public function __construct( - string|array $body = '', - string|null $type = null, - int|null $code = null, - array|null $headers = null, - string|null $charset = null - ) { + public function __construct($body = '', ?string $type = null, ?int $code = null, ?array $headers = null, ?string $charset = null) + { // array construction if (is_array($body) === true) { $params = $body; @@ -81,7 +91,8 @@ class Response /** * Improved `var_dump` output - * @codeCoverageIgnore + * + * @return array */ public function __debugInfo(): array { @@ -92,14 +103,22 @@ class Response * Makes it possible to convert the * entire response object to a string * to send the headers and print the body + * + * @return string */ public function __toString(): string { - return $this->send(); + try { + return $this->send(); + } catch (Throwable $e) { + return ''; + } } /** * Getter for the body + * + * @return string */ public function body(): string { @@ -108,6 +127,8 @@ class Response /** * Getter for the content type charset + * + * @return string */ public function charset(): string { @@ -116,6 +137,8 @@ class Response /** * Getter for the HTTP status code + * + * @return int */ public function code(): int { @@ -126,13 +149,13 @@ class Response * Creates a response that triggers * a file download for the given file * + * @param string $file + * @param string $filename * @param array $props Custom overrides for response props (e.g. headers) + * @return static */ - public static function download( - string $file, - string|null $filename = null, - array $props = [] - ): static { + public static function download(string $file, string $filename = null, array $props = []) + { if (file_exists($file) === false) { throw new Exception('The file could not be found'); } @@ -163,9 +186,11 @@ class Response * Creates a response for a file and * sends the file content to the browser * + * @param string $file * @param array $props Custom overrides for response props (e.g. headers) + * @return static */ - public static function file(string $file, array $props = []): static + public static function file(string $file, array $props = []) { $props = array_merge([ 'body' => F::read($file), @@ -193,42 +218,32 @@ class Response * Urls can be relative or absolute. * @since 3.7.0 * + * @param string $url + * @param int $code + * @return void + * * @codeCoverageIgnore */ - public static function go(string $url = '/', int $code = 302): never + public static function go(string $url = '/', int $code = 302) { die(static::redirect($url, $code)); } - /** - * Ensures that the callback does not produce the first body output - * (used to show when loading a file creates side effects) - */ - public static function guardAgainstOutput(Closure $callback, ...$args): mixed - { - $before = headers_sent(); - $result = $callback(...$args); - $after = headers_sent($file, $line); - - if ($before === false && $after === true) { - throw new LogicException("Disallowed output from file $file:$line, possible accidental whitespace?"); - } - - return $result; - } - /** * Getter for single headers * * @param string $key Name of the header + * @return string|null */ - public function header(string $key): string|null + public function header(string $key): ?string { return $this->headers[$key] ?? null; } /** * Getter for all headers + * + * @return array */ public function headers(): array { @@ -238,15 +253,17 @@ class Response /** * Creates a json response with appropriate * header and automatic conversion of arrays. + * + * @param string|array $body + * @param int $code + * @param bool $pretty + * @param array $headers + * @return static */ - public static function json( - string|array $body = '', - int|null $code = null, - bool|null $pretty = null, - array $headers = [] - ): static { + public static function json($body = '', ?int $code = null, ?bool $pretty = null, array $headers = []) + { if (is_array($body) === true) { - $body = json_encode($body, $pretty === true ? JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES : 0); + $body = json_encode($body, $pretty === true ? JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES : 0); } return new static([ @@ -261,8 +278,12 @@ class Response * Creates a redirect response, * which will send the visitor to the * given location. + * + * @param string $location + * @param int $code + * @return static */ - public static function redirect(string $location = '/', int $code = 302): static + public static function redirect(string $location = '/', int $code = 302) { return new static([ 'code' => $code, @@ -275,6 +296,8 @@ class Response /** * Sends all registered headers and * returns the response body + * + * @return string */ public function send(): string { @@ -297,6 +320,8 @@ class Response * Converts all relevant response attributes * to an associative array for debugging, * testing or whatever. + * + * @return array */ public function toArray(): array { @@ -311,6 +336,8 @@ class Response /** * Getter for the content type + * + * @return string */ public function type(): string { diff --git a/kirby/src/Http/Route.php b/kirby/src/Http/Route.php index 7d6dd7d..007e481 100644 --- a/kirby/src/Http/Route.php +++ b/kirby/src/Http/Route.php @@ -15,35 +15,47 @@ class Route { /** * The callback action function + * + * @var Closure */ - protected Closure $action; + protected $action; /** * Listed of parsed arguments + * + * @var array */ - protected array $arguments = []; + protected $arguments = []; /** * An array of all passed attributes + * + * @var array */ - protected array $attributes = []; + protected $attributes = []; /** * The registered request method + * + * @var string */ - protected string $method; + protected $method; /** * The registered pattern + * + * @var string */ - protected string $pattern; + protected $pattern; /** * Wildcards, which can be used in * Route patterns to make regular expressions * a little more human + * + * @var array */ - protected array $wildcards = [ + protected $wildcards = [ 'required' => [ '(:num)' => '(-?[0-9]+)', '(:alpha)' => '([a-zA-Z]+)', @@ -62,8 +74,12 @@ class Route /** * Magic getter for route attributes + * + * @param string $key + * @param array $arguments + * @return mixed */ - public function __call(string $key, array $args = null): mixed + public function __call(string $key, array $arguments = null) { return $this->attributes[$key] ?? null; } @@ -71,13 +87,14 @@ class Route /** * Creates a new Route object for the given * pattern(s), method(s) and the callback action + * + * @param string|array $pattern + * @param string|array $method + * @param Closure $action + * @param array $attributes */ - public function __construct( - string $pattern, - string $method, - Closure $action, - array $attributes = [] - ) { + public function __construct($pattern, $method, Closure $action, array $attributes = []) + { $this->action = $action; $this->attributes = $attributes; $this->method = $method; @@ -86,14 +103,18 @@ class Route /** * Getter for the action callback + * + * @return Closure */ - public function action(): Closure + public function action() { return $this->action; } /** * Returns all parsed arguments + * + * @return array */ public function arguments(): array { @@ -102,6 +123,8 @@ class Route /** * Getter for additional attributes + * + * @return array */ public function attributes(): array { @@ -110,6 +133,8 @@ class Route /** * Getter for the method + * + * @return string */ public function method(): string { @@ -118,8 +143,10 @@ class Route /** * Returns the route name if set + * + * @return string|null */ - public function name(): string|null + public function name(): ?string { return $this->attributes['name'] ?? null; } @@ -128,6 +155,8 @@ class Route * Throws a specific exception to tell * the router to jump to the next route * @since 3.0.3 + * + * @return void */ public static function next(): void { @@ -136,6 +165,8 @@ class Route /** * Getter for the pattern + * + * @return string */ public function pattern(): string { @@ -145,6 +176,9 @@ class Route /** * Converts the pattern into a full regular * expression by replacing all the wildcards + * + * @param string $pattern + * @return string */ public function regex(string $pattern): string { @@ -166,8 +200,12 @@ class Route /** * Tries to match the path with the regular expression and * extracts all arguments for the Route action + * + * @param string $pattern + * @param string $path + * @return array|false */ - public function parse(string $pattern, string $path): array|false + public function parse(string $pattern, string $path) { // check for direct matches if ($pattern === $path) { diff --git a/kirby/src/Http/Router.php b/kirby/src/Http/Router.php index f561bd3..aceb2b6 100644 --- a/kirby/src/Http/Router.php +++ b/kirby/src/Http/Router.php @@ -18,27 +18,35 @@ class Router { /** * Hook that is called after each route + * + * @var \Closure */ - protected Closure|null $afterEach; + protected $afterEach; /** * Hook that is called before each route + * + * @var \Closure */ - protected Closure|null $beforeEach; + protected $beforeEach; /** * Store for the current route, * if one can be found + * + * @var \Kirby\Http\Route|null */ - protected Route|null $route = null; + protected $route; /** * All registered routes, sorted by * their request method. This makes * it faster to find the right route * later. + * + * @var array */ - protected array $routes = [ + protected $routes = [ 'GET' => [], 'HEAD' => [], 'POST' => [], @@ -54,6 +62,7 @@ class Router * Creates a new router object and * registers all the given routes * + * @param array $routes * @param array $hooks Optional `beforeEach` and `afterEach` hooks */ public function __construct(array $routes = [], array $hooks = []) @@ -95,12 +104,14 @@ class Router * and then call the Route action with * the appropriate arguments and a Result * object. + * + * @param string $path + * @param string $method + * @param Closure|null $callback + * @return mixed */ - public function call( - string|null $path = null, - string $method = 'GET', - Closure|null $callback = null - ) { + public function call(string $path = null, string $method = 'GET', Closure $callback = null) + { $path ??= ''; $ignore = []; $result = null; @@ -109,7 +120,7 @@ class Router while ($loop === true) { $route = $this->find($path, $method, $ignore); - if ($this->beforeEach instanceof Closure) { + if (is_a($this->beforeEach, 'Closure') === true) { ($this->beforeEach)($route, $path, $method); } @@ -117,18 +128,15 @@ class Router if ($callback) { $result = $callback($route); } else { - $result = $route->action()->call( - $route, - ...$route->arguments() - ); + $result = $route->action()->call($route, ...$route->arguments()); } $loop = false; - } catch (Exceptions\NextRouteException) { + } catch (Exceptions\NextRouteException $e) { $ignore[] = $route; } - if ($this->afterEach instanceof Closure) { + if (is_a($this->afterEach, 'Closure') === true) { $final = $loop === false; $result = ($this->afterEach)($route, $path, $method, $result, $final); } @@ -141,13 +149,15 @@ class Router * Creates a micro-router and executes * the routing action immediately * @since 3.7.0 + * + * @param string|null $path + * @param string $method + * @param array $routes + * @param \Closure|null $callback + * @return mixed */ - public static function execute( - string|null $path = null, - string $method = 'GET', - array $routes = [], - Closure|null $callback = null - ) { + public static function execute(?string $path = null, string $method = 'GET', array $routes = [], ?Closure $callback = null) + { return (new static($routes))->call($path, $method, $callback); } @@ -156,12 +166,14 @@ class Router * The Route's arguments method is used to * find matches and return all the found * arguments in the path. + * + * @param string $path + * @param string $method + * @param array $ignore + * @return \Kirby\Http\Route|null */ - public function find( - string $path, - string $method, - array|null $ignore = null - ): Route { + public function find(string $path, string $method, array $ignore = null) + { if (isset($this->routes[$method]) === false) { throw new InvalidArgumentException('Invalid routing method: ' . $method, 400); } @@ -173,10 +185,7 @@ class Router $arguments = $route->parse($route->pattern(), $path); if ($arguments !== false) { - if ( - empty($ignore) === true || - in_array($route, $ignore) === false - ) { + if (empty($ignore) === true || in_array($route, $ignore) === false) { return $this->route = $route; } } @@ -190,8 +199,10 @@ class Router * This will only return something, * once Router::find() has been called * and only if a route was found. + * + * @return \Kirby\Http\Route|null */ - public function route(): Route|null + public function route() { return $this->route; } diff --git a/kirby/src/Http/Server.php b/kirby/src/Http/Server.php new file mode 100644 index 0000000..d16118f --- /dev/null +++ b/kirby/src/Http/Server.php @@ -0,0 +1,38 @@ + + * @link https://getkirby.com + * @copyright Bastian Allgeier + * @license https://opensource.org/licenses/MIT + * @deprecated 3.7.0 Use `Kirby\Http\Environment` instead + * @todo Remove in 3.8.0 + */ +class Server extends Facade +{ + public const HOST_FROM_SERVER = 1; + public const HOST_FROM_HEADER = 2; + public const HOST_ALLOW_EMPTY = 4; + + public static $cli; + public static $hosts; + + /** + * @return \Kirby\Http\Environment + */ + public static function instance() + { + return new Environment([ + 'cli' => static::$cli, + 'allowed' => static::$hosts + ]); + } +} diff --git a/kirby/src/Http/Uri.php b/kirby/src/Http/Uri.php index 08c4618..48f8587 100644 --- a/kirby/src/Http/Uri.php +++ b/kirby/src/Http/Uri.php @@ -4,7 +4,7 @@ namespace Kirby\Http; use Kirby\Cms\App; use Kirby\Exception\InvalidArgumentException; -use SensitiveParameter; +use Kirby\Toolkit\Properties; use Throwable; /** @@ -18,74 +18,129 @@ use Throwable; */ class Uri { + use Properties; + /** * Cache for the current Uri object + * + * @var Uri|null */ - public static Uri|null $current = null; + public static $current; /** * The fragment after the hash + * + * @var string|false */ - protected string|false|null $fragment; + protected $fragment; /** * The host address + * + * @var string */ - protected string|null $host; + protected $host; /** * The optional password for basic authentication + * + * @var string|false */ - protected string|false|null $password; + protected $password; /** * The optional list of params + * + * @var Params */ - protected Params $params; + protected $params; /** * The optional path + * + * @var Path */ - protected Path $path; + protected $path; /** * The optional port number + * + * @var int|false */ - protected int|false|null $port; + protected $port; /** * All original properties + * + * @var array */ - protected array $props; + protected $props; /** * The optional query string without leading ? + * + * @var Query */ - protected Query $query; + protected $query; /** * https or http + * + * @var string */ - protected string|null $scheme; + protected $scheme = 'http'; /** * Supported schemes + * + * @var array */ - protected static array $schemes = ['http', 'https', 'ftp']; + protected static $schemes = ['http', 'https', 'ftp']; - protected bool $slash; + /** + * @var bool + */ + protected $slash = false; /** * The optional username for basic authentication + * + * @var string|false */ - protected string|false|null $username = null; + protected $username; + + /** + * Magic caller to access all properties + * + * @param string $property + * @param array $arguments + * @return mixed + */ + public function __call(string $property, array $arguments = []) + { + return $this->$property ?? null; + } + + /** + * Make sure that cloning also clones + * the path and query objects + * + * @return void + */ + public function __clone() + { + $this->path = clone $this->path; + $this->query = clone $this->query; + $this->params = clone $this->params; + } /** * Creates a new URI object * + * @param array|string $props * @param array $inject Additional props to inject if a URL string is passed */ - public function __construct(array|string $props = [], array $inject = []) + public function __construct($props = [], array $inject = []) { if (is_string($props) === true) { $props = parse_url($props); @@ -100,40 +155,14 @@ class Uri $props = static::parsePath($props); } - $this->props = $props; - $this->setFragment($props['fragment'] ?? null); - $this->setHost($props['host'] ?? null); - $this->setParams($props['params'] ?? null); - $this->setPassword($props['password'] ?? null); - $this->setPath($props['path'] ?? null); - $this->setPort($props['port'] ?? null); - $this->setQuery($props['query'] ?? null); - $this->setScheme($props['scheme'] ?? 'http'); - $this->setSlash($props['slash'] ?? false); - $this->setUsername($props['username'] ?? null); - } - - /** - * Magic caller to access all properties - */ - public function __call(string $property, array $arguments = []) - { - return $this->$property ?? null; - } - - /** - * Make sure that cloning also clones - * the path and query objects - */ - public function __clone() - { - $this->path = clone $this->path; - $this->query = clone $this->query; - $this->params = clone $this->params; + $this->setProperties($this->props = $props); } /** * Magic getter + * + * @param string $property + * @return mixed */ public function __get(string $property) { @@ -142,6 +171,10 @@ class Uri /** * Magic setter + * + * @param string $property + * @param mixed $value + * @return void */ public function __set(string $property, $value): void { @@ -152,20 +185,24 @@ class Uri /** * Converts the URL object to string + * + * @return string */ public function __toString(): string { try { return $this->toString(); - } catch (Throwable) { + } catch (Throwable $e) { return ''; } } /** * Returns the auth details (username:password) + * + * @return string|null */ - public function auth(): string|null + public function auth(): ?string { $auth = trim($this->username . ':' . $this->password); return $auth !== ':' ? $auth : null; @@ -174,8 +211,10 @@ class Uri /** * Returns the base url (scheme + host) * without trailing slash + * + * @return string|null */ - public function base(): string|null + public function base(): ?string { if ($domain = $this->domain()) { return $this->scheme ? $this->scheme . '://' . $domain : $domain; @@ -187,8 +226,11 @@ class Uri /** * Clones the Uri object and applies optional * new props. + * + * @param array $props + * @return static */ - public function clone(array $props = []): static + public function clone(array $props = []) { $clone = clone $this; @@ -199,7 +241,11 @@ class Uri return $clone; } - public static function current(array $props = []): static + /** + * @param array $props + * @return static + */ + public static function current(array $props = []) { if (static::$current !== null) { return static::$current; @@ -215,11 +261,11 @@ class Uri } /** - * Returns the domain without scheme, path or query. - * Includes auth part when not empty. - * Includes port number when different from 80 or 443. + * Returns the domain without scheme, path or query + * + * @return string|null */ - public function domain(): string|null + public function domain(): ?string { if (empty($this->host) === true || $this->host === '/') { return null; @@ -234,31 +280,40 @@ class Uri $domain .= $this->host; - if ( - $this->port !== null && - in_array($this->port, [80, 443]) === false - ) { + if ($this->port !== null && in_array($this->port, [80, 443]) === false) { $domain .= ':' . $this->port; } return $domain; } + /** + * @return bool + */ public function hasFragment(): bool { return empty($this->fragment) === false; } + /** + * @return bool + */ public function hasPath(): bool { return $this->path()->isNotEmpty(); } + /** + * @return bool + */ public function hasQuery(): bool { return $this->query()->isNotEmpty(); } + /** + * @return bool + */ public function https(): bool { return $this->scheme() === 'https'; @@ -270,7 +325,7 @@ class Uri * * @return $this */ - public function idn(): static + public function idn() { if (empty($this->host) === false) { $this->setHost(Idn::decode($this->host)); @@ -281,8 +336,11 @@ class Uri /** * Creates an Uri object for the URL to the index.php * or any other executed script. + * + * @param array $props + * @return static */ - public static function index(array $props = []): static + public static function index(array $props = []) { if ($app = App::instance(null, true)) { $url = $app->url('index'); @@ -295,6 +353,8 @@ class Uri /** * Checks if the host exists + * + * @return bool */ public function isAbsolute(): bool { @@ -302,27 +362,30 @@ class Uri } /** + * @param string|null $fragment * @return $this */ - public function setFragment(string|null $fragment = null): static + public function setFragment(string $fragment = null) { $this->fragment = $fragment ? ltrim($fragment, '#') : null; return $this; } /** + * @param string $host * @return $this */ - public function setHost(string|null $host = null): static + public function setHost(string $host = null) { $this->host = $host; return $this; } /** + * @param \Kirby\Http\Params|string|array|false|null $params * @return $this */ - public function setParams(Params|string|array|false|null $params = null): static + public function setParams($params = null) { // ensure that the special constructor value of `false` // is never passed through as it's not supported by `Params` @@ -330,34 +393,35 @@ class Uri $params = []; } - $this->params = $params instanceof Params ? $params : new Params($params); + $this->params = is_a($params, 'Kirby\Http\Params') === true ? $params : new Params($params); return $this; } /** + * @param string|null $password * @return $this */ - public function setPassword( - #[SensitiveParameter] - string|null $password = null - ): static { + public function setPassword(string $password = null) + { $this->password = $password; return $this; } /** + * @param \Kirby\Http\Path|string|array|null $path * @return $this */ - public function setPath(Path|string|array|null $path = null): static + public function setPath($path = null) { - $this->path = $path instanceof Path ? $path : new Path($path); + $this->path = is_a($path, 'Kirby\Http\Path') === true ? $path : new Path($path); return $this; } /** + * @param int|null $port * @return $this */ - public function setPort(int|null $port = null): static + public function setPort(int $port = null) { if ($port === 0) { $port = null; @@ -374,18 +438,20 @@ class Uri } /** + * @param \Kirby\Http\Query|string|array|null $query * @return $this */ - public function setQuery(Query|string|array|null $query = null): static + public function setQuery($query = null) { - $this->query = $query instanceof Query ? $query : new Query($query); + $this->query = is_a($query, 'Kirby\Http\Query') === true ? $query : new Query($query); return $this; } /** + * @param string $scheme * @return $this */ - public function setScheme(string|null $scheme = null): static + public function setScheme(string $scheme = null) { if ($scheme !== null && in_array($scheme, static::$schemes) === false) { throw new InvalidArgumentException('Invalid URL scheme: ' . $scheme); @@ -399,18 +465,20 @@ class Uri * Set if a trailing slash should be added to * the path when the URI is being built * + * @param bool $slash * @return $this */ - public function setSlash(bool $slash = false): static + public function setSlash(bool $slash = false) { $this->slash = $slash; return $this; } /** + * @param string|null $username * @return $this */ - public function setUsername(string|null $username = null): static + public function setUsername(string $username = null) { $this->username = $username; return $this; @@ -418,12 +486,14 @@ class Uri /** * Converts the Url object to an array + * + * @return array */ public function toArray(): array { $array = []; - foreach ($this->props as $key => $value) { + foreach ($this->propertyData as $key => $value) { $value = $this->$key; if (is_object($value) === true) { @@ -443,6 +513,8 @@ class Uri /** * Returns the full URL as string + * + * @return string */ public function toString(): string { @@ -476,7 +548,7 @@ class Uri * * @return $this */ - public function unIdn(): static + public function unIdn() { if (empty($this->host) === false) { $this->setHost(Idn::encode($this->host)); @@ -488,6 +560,7 @@ class Uri * Parses the path inside the props and extracts * the params unless disabled * + * @param array $props * @return array Modified props array */ protected static function parsePath(array $props): array diff --git a/kirby/src/Http/Url.php b/kirby/src/Http/Url.php index 9360040..e0c3cdf 100644 --- a/kirby/src/Http/Url.php +++ b/kirby/src/Http/Url.php @@ -17,46 +17,57 @@ class Url { /** * The base Url to build absolute Urls from + * + * @var string */ - public static string|null $home = '/'; + public static $home = '/'; /** - * The current Uri object as string + * The current Uri object + * + * @var Uri */ - public static string|null $current = null; + public static $current = null; /** * Facade for all Uri object methods + * + * @param string $method + * @param array $arguments + * @return mixed */ - public static function __callStatic(string $method, array $arguments) + public static function __callStatic(string $method, $arguments) { - $uri = new Uri($arguments[0] ?? static::current()); - return $uri->$method(...array_slice($arguments, 1)); + return (new Uri($arguments[0] ?? static::current()))->$method(...array_slice($arguments, 1)); } /** * Url Builder * Actually just a factory for `new Uri($parts)` + * + * @param array $parts + * @param string|null $url + * @return string */ - public static function build( - array $parts = [], - string|null $url = null - ): string { - $url ??= static::current(); - $uri = new Uri($url); - return $uri->clone($parts)->toString(); + public static function build(array $parts = [], string $url = null): string + { + return (string)(new Uri($url ?? static::current()))->clone($parts); } /** * Returns the current url with all bells and whistles + * + * @return string */ public static function current(): string { - return static::$current ??= static::toObject()->toString(); + return static::$current = static::$current ?? static::toObject()->toString(); } /** * Returns the url for the current directory + * + * @return string */ public static function currentDir(): string { @@ -65,20 +76,20 @@ class Url /** * Tries to fix a broken url without protocol - * @psalm-return ($url is null ? string|null : string) + * + * @param string|null $url + * @return string */ - public static function fix(string|null $url = null): string|null + public static function fix(string $url = null): string { // make sure to not touch absolute urls - if (!preg_match('!^(https|http|ftp)\:\/\/!i', $url ?? '')) { - return 'http://' . $url; - } - - return $url; + return (!preg_match('!^(https|http|ftp)\:\/\/!i', $url ?? '')) ? 'http://' . $url : $url; } /** * Returns the home url if defined + * + * @return string */ public static function home(): string { @@ -87,6 +98,9 @@ class Url /** * Returns the url to the executed script + * + * @param array $props + * @return string */ public static function index(array $props = []): string { @@ -95,22 +109,27 @@ class Url /** * Checks if an URL is absolute + * + * @param string|null $url + * @return bool */ - public static function isAbsolute(string|null $url = null): bool + public static function isAbsolute(string $url = null): bool { // matches the following groups of URLs: // //example.com/uri // http://example.com/uri, https://example.com/uri, ftp://example.com/uri // mailto:example@example.com, geo:49.0158,8.3239?z=11 - return - $url !== null && - preg_match('!^(//|[a-z0-9+-.]+://|mailto:|tel:|geo:)!i', $url) === 1; + return $url !== null && preg_match('!^(//|[a-z0-9+-.]+://|mailto:|tel:|geo:)!i', $url) === 1; } /** * Convert a relative path into an absolute URL + * + * @param string|null $path + * @param string|null $home + * @return string */ - public static function makeAbsolute(string|null $path = null, string|null $home = null): string + public static function makeAbsolute(string $path = null, string $home = null): string { if ($path === '' || $path === '/' || $path === null) { return $home ?? static::home(); @@ -137,27 +156,32 @@ class Url /** * Returns the path for the given url + * + * @param string|array|null $url + * @param bool $leadingSlash + * @param bool $trailingSlash + * @return string */ - public static function path( - string|array|null $url = null, - bool $leadingSlash = false, - bool $trailingSlash = false - ): string { - return Url::toObject($url) - ->path() - ->toString($leadingSlash, $trailingSlash); + public static function path($url = null, bool $leadingSlash = false, bool $trailingSlash = false): string + { + return Url::toObject($url)->path()->toString($leadingSlash, $trailingSlash); } /** * Returns the query for the given url + * + * @param string|array|null $url + * @return string */ - public static function query(string|array|null $url = null): string + public static function query($url = null): string { return Url::toObject($url)->query()->toString(); } /** * Return the last url the user has been on if detectable + * + * @return string */ public static function last(): string { @@ -166,13 +190,15 @@ class Url /** * Shortens the Url by removing all unnecessary parts + * + * @param string $url + * @param int $length + * @param bool $base + * @param string $rep + * @return string */ - public static function short( - string|null $url = null, - int $length = 0, - bool $base = false, - string $rep = '…' - ): string { + public static function short($url = null, int $length = 0, bool $base = false, string $rep = '…'): string + { $uri = static::toObject($url); $uri->fragment = null; @@ -186,42 +212,53 @@ class Url $uri->slash = false; $url = $base ? $uri->base() : $uri->toString(); - $url = str_replace('www.', '', $url ?? ''); + $url = str_replace('www.', '', $url); return Str::short($url, $length, $rep); } /** * Removes the path from the Url + * + * @param string $url + * @return string */ - public static function stripPath(string|null $url = null): string + public static function stripPath($url = null): string { return static::toObject($url)->setPath(null)->toString(); } /** * Removes the query string from the Url + * + * @param string $url + * @return string */ - public static function stripQuery(string|null $url = null): string + public static function stripQuery($url = null): string { return static::toObject($url)->setQuery(null)->toString(); } /** * Removes the fragment (hash) from the Url + * + * @param string $url + * @return string */ - public static function stripFragment(string|null $url = null): string + public static function stripFragment($url = null): string { return static::toObject($url)->setFragment(null)->toString(); } /** * Smart resolver for internal and external urls + * + * @param string $path + * @param mixed $options + * @return string */ - public static function to( - string|null $path = null, - array $options = null - ): string { + public static function to(string $path = null, $options = null): string + { // make sure $path is string $path ??= ''; @@ -241,8 +278,11 @@ class Url /** * Converts the Url to a Uri object + * + * @param string $url + * @return \Kirby\Http\Uri */ - public static function toObject(string|null $url = null): Uri + public static function toObject($url = null) { return $url === null ? Uri::current() : new Uri($url); } diff --git a/kirby/src/Http/Visitor.php b/kirby/src/Http/Visitor.php index ea2ac2e..6c1b2ac 100644 --- a/kirby/src/Http/Visitor.php +++ b/kirby/src/Http/Visitor.php @@ -20,10 +20,29 @@ use Kirby\Toolkit\Str; */ class Visitor { - protected string|null $ip = null; - protected string|null $userAgent = null; - protected string|null $acceptedLanguage = null; - protected string|null $acceptedMimeType = null; + /** + * IP address + * @var string|null + */ + protected $ip; + + /** + * user agent + * @var string|null + */ + protected $userAgent; + + /** + * accepted language + * @var string|null + */ + protected $acceptedLanguage; + + /** + * accepted mime type + * @var string|null + */ + protected $acceptedMimeType; /** * Creates a new visitor object. @@ -31,22 +50,15 @@ class Visitor * modify the information about the visitor. * * By default everything is pulled from $_SERVER + * + * @param array $arguments */ public function __construct(array $arguments = []) { - $ip = $arguments['ip'] ?? null; - $ip ??= Environment::getGlobally('REMOTE_ADDR', ''); - $agent = $arguments['userAgent'] ?? null; - $agent ??= Environment::getGlobally('HTTP_USER_AGENT', ''); - $language = $arguments['acceptedLanguage'] ?? null; - $language ??= Environment::getGlobally('HTTP_ACCEPT_LANGUAGE', ''); - $mime = $arguments['acceptedMimeType'] ?? null; - $mime ??= Environment::getGlobally('HTTP_ACCEPT', ''); - - $this->ip($ip); - $this->userAgent($agent); - $this->acceptedLanguage($language); - $this->acceptedMimeType($mime); + $this->ip($arguments['ip'] ?? Environment::getGlobally('REMOTE_ADDR', '')); + $this->userAgent($arguments['userAgent'] ?? Environment::getGlobally('HTTP_USER_AGENT', '')); + $this->acceptedLanguage($arguments['acceptedLanguage'] ?? Environment::getGlobally('HTTP_ACCEPT_LANGUAGE', '')); + $this->acceptedMimeType($arguments['acceptedMimeType'] ?? Environment::getGlobally('HTTP_ACCEPT', '')); } /** @@ -54,11 +66,11 @@ class Visitor * provided or returns the user's * accepted language otherwise * - * @return $this|\Kirby\Toolkit\Obj|null + * @param string|null $acceptedLanguage + * @return \Kirby\Toolkit\Obj|\Kirby\Http\Visitor|null */ - public function acceptedLanguage( - string|null $acceptedLanguage = null - ): static|Obj|null { + public function acceptedLanguage(string $acceptedLanguage = null) + { if ($acceptedLanguage === null) { return $this->acceptedLanguages()->first(); } @@ -70,8 +82,10 @@ class Visitor /** * Returns an array of all accepted languages * including their quality and locale + * + * @return \Kirby\Toolkit\Collection */ - public function acceptedLanguages(): Collection + public function acceptedLanguages() { $accepted = Str::accepted($this->acceptedLanguage); $languages = []; @@ -97,6 +111,9 @@ class Visitor /** * Checks if the user accepts the given language + * + * @param string $code + * @return bool */ public function acceptsLanguage(string $code): bool { @@ -116,11 +133,11 @@ class Visitor * provided or returns the user's * accepted mime type otherwise * - * @return $this|\Kirby\Toolkit\Obj|null + * @param string|null $acceptedMimeType + * @return \Kirby\Toolkit\Obj|\Kirby\Http\Visitor */ - public function acceptedMimeType( - string|null $acceptedMimeType = null - ): static|Obj|null { + public function acceptedMimeType(string $acceptedMimeType = null) + { if ($acceptedMimeType === null) { return $this->acceptedMimeTypes()->first(); } @@ -131,8 +148,10 @@ class Visitor /** * Returns a collection of all accepted mime types + * + * @return \Kirby\Toolkit\Collection */ - public function acceptedMimeTypes(): Collection + public function acceptedMimeTypes() { $accepted = Str::accepted($this->acceptedMimeType); $mimes = []; @@ -149,6 +168,9 @@ class Visitor /** * Checks if the user accepts the given mime type + * + * @param string $mimeType + * @return bool */ public function acceptsMimeType(string $mimeType): bool { @@ -163,7 +185,7 @@ class Visitor * @param string ...$mimeTypes MIME types to query for * @return string|null Preferred MIME type */ - public function preferredMimeType(string ...$mimeTypes): string|null + public function preferredMimeType(string ...$mimeTypes): ?string { foreach ($this->acceptedMimeTypes() as $acceptedMime) { // look for direct matches @@ -186,11 +208,12 @@ class Visitor * Returns true if the visitor prefers a JSON response over * an HTML response based on the `Accept` request header * @since 3.3.0 + * + * @return bool */ public function prefersJson(): bool { - $preferred = $this->preferredMimeType('application/json', 'text/html'); - return $preferred === 'application/json'; + return $this->preferredMimeType('application/json', 'text/html') === 'application/json'; } /** @@ -198,14 +221,14 @@ class Visitor * or returns the ip of the current * visitor otherwise * - * @return $this|string|null + * @param string|null $ip + * @return string|Visitor|null */ - public function ip(string|null $ip = null): static|string|null + public function ip(string $ip = null) { if ($ip === null) { return $this->ip; } - $this->ip = $ip; return $this; } @@ -215,14 +238,14 @@ class Visitor * or returns the user agent string of * the current visitor otherwise * - * @return $this|string|null + * @param string|null $userAgent + * @return string|Visitor|null */ - public function userAgent(string|null $userAgent = null): static|string|null + public function userAgent(string $userAgent = null) { if ($userAgent === null) { return $this->userAgent; } - $this->userAgent = $userAgent; return $this; } diff --git a/kirby/src/Image/Camera.php b/kirby/src/Image/Camera.php index c149c2e..3cfb793 100644 --- a/kirby/src/Image/Camera.php +++ b/kirby/src/Image/Camera.php @@ -13,9 +13,25 @@ namespace Kirby\Image; */ class Camera { - protected string|null $make; - protected string|null $model; + /** + * Make exif data + * + * @var string|null + */ + protected $make; + /** + * Model exif data + * + * @var string|null + */ + protected $model; + + /** + * Constructor + * + * @param array $exif + */ public function __construct(array $exif) { $this->make = $exif['Make'] ?? null; @@ -24,22 +40,28 @@ class Camera /** * Returns the make of the camera + * + * @return string */ - public function make(): string|null + public function make(): ?string { return $this->make; } /** * Returns the camera model + * + * @return string */ - public function model(): string|null + public function model(): ?string { return $this->model; } /** * Converts the object into a nicely readable array + * + * @return array */ public function toArray(): array { @@ -51,6 +73,8 @@ class Camera /** * Returns the full make + model name + * + * @return string */ public function __toString(): string { @@ -59,7 +83,8 @@ class Camera /** * Improved `var_dump` output - * @codeCoverageIgnore + * + * @return array */ public function __debugInfo(): array { diff --git a/kirby/src/Image/Darkroom.php b/kirby/src/Image/Darkroom.php index 7d727e7..642273a 100644 --- a/kirby/src/Image/Darkroom.php +++ b/kirby/src/Image/Darkroom.php @@ -3,8 +3,6 @@ namespace Kirby\Image; use Exception; -use Kirby\Image\Darkroom\GdLib; -use Kirby\Image\Darkroom\ImageMagick; /** * A wrapper around resizing and cropping @@ -18,14 +16,23 @@ use Kirby\Image\Darkroom\ImageMagick; */ class Darkroom { - public static array $types = [ - 'gd' => GdLib::class, - 'im' => ImageMagick::class + public static $types = [ + 'gd' => 'Kirby\Image\Darkroom\GdLib', + 'im' => 'Kirby\Image\Darkroom\ImageMagick' ]; - public function __construct( - protected array $settings = [] - ) { + /** + * @var array + */ + protected $settings = []; + + /** + * Darkroom constructor + * + * @param array $settings + */ + public function __construct(array $settings = []) + { $this->settings = array_merge($this->defaults(), $settings); } @@ -33,9 +40,12 @@ class Darkroom * Creates a new Darkroom instance for the given * type/driver * + * @param string $type + * @param array $settings + * @return mixed * @throws \Exception */ - public static function factory(string $type, array $settings = []): object + public static function factory(string $type, array $settings = []) { if (isset(static::$types[$type]) === false) { throw new Exception('Invalid Darkroom type'); @@ -47,6 +57,8 @@ class Darkroom /** * Returns the default thumb settings + * + * @return array */ protected function defaults(): array { @@ -60,13 +72,15 @@ class Darkroom 'quality' => 90, 'scaleHeight' => null, 'scaleWidth' => null, - 'sharpen' => null, 'width' => null, ]; } /** * Normalizes all thumb options + * + * @param array $options + * @return array */ protected function options(array $options = []): array { @@ -94,13 +108,10 @@ class Darkroom unset($options['bw']); } - // normalize the sharpen option - if ($options['sharpen'] === true) { - $options['sharpen'] = 50; + if ($options['quality'] === null) { + $options['quality'] = $this->settings['quality']; } - $options['quality'] ??= $this->settings['quality']; - return $options; } @@ -108,30 +119,28 @@ class Darkroom * Calculates the dimensions of the final thumb based * on the given options and returns a full array with * all the final options to be used for the image generator + * + * @param string $file + * @param array $options + * @return array */ - public function preprocess(string $file, array $options = []): array + public function preprocess(string $file, array $options = []) { $options = $this->options($options); $image = new Image($file); - $options['sourceWidth'] = $image->width(); - $options['sourceHeight'] = $image->height(); + $dimensions = $image->dimensions(); + $thumbDimensions = $dimensions->thumb($options); - $dimensions = $image->dimensions(); - $thumbDimensions = $dimensions->thumb($options); + $sourceWidth = $image->width(); + $sourceHeight = $image->height(); $options['width'] = $thumbDimensions->width(); $options['height'] = $thumbDimensions->height(); // scale ratio compared to the source dimensions - $options['scaleWidth'] = Focus::ratio( - $options['width'], - $options['sourceWidth'] - ); - $options['scaleHeight'] = Focus::ratio( - $options['height'], - $options['sourceHeight'] - ); + $options['scaleWidth'] = $sourceWidth ? $options['width'] / $sourceWidth : null; + $options['scaleHeight'] = $sourceHeight ? $options['height'] / $sourceHeight : null; return $options; } @@ -139,6 +148,10 @@ class Darkroom /** * This method must be replaced by the driver to run the * actual image processing job. + * + * @param string $file + * @param array $options + * @return array */ public function process(string $file, array $options = []): array { diff --git a/kirby/src/Image/Darkroom/GdLib.php b/kirby/src/Image/Darkroom/GdLib.php index 0e837d6..bc381e6 100644 --- a/kirby/src/Image/Darkroom/GdLib.php +++ b/kirby/src/Image/Darkroom/GdLib.php @@ -5,7 +5,6 @@ namespace Kirby\Image\Darkroom; use claviska\SimpleImage; use Kirby\Filesystem\Mime; use Kirby\Image\Darkroom; -use Kirby\Image\Focus; /** * GdLib @@ -20,6 +19,10 @@ class GdLib extends Darkroom { /** * Processes the image with the SimpleImage library + * + * @param string $file + * @param array $options + * @return array */ public function process(string $file, array $options = []): array { @@ -33,9 +36,8 @@ class GdLib extends Darkroom $image = $this->autoOrient($image, $options); $image = $this->blur($image, $options); $image = $this->grayscale($image, $options); - $image = $this->sharpen($image, $options); - $image->toFile($file, $mime, $options); + $image->toFile($file, $mime, $options['quality']); return $options; } @@ -43,8 +45,12 @@ class GdLib extends Darkroom /** * Activates the autoOrient option in SimpleImage * unless this is deactivated + * + * @param \claviska\SimpleImage $image + * @param $options + * @return \claviska\SimpleImage */ - protected function autoOrient(SimpleImage $image, array $options): SimpleImage + protected function autoOrient(SimpleImage $image, $options) { if ($options['autoOrient'] === false) { return $image; @@ -55,48 +61,28 @@ class GdLib extends Darkroom /** * Wrapper around SimpleImage's resize and crop methods + * + * @param \claviska\SimpleImage $image + * @param array $options + * @return \claviska\SimpleImage */ - protected function resize(SimpleImage $image, array $options): SimpleImage + protected function resize(SimpleImage $image, array $options) { - // just resize, no crop if ($options['crop'] === false) { return $image->resize($options['width'], $options['height']); } - // crop based on focus point - if (Focus::isFocalPoint($options['crop']) === true) { - // get crop coords for focal point: - // if image needs to be cropped, crop before resizing - if ($focus = Focus::coords( - $options['crop'], - $options['sourceWidth'], - $options['sourceHeight'], - $options['width'], - $options['height'] - )) { - $image->crop( - $focus['x1'], - $focus['y1'], - $focus['x2'], - $focus['y2'] - ); - } - - return $image->thumbnail($options['width'], $options['height']); - } - - // normal crop with crop anchor - return $image->thumbnail( - $options['width'], - $options['height'] ?? $options['width'], - $options['crop'] - ); + return $image->thumbnail($options['width'], $options['height'] ?? $options['width'], $options['crop']); } /** * Applies the correct blur settings for SimpleImage + * + * @param \claviska\SimpleImage $image + * @param array $options + * @return \claviska\SimpleImage */ - protected function blur(SimpleImage $image, array $options): SimpleImage + protected function blur(SimpleImage $image, array $options) { if ($options['blur'] === false) { return $image; @@ -107,8 +93,12 @@ class GdLib extends Darkroom /** * Applies grayscale conversion if activated in the options. + * + * @param \claviska\SimpleImage $image + * @param array $options + * @return \claviska\SimpleImage */ - protected function grayscale(SimpleImage $image, array $options): SimpleImage + protected function grayscale(SimpleImage $image, array $options) { if ($options['grayscale'] === false) { return $image; @@ -117,22 +107,13 @@ class GdLib extends Darkroom return $image->desaturate(); } - /** - * Applies sharpening if activated in the options. - */ - protected function sharpen(SimpleImage $image, array $options): SimpleImage - { - if (is_int($options['sharpen']) === false) { - return $image; - } - - return $image->sharpen($options['sharpen']); - } - /** * Returns mime type based on `format` option + * + * @param array $options + * @return string|null */ - protected function mime(array $options): string|null + protected function mime(array $options): ?string { if ($options['format'] === null) { return null; diff --git a/kirby/src/Image/Darkroom/ImageMagick.php b/kirby/src/Image/Darkroom/ImageMagick.php index 1fc767a..33e33aa 100644 --- a/kirby/src/Image/Darkroom/ImageMagick.php +++ b/kirby/src/Image/Darkroom/ImageMagick.php @@ -5,7 +5,6 @@ namespace Kirby\Image\Darkroom; use Exception; use Kirby\Filesystem\F; use Kirby\Image\Darkroom; -use Kirby\Image\Focus; /** * ImageMagick @@ -21,49 +20,67 @@ class ImageMagick extends Darkroom /** * Activates imagemagick's auto-orient feature unless * it is deactivated via the options + * + * @param string $file + * @param array $options + * @return string */ - protected function autoOrient(string $file, array $options): string|null + protected function autoOrient(string $file, array $options) { if ($options['autoOrient'] === true) { return '-auto-orient'; } - - return null; } /** * Applies the blur settings + * + * @param string $file + * @param array $options + * @return string */ - protected function blur(string $file, array $options): string|null + protected function blur(string $file, array $options) { if ($options['blur'] !== false) { return '-blur ' . escapeshellarg('0x' . $options['blur']); } - - return null; } /** * Keep animated gifs + * + * @param string $file + * @param array $options + * @return string */ - protected function coalesce(string $file, array $options): string|null + protected function coalesce(string $file, array $options) { if (F::extension($file) === 'gif') { return '-coalesce'; } - - return null; } /** * Creates the convert command with the right path to the binary file + * + * @param string $file + * @param array $options + * @return string */ protected function convert(string $file, array $options): string { $command = escapeshellarg($options['bin']); - // default is limiting to single-threading to keep CPU usage sane - $command .= ' -limit thread ' . escapeshellarg($options['threads']); + // limit to single-threading to keep CPU usage sane + $command .= ' -limit thread 1'; + + // add JPEG size hint to optimize CPU and memory usage + if (F::mime($file) === 'image/jpeg') { + // add hint only when downscaling + if ($options['scaleWidth'] < 1 && $options['scaleHeight'] < 1) { + $command .= ' -define ' . escapeshellarg(sprintf('jpeg:size=%dx%d', $options['width'], $options['height'])); + } + } // append input file return $command . ' ' . escapeshellarg($file); @@ -71,58 +88,53 @@ class ImageMagick extends Darkroom /** * Returns additional default parameters for imagemagick + * + * @return array */ protected function defaults(): array { return parent::defaults() + [ 'bin' => 'convert', 'interlace' => false, - 'threads' => 1, ]; } /** * Applies the correct settings for grayscale images + * + * @param string $file + * @param array $options + * @return string */ - protected function grayscale(string $file, array $options): string|null + protected function grayscale(string $file, array $options) { if ($options['grayscale'] === true) { return '-colorspace gray'; } - - return null; - } - - /** - * Applies sharpening if activated in the options. - */ - protected function sharpen(string $file, array $options): string|null - { - if (is_int($options['sharpen']) === false) { - return null; - } - - $amount = max(1, min(100, $options['sharpen'])) / 100; - return '-sharpen ' . escapeshellarg('0x' . $amount); } /** * Applies the correct settings for interlaced JPEGs if * activated via options + * + * @param string $file + * @param array $options + * @return string */ - protected function interlace(string $file, array $options): string|null + protected function interlace(string $file, array $options) { if ($options['interlace'] === true) { return '-interlace line'; } - - return null; } /** * Creates and runs the full imagemagick command * to process the image * + * @param string $file + * @param array $options + * @return array * @throws \Exception */ public function process(string $file, array $options = []): array @@ -139,7 +151,6 @@ class ImageMagick extends Darkroom $command[] = $this->resize($file, $options); $command[] = $this->quality($file, $options); $command[] = $this->blur($file, $options); - $command[] = $this->sharpen($file, $options); $command[] = $this->save($file, $options); // remove all null values and join the parts @@ -158,6 +169,10 @@ class ImageMagick extends Darkroom /** * Applies the correct JPEG compression quality settings + * + * @param string $file + * @param array $options + * @return string */ protected function quality(string $file, array $options): string { @@ -167,6 +182,10 @@ class ImageMagick extends Darkroom /** * Creates the correct options to crop or resize the image * and translates the crop positions for imagemagick + * + * @param string $file + * @param array $options + * @return string */ protected function resize(string $file, array $options): string { @@ -175,39 +194,20 @@ class ImageMagick extends Darkroom return '-thumbnail ' . escapeshellarg(sprintf('%sx%s!', $options['width'], $options['height'])); } - // crop based on focus point - if (Focus::isFocalPoint($options['crop']) === true) { - if ($focus = Focus::coords( - $options['crop'], - $options['sourceWidth'], - $options['sourceHeight'], - $options['width'], - $options['height'] - )) { - return sprintf( - '-crop %sx%s+%s+%s -resize %sx%s^', - $focus['width'], - $focus['height'], - $focus['x1'], - $focus['y1'], - $options['width'], - $options['height'] - ); - } - } - - // translate the gravity option into something imagemagick understands - $gravity = match ($options['crop'] ?? null) { + $gravities = [ 'top left' => 'NorthWest', 'top' => 'North', 'top right' => 'NorthEast', 'left' => 'West', + 'center' => 'Center', 'right' => 'East', 'bottom left' => 'SouthWest', 'bottom' => 'South', - 'bottom right' => 'SouthEast', - default => 'Center' - }; + 'bottom right' => 'SouthEast' + ]; + + // translate the gravity option into something imagemagick understands + $gravity = $gravities[$options['crop']] ?? 'Center'; $command = '-thumbnail ' . escapeshellarg(sprintf('%sx%s^', $options['width'], $options['height'])); $command .= ' -gravity ' . escapeshellarg($gravity); @@ -218,6 +218,10 @@ class ImageMagick extends Darkroom /** * Creates the option for the output file + * + * @param string $file + * @param array $options + * @return string */ protected function save(string $file, array $options): string { @@ -230,6 +234,10 @@ class ImageMagick extends Darkroom /** * Removes all metadata from the image + * + * @param string $file + * @param array $options + * @return string */ protected function strip(string $file, array $options): string { diff --git a/kirby/src/Image/Dimensions.php b/kirby/src/Image/Dimensions.php index cf6d334..30931c6 100644 --- a/kirby/src/Image/Dimensions.php +++ b/kirby/src/Image/Dimensions.php @@ -2,8 +2,6 @@ namespace Kirby\Image; -use Kirby\Toolkit\Str; - /** * The Dimension class is used to provide additional * methods for images and possibly other objects with @@ -18,15 +16,36 @@ use Kirby\Toolkit\Str; */ class Dimensions { - public function __construct( - public int $width, - public int $height - ) { + /** + * the height of the parent object + * + * @var int + */ + public $height = 0; + + /** + * the width of the parent object + * + * @var int + */ + public $width = 0; + + /** + * Constructor + * + * @param int $width + * @param int $height + */ + public function __construct(int $width, int $height) + { + $this->width = $width; + $this->height = $height; } /** * Improved `var_dump` output - * @codeCoverageIgnore + * + * @return array */ public function __debugInfo(): array { @@ -35,6 +54,8 @@ class Dimensions /** * Echos the dimensions as width × height + * + * @return string */ public function __toString(): string { @@ -44,9 +65,11 @@ class Dimensions /** * Crops the dimensions by width and height * + * @param int $width + * @param int|null $height * @return $this */ - public function crop(int $width, int|null $height = null): static + public function crop(int $width, int $height = null) { $this->width = $width; $this->height = $width; @@ -60,8 +83,10 @@ class Dimensions /** * Returns the height + * + * @return int */ - public function height(): int + public function height() { return $this->height; } @@ -87,7 +112,7 @@ class Dimensions * upscaled to fit the box if smaller * @return $this object with recalculated dimensions */ - public function fit(int $box, bool $force = false): static + public function fit(int $box, bool $force = false) { if ($this->width === 0 || $this->height === 0) { $this->width = $box; @@ -139,10 +164,8 @@ class Dimensions * upscaled to fit the box if smaller * @return $this object with recalculated dimensions */ - public function fitHeight( - int|null $fit = null, - bool $force = false - ): static { + public function fitHeight(int $fit = null, bool $force = false) + { return $this->fitSize('height', $fit, $force); } @@ -155,11 +178,8 @@ class Dimensions * upscaled to fit the box if smaller * @return $this object with recalculated dimensions */ - protected function fitSize( - string $ref, - int|null $fit = null, - bool $force = false - ): static { + protected function fitSize(string $ref, int $fit = null, bool $force = false) + { if ($fit === 0 || $fit === null) { return $this; } @@ -197,10 +217,8 @@ class Dimensions * upscaled to fit the box if smaller * @return $this object with recalculated dimensions */ - public function fitWidth( - int|null $fit = null, - bool $force = false - ): static { + public function fitWidth(int $fit = null, bool $force = false) + { return $this->fitSize('width', $fit, $force); } @@ -209,13 +227,11 @@ class Dimensions * * @param int|null $width the max height * @param int|null $height the max width + * @param bool $force * @return $this */ - public function fitWidthAndHeight( - int|null $width = null, - int|null $height = null, - bool $force = false - ): static { + public function fitWidthAndHeight(int $width = null, int $height = null, bool $force = false) + { if ($this->width > $this->height) { $this->fitWidth($width, $force); @@ -237,8 +253,11 @@ class Dimensions /** * Detect the dimensions for an image file + * + * @param string $root + * @return static */ - public static function forImage(string $root): static + public static function forImage(string $root) { if (file_exists($root) === false) { return new static(0, 0); @@ -250,8 +269,11 @@ class Dimensions /** * Detect the dimensions for a svg file + * + * @param string $root + * @return static */ - public static function forSvg(string $root): static + public static function forSvg(string $root) { // avoid xml errors libxml_use_internal_errors(true); @@ -262,28 +284,13 @@ class Dimensions $xml = simplexml_load_string($content); if ($xml !== false) { - $attr = $xml->attributes(); - $rawWidth = $attr->width; - $width = (int)$rawWidth; - $rawHeight = $attr->height; - $height = (int)$rawHeight; - - // use viewbox values if direct attributes are 0 - // or based on percentages - if (empty($attr->viewBox) === false) { - $box = explode(' ', $attr->viewBox); - - // when using viewbox values, make sure to subtract - // first two box values from last two box values - // to retrieve the absolute dimensions - - if (Str::endsWith($rawWidth, '%') === true || $width === 0) { - $width = (int)($box[2] ?? 0) - (int)($box[0] ?? 0); - } - - if (Str::endsWith($rawHeight, '%') === true || $height === 0) { - $height = (int)($box[3] ?? 0) - (int)($box[1] ?? 0); - } + $attr = $xml->attributes(); + $width = (int)($attr->width); + $height = (int)($attr->height); + if (($width === 0 || $height === 0) && empty($attr->viewBox) === false) { + $box = explode(' ', $attr->viewBox); + $width = (int)($box[2] ?? 0); + $height = (int)($box[3] ?? 0); } } @@ -292,6 +299,8 @@ class Dimensions /** * Checks if the dimensions are landscape + * + * @return bool */ public function landscape(): bool { @@ -300,18 +309,20 @@ class Dimensions /** * Returns a string representation of the orientation + * + * @return string|false */ - public function orientation(): string|false + public function orientation() { if (!$this->ratio()) { return false; } - if ($this->portrait() === true) { + if ($this->portrait()) { return 'portrait'; } - if ($this->landscape() === true) { + if ($this->landscape()) { return 'landscape'; } @@ -320,6 +331,8 @@ class Dimensions /** * Checks if the dimensions are portrait + * + * @return bool */ public function portrait(): bool { @@ -336,6 +349,8 @@ class Dimensions * // output: 1.5625 * * + * + * @return float */ public function ratio(): float { @@ -343,23 +358,24 @@ class Dimensions return $this->width / $this->height; } - return 0.0; + return 0; } /** - * Resizes image + * @param int|null $width + * @param int|null $height + * @param bool $force * @return $this */ - public function resize( - int|null $width = null, - int|null $height = null, - bool $force = false - ): static { + public function resize(int $width = null, int $height = null, bool $force = false) + { return $this->fitWidthAndHeight($width, $height, $force); } /** * Checks if the dimensions are square + * + * @return bool */ public function square(): bool { @@ -369,9 +385,10 @@ class Dimensions /** * Resize and crop * + * @param array $options * @return $this */ - public function thumb(array $options = []): static + public function thumb(array $options = []) { $width = $options['width'] ?? null; $height = $options['height'] ?? null; @@ -388,6 +405,8 @@ class Dimensions /** * Converts the dimensions object * to a plain PHP array + * + * @return array */ public function toArray(): array { @@ -401,6 +420,8 @@ class Dimensions /** * Returns the width + * + * @return int */ public function width(): int { diff --git a/kirby/src/Image/Exif.php b/kirby/src/Image/Exif.php index f32afd0..9405271 100644 --- a/kirby/src/Image/Exif.php +++ b/kirby/src/Image/Exif.php @@ -16,33 +16,86 @@ use Kirby\Toolkit\V; class Exif { /** - * The raw exif array + * the parent image object + * @var \Kirby\Image\Image */ - protected array $data = []; + protected $image; - protected Camera|null $camera = null; - protected Location|null $location = null; - protected string|null $timestamp = null; - protected string|null $exposure = null; - protected string|null $aperture = null; - protected string|null $iso = null; - protected string|null $focalLength = null; - protected bool|null $isColor = null; + /** + * the raw exif array + * @var array + */ + protected $data = []; - public function __construct( - protected Image $image - ) { - $this->data = $this->read(); - $this->timestamp = $this->parseTimestamp(); - $this->exposure = $this->data['ExposureTime'] ?? null; - $this->iso = $this->data['ISOSpeedRatings'] ?? null; - $this->focalLength = $this->parseFocalLength(); - $this->aperture = $this->computed()['ApertureFNumber'] ?? null; - $this->isColor = V::accepted($this->computed()['IsColor'] ?? null); + /** + * the camera object with model and make + * @var Camera + */ + protected $camera; + + /** + * the location object + * @var Location + */ + protected $location; + + /** + * the timestamp + * + * @var string + */ + protected $timestamp; + + /** + * the exposure value + * + * @var string + */ + protected $exposure; + + /** + * the aperture value + * + * @var string + */ + protected $aperture; + + /** + * iso value + * + * @var string + */ + protected $iso; + + /** + * focal length + * + * @var string + */ + protected $focalLength; + + /** + * color or black/white + * @var bool + */ + protected $isColor; + + /** + * Constructor + * + * @param \Kirby\Image\Image $image + */ + public function __construct(Image $image) + { + $this->image = $image; + $this->data = $this->read(); + $this->parse(); } /** * Returns the raw data array from the parser + * + * @return array */ public function data(): array { @@ -51,78 +104,106 @@ class Exif /** * Returns the Camera object + * + * @return \Kirby\Image\Camera|null */ - public function camera(): Camera + public function camera() { - return $this->camera ??= new Camera($this->data); + if ($this->camera !== null) { + return $this->camera; + } + + return $this->camera = new Camera($this->data); } /** * Returns the location object + * + * @return \Kirby\Image\Location|null */ - public function location(): Location + public function location() { - return $this->location ??= new Location($this->data); + if ($this->location !== null) { + return $this->location; + } + + return $this->location = new Location($this->data); } /** * Returns the timestamp + * + * @return string|null */ - public function timestamp(): string|null + public function timestamp() { return $this->timestamp; } /** * Returns the exposure + * + * @return string|null */ - public function exposure(): string|null + public function exposure() { return $this->exposure; } /** * Returns the aperture + * + * @return string|null */ - public function aperture(): string|null + public function aperture() { return $this->aperture; } /** * Returns the iso value + * + * @return int|null */ - public function iso(): string|null + public function iso() { return $this->iso; } /** * Checks if this is a color picture + * + * @return bool|null */ - public function isColor(): bool|null + public function isColor() { return $this->isColor; } /** * Checks if this is a bw picture + * + * @return bool|null */ - public function isBW(): bool|null + public function isBW(): ?bool { return ($this->isColor !== null) ? $this->isColor === false : null; } /** * Returns the focal length + * + * @return string|null */ - public function focalLength(): string|null + public function focalLength() { return $this->focalLength; } /** * Read the exif data of the image object if possible + * + * @return mixed */ protected function read(): array { @@ -138,6 +219,8 @@ class Exif /** * Get all computed data + * + * @return array */ protected function computed(): array { @@ -145,14 +228,27 @@ class Exif } /** - * Return the timestamp when the picture has been taken + * Pareses and stores all relevant exif data */ - protected function parseTimestamp(): string + protected function parse() + { + $this->timestamp = $this->parseTimestamp(); + $this->exposure = $this->data['ExposureTime'] ?? null; + $this->iso = $this->data['ISOSpeedRatings'] ?? null; + $this->focalLength = $this->parseFocalLength(); + $this->aperture = $this->computed()['ApertureFNumber'] ?? null; + $this->isColor = V::accepted($this->computed()['IsColor'] ?? null); + } + + /** + * Return the timestamp when the picture has been taken + * + * @return string|int + */ + protected function parseTimestamp() { if (isset($this->data['DateTimeOriginal']) === true) { - if ($time = strtotime($this->data['DateTimeOriginal'])) { - return (string)$time; - } + return strtotime($this->data['DateTimeOriginal']); } return $this->data['FileDateTime'] ?? $this->image->modified(); @@ -160,23 +256,24 @@ class Exif /** * Return the focal length + * + * @return string|null */ - protected function parseFocalLength(): string|null + protected function parseFocalLength() { - return - $this->data['FocalLength'] ?? - $this->data['FocalLengthIn35mmFilm'] ?? - null; + return $this->data['FocalLength'] ?? $this->data['FocalLengthIn35mmFilm'] ?? null; } /** * Converts the object into a nicely readable array + * + * @return array */ public function toArray(): array { return [ - 'camera' => $this->camera()->toArray(), - 'location' => $this->location()->toArray(), + 'camera' => $this->camera() ? $this->camera()->toArray() : null, + 'location' => $this->location() ? $this->location()->toArray() : null, 'timestamp' => $this->timestamp(), 'exposure' => $this->exposure(), 'aperture' => $this->aperture(), @@ -188,7 +285,8 @@ class Exif /** * Improved `var_dump` output - * @codeCoverageIgnore + * + * @return array */ public function __debugInfo(): array { diff --git a/kirby/src/Image/Focus.php b/kirby/src/Image/Focus.php deleted file mode 100644 index da1dc73..0000000 --- a/kirby/src/Image/Focus.php +++ /dev/null @@ -1,110 +0,0 @@ - - * @link https://getkirby.com - * @copyright Bastian Allgeier - * @license https://opensource.org/licenses/MIT - */ -class Focus -{ - /** - * Generates crop coordinates based on focal point - */ - public static function coords( - string $crop, - int $sourceWidth, - int $sourceHeight, - int $width, - int $height - ): array|null { - [$x, $y] = static::parse($crop); - - // determine aspect ratios - $ratioSource = static::ratio($sourceWidth, $sourceHeight); - $ratioThumb = static::ratio($width, $height); - - // no cropping necessary - if ($ratioSource == $ratioThumb) { - return null; - } - - // defaults - $width = $sourceWidth; - $height = $sourceHeight; - - if ($ratioThumb > $ratioSource) { - $height = $sourceWidth / $ratioThumb; - } else { - $width = $sourceHeight * $ratioThumb; - } - - // calculate focus for original image - $x = $sourceWidth * $x; - $y = $sourceHeight * $y; - - $x1 = max(0, $x - $width / 2); - $y1 = max(0, $y - $height / 2); - - // off canvas? - if ($x1 + $width > $sourceWidth) { - $x1 = $sourceWidth - $width; - } - - if ($y1 + $height > $sourceHeight) { - $y1 = $sourceHeight - $height; - } - - return [ - 'x1' => (int)floor($x1), - 'y1' => (int)floor($y1), - 'x2' => (int)floor($x1 + $width), - 'y2' => (int)floor($y1 + $height), - 'width' => (int)floor($width), - 'height' => (int)floor($height), - ]; - } - - public static function isFocalPoint(string $value): bool - { - return Str::contains($value, '%') === true; - } - - /** - * Transforms the focal point's string value (from content field) - * to a [x, y] array (values 0.0-1.0) - */ - public static function parse(string $value): array - { - // support for former Focus plugin - if (Str::startsWith($value, '{') === true) { - $focus = json_decode($value); - return [$focus->x, $focus->y]; - } - - preg_match_all("/(\d{1,3}\.?\d*)[%|,|\s]*/", $value, $points); - - return A::map( - $points[1], - function ($point) { - $point = (float)$point; - $point = $point > 1 ? $point / 100 : $point; - return round($point, 3); - } - ); - } - - /** - * Calculates the image ratio - */ - public static function ratio(int $width, int $height): float - { - return $height !== 0 ? $width / $height : 0; - } -} diff --git a/kirby/src/Image/Image.php b/kirby/src/Image/Image.php index 6a5ad25..b505a9a 100644 --- a/kirby/src/Image/Image.php +++ b/kirby/src/Image/Image.php @@ -2,8 +2,6 @@ namespace Kirby\Image; -use Kirby\Content\Content; -use Kirby\Exception\LogicException; use Kirby\Filesystem\File; use Kirby\Toolkit\Html; @@ -24,10 +22,20 @@ use Kirby\Toolkit\Html; */ class Image extends File { - protected Exif|null $exif = null; - protected Dimensions|null $dimensions = null; + /** + * @var \Kirby\Image\Exif|null + */ + protected $exif; - public static array $resizableTypes = [ + /** + * @var \Kirby\Image\Dimensions|null + */ + protected $dimensions; + + /** + * @var array + */ + public static $resizableTypes = [ 'jpg', 'jpeg', 'gif', @@ -35,7 +43,10 @@ class Image extends File 'webp' ]; - public static array $viewableTypes = [ + /** + * @var array + */ + public static $viewableTypes = [ 'avif', 'jpg', 'jpeg', @@ -47,8 +58,10 @@ class Image extends File /** * Validation rules to be used for `::match()` + * + * @var array */ - public static array $validations = [ + public static $validations = [ 'maxsize' => ['size', 'max'], 'minsize' => ['size', 'min'], 'maxwidth' => ['width', 'max'], @@ -60,6 +73,8 @@ class Image extends File /** * Returns the `` tag for the image object + * + * @return string */ public function __toString(): string { @@ -68,19 +83,20 @@ class Image extends File /** * Returns the dimensions of the file if possible + * + * @return \Kirby\Image\Dimensions */ - public function dimensions(): Dimensions + public function dimensions() { if ($this->dimensions !== null) { return $this->dimensions; } if (in_array($this->mime(), [ - 'image/avif', - 'image/gif', 'image/jpeg', 'image/jp2', 'image/png', + 'image/gif', 'image/webp' ])) { return $this->dimensions = Dimensions::forImage($this->root); @@ -95,14 +111,18 @@ class Image extends File /** * Returns the exif object for this file (if image) + * + * @return \Kirby\Image\Exif */ - public function exif(): Exif + public function exif() { return $this->exif ??= new Exif($this); } /** * Returns the height of the asset + * + * @return int */ public function height(): int { @@ -111,29 +131,19 @@ class Image extends File /** * Converts the file to html + * + * @param array $attr + * @return string */ public function html(array $attr = []): string { - // if no alt text explicitly provided, - // try to infer from model content file - if ( - $this->model !== null && - method_exists($this->model, 'content') === true && - $this->model->content() instanceof Content && - $this->model->content()->get('alt')->isNotEmpty() === true - ) { - $attr['alt'] ??= $this->model->content()->get('alt')->value(); - } - - if ($url = $this->url()) { - return Html::img($url, $attr); - } - - throw new LogicException('Calling Image::html() requires that the URL property is not null'); + return Html::img($this->url(), $attr); } /** * Returns the PHP imagesize array + * + * @return array */ public function imagesize(): array { @@ -142,6 +152,8 @@ class Image extends File /** * Checks if the dimensions of the asset are portrait + * + * @return bool */ public function isPortrait(): bool { @@ -150,6 +162,8 @@ class Image extends File /** * Checks if the dimensions of the asset are landscape + * + * @return bool */ public function isLandscape(): bool { @@ -158,6 +172,8 @@ class Image extends File /** * Checks if the dimensions of the asset are square + * + * @return bool */ public function isSquare(): bool { @@ -166,6 +182,8 @@ class Image extends File /** * Checks if the file is a resizable image + * + * @return bool */ public function isResizable(): bool { @@ -175,6 +193,8 @@ class Image extends File /** * Checks if a preview can be displayed for the file * in the Panel or in the frontend + * + * @return bool */ public function isViewable(): bool { @@ -183,6 +203,8 @@ class Image extends File /** * Returns the ratio of the asset + * + * @return float */ public function ratio(): float { @@ -191,15 +213,19 @@ class Image extends File /** * Returns the orientation as string - * `landscape` | `portrait` | `square` + * landscape | portrait | square + * + * @return string */ - public function orientation(): string|false + public function orientation(): string { return $this->dimensions()->orientation(); } /** * Converts the object to an array + * + * @return array */ public function toArray(): array { @@ -215,6 +241,8 @@ class Image extends File /** * Returns the width of the asset + * + * @return int */ public function width(): int { diff --git a/kirby/src/Image/Location.php b/kirby/src/Image/Location.php index 0eddb68..00b65c4 100644 --- a/kirby/src/Image/Location.php +++ b/kirby/src/Image/Location.php @@ -14,8 +14,19 @@ namespace Kirby\Image; */ class Location { - protected float|null $lat = null; - protected float|null $lng = null; + /** + * latitude + * + * @var float|null + */ + protected $lat; + + /** + * longitude + * + * @var float|null + */ + protected $lng; /** * Constructor @@ -24,43 +35,44 @@ class Location */ public function __construct(array $exif) { - if ( - isset($exif['GPSLatitude']) === true && + if (isset($exif['GPSLatitude']) === true && isset($exif['GPSLatitudeRef']) === true && isset($exif['GPSLongitude']) === true && isset($exif['GPSLongitudeRef']) === true ) { - $this->lat = $this->gps( - $exif['GPSLatitude'], - $exif['GPSLatitudeRef'] - ); - $this->lng = $this->gps( - $exif['GPSLongitude'], - $exif['GPSLongitudeRef'] - ); + $this->lat = $this->gps($exif['GPSLatitude'], $exif['GPSLatitudeRef']); + $this->lng = $this->gps($exif['GPSLongitude'], $exif['GPSLongitudeRef']); } } /** * Returns the latitude + * + * @return float|null */ - public function lat(): float|null + public function lat() { return $this->lat; } /** * Returns the longitude + * + * @return float|null */ - public function lng(): float|null + public function lng() { return $this->lng; } /** * Converts the gps coordinates + * + * @param string|array $coord + * @param string $hemi + * @return float */ - protected function gps(array $coord, string $hemi): float + protected function gps($coord, string $hemi): float { $degrees = count($coord) > 0 ? $this->num($coord[0]) : 0; $minutes = count($coord) > 1 ? $this->num($coord[1]) : 0; @@ -74,6 +86,9 @@ class Location /** * Converts coordinates to floats + * + * @param string $part + * @return float */ protected function num(string $part): float { @@ -88,6 +103,8 @@ class Location /** * Converts the object into a nicely readable array + * + * @return array */ public function toArray(): array { @@ -99,15 +116,18 @@ class Location /** * Echos the entire location as lat, lng + * + * @return string */ public function __toString(): string { - return trim($this->lat() . ', ' . $this->lng(), ','); + return trim(trim($this->lat() . ', ' . $this->lng(), ',')); } /** * Improved `var_dump` output - * @codeCoverageIgnore + * + * @return array */ public function __debugInfo(): array { diff --git a/kirby/src/Image/QrCode.php b/kirby/src/Image/QrCode.php deleted file mode 100644 index d675f41..0000000 --- a/kirby/src/Image/QrCode.php +++ /dev/null @@ -1,1611 +0,0 @@ -, - * Lukas Bestle - * @link https://getkirby.com - * @copyright Bastian Allgeier - * @license https://opensource.org/licenses/MIT - * - * QR Code® is a registered trademark of DENSO WAVE INCORPORATED. - * - * The code of this class is based on: - * https://github.com/psyon/php-qrcode - * - * qrcode.php - Generate QR Codes. MIT license. - * - * Copyright for portions of this project are held by Kreative Software, 2016-2018. - * All other copyright for the project are held by Donald Becker, 2019 - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ -class QrCode -{ - public function __construct(public string $data) - { - } - - /** - * Returns the QR code as a PNG data URI - * - * @param int|null $size Image width/height in pixels, defaults to a size per module of 4x4 - * @param string $color Foreground color in hex format - * @param string $back Background color in hex format - * @param int $border Border size in number of modules - */ - public function toDataUri( - int|null $size = null, - string $color = '#000000', - string $back = '#ffffff', - int $border = 4 - ): string { - $image = $this->toImage($size, $color, $back, $border); - - ob_start(); - imagepng($image); - imagedestroy($image); - $data = ob_get_contents(); - ob_end_clean(); - - return 'data:image/png;base64,' . base64_encode($data); - } - - /** - * Returns the QR code as a GdImage object - * - * @param int|null $size Image width/height in pixels, defaults to a size per module of 4x4 - * @param string $color Foreground color in hex format - * @param string $back Background color in hex format - * @param int $border Border size in number of modules - */ - public function toImage( - int|null $size = null, - string $color = '#000000', - string $back = '#ffffff', - int $border = 4 - ): GdImage { - // get code and size measurements - $code = $this->encode($border); - [$width, $height] = $this->measure($code); - $size ??= ceil($width * 4); - $ws = $size / $width; - $hs = $size / $height; - - // create image baseplate - $image = imagecreatetruecolor($size, $size); - - $allocateColor = function (string $hex) use ($image) { - $hex = preg_replace('/[^0-9A-Fa-f]/', '', $hex); - $r = hexdec(substr($hex, 0, 2)); - $g = hexdec(substr($hex, 2, 2)); - $b = hexdec(substr($hex, 4, 2)); - return imagecolorallocate($image, $r, $g, $b); - }; - - $back = $allocateColor($back); - $color = $allocateColor($color); - imagefill($image, 0, 0, $back); - - // paint square for each module - $this->eachModuleGroup( - $code, - fn ($x, $y, $width, $height) => imagefilledrectangle( - $image, - floor($x * $ws), - floor($y * $hs), - floor($x * $ws + $ws * $width) - 1, - floor($y * $hs + $hs * $height) - 1, - $color - ) - ); - - return $image; - } - - /** - * Returns the QR code as `` element - * - * @param int|string|null $size Optional CSS width of the `` element - * @param string $color Foreground color in hex format - * @param string $back Background color in hex format - * @param int $border Border size in number of modules - */ - public function toSvg( - int|string|null $size = null, - string $color = '#000000', - string $back = '#ffffff', - int $border = 4 - ): string { - $code = $this->encode($border); - [$vbw, $vbh] = $this->measure($code); - - $modules = $this->eachModuleGroup( - $code, - fn ($x, $y, $width, $height) => 'M' . $x . ',' . $y . 'h' . $width . 'v' . $height . 'h-' . $width . 'z' - ); - - $size = $size ? ' style="width: ' . $size . '"' : ''; - - return '' . - '' . - '' . - ''; - } - - public function __toString(): string - { - return $this->toSvg(); - } - - /** - * Saves the QR code to a file. - * Supported formats: gif, jpg, jpeg, png, svg, webp - * - * @param string $file Path to the output file with one of the supported file extensions - * @param int|string|null $size Optional image width/height in pixels (defaults to a size per module of 4x4) or CSS width of the `` element - * @param string $color Foreground color in hex format - * @param string $back Background color in hex format - * @param int $border Border size in number of modules - */ - public function write( - string $file, - int|string|null $size = null, - string $color = '#000000', - string $back = '#ffffff', - int $border = 4 - ): void { - $format = F::extension($file); - $args = [$size, $color, $back, $border]; - - match ($format) { - 'gif' => imagegif($this->toImage(...$args), $file), - 'jpg', - 'jpeg' => imagejpeg($this->toImage(...$args), $file), - 'png' => imagepng($this->toImage(...$args), $file), - 'svg' => F::write($file, $this->toSvg(...$args)), - 'webp' => imagewebp($this->toImage(...$args), $file), - default => throw new InvalidArgumentException('Cannot write QR code as ' . $format) - }; - } - - protected function applyMask(array $matrix, int $size, int $mask): array - { - for ($i = 0; $i < $size; $i++) { - for ($j = 0; $j < $size; $j++) { - if ($matrix[$i][$j] >= 4 && $this->mask($mask, $i, $j)) { - $matrix[$i][$j] ^= 1; - } - } - } - - return $matrix; - } - - protected function applyBestMask(array $matrix, int $size): array - { - $mask = 0; - $mmatrix = $this->applyMask($matrix, $size, $mask); - $penalty = $this->penalty($mmatrix, $size); - - for ($tmask = 1; $tmask < 8; $tmask++) { - $tmatrix = $this->applyMask($matrix, $size, $tmask); - $tpenalty = $this->penalty($tmatrix, $size); - - if ($tpenalty < $penalty) { - $mask = $tmask; - $mmatrix = $tmatrix; - $penalty = $tpenalty; - } - } - - return [$mask, $mmatrix]; - } - - protected function createMatrix(int $version, array $data): array - { - $size = $version * 4 + 17; - $matrix = []; - $row = array_fill(0, $size, 0); - - for ($i = 0; $i < $size; $i++) { - $matrix[] = $row; - } - - // finder patterns - for ($i = 0; $i < 8; $i++) { - for ($j = 0; $j < 8; $j++) { - $m = (($i == 7 || $j == 7) ? 2 : - (($i == 0 || $j == 0 || $i == 6 || $j == 6) ? 3 : - (($i == 1 || $j == 1 || $i == 5 || $j == 5) ? 2 : 3))); - $matrix[$i][$j] = $m; - $matrix[$size - $i - 1][$j] = $m; - $matrix[$i][$size - $j - 1] = $m; - } - } - - // alignment patterns - if ($version >= 2) { - $alignment = static::ALIGNMENT_PATTERNS[$version - 2]; - - foreach ($alignment as $i) { - foreach ($alignment as $j) { - if (!$matrix[$i][$j]) { - for ($ii = -2; $ii <= 2; $ii++) { - for ($jj = -2; $jj <= 2; $jj++) { - $m = (max(abs($ii), abs($jj)) & 1) ^ 3; - $matrix[$i + $ii][$j + $jj] = $m; - } - } - } - } - } - } - - // timing patterns - for ($i = $size - 9; $i >= 8; $i--) { - $matrix[$i][6] = ($i & 1) ^ 3; - $matrix[6][$i] = ($i & 1) ^ 3; - } - - // dark module – such an ominous name for such an innocuous thing - $matrix[$size - 8][8] = 3; - - // format information area - for ($i = 0; $i <= 8; $i++) { - if (!$matrix[$i][8]) { - $matrix[$i][8] = 1; - } - if (!$matrix[8][$i]) { - $matrix[8][$i] = 1; - } - if ($i && !$matrix[$size - $i][8]) { - $matrix[$size - $i][8] = 1; - } - if ($i && !$matrix[8][$size - $i]) { - $matrix[8][$size - $i] = 1; - } - } - - // version information area - if ($version >= 7) { - for ($i = 9; $i < 12; $i++) { - for ($j = 0; $j < 6; $j++) { - $matrix[$size - $i][$j] = 1; - $matrix[$j][$size - $i] = 1; - } - } - } - - // data - $col = $size - 1; - $row = $size - 1; - $dir = -1; - $offset = 0; - $length = count($data); - - while ($col > 0 && $offset < $length) { - if (!$matrix[$row][$col]) { - $matrix[$row][$col] = $data[$offset] ? 5 : 4; - $offset++; - } - if (!$matrix[$row][$col - 1]) { - $matrix[$row][$col - 1] = $data[$offset] ? 5 : 4; - $offset++; - } - $row += $dir; - if ($row < 0 || $row >= $size) { - $dir = -$dir; - $row += $dir; - $col -= 2; - - if ($col == 6) { - $col--; - } - } - } - - return [$size, $matrix]; - } - - /** - * Loops over every row and column, finds all modules that can - * be grouped as rectangle (starting at the top left corner) - * and applies the given action to each active module group - */ - protected function eachModuleGroup(array $code, Closure $action): array - { - $result = []; - $xStart = $code['q'][3]; - $yStart = $code['q'][0]; - - // generate empty matrix to track what modules have been covered - $covered = array_fill(0, count($code['bits']), array_fill(0, count($code['bits'][0]), 0)); - - foreach ($code['bits'] as $by => $row) { - foreach ($row as $bx => $module) { - // skip if module is inactive or already covered - if ($module === 0 || $covered[$by][$bx] === 1) { - continue; - } - - $width = 0; - $height = 0; - - $rowLength = count($row); - $colLength = count($code['bits']); - - // extend to the right as long as the modules are active - // and use this to determine the width of the group - for ($x = $bx; $x < $rowLength; $x++) { - if ($row[$x] === 0) { - break; - } - $width++; - $covered[$by][$x] = 1; - } - - // extend downwards as long as all the modules - // at the same width range are active; - // use this to determine the height of the group - for ($y = $by; $y < $colLength; $y++) { - $below = array_slice($code['bits'][$y], $bx, $width); - - // if the sum is less than the width, - // there is at least one inactive module - if (array_sum($below) < $width) { - break; - } - - $height++; - - for ($x = $bx; $x < $bx + $width; $x++) { - $covered[$y][$x] = 1; - } - } - - $result[] = $action( - $xStart + $bx, - $yStart + $by, - $width, - $height - ); - } - } - - return $result; - } - - protected function encode(int $q = 4): array - { - [$data, $version, $ecl, $ec] = $this->encodeData(); - $data = $this->encodeErrorCorrection($data, $ec, $version); - [$size, $mtx] = $this->createMatrix($version, $data); - [$mask, $mtx] = $this->applyBestMask($mtx, $size); - $mtx = $this->finalizeMatrix($mtx, $size, $ecl, $mask, $version); - - return [ - 'q' => [$q, $q, $q, $q], - 'size' => [$size, $size], - 'bits' => $mtx - ]; - } - - protected function encodeData(): array - { - $mode = $this->mode(); - [$version, $ecl] = $this->version($mode); - - $group = match (true) { - $version >= 27 => 2, - $version >= 10 => 1, - default => 0 - }; - - $ec = static::EC_PARAMS[($version - 1) * 4 + $ecl]; - - // don't cut off mid-character if exceeding capacity - $max_chars = static::CAPACITY[$version - 1][$ecl][$mode]; - - if ($mode == 3) { - $max_chars <<= 1; - } - - $data = substr($this->data, 0, $max_chars); - - // convert from character level to bit level - $code = match ($mode) { - 0 => $this->encodeNumeric($data, $group), - 1 => $this->encodeAlphanum($data, $group), - 2 => $this->encodeBinary($data, $group), - default => throw new LogicException('Invalid QR mode') // @codeCoverageIgnore - }; - - $code = array_merge($code, array_fill(0, 4, 0)); - - if ($remainder = count($code) % 8) { - $code = array_merge($code, array_fill(0, 8 - $remainder, 0)); - } - - // convert from bit level to byte level - $data = []; - - for ($i = 0, $n = count($code); $i < $n; $i += 8) { - $byte = 0; - - if ($code[$i + 0]) { - $byte |= 0x80; - } - if ($code[$i + 1]) { - $byte |= 0x40; - } - if ($code[$i + 2]) { - $byte |= 0x20; - } - if ($code[$i + 3]) { - $byte |= 0x10; - } - if ($code[$i + 4]) { - $byte |= 0x08; - } - if ($code[$i + 5]) { - $byte |= 0x04; - } - if ($code[$i + 6]) { - $byte |= 0x02; - } - if ($code[$i + 7]) { - $byte |= 0x01; - } - - $data[] = $byte; - } - - for ( - $i = count($data), - $a = 1, - $n = $ec[0]; - $i < $n; - $i++, - $a ^= 1 - ) { - $data[] = $a ? 236 : 17; - } - - return [ - $data, - $version, - $ecl, - $ec - ]; - } - - protected function encodeNumeric($data, $version_group): array - { - $code = [0, 0, 0, 1]; - $length = strlen($data); - - switch ($version_group) { - case 2: // 27 - 40 - $code[] = $length & 0x2000; - $code[] = $length & 0x1000; - // no break - case 1: // 10 - 26 - $code[] = $length & 0x0800; - $code[] = $length & 0x0400; - // no break - case 0: // 1 - 9 - $code[] = $length & 0x0200; - $code[] = $length & 0x0100; - $code[] = $length & 0x0080; - $code[] = $length & 0x0040; - $code[] = $length & 0x0020; - $code[] = $length & 0x0010; - $code[] = $length & 0x0008; - $code[] = $length & 0x0004; - $code[] = $length & 0x0002; - $code[] = $length & 0x0001; - } - for ($i = 0; $i < $length; $i += 3) { - $group = substr($data, $i, 3); - switch (strlen($group)) { - case 3: - $code[] = $group & 0x200; - $code[] = $group & 0x100; - $code[] = $group & 0x080; - // no break - case 2: - $code[] = $group & 0x040; - $code[] = $group & 0x020; - $code[] = $group & 0x010; - // no break - case 1: - $code[] = $group & 0x008; - $code[] = $group & 0x004; - $code[] = $group & 0x002; - $code[] = $group & 0x001; - } - } - return $code; - } - - protected function encodeAlphanum($data, $version_group): array - { - $alphabet = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:'; - $code = [0, 0, 1, 0]; - $length = strlen($data); - switch ($version_group) { - case 2: // 27 - 40 - $code[] = $length & 0x1000; - $code[] = $length & 0x0800; - // no break - case 1: // 10 - 26 - $code[] = $length & 0x0400; - $code[] = $length & 0x0200; - // no break - case 0: // 1 - 9 - $code[] = $length & 0x0100; - $code[] = $length & 0x0080; - $code[] = $length & 0x0040; - $code[] = $length & 0x0020; - $code[] = $length & 0x0010; - $code[] = $length & 0x0008; - $code[] = $length & 0x0004; - $code[] = $length & 0x0002; - $code[] = $length & 0x0001; - } - for ($i = 0; $i < $length; $i += 2) { - $group = substr($data, $i, 2); - if (strlen($group) > 1) { - $c1 = strpos($alphabet, substr($group, 0, 1)); - $c2 = strpos($alphabet, substr($group, 1, 1)); - $ch = $c1 * 45 + $c2; - $code[] = $ch & 0x400; - $code[] = $ch & 0x200; - $code[] = $ch & 0x100; - $code[] = $ch & 0x080; - $code[] = $ch & 0x040; - $code[] = $ch & 0x020; - $code[] = $ch & 0x010; - $code[] = $ch & 0x008; - $code[] = $ch & 0x004; - $code[] = $ch & 0x002; - $code[] = $ch & 0x001; - } else { - $ch = strpos($alphabet, $group); - $code[] = $ch & 0x020; - $code[] = $ch & 0x010; - $code[] = $ch & 0x008; - $code[] = $ch & 0x004; - $code[] = $ch & 0x002; - $code[] = $ch & 0x001; - } - } - return $code; - } - - protected function encodeBinary(string $data, int $version_group): array - { - $code = [0, 1, 0, 0]; - $length = strlen($data); - - switch ($version_group) { - case 2: // 27 - 40 - case 1: // 10 - 26 - $code[] = $length & 0x8000; - $code[] = $length & 0x4000; - $code[] = $length & 0x2000; - $code[] = $length & 0x1000; - $code[] = $length & 0x0800; - $code[] = $length & 0x0400; - $code[] = $length & 0x0200; - $code[] = $length & 0x0100; - // no break - case 0: // 1 - 9 - $code[] = $length & 0x0080; - $code[] = $length & 0x0040; - $code[] = $length & 0x0020; - $code[] = $length & 0x0010; - $code[] = $length & 0x0008; - $code[] = $length & 0x0004; - $code[] = $length & 0x0002; - $code[] = $length & 0x0001; - } - - for ($i = 0; $i < $length; $i++) { - $ch = ord(substr($data, $i, 1)); - $code[] = $ch & 0x80; - $code[] = $ch & 0x40; - $code[] = $ch & 0x20; - $code[] = $ch & 0x10; - $code[] = $ch & 0x08; - $code[] = $ch & 0x04; - $code[] = $ch & 0x02; - $code[] = $ch & 0x01; - } - - return $code; - } - - protected function encodeErrorCorrection( - array $data, - array $ec_params, - int $version - ): array { - $blocks = $this->errorCorrectionSplit($data, $ec_params); - $ec_blocks = []; - - for ($i = 0, $n = count($blocks); $i < $n; $i++) { - $ec_blocks[] = $this->errorCorrectionDivide($blocks[$i], $ec_params); - } - - $data = $this->errorCorrectionInterleave($blocks); - $ec_data = $this->errorCorrectionInterleave($ec_blocks); - $code = []; - - foreach ($data as $ch) { - $code[] = $ch & 0x80; - $code[] = $ch & 0x40; - $code[] = $ch & 0x20; - $code[] = $ch & 0x10; - $code[] = $ch & 0x08; - $code[] = $ch & 0x04; - $code[] = $ch & 0x02; - $code[] = $ch & 0x01; - } - foreach ($ec_data as $ch) { - $code[] = $ch & 0x80; - $code[] = $ch & 0x40; - $code[] = $ch & 0x20; - $code[] = $ch & 0x10; - $code[] = $ch & 0x08; - $code[] = $ch & 0x04; - $code[] = $ch & 0x02; - $code[] = $ch & 0x01; - } - for ($n = static::REMAINER_BITS[$version - 1]; $n > 0; $n--) { - $code[] = 0; - } - - return $code; - } - - protected function errorCorrectionSplit(array $data, array $ec): array - { - $blocks = []; - $offset = 0; - - for ($i = $ec[2], $length = $ec[3]; $i > 0; $i--) { - $blocks[] = array_slice($data, $offset, $length); - $offset += $length; - } - for ($i = $ec[4], $length = $ec[5]; $i > 0; $i--) { - $blocks[] = array_slice($data, $offset, $length); - $offset += $length; - } - - return $blocks; - } - - protected function errorCorrectionDivide(array $data, array $ec): array - { - $num_data = count($data); - $num_error = $ec[1]; - $generator = static::EC_POLYNOMIALS[$num_error]; - $message = $data; - - for ($i = 0; $i < $num_error; $i++) { - $message[] = 0; - } - - for ($i = 0; $i < $num_data; $i++) { - if ($message[$i]) { - $leadterm = static::LOG[$message[$i]]; - - for ($j = 0; $j <= $num_error; $j++) { - $term = ($generator[$j] + $leadterm) % 255; - $message[$i + $j] ^= static::EXP[$term]; - } - } - } - - return array_slice($message, $num_data, $num_error); - } - - protected function errorCorrectionInterleave(array $blocks): array - { - $data = []; - $num_blocks = count($blocks); - - for ($offset = 0; true; $offset++) { - $break = true; - - for ($i = 0; $i < $num_blocks; $i++) { - if (isset($blocks[$i][$offset]) === true) { - $data[] = $blocks[$i][$offset]; - $break = false; - } - } - - if ($break) { - break; - } - } - - return $data; - } - - protected function finalizeMatrix( - array $matrix, - int $size, - int $ecl, - int $mask, - int $version - ): array { - // Format info - $format = static::FORMAT_INFO[$ecl * 8 + $mask]; - $matrix[8][0] = $format[0]; - $matrix[8][1] = $format[1]; - $matrix[8][2] = $format[2]; - $matrix[8][3] = $format[3]; - $matrix[8][4] = $format[4]; - $matrix[8][5] = $format[5]; - $matrix[8][7] = $format[6]; - $matrix[8][8] = $format[7]; - $matrix[7][8] = $format[8]; - $matrix[5][8] = $format[9]; - $matrix[4][8] = $format[10]; - $matrix[3][8] = $format[11]; - $matrix[2][8] = $format[12]; - $matrix[1][8] = $format[13]; - $matrix[0][8] = $format[14]; - $matrix[$size - 1][8] = $format[0]; - $matrix[$size - 2][8] = $format[1]; - $matrix[$size - 3][8] = $format[2]; - $matrix[$size - 4][8] = $format[3]; - $matrix[$size - 5][8] = $format[4]; - $matrix[$size - 6][8] = $format[5]; - $matrix[$size - 7][8] = $format[6]; - $matrix[8][$size - 8] = $format[7]; - $matrix[8][$size - 7] = $format[8]; - $matrix[8][$size - 6] = $format[9]; - $matrix[8][$size - 5] = $format[10]; - $matrix[8][$size - 4] = $format[11]; - $matrix[8][$size - 3] = $format[12]; - $matrix[8][$size - 2] = $format[13]; - $matrix[8][$size - 1] = $format[14]; - - // version info - if ($version >= 7) { - $version = static::VERSION_INFO[$version - 7]; - - for ($i = 0; $i < 18; $i++) { - $r = $size - 9 - ($i % 3); - $c = 5 - floor($i / 3); - $matrix[$r][$c] = $version[$i]; - $matrix[$c][$r] = $version[$i]; - } - } - - // patterns and data - for ($i = 0; $i < $size; $i++) { - for ($j = 0; $j < $size; $j++) { - $matrix[$i][$j] &= 1; - } - } - - return $matrix; - } - - protected function mask(int $mask, int $row, int $column): int - { - return match ($mask) { - 0 => !(($row + $column) % 2), - 1 => !($row % 2), - 2 => !($column % 3), - 3 => !(($row + $column) % 3), - 4 => !((floor($row / 2) + floor($column / 3)) % 2), - 5 => !(((($row * $column) % 2) + (($row * $column) % 3))), - 6 => !(((($row * $column) % 2) + (($row * $column) % 3)) % 2), - 7 => !(((($row + $column) % 2) + (($row * $column) % 3)) % 2), - default => throw new LogicException('Invalid QR mask') // @codeCoverageIgnore - }; - } - - /** - * Returns width and height based on the - * generated modules and quiet zone - */ - protected function measure($code): array - { - return [ - $code['q'][3] + $code['size'][0] + $code['q'][1], - $code['q'][0] + $code['size'][1] + $code['q'][2] - ]; - } - - /** - * Detect what encoding mode (numeric, alphanumeric, binary) - * can be used - */ - protected function mode(): int - { - // numeric - if (preg_match('/^[0-9]*$/', $this->data)) { - return 0; - } - - // alphanumeric - if (preg_match('/^[0-9A-Z .\/:$%*+-]*$/', $this->data)) { - return 1; - } - - return 2; - } - - protected function penalty(array &$matrix, int $size): int - { - $score = $this->penalty1($matrix, $size); - $score += $this->penalty2($matrix, $size); - $score += $this->penalty3($matrix, $size); - $score += $this->penalty4($matrix, $size); - return $score; - } - - protected function penalty1(array &$matrix, int $size): int - { - $score = 0; - - for ($i = 0; $i < $size; $i++) { - $rowvalue = 0; - $rowcount = 0; - $colvalue = 0; - $colcount = 0; - - for ($j = 0; $j < $size; $j++) { - $rv = ($matrix[$i][$j] == 5 || $matrix[$i][$j] == 3) ? 1 : 0; - $cv = ($matrix[$j][$i] == 5 || $matrix[$j][$i] == 3) ? 1 : 0; - - if ($rv == $rowvalue) { - $rowcount++; - } else { - if ($rowcount >= 5) { - $score += $rowcount - 2; - } - $rowvalue = $rv; - $rowcount = 1; - } - - if ($cv == $colvalue) { - $colcount++; - } else { - if ($colcount >= 5) { - $score += $colcount - 2; - } - $colvalue = $cv; - $colcount = 1; - } - } - - if ($rowcount >= 5) { - $score += $rowcount - 2; - } - if ($colcount >= 5) { - $score += $colcount - 2; - } - } - - return $score; - } - - protected function penalty2(array &$matrix, int $size): int - { - $score = 0; - - for ($i = 1; $i < $size; $i++) { - for ($j = 1; $j < $size; $j++) { - $v1 = $matrix[$i - 1][$j - 1]; - $v2 = $matrix[$i - 1][$j ]; - $v3 = $matrix[$i ][$j - 1]; - $v4 = $matrix[$i ][$j ]; - $v1 = ($v1 == 5 || $v1 == 3) ? 1 : 0; - $v2 = ($v2 == 5 || $v2 == 3) ? 1 : 0; - $v3 = ($v3 == 5 || $v3 == 3) ? 1 : 0; - $v4 = ($v4 == 5 || $v4 == 3) ? 1 : 0; - - if ($v1 == $v2 && $v2 == $v3 && $v3 == $v4) { - $score += 3; - } - } - } - - return $score; - } - - protected function penalty3(array &$matrix, int $size): int - { - $score = 0; - - for ($i = 0; $i < $size; $i++) { - $rowvalue = 0; - $colvalue = 0; - - for ($j = 0; $j < 11; $j++) { - $rv = ($matrix[$i][$j] == 5 || $matrix[$i][$j] == 3) ? 1 : 0; - $cv = ($matrix[$j][$i] == 5 || $matrix[$j][$i] == 3) ? 1 : 0; - $rowvalue = (($rowvalue << 1) & 0x7FF) | $rv; - $colvalue = (($colvalue << 1) & 0x7FF) | $cv; - } - - if ($rowvalue == 0x5D0 || $rowvalue == 0x5D) { - $score += 40; - } - if ($colvalue == 0x5D0 || $colvalue == 0x5D) { - $score += 40; - } - - for ($j = 11; $j < $size; $j++) { - $rv = ($matrix[$i][$j] == 5 || $matrix[$i][$j] == 3) ? 1 : 0; - $cv = ($matrix[$j][$i] == 5 || $matrix[$j][$i] == 3) ? 1 : 0; - $rowvalue = (($rowvalue << 1) & 0x7FF) | $rv; - $colvalue = (($colvalue << 1) & 0x7FF) | $cv; - - if ($rowvalue == 0x5D0 || $rowvalue == 0x5D) { - $score += 40; - } - - if ($colvalue == 0x5D0 || $colvalue == 0x5D) { - $score += 40; - } - } - } - - return $score; - } - - protected function penalty4(array &$matrix, int $size): int - { - $dark = 0; - - for ($i = 0; $i < $size; $i++) { - for ($j = 0; $j < $size; $j++) { - if ($matrix[$i][$j] == 5 || $matrix[$i][$j] == 3) { - $dark++; - } - } - } - - $dark *= 20; - $dark /= $size * $size; - $a = abs(floor($dark) - 10); - $b = abs(ceil($dark) - 10); - return min($a, $b) * 10; - } - - /** - * Detect what version needs to be used by - * trying to maximize the error correction level - */ - protected function version(int $mode): array - { - $length = strlen($this->data); - - if ($mode == 3) { - $length >>= 1; - } - - $ecl = 0; - - // first try to find the minimum version - // that can contain the data - for ($version = 1; $version <= 40; $version++) { - if ($length <= static::CAPACITY[$version - 1][$ecl][$mode]) { - break; - } - } - - // with the version in place, try to raise - // the error correction level as long as - // the data still fits - for ($newEcl = 1; $newEcl <= 3; $newEcl++) { - if ($length <= static::CAPACITY[$version - 1][$newEcl][$mode]) { - $ecl = $newEcl; - } - } - - return [$version, $ecl]; - } - - /** - * maximum encodable characters = $qr_capacity [ (version - 1) ] - * [ (0 for L, 1 for M, 2 for Q, 3 for H) ] - * [ (0 for numeric, 1 for alpha, 2 for binary) ] - */ - protected const CAPACITY = [ - [ - [ 41, 25, 17], - [ 34, 20, 14], - [ 27, 16, 11], - [ 17, 10, 7] - ], - [ - [ 77, 47, 32], - [ 63, 38, 26], - [ 48, 29, 20], - [ 34, 20, 14] - ], - [ - [ 127, 77, 53], - [ 101, 61, 42], - [ 77, 47, 32], - [ 58, 35, 24] - ], - [ - [ 187, 114, 78], - [ 149, 90, 62], - [ 111, 67, 46], - [ 82, 50, 34] - ], - [ - [ 255, 154, 106], - [ 202, 122, 84], - [ 144, 87, 60], - [ 106, 64, 44] - ], - [ - [ 322, 195, 134], - [ 255, 154, 106], - [ 178, 108, 74], - [ 139, 84, 58] - ], - [ - [ 370, 224, 154], - [ 293, 178, 122], - [ 207, 125, 86], - [ 154, 93, 64] - ], - [ - [ 461, 279, 192], - [ 365, 221, 152], - [ 259, 157, 108], - [ 202, 122, 84] - ], - [ - [ 552, 335, 230], - [ 432, 262, 180], - [ 312, 189, 130], - [ 235, 143, 98]], - [ - [ 652, 395, 271], - [ 513, 311, 213], - [ 364, 221, 151], - [ 288, 174, 119] - ], - [ - [ 772, 468, 321], - [ 604, 366, 251], - [ 427, 259, 177], - [ 331, 200, 137] - ], - [ - [ 883, 535, 367], - [ 691, 419, 287], - [ 489, 296, 203], - [ 374, 227, 155] - ], - [ - [1022, 619, 425], - [ 796, 483, 331], - [ 580, 352, 241], - [ 427, 259, 177] - ], - [ - [1101, 667, 458], - [ 871, 528, 362], - [ 621, 376, 258], - [ 468, 283, 194] - ], - [ - [1250, 758, 520], - [ 991, 600, 412], - [ 703, 426, 292], - [ 530, 321, 220] - ], - [ - [1408, 854, 586], - [1082, 656, 450], - [ 775, 470, 322], - [ 602, 365, 250] - ], - [ - [1548, 938, 644], - [1212, 734, 504], - [ 876, 531, 364], - [ 674, 408, 280] - ], - [ - [1725, 1046, 718], - [1346, 816, 560], - [ 948, 574, 394], - [ 746, 452, 310] - ], - [ - [1903, 1153, 792], - [1500, 909, 624], - [1063, 644, 442], - [ 813, 493, 338] - ], - [ - [2061, 1249, 858], - [1600, 970, 666], - [1159, 702, 482], - [ 919, 557, 382] - ], - [ - [2232, 1352, 929], - [1708, 1035, 711], - [1224, 742, 509], - [ 969, 587, 403] - ], - [ - [2409, 1460, 1003], - [1872, 1134, 779], - [1358, 823, 565], - [1056, 640, 439] - ], - [ - [2620, 1588, 1091], - [2059, 1248, 857], - [1468, 890, 611], - [1108, 672, 461] - ], - [ - [2812, 1704, 1171], - [2188, 1326, 911], - [1588, 963, 661], - [1228, 744, 511] - ], - [ - [3057, 1853, 1273], - [2395, 1451, 997], - [1718, 1041, 715], - [1286, 779, 535] - ], - [ - [3283, 1990, 1367], - [2544, 1542, 1059], - [1804, 1094, 751], - [1425, 864, 593] - ], - [ - [3517, 2132, 1465], - [2701, 1637, 1125], - [1933, 1172, 805], - [1501, 910, 625] - ], - [ - [3669, 2223, 1528], - [2857, 1732, 1190], - [2085, 1263, 868], - [1581, 958, 658] - ], - [ - [3909, 2369, 1628], - [3035, 1839, 1264], - [2181, 1322, 908], - [1677, 1016, 698] - ], - [ - [4158, 2520, 1732], - [3289, 1994, 1370], - [2358, 1429, 982], - [1782, 1080, 742] - ], - [ - [4417, 2677, 1840], - [3486, 2113, 1452], - [2473, 1499, 1030], - [1897, 1150, 790] - ], - [ - [4686, 2840, 1952], - [3693, 2238, 1538], - [2670, 1618, 1112], - [2022, 1226, 842] - ], - [ - [4965, 3009, 2068], - [3909, 2369, 1628], - [2805, 1700, 1168], - [2157, 1307, 898] - ], - [ - [5253, 3183, 2188], - [4134, 2506, 1722], - [2949, 1787, 1228], - [2301, 1394, 958] - ], - [ - [5529, 3351, 2303], - [4343, 2632, 1809], - [3081, 1867, 1283], - [2361, 1431, 983] - ], - [ - [5836, 3537, 2431], - [4588, 2780, 1911], - [3244, 1966, 1351], - [2524, 1530, 1051] - ], - [ - [6153, 3729, 2563], - [4775, 2894, 1989], - [3417, 2071, 1423], - [2625, 1591, 1093] - ], - [ - [6479, 3927, 2699], - [5039, 3054, 2099], - [3599, 2181, 1499], - [2735, 1658, 1139] - ], - [ - [6743, 4087, 2809], - [5313, 3220, 2213], - [3791, 2298, 1579], - [2927, 1774, 1219] - ], - [ - [7089, 4296, 2953], - [5596, 3391, 2331], - [3993, 2420, 1663], - [3057, 1852, 1273] - ], - ]; - - /** - * $qr_ec_params[ - * 4 * (version - 1) + (0 for L, 1 for M, 2 for Q, 3 for H) - * ] = [ - * total number of data codewords, - * number of error correction codewords per block, - * number of blocks in first group, - * number of data codewords per block in first group, - * number of blocks in second group, - * number of data codewords per block in second group - * ); - */ - protected const EC_PARAMS = [ - [ 19, 7, 1, 19, 0, 0], - [ 16, 10, 1, 16, 0, 0], - [ 13, 13, 1, 13, 0, 0], - [ 9, 17, 1, 9, 0, 0], - [ 34, 10, 1, 34, 0, 0], - [ 28, 16, 1, 28, 0, 0], - [ 22, 22, 1, 22, 0, 0], - [ 16, 28, 1, 16, 0, 0], - [ 55, 15, 1, 55, 0, 0], - [ 44, 26, 1, 44, 0, 0], - [ 34, 18, 2, 17, 0, 0], - [ 26, 22, 2, 13, 0, 0], - [ 80, 20, 1, 80, 0, 0], - [ 64, 18, 2, 32, 0, 0], - [ 48, 26, 2, 24, 0, 0], - [ 36, 16, 4, 9, 0, 0], - [ 108, 26, 1, 108, 0, 0], - [ 86, 24, 2, 43, 0, 0], - [ 62, 18, 2, 15, 2, 16], - [ 46, 22, 2, 11, 2, 12], - [ 136, 18, 2, 68, 0, 0], - [ 108, 16, 4, 27, 0, 0], - [ 76, 24, 4, 19, 0, 0], - [ 60, 28, 4, 15, 0, 0], - [ 156, 20, 2, 78, 0, 0], - [ 124, 18, 4, 31, 0, 0], - [ 88, 18, 2, 14, 4, 15], - [ 66, 26, 4, 13, 1, 14], - [ 194, 24, 2, 97, 0, 0], - [ 154, 22, 2, 38, 2, 39], - [ 110, 22, 4, 18, 2, 19], - [ 86, 26, 4, 14, 2, 15], - [ 232, 30, 2, 116, 0, 0], - [ 182, 22, 3, 36, 2, 37], - [ 132, 20, 4, 16, 4, 17], - [ 100, 24, 4, 12, 4, 13], - [ 274, 18, 2, 68, 2, 69], - [ 216, 26, 4, 43, 1, 44], - [ 154, 24, 6, 19, 2, 20], - [ 122, 28, 6, 15, 2, 16], - [ 324, 20, 4, 81, 0, 0], - [ 254, 30, 1, 50, 4, 51], - [ 180, 28, 4, 22, 4, 23], - [ 140, 24, 3, 12, 8, 13], - [ 370, 24, 2, 92, 2, 93], - [ 290, 22, 6, 36, 2, 37], - [ 206, 26, 4, 20, 6, 21], - [ 158, 28, 7, 14, 4, 15], - [ 428, 26, 4, 107, 0, 0], - [ 334, 22, 8, 37, 1, 38], - [ 244, 24, 8, 20, 4, 21], - [ 180, 22, 12, 11, 4, 12], - [ 461, 30, 3, 115, 1, 116], - [ 365, 24, 4, 40, 5, 41], - [ 261, 20, 11, 16, 5, 17], - [ 197, 24, 11, 12, 5, 13], - [ 523, 22, 5, 87, 1, 88], - [ 415, 24, 5, 41, 5, 42], - [ 295, 30, 5, 24, 7, 25], - [ 223, 24, 11, 12, 7, 13], - [ 589, 24, 5, 98, 1, 99], - [ 453, 28, 7, 45, 3, 46], - [ 325, 24, 15, 19, 2, 20], - [ 253, 30, 3, 15, 13, 16], - [ 647, 28, 1, 107, 5, 108], - [ 507, 28, 10, 46, 1, 47], - [ 367, 28, 1, 22, 15, 23], - [ 283, 28, 2, 14, 17, 15], - [ 721, 30, 5, 120, 1, 121], - [ 563, 26, 9, 43, 4, 44], - [ 397, 28, 17, 22, 1, 23], - [ 313, 28, 2, 14, 19, 15], - [ 795, 28, 3, 113, 4, 114], - [ 627, 26, 3, 44, 11, 45], - [ 445, 26, 17, 21, 4, 22], - [ 341, 26, 9, 13, 16, 14], - [ 861, 28, 3, 107, 5, 108], - [ 669, 26, 3, 41, 13, 42], - [ 485, 30, 15, 24, 5, 25], - [ 385, 28, 15, 15, 10, 16], - [ 932, 28, 4, 116, 4, 117], - [ 714, 26, 17, 42, 0, 0], - [ 512, 28, 17, 22, 6, 23], - [ 406, 30, 19, 16, 6, 17], - [1006, 28, 2, 111, 7, 112], - [ 782, 28, 17, 46, 0, 0], - [ 568, 30, 7, 24, 16, 25], - [ 442, 24, 34, 13, 0, 0], - [1094, 30, 4, 121, 5, 122], - [ 860, 28, 4, 47, 14, 48], - [ 614, 30, 11, 24, 14, 25], - [ 464, 30, 16, 15, 14, 16], - [1174, 30, 6, 117, 4, 118], - [ 914, 28, 6, 45, 14, 46], - [ 664, 30, 11, 24, 16, 25], - [ 514, 30, 30, 16, 2, 17], - [1276, 26, 8, 106, 4, 107], - [1000, 28, 8, 47, 13, 48], - [ 718, 30, 7, 24, 22, 25], - [ 538, 30, 22, 15, 13, 16], - [1370, 28, 10, 114, 2, 115], - [1062, 28, 19, 46, 4, 47], - [ 754, 28, 28, 22, 6, 23], - [ 596, 30, 33, 16, 4, 17], - [1468, 30, 8, 122, 4, 123], - [1128, 28, 22, 45, 3, 46], - [ 808, 30, 8, 23, 26, 24], - [ 628, 30, 12, 15, 28, 16], - [1531, 30, 3, 117, 10, 118], - [1193, 28, 3, 45, 23, 46], - [ 871, 30, 4, 24, 31, 25], - [ 661, 30, 11, 15, 31, 16], - [1631, 30, 7, 116, 7, 117], - [1267, 28, 21, 45, 7, 46], - [ 911, 30, 1, 23, 37, 24], - [ 701, 30, 19, 15, 26, 16], - [1735, 30, 5, 115, 10, 116], - [1373, 28, 19, 47, 10, 48], - [ 985, 30, 15, 24, 25, 25], - [ 745, 30, 23, 15, 25, 16], - [1843, 30, 13, 115, 3, 116], - [1455, 28, 2, 46, 29, 47], - [1033, 30, 42, 24, 1, 25], - [ 793, 30, 23, 15, 28, 16], - [1955, 30, 17, 115, 0, 0], - [1541, 28, 10, 46, 23, 47], - [1115, 30, 10, 24, 35, 25], - [ 845, 30, 19, 15, 35, 16], - [2071, 30, 17, 115, 1, 116], - [1631, 28, 14, 46, 21, 47], - [1171, 30, 29, 24, 19, 25], - [ 901, 30, 11, 15, 46, 16], - [2191, 30, 13, 115, 6, 116], - [1725, 28, 14, 46, 23, 47], - [1231, 30, 44, 24, 7, 25], - [ 961, 30, 59, 16, 1, 17], - [2306, 30, 12, 121, 7, 122], - [1812, 28, 12, 47, 26, 48], - [1286, 30, 39, 24, 14, 25], - [ 986, 30, 22, 15, 41, 16], - [2434, 30, 6, 121, 14, 122], - [1914, 28, 6, 47, 34, 48], - [1354, 30, 46, 24, 10, 25], - [1054, 30, 2, 15, 64, 16], - [2566, 30, 17, 122, 4, 123], - [1992, 28, 29, 46, 14, 47], - [1426, 30, 49, 24, 10, 25], - [1096, 30, 24, 15, 46, 16], - [2702, 30, 4, 122, 18, 123], - [2102, 28, 13, 46, 32, 47], - [1502, 30, 48, 24, 14, 25], - [1142, 30, 42, 15, 32, 16], - [2812, 30, 20, 117, 4, 118], - [2216, 28, 40, 47, 7, 48], - [1582, 30, 43, 24, 22, 25], - [1222, 30, 10, 15, 67, 16], - [2956, 30, 19, 118, 6, 119], - [2334, 28, 18, 47, 31, 48], - [1666, 30, 34, 24, 34, 25], - [1276, 30, 20, 15, 61, 16], - ]; - - protected const EC_POLYNOMIALS = [ - 7 => [0, 87, 229, 146, 149, 238, 102, 21], - 10 => [0, 251, 67, 46, 61, 118, 70, 64, 94, 32, 45], - 13 => [0, 74, 152, 176, 100, 86, 100, 106, 104, 130, 218, 206, 140, 78], - 15 => [0, 8, 183, 61, 91, 202, 37, 51, 58, 58, 237, 140, 124, 5, 99, 105], - 16 => [0, 120, 104, 107, 109, 102, 161, 76, 3, 91, 191, 147, 169, 182, 194, 225, 120], - 17 => [0, 43, 139, 206, 78, 43, 239, 123, 206, 214, 147, 24, 99, 150, 39, 243, 163, 136], - 18 => [0, 215, 234, 158, 94, 184, 97, 118, 170, 79, 187, 152, 148, 252, 179, 5, 98, 96, 153], - 20 => [0, 17, 60, 79, 50, 61, 163, 26, 187, 202, 180, 221, 225, 83, 239, 156, 164, 212, 212, 188, 190], - 22 => [0, 210, 171, 247, 242, 93, 230, 14, 109, 221, 53, 200, 74, 8, 172, 98, 80, 219, 134, 160, 105, 165, 231], - 24 => [0, 229, 121, 135, 48, 211, 117, 251, 126, 159, 180, 169, 152, 192, 226, 228, 218, 111, 0, 117, 232, 87, 96, 227, 21], - 26 => [0, 173, 125, 158, 2, 103, 182, 118, 17, 145, 201, 111, 28, 165, 53, 161, 21, 245, 142, 13, 102, 48, 227, 153, 145, 218, 70], - 28 => [0, 168, 223, 200, 104, 224, 234, 108, 180, 110, 190, 195, 147, 205, 27, 232, 201, 21, 43, 245, 87, 42, 195, 212, 119, 242, 37, 9, 123], - 30 => [0, 41, 173, 145, 152, 216, 31, 179, 182, 50, 48, 110, 86, 239, 96, 222, 125, 42, 173, 226, 193, 224, 130, 156, 37, 251, 216, 238, 40, 192, 180], - ]; - - protected const LOG = [0, 0, 1, 25, 2, 50, 26, 198, 3, 223, 51, 238, 27, 104, 199, 75, 4, 100, 224, 14, 52, 141, 239, 129, 28, 193, 105, 248, 200, 8, 76, 113, 5, 138, 101, 47, 225, 36, 15, 33, 53, 147, 142, 218, 240, 18, 130, 69, 29, 181, 194, 125, 106, 39, 249, 185, 201, 154, 9, 120, 77, 228, 114, 166, 6, 191, 139, 98, 102, 221, 48, 253, 226, 152, 37, 179, 16, 145, 34, 136, 54, 208, 148, 206, 143, 150, 219, 189, 241, 210, 19, 92, 131, 56, 70, 64, 30, 66, 182, 163, 195, 72, 126, 110, 107, 58, 40, 84, 250, 133, 186, 61, 202, 94, 155, 159, 10, 21, 121, 43, 78, 212, 229, 172, 115, 243, 167, 87, 7, 112, 192, 247, 140, 128, 99, 13, 103, 74, 222, 237, 49, 197, 254, 24, 227, 165, 153, 119, 38, 184, 180, 124, 17, 68, 146, 217, 35, 32, 137, 46, 55, 63, 209, 91, 149, 188, 207, 205, 144, 135, 151, 178, 220, 252, 190, 97, 242, 86, 211, 171, 20, 42, 93, 158, 132, 60, 57, 83, 71, 109, 65, 162, 31, 45, 67, 216, 183, 123, 164, 118, 196, 23, 73, 236, 127, 12, 111, 246, 108, 161, 59, 82, 41, 157, 85, 170, 251, 96, 134, 177, 187, 204, 62, 90, 203, 89, 95, 176, 156, 169, 160, 81, 11, 245, 22, 235, 122, 117, 44, 215, 79, 174, 213, 233, 230, 231, 173, 232, 116, 214, 244, 234, 168, 80, 88, 175]; - - protected const EXP = [1, 2, 4, 8, 16, 32, 64, 128, 29, 58, 116, 232, 205, 135, 19, 38, 76, 152, 45, 90, 180, 117, 234, 201, 143, 3, 6, 12, 24, 48, 96, 192, 157, 39, 78, 156, 37, 74, 148, 53, 106, 212, 181, 119, 238, 193, 159, 35, 70, 140, 5, 10, 20, 40, 80, 160, 93, 186, 105, 210, 185, 111, 222, 161, 95, 190, 97, 194, 153, 47, 94, 188, 101, 202, 137, 15, 30, 60, 120, 240, 253, 231, 211, 187, 107, 214, 177, 127, 254, 225, 223, 163, 91, 182, 113, 226, 217, 175, 67, 134, 17, 34, 68, 136, 13, 26, 52, 104, 208, 189, 103, 206, 129, 31, 62, 124, 248, 237, 199, 147, 59, 118, 236, 197, 151, 51, 102, 204, 133, 23, 46, 92, 184, 109, 218, 169, 79, 158, 33, 66, 132, 21, 42, 84, 168, 77, 154, 41, 82, 164, 85, 170, 73, 146, 57, 114, 228, 213, 183, 115, 230, 209, 191, 99, 198, 145, 63, 126, 252, 229, 215, 179, 123, 246, 241, 255, 227, 219, 171, 75, 150, 49, 98, 196, 149, 55, 110, 220, 165, 87, 174, 65, 130, 25, 50, 100, 200, 141, 7, 14, 28, 56, 112, 224, 221, 167, 83, 166, 81, 162, 89, 178, 121, 242, 249, 239, 195, 155, 43, 86, 172, 69, 138, 9, 18, 36, 72, 144, 61, 122, 244, 245, 247, 243, 251, 235, 203, 139, 11, 22, 44, 88, 176, 125, 250, 233, 207, 131, 27, 54, 108, 216, 173, 71, 142, 1]; - - protected const REMAINER_BITS = [0, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0]; - - protected const ALIGNMENT_PATTERNS = [ - [6, 18], - [6, 22], - [6, 26], - [6, 30], - [6, 34], - [6, 22, 38], - [6, 24, 42], - [6, 26, 46], - [6, 28, 50], - [6, 30, 54], - [6, 32, 58], - [6, 34, 62], - [6, 26, 46, 66], - [6, 26, 48, 70], - [6, 26, 50, 74], - [6, 30, 54, 78], - [6, 30, 56, 82], - [6, 30, 58, 86], - [6, 34, 62, 90], - [6, 28, 50, 72, 94], - [6, 26, 50, 74, 98], - [6, 30, 54, 78, 102], - [6, 28, 54, 80, 106], - [6, 32, 58, 84, 110], - [6, 30, 58, 86, 114], - [6, 34, 62, 90, 118], - [6, 26, 50, 74, 98, 122], - [6, 30, 54, 78, 102, 126], - [6, 26, 52, 78, 104, 130], - [6, 30, 56, 82, 108, 134], - [6, 34, 60, 86, 112, 138], - [6, 30, 58, 86, 114, 142], - [6, 34, 62, 90, 118, 146], - [6, 30, 54, 78, 102, 126, 150], - [6, 24, 50, 76, 102, 128, 154], - [6, 28, 54, 80, 106, 132, 158], - [6, 32, 58, 84, 110, 136, 162], - [6, 26, 54, 82, 110, 138, 166], - [6, 30, 58, 86, 114, 142, 170], - ]; - - /** - * format info string = $qr_format_info[ - * (0 for L, 8 for M, 16 for Q, 24 for H) + mask - *]; - */ - protected const FORMAT_INFO = [ - [1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0], - [1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1], - [1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0], - [1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1], - [1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1], - [1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0], - [1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1], - [1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0], - [1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0], - [1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1], - [1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0], - [1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1], - [1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1], - [1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0], - [1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1], - [1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0], - [0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1], - [0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0], - [0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1], - [0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0], - [0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0], - [0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1], - [0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0], - [0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1], - [0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1], - [0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0], - [0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1], - [0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0], - [0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0], - [0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1], - [0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0], - [0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1] - ]; - - /** - * version info string = $qr_version_info[ (version - 7) ] - */ - protected const VERSION_INFO = [ - [0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0], - [0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0], - [0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1], - [0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1], - [0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0], - [0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0], - [0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1], - [0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1], - [0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0], - [0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0], - [0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1], - [0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1], - [0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0], - [0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0], - [0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1], - [0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1], - [0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0], - [0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0], - [0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1], - [0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1], - [0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0], - [0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0], - [0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1], - [0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1], - [0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0], - [1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1], - [1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0], - [1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0], - [1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1], - [1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1], - [1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0], - [1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0], - [1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1], - [1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1] - ]; -} diff --git a/kirby/src/Option/Option.php b/kirby/src/Option/Option.php deleted file mode 100644 index 3e58741..0000000 --- a/kirby/src/Option/Option.php +++ /dev/null @@ -1,64 +0,0 @@ - - * @link https://getkirby.com - * @copyright Bastian Allgeier - * @license https://opensource.org/licenses/MIT - */ -class Option -{ - public function __construct( - public string|int|float|null $value, - public bool $disabled = false, - public NodeIcon|null $icon = null, - public NodeText|null $info = null, - public NodeText|null $text = null - ) { - $this->text ??= new NodeText(['en' => $this->value]); - } - - public static function factory(string|int|float|null|array $props): static - { - if (is_array($props) === false) { - $props = ['value' => $props]; - } - - $props = Factory::apply($props, [ - 'icon' => NodeIcon::class, - 'info' => NodeText::class, - 'text' => NodeText::class - ]); - - return new static(...$props); - } - - public function id(): string|int|float - { - return $this->value ?? ''; - } - - /** - * Renders all data for the option - */ - public function render(ModelWithContent $model): array - { - return [ - 'disabled' => $this->disabled, - 'icon' => $this->icon?->render($model), - 'info' => $this->info?->render($model), - 'text' => $this->text?->render($model), - 'value' => $this->value - ]; - } -} diff --git a/kirby/src/Option/Options.php b/kirby/src/Option/Options.php deleted file mode 100644 index de16a14..0000000 --- a/kirby/src/Option/Options.php +++ /dev/null @@ -1,57 +0,0 @@ - - * @link https://getkirby.com - * @copyright Bastian Allgeier - * @license https://opensource.org/licenses/MIT - */ -class Options extends Collection -{ - public const TYPE = Option::class; - - public function __construct(array $objects = []) - { - foreach ($objects as $object) { - $this->__set($object->value, $object); - } - } - - public static function factory(array $items = []): static - { - $collection = new static(); - - foreach ($items as $key => $option) { - // convert an associative value => text array into props; - // skip if option is already an array of option props - if ( - is_array($option) === false || - array_key_exists('value', $option) === false - ) { - $option = match (true) { - is_string($key) => ['value' => $key, 'text' => $option], - default => ['value' => $option] - }; - } - - $option = Option::factory($option); - $collection->__set($option->id(), $option); - } - - return $collection; - } - - public function render(ModelWithContent $model): array - { - return array_values(parent::render($model)); - } -} diff --git a/kirby/src/Option/OptionsApi.php b/kirby/src/Option/OptionsApi.php deleted file mode 100644 index a3b7ae8..0000000 --- a/kirby/src/Option/OptionsApi.php +++ /dev/null @@ -1,148 +0,0 @@ -, - * Nico Hoffmann - * @link https://getkirby.com - * @copyright Bastian Allgeier - * @license https://opensource.org/licenses/MIT - */ -class OptionsApi extends OptionsProvider -{ - public function __construct( - public string $url, - public string|null $query = null, - public string|null $text = null, - public string|null $value = null - ) { - } - - public function defaults(): static - { - $this->text ??= '{{ item.value }}'; - $this->value ??= '{{ item.key }}'; - return $this; - } - - public static function factory(string|array $props): static - { - if (is_string($props) === true) { - return new static(url: $props); - } - - return new static( - url: $props['url'], - query: $props['query'] ?? $props['fetch'] ?? null, - text: $props['text'] ?? null, - value: $props['value'] ?? null - ); - } - - /** - * Loads the API content from a remote URL - * or local file (or from cache) - */ - public function load(ModelWithContent $model): array|null - { - // resolve query templates in $this->url string - $url = $model->toSafeString($this->url); - - // URL, request via cURL - if (Url::isAbsolute($url) === true) { - return Remote::get($url)->json(); - } - - // local file - return Json::read($url); - } - - public static function polyfill(array|string $props = []): array - { - if (is_string($props) === true) { - return ['url' => $props]; - } - - if ($query = $props['fetch'] ?? null) { - $props['query'] ??= $query; - unset($props['fetch']); - } - - return $props; - } - - /** - * Creates the actual options by loading - * data from the API and resolving it to - * the correct text-value entries - * - * @param bool $safeMode Whether to escape special HTML characters in - * the option text for safe output in the Panel; - * only set to `false` if the text is later escaped! - */ - public function resolve(ModelWithContent $model, bool $safeMode = true): Options - { - // use cached options if present - // @codeCoverageIgnoreStart - if ($this->options !== null) { - return $this->options; - } - // @codeCoverageIgnoreEnd - - // apply property defaults - $this->defaults(); - - // load data from URL and convert from JSON to array - $data = $this->load($model); - - // @codeCoverageIgnoreStart - if ($data === null) { - throw new NotFoundException('Options could not be loaded from API: ' . $model->toSafeString($this->url)); - } - // @codeCoverageIgnoreEnd - - // turn data into Nest so that it can be queried - // or field methods applied to the data - $data = Nest::create($data); - - // optionally query a substructure inside the data array - $data = Query::factory($this->query)->resolve($data); - $options = []; - - // create options by resolving text and value query strings - // for each item from the data - foreach ($data as $key => $item) { - // convert simple `key: value` API data - if (is_string($item) === true) { - $item = new Field(null, $key, $item); - } - - $safeMethod = $safeMode === true ? 'toSafeString' : 'toString'; - - $options[] = [ - // value is always a raw string - 'value' => $model->toString($this->value, ['item' => $item]), - // text is only a raw string when using {< >} - // or when the safe mode is explicitly disabled (select field) - 'text' => $model->$safeMethod($this->text, ['item' => $item]) - ]; - } - - // create Options object and render this subsequently - return $this->options = Options::factory($options); - } -} diff --git a/kirby/src/Option/OptionsProvider.php b/kirby/src/Option/OptionsProvider.php deleted file mode 100644 index 433b2ab..0000000 --- a/kirby/src/Option/OptionsProvider.php +++ /dev/null @@ -1,38 +0,0 @@ - - * @link https://getkirby.com - * @copyright Bastian Allgeier - * @license https://opensource.org/licenses/MIT - */ -abstract class OptionsProvider -{ - public Options|null $options = null; - - /** - * Returns options as array - */ - public function render(ModelWithContent $model) - { - return $this->resolve($model)->render($model); - } - - /** - * Dynamically determines the actual options and resolves - * them to the correct text-value entries - * - * @param bool $safeMode Whether to escape special HTML characters in - * the option text for safe output in the Panel; - * only set to `false` if the text is later escaped! - */ - abstract public function resolve(ModelWithContent $model, bool $safeMode = true): Options; -} diff --git a/kirby/src/Option/OptionsQuery.php b/kirby/src/Option/OptionsQuery.php deleted file mode 100644 index 77312c4..0000000 --- a/kirby/src/Option/OptionsQuery.php +++ /dev/null @@ -1,186 +0,0 @@ -, - * Nico Hoffmann - * @link https://getkirby.com - * @copyright Bastian Allgeier - * @license https://opensource.org/licenses/MIT - */ -class OptionsQuery extends OptionsProvider -{ - public function __construct( - public string $query, - public string|null $text = null, - public string|null $value = null - ) { - } - - protected function collection(array $array): Collection - { - foreach ($array as $key => $value) { - if (is_scalar($value) === true) { - $array[$key] = new Obj([ - 'key' => new Field(null, 'key', $key), - 'value' => new Field(null, 'value', $value), - ]); - } - } - - return new Collection($array); - } - - public static function factory(string|array $props): static - { - if (is_string($props) === true) { - return new static(query: $props); - } - - return new static( - query: $props['query'] ?? $props['fetch'], - text: $props['text'] ?? null, - value: $props['value'] ?? null - ); - } - - /** - * Returns defaults for the following based on item type: - * [query entry alias, default text query, default value query] - */ - protected function itemToDefaults(array|object $item): array - { - return match (true) { - is_array($item), - $item instanceof Obj => [ - 'arrayItem', - '{{ item.value }}', - '{{ item.value }}' - ], - - $item instanceof StructureObject => [ - 'structureItem', - '{{ item.title }}', - '{{ item.id }}' - ], - - $item instanceof Block => [ - 'block', - '{{ block.type }}: {{ block.id }}', - '{{ block.id }}' - ], - - $item instanceof Page => [ - 'page', - '{{ page.title }}', - '{{ page.id }}' - ], - - $item instanceof File => [ - 'file', - '{{ file.filename }}', - '{{ file.id }}' - ], - - $item instanceof User => [ - 'user', - '{{ user.username }}', - '{{ user.email }}' - ], - - default => [ - 'item', - '{{ item.value }}', - '{{ item.value }}' - ] - }; - } - - public static function polyfill(array|string $props = []): array - { - if (is_string($props) === true) { - return ['query' => $props]; - } - - if ($query = $props['fetch'] ?? null) { - $props['query'] ??= $query; - unset($props['fetch']); - } - - return $props; - } - - /** - * Creates the actual options by running - * the query on the model and resolving it to - * the correct text-value entries - * - * @param bool $safeMode Whether to escape special HTML characters in - * the option text for safe output in the Panel; - * only set to `false` if the text is later escaped! - */ - public function resolve(ModelWithContent $model, bool $safeMode = true): Options - { - // use cached options if present - // @codeCoverageIgnoreStart - if ($this->options !== null) { - return $this->options; - } - // @codeCoverageIgnoreEnd - - // run query - $result = $model->query($this->query); - - // the query already returned an options collection - if ($result instanceof Options) { - return $result; - } - - // convert result to a collection - if (is_array($result) === true) { - $result = $this->collection($result); - } - - if ($result instanceof Collection === false) { - $type = is_object($result) === true ? get_class($result) : gettype($result); - - throw new InvalidArgumentException('Invalid query result data: ' . $type); - } - - // create options array - $options = $result->toArray(function ($item) use ($model, $safeMode) { - // get defaults based on item type - [$alias, $text, $value] = $this->itemToDefaults($item); - $data = ['item' => $item, $alias => $item]; - - // value is always a raw string - $value = $model->toString($this->value ?? $value, $data); - - // text is only a raw string when using {< >} - // or when the safe mode is explicitly disabled (select field) - $safeMethod = $safeMode === true ? 'toSafeString' : 'toString'; - $text = $model->$safeMethod($this->text ?? $text, $data); - - return compact('text', 'value'); - }); - - return $this->options = Options::factory($options); - } -} diff --git a/kirby/src/Panel/Assets.php b/kirby/src/Panel/Assets.php deleted file mode 100644 index 1bf45a8..0000000 --- a/kirby/src/Panel/Assets.php +++ /dev/null @@ -1,324 +0,0 @@ - - * @link https://getkirby.com - * @copyright Bastian Allgeier - * @license https://getkirby.com/license - * @since 4.0.0 - */ -class Assets -{ - protected bool $dev; - protected App $kirby; - protected string $nonce; - protected Plugins $plugins; - protected string $url; - protected bool $vite; - - public function __construct() - { - $this->kirby = App::instance(); - $this->nonce = $this->kirby->nonce(); - $this->plugins = new Plugins(); - - $vite = $this->kirby->roots()->panel() . '/.vite-running'; - $this->vite = is_file($vite) === true; - - // get the assets from the Vite dev server in dev mode; - // dev mode = explicitly enabled in the config AND Vite is running - $dev = $this->kirby->option('panel.dev', false); - $this->dev = $dev !== false && $this->vite === true; - - // get the base URL - $this->url = $this->url(); - } - - /** - * Get all CSS files - */ - public function css(): array - { - $css = [ - 'index' => $this->url . '/css/style.min.css', - 'plugins' => $this->plugins->url('css'), - ...$this->custom('panel.css') - ]; - - // during dev mode we do not need to load - // the general stylesheet (as styling will be inlined) - if ($this->dev === true) { - $css['index'] = null; - } - - return array_filter($css); - } - - /** - * Check for a custom asset file from the - * config (e.g. panel.css or panel.js) - */ - public function custom(string $option): array - { - $customs = []; - - if ($assets = $this->kirby->option($option)) { - $assets = A::wrap($assets); - - foreach ($assets as $index => $path) { - if (Url::isAbsolute($path) === true) { - $customs['custom-' . $index] = $path; - continue; - } - - $asset = new Asset($path); - - if ($asset->exists() === true) { - $customs['custom-' . $index] = $asset->url() . '?' . $asset->modified(); - } - } - } - - return $customs; - } - - /** - * Generates an array with all assets - * that need to be loaded for the panel (js, css, icons) - */ - public function external(): array - { - return [ - 'css' => $this->css(), - 'icons' => $this->favicons(), - // loader for plugins' index.dev.mjs files – inlined, - // so we provide the code instead of the asset URL - 'plugin-imports' => $this->plugins->read('mjs'), - 'js' => $this->js() - ]; - } - - /** - * Returns array of favicon icons - * based on config option - * - * @todo Deprecate `url` option in v5, use `href` option instead - * @todo Deprecate `rel` usage as array key in v5, use `rel` option instead - * - * @throws \Kirby\Exception\InvalidArgumentException - */ - public function favicons(): array - { - $icons = $this->kirby->option('panel.favicon', [ - [ - 'rel' => 'apple-touch-icon', - 'type' => 'image/png', - 'href' => $this->url . '/apple-touch-icon.png' - ], - [ - 'rel' => 'alternate icon', - 'type' => 'image/png', - 'href' => $this->url . '/favicon.png' - ], - [ - 'rel' => 'shortcut icon', - 'type' => 'image/svg+xml', - 'href' => $this->url . '/favicon.svg' - ], - [ - 'rel' => 'apple-touch-icon', - 'type' => 'image/png', - 'href' => $this->url . '/apple-touch-icon-dark.png', - 'media' => '(prefers-color-scheme: dark)' - ], - [ - 'rel' => 'alternate icon', - 'type' => 'image/png', - 'href' => $this->url . '/favicon-dark.png', - 'media' => '(prefers-color-scheme: dark)' - ] - ]); - - if (is_array($icons) === true) { - // normalize options - foreach ($icons as $rel => &$icon) { - // TODO: remove this backward compatibility check in v6 - if (isset($icon['url']) === true) { - $icon['href'] = $icon['url']; - unset($icon['url']); - } - - // TODO: remove this backward compatibility check in v6 - if (is_string($rel) === true && isset($icon['rel']) === false) { - $icon['rel'] = $rel; - } - - $icon['href'] = Url::to($icon['href']); - $icon['nonce'] = $this->nonce; - } - - return array_values($icons); - } - - // make sure to convert favicon string to array - if (is_string($icons) === true) { - return [ - [ - 'rel' => 'shortcut icon', - 'type' => F::mime($icons), - 'href' => Url::to($icons), - 'nonce' => $this->nonce - ] - ]; - } - - throw new InvalidArgumentException('Invalid panel.favicon option'); - } - - /** - * Load the SVG icon sprite - * This will be injected in the - * initial HTML document for the Panel - */ - public function icons(): string - { - $dir = $this->kirby->root('panel') . '/'; - $dir .= $this->dev ? 'public' : 'dist'; - $icons = F::read($dir . '/img/icons.svg'); - $icons = preg_replace('//', '', $icons); - return $icons; - } - - /** - * Get all js files - */ - public function js(): array - { - $js = [ - 'vue' => [ - 'nonce' => $this->nonce, - 'src' => $this->url . '/js/vue.min.js' - ], - 'vendor' => [ - 'nonce' => $this->nonce, - 'src' => $this->url . '/js/vendor.min.js', - 'type' => 'module' - ], - 'pluginloader' => [ - 'nonce' => $this->nonce, - 'src' => $this->url . '/js/plugins.js', - 'type' => 'module' - ], - 'plugins' => [ - 'nonce' => $this->nonce, - 'src' => $this->plugins->url('js'), - 'defer' => true - ], - ...A::map($this->custom('panel.js'), fn ($src) => [ - 'nonce' => $this->nonce, - 'src' => $src, - 'type' => 'module' - ]), - 'index' => [ - 'nonce' => $this->nonce, - 'src' => $this->url . '/js/index.min.js', - 'type' => 'module' - ], - ]; - - - // during dev mode, add vite client and adapt - // path to `index.js` - vendor does not need - // to be loaded in dev mode - if ($this->dev === true) { - // load the non-minified index.js, remove vendor script and - // development version of Vue - $js['vendor']['src'] = null; - $js['index']['src'] = $this->url . '/src/index.js'; - $js['vue']['src'] = $this->url . '/node_modules/vue/dist/vue.js'; - - // add vite dev client - $js['vite'] = [ - 'nonce' => $this->nonce, - 'src' => $this->url . '/@vite/client', - 'type' => 'module' - ]; - } - - return array_filter($js, fn ($js) => empty($js['src']) === false); - } - - /** - * Links all dist files in the media folder - * and returns the link to the requested asset - * - * @throws \Kirby\Exception\Exception If Panel assets could not be moved to the public directory - */ - public function link(): bool - { - $mediaRoot = $this->kirby->root('media') . '/panel'; - $panelRoot = $this->kirby->root('panel') . '/dist'; - $versionHash = $this->kirby->versionHash(); - $versionRoot = $mediaRoot . '/' . $versionHash; - - // check if the version already exists - if (is_dir($versionRoot) === true) { - return false; - } - - // delete the panel folder and all previous versions - Dir::remove($mediaRoot); - - // recreate the panel folder - Dir::make($mediaRoot, true); - - // copy assets to the dist folder - if (Dir::copy($panelRoot, $versionRoot) !== true) { - throw new Exception('Panel assets could not be linked'); - } - - return true; - } - - /** - * Get the base URL for all assets depending on dev mode - */ - public function url(): string - { - // vite is not running, use production assets - if ($this->dev === false) { - return $this->kirby->url('media') . '/panel/' . $this->kirby->versionHash(); - } - - // explicitly configured base URL - $dev = $this->kirby->option('panel.dev'); - if (is_string($dev) === true) { - return $dev; - } - - // port 3000 of the current Kirby request - return rtrim($this->kirby->request()->url([ - 'port' => 3000, - 'path' => null, - 'params' => null, - 'query' => null - ])->toString(), '/'); - } -} diff --git a/kirby/src/Panel/ChangesDialog.php b/kirby/src/Panel/ChangesDialog.php deleted file mode 100644 index 7053626..0000000 --- a/kirby/src/Panel/ChangesDialog.php +++ /dev/null @@ -1,71 +0,0 @@ -multilang(); - $changes = []; - - foreach ($ids as $id) { - try { - // parse the given ID to extract - // the path and an optional query - $uri = new Uri($id); - $path = $uri->path()->toString(); - $query = $uri->query(); - $model = Find::parent($path); - $item = $model->panel()->dropdownOption(); - - // add the language to each option, if it is included in the query - // of the given ID and the language actually exists - if ( - $multilang && - $query->language && - $language = $kirby->language($query->language) - ) { - $item['text'] .= ' (' . $language->code() . ')'; - $item['link'] .= '?language=' . $language->code(); - } - - $item['text'] = Escape::html($item['text']); - - $changes[] = $item; - } catch (Throwable) { - continue; - } - } - - return $changes; - } - - public function load(): array - { - return $this->state(); - } - - public function state(bool $loading = true, array $changes = []) - { - return [ - 'component' => 'k-changes-dialog', - 'props' => [ - 'changes' => $changes, - 'loading' => $loading - ] - ]; - } - - public function submit(array $ids): array - { - return $this->state(false, $this->changes($ids)); - } -} diff --git a/kirby/src/Panel/Dialog.php b/kirby/src/Panel/Dialog.php index df43c4a..a7825e9 100644 --- a/kirby/src/Panel/Dialog.php +++ b/kirby/src/Panel/Dialog.php @@ -2,12 +2,10 @@ namespace Kirby\Panel; -use Kirby\Http\Response; - /** * The Dialog response class handles Fiber * requests to render the JSON object for - * Panel dialogs and creates the routes + * Panel dialogs * @since 3.6.0 * * @package Kirby Panel @@ -18,12 +16,16 @@ use Kirby\Http\Response; */ class Dialog extends Json { - protected static string $key = '$dialog'; + protected static $key = '$dialog'; /** * Renders dialogs + * + * @param mixed $data + * @param array $options + * @return \Kirby\Http\Response */ - public static function response($data, array $options = []): Response + public static function response($data, array $options = []) { // interpret true as success if ($data === true) { @@ -34,39 +36,4 @@ class Dialog extends Json return parent::response($data, $options); } - - /** - * Builds the routes for a dialog - */ - public static function routes( - string $id, - string $areaId, - string $prefix = '', - array $options = [] - ) { - $routes = []; - - // create the full pattern with dialogs prefix - $pattern = trim($prefix . '/' . ($options['pattern'] ?? $id), '/'); - $type = str_replace('$', '', static::$key); - - // load event - $routes[] = [ - 'pattern' => $pattern, - 'type' => $type, - 'area' => $areaId, - 'action' => $options['load'] ?? fn () => 'The load handler is missing' - ]; - - // submit event - $routes[] = [ - 'pattern' => $pattern, - 'type' => $type, - 'area' => $areaId, - 'method' => 'POST', - 'action' => $options['submit'] ?? fn () => 'The submit handler is missing' - ]; - - return $routes; - } } diff --git a/kirby/src/Panel/Document.php b/kirby/src/Panel/Document.php index 1c145f0..1e46e3f 100644 --- a/kirby/src/Panel/Document.php +++ b/kirby/src/Panel/Document.php @@ -3,6 +3,12 @@ namespace Kirby\Panel; use Kirby\Cms\App; +use Kirby\Cms\Helpers; +use Kirby\Exception\Exception; +use Kirby\Exception\InvalidArgumentException; +use Kirby\Filesystem\Asset; +use Kirby\Filesystem\Dir; +use Kirby\Filesystem\F; use Kirby\Http\Response; use Kirby\Http\Uri; use Kirby\Toolkit\Tpl; @@ -23,17 +29,254 @@ use Throwable; class Document { /** - * Renders the panel document + * Generates an array with all assets + * that need to be loaded for the panel (js, css, icons) + * + * @return array */ - public static function response(array $fiber): Response + public static function assets(): array { - $kirby = App::instance(); - $assets = new Assets(); + $kirby = App::instance(); + $nonce = $kirby->nonce(); + + // get the assets from the Vite dev server in dev mode; + // dev mode = explicitly enabled in the config AND Vite is running + $dev = $kirby->option('panel.dev', false); + $isDev = $dev !== false && is_file($kirby->roots()->panel() . '/.vite-running') === true; + + if ($isDev === true) { + // vite on explicitly configured base URL or port 3000 + // of the current Kirby request + if (is_string($dev) === true) { + $url = $dev; + } else { + $url = rtrim($kirby->request()->url([ + 'port' => 3000, + 'path' => null, + 'params' => null, + 'query' => null + ])->toString(), '/'); + } + } else { + // vite is not running, use production assets + $url = $kirby->url('media') . '/panel/' . $kirby->versionHash(); + } + + // fetch all plugins + $plugins = new Plugins(); + + $assets = [ + 'css' => [ + 'index' => $url . '/css/style.css', + 'plugins' => $plugins->url('css'), + 'custom' => static::customAsset('panel.css'), + ], + 'icons' => static::favicon($url), + // loader for plugins' index.dev.mjs files – inlined, so we provide the code instead of the asset URL + 'plugin-imports' => $plugins->read('mjs'), + 'js' => [ + 'vendor' => [ + 'nonce' => $nonce, + 'src' => $url . '/js/vendor.js', + 'type' => 'module' + ], + 'pluginloader' => [ + 'nonce' => $nonce, + 'src' => $url . '/js/plugins.js', + 'type' => 'module' + ], + 'plugins' => [ + 'nonce' => $nonce, + 'src' => $plugins->url('js'), + 'defer' => true + ], + 'custom' => [ + 'nonce' => $nonce, + 'src' => static::customAsset('panel.js'), + 'type' => 'module' + ], + 'index' => [ + 'nonce' => $nonce, + 'src' => $url . '/js/index.js', + 'type' => 'module' + ], + ] + ]; + + // during dev mode, add vite client and adapt + // path to `index.js` - vendor and stylesheet + // don't need to be loaded in dev mode + if ($isDev === true) { + $assets['js']['vite'] = [ + 'nonce' => $nonce, + 'src' => $url . '/@vite/client', + 'type' => 'module' + ]; + $assets['js']['index'] = [ + 'nonce' => $nonce, + 'src' => $url . '/src/index.js', + 'type' => 'module' + ]; + + unset($assets['css']['index'], $assets['js']['vendor']); + } + + // remove missing files + $assets['css'] = array_filter($assets['css']); + $assets['js'] = array_filter( + $assets['js'], + fn ($js) => empty($js['src']) === false + ); + + return $assets; + } + + /** + * Check for a custom asset file from the + * config (e.g. panel.css or panel.js) + * @since 3.7.0 + * + * @param string $option asset option name + * @return string|null + */ + public static function customAsset(string $option): ?string + { + if ($path = App::instance()->option($option)) { + $asset = new Asset($path); + + if ($asset->exists() === true) { + return $asset->url() . '?' . $asset->modified(); + } + } + + return null; + } + + /** + * @deprecated 3.7.0 Use `Document::customAsset('panel.css)` instead + * @todo remove in 3.8.0 + * @codeCoverageIgnore + */ + public static function customCss(): ?string + { + Helpers::deprecated('Panel\Document::customCss() has been deprecated and will be removed in Kirby 3.8.0. Use Panel\Document::customAsset(\'panel.css\') instead.'); + return static::customAsset('panel.css'); + } + + /** + * @deprecated 3.7.0 Use `Document::customAsset('panel.js)` instead + * @todo remove in 3.8.0 + * @codeCoverageIgnore + */ + public static function customJs(): ?string + { + Helpers::deprecated('Panel\Document::customJs() has been deprecated and will be removed in Kirby 3.8.0. Use Panel\Document::customAsset(\'panel.js\') instead.'); + return static::customAsset('panel.js'); + } + + /** + * Returns array of favion icons + * based on config option + * @since 3.7.0 + * + * @param string $url URL prefix for default icons + * @return array + */ + public static function favicon(string $url = ''): array + { + $kirby = App::instance(); + $icons = $kirby->option('panel.favicon', [ + 'apple-touch-icon' => [ + 'type' => 'image/png', + 'url' => $url . '/apple-touch-icon.png', + ], + 'shortcut icon' => [ + 'type' => 'image/svg+xml', + 'url' => $url . '/favicon.svg', + ], + 'alternate icon' => [ + 'type' => 'image/png', + 'url' => $url . '/favicon.png', + ] + ]); + + if (is_array($icons) === true) { + return $icons; + } + + // make sure to convert favicon string to array + if (is_string($icons) === true) { + return [ + 'shortcut icon' => [ + 'type' => F::mime($icons), + 'url' => $icons, + ] + ]; + } + + throw new InvalidArgumentException('Invalid panel.favicon option'); + } + + /** + * Load the SVG icon sprite + * This will be injected in the + * initial HTML document for the Panel + * + * @return string + */ + public static function icons(): string + { + return F::read(App::instance()->root('kirby') . '/panel/dist/img/icons.svg'); + } + + /** + * Links all dist files in the media folder + * and returns the link to the requested asset + * + * @return bool + * @throws \Kirby\Exception\Exception If Panel assets could not be moved to the public directory + */ + public static function link(): bool + { + $kirby = App::instance(); + $mediaRoot = $kirby->root('media') . '/panel'; + $panelRoot = $kirby->root('panel') . '/dist'; + $versionHash = $kirby->versionHash(); + $versionRoot = $mediaRoot . '/' . $versionHash; + + // check if the version already exists + if (is_dir($versionRoot) === true) { + return false; + } + + // delete the panel folder and all previous versions + Dir::remove($mediaRoot); + + // recreate the panel folder + Dir::make($mediaRoot, true); + + // copy assets to the dist folder + if (Dir::copy($panelRoot, $versionRoot) !== true) { + throw new Exception('Panel assets could not be linked'); + } + + return true; + } + + /** + * Renders the panel document + * + * @param array $fiber + * @return \Kirby\Http\Response + */ + public static function response(array $fiber) + { + $kirby = App::instance(); // Full HTML response // @codeCoverageIgnoreStart try { - if ($assets->link() === true) { + if (static::link() === true) { usleep(1); Response::go($kirby->url('base') . '/' . $kirby->path()); } @@ -43,27 +286,30 @@ class Document // @codeCoverageIgnoreEnd // get the uri object for the panel url - $uri = new Uri($kirby->url('panel')); + $uri = new Uri($url = $kirby->url('panel')); // proper response code $code = $fiber['$view']['code'] ?? 200; // load the main Panel view template $body = Tpl::load($kirby->root('kirby') . '/views/panel.php', [ - 'assets' => $assets->external(), - 'icons' => $assets->icons(), + 'assets' => static::assets(), + 'icons' => static::icons(), 'nonce' => $kirby->nonce(), 'fiber' => $fiber, 'panelUrl' => $uri->path()->toString(true) . '/', ]); - $frameAncestors = $kirby->option('panel.frameAncestors'); - $frameAncestors = match (true) { - $frameAncestors === true => "'self'", - is_array($frameAncestors) => "'self' " . implode(' ', $frameAncestors), - is_string($frameAncestors) => $frameAncestors, - default => "'none'" - }; + $frameAncestorsOption = $kirby->option('panel.frameAncestors'); + if ($frameAncestorsOption === true) { + $frameAncestors = "'self'"; + } elseif (is_array($frameAncestorsOption)) { + $frameAncestors = "'self' " . implode(' ', $frameAncestorsOption); + } elseif (is_string($frameAncestorsOption)) { + $frameAncestors = $frameAncestorsOption; + } else { + $frameAncestors = "'none'"; + } return new Response($body, 'text/html', $code, [ 'Content-Security-Policy' => 'frame-ancestors ' . $frameAncestors diff --git a/kirby/src/Panel/Drawer.php b/kirby/src/Panel/Drawer.php deleted file mode 100644 index 0952088..0000000 --- a/kirby/src/Panel/Drawer.php +++ /dev/null @@ -1,21 +0,0 @@ - - * @link https://getkirby.com - * @copyright Bastian Allgeier - * @license https://getkirby.com/license - */ -class Drawer extends Dialog -{ - protected static string $key = '$drawer'; -} diff --git a/kirby/src/Panel/Dropdown.php b/kirby/src/Panel/Dropdown.php index de01bf6..42bdd91 100644 --- a/kirby/src/Panel/Dropdown.php +++ b/kirby/src/Panel/Dropdown.php @@ -2,8 +2,12 @@ namespace Kirby\Panel; -use Closure; -use Kirby\Http\Response; +use Kirby\Cms\App; +use Kirby\Cms\Find; +use Kirby\Exception\LogicException; +use Kirby\Http\Uri; +use Kirby\Toolkit\Str; +use Throwable; /** * The Dropdown response class handles Fiber @@ -19,12 +23,61 @@ use Kirby\Http\Response; */ class Dropdown extends Json { - protected static string $key = '$dropdown'; + protected static $key = '$dropdown'; + + /** + * Returns the options for the changes dropdown + * + * @return array + */ + public static function changes(): array + { + $kirby = App::instance(); + $multilang = $kirby->multilang(); + $ids = Str::split($kirby->request()->get('ids')); + $options = []; + + foreach ($ids as $id) { + try { + // parse the given ID to extract + // the path and an optional query + $uri = new Uri($id); + $path = $uri->path()->toString(); + $query = $uri->query(); + $option = Find::parent($path)->panel()->dropdownOption(); + + // add the language to each option, if it is included in the query + // of the given ID and the language actually exists + if ($multilang && $query->language && $language = $kirby->language($query->language)) { + $option['text'] .= ' (' . $language->code() . ')'; + $option['link'] .= '?language=' . $language->code(); + } + + $options[] = $option; + } catch (Throwable $e) { + continue; + } + } + + // the given set of ids does not match any + // real models. This means that the stored ids + // in local storage are not correct and the changes + // store needs to be cleared + if (empty($options) === true) { + throw new LogicException('No changes for given models'); + } + + return $options; + } /** * Renders dropdowns + * + * @param mixed $data + * @param array $options + * @return \Kirby\Http\Response */ - public static function response($data, array $options = []): Response + public static function response($data, array $options = []) { if (is_array($data) === true) { $data = [ @@ -34,38 +87,4 @@ class Dropdown extends Json return parent::response($data, $options); } - - /** - * Routes for the dropdown - */ - public static function routes( - string $id, - string $areaId, - string $prefix = '', - Closure|array $options = [] - ): array { - // Handle shortcuts for dropdowns. The name is the pattern - // and options are defined in a Closure - if ($options instanceof Closure) { - $options = [ - 'pattern' => $id, - 'action' => $options - ]; - } - - // create the full pattern with dialogs prefix - $pattern = trim($prefix . '/' . ($options['pattern'] ?? $id), '/'); - $type = str_replace('$', '', static::$key); - - return [ - // load event - [ - 'pattern' => $pattern, - 'type' => $type, - 'area' => $areaId, - 'method' => 'GET|POST', - 'action' => $options['options'] ?? $options['action'] - ] - ]; - } } diff --git a/kirby/src/Panel/Field.php b/kirby/src/Panel/Field.php index e895712..3d02d21 100644 --- a/kirby/src/Panel/Field.php +++ b/kirby/src/Panel/Field.php @@ -4,12 +4,8 @@ namespace Kirby\Panel; use Kirby\Cms\App; use Kirby\Cms\File; -use Kirby\Cms\ModelWithContent; use Kirby\Cms\Page; -use Kirby\Form\Form; -use Kirby\Http\Router; use Kirby\Toolkit\I18n; -use Kirby\Toolkit\Str; /** * Provides common field prop definitions @@ -24,60 +20,11 @@ use Kirby\Toolkit\Str; */ class Field { - /** - * Creates the routes for a field dialog - * This is most definitely not a good place for this - * method, but as long as the other classes are - * not fully refactored, it still feels appropriate - */ - public static function dialog( - ModelWithContent $model, - string $fieldName, - string|null $path = null, - string $method = 'GET', - ) { - $field = Form::for($model)->field($fieldName); - $routes = []; - - foreach ($field->dialogs() as $dialogId => $dialog) { - $routes = array_merge($routes, Dialog::routes( - id: $dialogId, - areaId: 'site', - options: $dialog - )); - } - - return Router::execute($path, $method, $routes); - } - - /** - * Creates the routes for a field drawer - * This is most definitely not a good place for this - * method, but as long as the other classes are - * not fully refactored, it still feels appropriate - */ - public static function drawer( - ModelWithContent $model, - string $fieldName, - string|null $path = null, - string $method = 'GET', - ) { - $field = Form::for($model)->field($fieldName); - $routes = []; - - foreach ($field->drawers() as $drawerId => $drawer) { - $routes = array_merge($routes, Drawer::routes( - id: $drawerId, - areaId: 'site', - options: $drawer - )); - } - - return Router::execute($path, $method, $routes); - } - /** * A standard email field + * + * @param array $props + * @return array */ public static function email(array $props = []): array { @@ -90,6 +37,10 @@ class Field /** * File position + * + * @param \Kirby\Cms\File + * @param array $props + * @return array */ public static function filePosition(File $file, array $props = []): array { @@ -127,13 +78,20 @@ class Field } + /** + * @return array + */ public static function hidden(): array { - return ['hidden' => true]; + return ['type' => 'hidden']; } /** * Page position + * + * @param \Kirby\Cms\Page + * @param array $props + * @return array */ public static function pagePosition(Page $page, array $props = []): array { @@ -179,6 +137,9 @@ class Field /** * A regular password field + * + * @param array $props + * @return array */ public static function password(array $props = []): array { @@ -190,11 +151,15 @@ class Field /** * User role radio buttons + * + * @param array $props + * @return array */ public static function role(array $props = []): array { $kirby = App::instance(); - $isAdmin = $kirby->user()?->isAdmin() ?? false; + $user = $kirby->user(); + $isAdmin = $user && $user->isAdmin(); $roles = []; foreach ($kirby->roles() as $role) { @@ -218,19 +183,25 @@ class Field ], $props); } + /** + * @param array $props + * @return array + */ public static function slug(array $props = []): array { return array_merge([ 'label' => I18n::translate('slug'), 'type' => 'slug', - 'allow' => Str::$defaults['slug']['allowed'] ], $props); } - public static function template( - array|null $blueprints = [], - array|null $props = [] - ): array { + /** + * @param array $blueprints + * @param array $props + * @return array + */ + public static function template(?array $blueprints = [], ?array $props = []): array + { $options = []; foreach ($blueprints as $blueprint) { @@ -250,6 +221,10 @@ class Field ], $props); } + /** + * @param array $props + * @return array + */ public static function title(array $props = []): array { return array_merge([ @@ -261,6 +236,9 @@ class Field /** * Panel translation select box + * + * @param array $props + * @return array */ public static function translation(array $props = []): array { @@ -275,12 +253,16 @@ class Field return array_merge([ 'label' => I18n::translate('language'), 'type' => 'select', - 'icon' => 'translate', + 'icon' => 'globe', 'options' => $translations, 'empty' => false ], $props); } + /** + * @param array $props + * @return array + */ public static function username(array $props = []): array { return array_merge([ diff --git a/kirby/src/Panel/File.php b/kirby/src/Panel/File.php index d58e7a1..c78fa7e 100644 --- a/kirby/src/Panel/File.php +++ b/kirby/src/Panel/File.php @@ -2,9 +2,6 @@ namespace Kirby\Panel; -use Kirby\Cms\File as CmsFile; -use Kirby\Cms\ModelWithContent; -use Kirby\Filesystem\Asset; use Kirby\Toolkit\I18n; use Throwable; @@ -23,10 +20,12 @@ class File extends Model /** * @var \Kirby\Cms\File */ - protected ModelWithContent $model; + protected $model; /** * Breadcrumb array + * + * @return array */ public function breadcrumb(): array { @@ -35,7 +34,6 @@ class File extends Model switch ($parent::CLASS_ALIAS) { case 'user': - /** @var \Kirby\Cms\User $parent */ // The breadcrumb is not necessary // on the account view if ($parent->isLoggedIn() === false) { @@ -46,13 +44,10 @@ class File extends Model } break; case 'page': - /** @var \Kirby\Cms\Page $parent */ - $breadcrumb = $this->model->parents()->flip()->values( - fn ($parent) => [ - 'label' => $parent->title()->toString(), - 'link' => $parent->panel()->url(true), - ] - ); + $breadcrumb = $this->model->parents()->flip()->values(fn ($parent) => [ + 'label' => $parent->title()->toString(), + 'link' => $parent->panel()->url(true), + ]); } // add the file @@ -72,54 +67,47 @@ class File extends Model * * @internal * @param string|null $type (`auto`|`kirbytext`|`markdown`) + * @param bool $absolute + * @return string */ - public function dragText( - string|null $type = null, - bool $absolute = false - ): string { + public function dragText(string $type = null, bool $absolute = false): string + { $type = $this->dragTextType($type); - $url = $this->model->filename(); - $file = $this->model->type(); + $url = $absolute ? $this->model->id() : $this->model->filename(); - // By default only the filename is added as relative URL. - // If an absolute URL is required, either use the permalink - // for markdown notation or the UUID for Kirbytext (since - // Kirbytags support can resolve UUIDs directly) - if ($absolute === true) { - $url = match ($type) { - 'markdown' => $this->model->permalink(), - default => $this->model->uuid() - }; - - // if UUIDs are disabled, fall back to URL - $url ??= $this->model->url(); - } - - if ($callback = $this->dragTextFromCallback($type, $url)) { - return $callback; + if ($dragTextFromCallback = $this->dragTextFromCallback($type, $url)) { + return $dragTextFromCallback; } if ($type === 'markdown') { - return match ($file) { - 'image' => '![' . $this->model->alt() . '](' . $url . ')', - default => '[' . $this->model->filename() . '](' . $url . ')' - }; + if ($this->model->type() === 'image') { + return '![' . $this->model->alt() . '](' . $url . ')'; + } + + return '[' . $this->model->filename() . '](' . $url . ')'; } - return match ($file) { - 'image', 'video' => '(' . $file . ': ' . $url . ')', - default => '(file: ' . $url . ')' - }; + if ($this->model->type() === 'image') { + return '(image: ' . $url . ')'; + } + if ($this->model->type() === 'video') { + return '(video: ' . $url . ')'; + } + + return '(file: ' . $url . ')'; } /** * Provides options for the file dropdown + * + * @param array $options + * @return array */ public function dropdown(array $options = []): array { - $file = $this->model; - $request = $file->kirby()->request(); - $defaults = $request->get(['view', 'update', 'delete']); + $file = $this->model; + + $defaults = $file->kirby()->request()->get(['view', 'update', 'delete']); $options = array_merge($defaults, $options); $permissions = $this->options(['preview']); @@ -144,7 +132,15 @@ class File extends Model 'disabled' => $this->isDisabledDropdownOption('changeName', $options, $permissions) ]; + $result[] = [ + 'click' => 'replace', + 'icon' => 'upload', + 'text' => I18n::translate('replace'), + 'disabled' => $this->isDisabledDropdownOption('replace', $options, $permissions) + ]; + if ($view === 'list') { + $result[] = '-'; $result[] = [ 'dialog' => $url . '/changeSort', 'icon' => 'sort', @@ -153,22 +149,6 @@ class File extends Model ]; } - $result[] = [ - 'dialog' => $url . '/changeTemplate', - 'icon' => 'template', - 'text' => I18n::translate('file.changeTemplate'), - 'disabled' => $this->isDisabledDropdownOption('changeTemplate', $options, $permissions) - ]; - - $result[] = '-'; - - $result[] = [ - 'click' => 'replace', - 'icon' => 'upload', - 'text' => I18n::translate('replace'), - 'disabled' => $this->isDisabledDropdownOption('replace', $options, $permissions) - ]; - $result[] = '-'; $result[] = [ 'dialog' => $url . '/delete', @@ -183,7 +163,9 @@ class File extends Model /** * Returns the setup for a dropdown option * which is used in the changes dropdown - * for example + * for example. + * + * @return array */ public function dropdownOption(): array { @@ -195,36 +177,39 @@ class File extends Model /** * Returns the Panel icon color + * + * @return string */ protected function imageColor(): string { $types = [ - 'archive' => 'gray-500', - 'audio' => 'aqua-500', - 'code' => 'pink-500', - 'document' => 'red-500', - 'image' => 'orange-500', - 'video' => 'yellow-500', + 'image' => 'orange-400', + 'video' => 'yellow-400', + 'document' => 'red-400', + 'audio' => 'aqua-400', + 'code' => 'blue-400', + 'archive' => 'gray-500' ]; $extensions = [ - 'csv' => 'green-500', - 'doc' => 'blue-500', - 'docx' => 'blue-500', - 'indd' => 'purple-500', - 'rtf' => 'blue-500', - 'xls' => 'green-500', - 'xlsx' => 'green-500', + 'indd' => 'purple-400', + 'xls' => 'green-400', + 'xlsx' => 'green-400', + 'csv' => 'green-400', + 'docx' => 'blue-400', + 'doc' => 'blue-400', + 'rtf' => 'blue-400' ]; - return - $extensions[$this->model->extension()] ?? - $types[$this->model->type()] ?? - parent::imageDefaults()['color']; + return $extensions[$this->model->extension()] ?? + $types[$this->model->type()] ?? + parent::imageDefaults()['color']; } /** * Default settings for the file's Panel image + * + * @return array */ protected function imageDefaults(): array { @@ -236,42 +221,45 @@ class File extends Model /** * Returns the Panel icon type + * + * @return string */ protected function imageIcon(): string { $types = [ - 'archive' => 'archive', - 'audio' => 'audio', - 'code' => 'code', - 'document' => 'document', 'image' => 'image', 'video' => 'video', + 'document' => 'document', + 'audio' => 'audio', + 'code' => 'code', + 'archive' => 'archive' ]; $extensions = [ - 'csv' => 'table', - 'doc' => 'pen', - 'docx' => 'pen', - 'md' => 'markdown', - 'mdown' => 'markdown', - 'rtf' => 'pen', 'xls' => 'table', 'xlsx' => 'table', + 'csv' => 'table', + 'docx' => 'pen', + 'doc' => 'pen', + 'rtf' => 'pen', + 'mdown' => 'markdown', + 'md' => 'markdown' ]; - return - $extensions[$this->model->extension()] ?? - $types[$this->model->type()] ?? - 'file'; + return $extensions[$this->model->extension()] ?? + $types[$this->model->type()] ?? + 'file'; } /** * Returns the image file object based on provided query + * * @internal + * @param string|null $query + * @return \Kirby\Cms\File|\Kirby\Filesystem\Asset|null */ - protected function imageSource( - string|null $query = null - ): CmsFile|Asset|null { + protected function imageSource(string $query = null) + { if ($query === null && $this->model->isViewable()) { return $this->model; } @@ -279,45 +267,12 @@ class File extends Model return parent::imageSource($query); } - /** - * Whether focus can be added in Panel view - */ - public function isFocusable(): bool - { - // blueprint option - $option = $this->model->blueprint()->focus(); - // fallback to whether the file is viewable - // (images should be focusable by default, others not) - $option ??= $this->model->isViewable(); - - if ($option === false) { - return false; - } - - // ensure that user can update content file - if ($this->options()['update'] === false) { - return false; - } - - $kirby = $this->model->kirby(); - - // ensure focus is only added when editing primary/only language - if ( - $kirby->multilang() === false || - $kirby->languages()->count() === 0 || - $kirby->language()->isDefault() === true - ) { - return true; - } - - return false; - } - /** * Returns an array of all actions * that can be performed in the Panel * * @param array $unlock An array of options that will be force-unlocked + * @return array */ public function options(array $unlock = []): array { @@ -327,7 +282,7 @@ class File extends Model // check if the file type is allowed at all, // otherwise it cannot be replaced $this->model->match($this->model->blueprint()->accept()); - } catch (Throwable) { + } catch (Throwable $e) { $options['replace'] = false; } @@ -336,6 +291,8 @@ class File extends Model /** * Returns the full path without leading slash + * + * @return string */ public function path(): string { @@ -345,41 +302,51 @@ class File extends Model /** * Prepares the response data for file pickers * and file fields + * + * @param array|null $params + * @return array */ public function pickerData(array $params = []): array { - $name = $this->model->filename(); $id = $this->model->id(); + $name = $this->model->filename(); if (empty($params['model']) === false) { - $parent = $this->model->parent(); - - // if the file belongs to the current parent model, - // store only name as ID to keep its path relative to the model - $id = $parent === $params['model'] ? $name : $id; + $parent = $this->model->parent(); + $uuid = $parent === $params['model'] ? $name : $id; $absolute = $parent !== $params['model']; } $params['text'] ??= '{{ file.filename }}'; return array_merge(parent::pickerData($params), [ - 'dragText' => $this->dragText('auto', $absolute ?? false), 'filename' => $name, - 'id' => $id, + 'dragText' => $this->dragText('auto', $absolute ?? false), 'type' => $this->model->type(), - 'url' => $this->model->url() + 'url' => $this->model->url(), + 'uuid' => $uuid ?? $id, ]); } /** * Returns the data array for the * view's component props + * * @internal + * + * @return array */ public function props(): array { $file = $this->model; $dimensions = $file->dimensions(); + $siblings = $file->templateSiblings()->sortBy( + 'sort', + 'asc', + 'filename', + 'asc' + ); + return array_merge( parent::props(), @@ -401,13 +368,12 @@ class File extends Model 'url' => $file->url(), ], 'preview' => [ - 'focusable' => $this->isFocusable(), - 'image' => $this->image([ + 'image' => $this->image([ 'back' => 'transparent', 'ratio' => '1/1' ], 'cards'), - 'url' => $url = $file->previewUrl(), - 'details' => [ + 'url' => $url = $file->previewUrl(), + 'details' => [ [ 'title' => I18n::translate('template'), 'text' => $file->template() ?? '—' @@ -442,7 +408,10 @@ class File extends Model /** * Returns navigation array with * previous and next file + * * @internal + * + * @return array */ public function prevNext(): array { @@ -455,11 +424,11 @@ class File extends Model ); return [ - 'next' => function () use ($file, $siblings): array|null { + 'next' => function () use ($file, $siblings): ?array { $next = $siblings->nth($siblings->indexOf($file) + 1); return $this->toPrevNextLink($next, 'filename'); }, - 'prev' => function () use ($file, $siblings): array|null { + 'prev' => function () use ($file, $siblings): ?array { $prev = $siblings->nth($siblings->indexOf($file) - 1); return $this->toPrevNextLink($prev, 'filename'); } @@ -468,6 +437,9 @@ class File extends Model /** * Returns the url to the editing view * in the panel + * + * @param bool $relative + * @return string */ public function url(bool $relative = false): string { @@ -478,16 +450,21 @@ class File extends Model /** * Returns the data array for * this model's Panel view + * * @internal + * + * @return array */ public function view(): array { + $file = $this->model; + return [ - 'breadcrumb' => fn (): array => $this->model->panel()->breadcrumb(), + 'breadcrumb' => fn (): array => $file->panel()->breadcrumb(), 'component' => 'k-file-view', 'props' => $this->props(), 'search' => 'files', - 'title' => $this->model->filename(), + 'title' => $file->filename(), ]; } } diff --git a/kirby/src/Panel/Home.php b/kirby/src/Panel/Home.php index 3abb1c4..434673c 100644 --- a/kirby/src/Panel/Home.php +++ b/kirby/src/Panel/Home.php @@ -38,6 +38,9 @@ class Home * It will go through the entire menu and * take the first area which is not disabled * or locked in other ways + * + * @param \Kirby\Cms\User $user + * @return string */ public static function alternative(User $user): string { @@ -50,8 +53,7 @@ class Home // needed to create a proper menu $areas = Panel::areas(); - $menu = new Menu($areas, $permissions->toArray()); - $menu = $menu->entries(); + $menu = View::menu($areas, $permissions->toArray()); // go through the menu and search for the first // available view we can go to @@ -66,16 +68,11 @@ class Home continue; } - // skip buttons that don't open a link - // (but e.g. a dialog) - if (isset($menuItem['link']) === false) { + // skip the logout button + if ($menuItem['id'] === 'logout') { continue; } - // skip the logout button - if ($menuItem['link'] === 'logout') { - continue; - } return Panel::url($menuItem['link']); } @@ -88,6 +85,10 @@ class Home * panel path. This is quite tricky, because we * need to call a trimmed down router to check * for available routes and their firewall status. + * + * @param \Kirby\Cms\User + * @param string $path + * @return bool */ public static function hasAccess(User $user, string $path): bool { @@ -106,10 +107,9 @@ class Home // create a dummy router to check if we can access this route at all try { return Router::execute($path, 'GET', $routes, function ($route) use ($user) { - $attrs = $route->attributes(); - $auth = $attrs['auth'] ?? true; - $areaId = $attrs['area'] ?? null; - $type = $attrs['type'] ?? 'view'; + $auth = $route->attributes()['auth'] ?? true; + $areaId = $route->attributes()['area'] ?? null; + $type = $route->attributes()['type'] ?? 'view'; // only allow redirects to views if ($type !== 'view') { @@ -124,7 +124,7 @@ class Home // check the firewall return Panel::hasAccess($user, $areaId); }); - } catch (Throwable) { + } catch (Throwable $e) { return false; } } @@ -134,28 +134,35 @@ class Home * as the index URL of the Kirby installation. * This is used to block external URLs to third-party * domains as redirect options. + * + * @param \Kirby\Http\Uri $uri + * @return bool */ public static function hasValidDomain(Uri $uri): bool { $rootUrl = App::instance()->site()->url(); - $rootUri = new Uri($rootUrl); - return $uri->domain() === $rootUri->domain(); + return $uri->domain() === (new Uri($rootUrl))->domain(); } /** - * Checks if the given URL is a Panel Url + * Checks if the given URL is a Panel Url. + * + * @param string $url + * @return bool */ public static function isPanelUrl(string $url): bool { - $panel = App::instance()->url('panel'); - return Str::startsWith($url, $panel); + return Str::startsWith($url, App::instance()->url('panel')); } /** * Returns the path after /panel/ which can then * be used in the router or to find a matching view + * + * @param string $url + * @return string|null */ - public static function panelPath(string $url): string|null + public static function panelPath(string $url): ?string { $after = Str::after($url, App::instance()->url('panel')); return trim($after, '/'); @@ -166,16 +173,16 @@ class Home * before the last logout. We take this Url if possible * to redirect the user back to the last point where they * left before they got logged out. + * + * @return string|null */ - public static function remembered(): string|null + public static function remembered(): ?string { // check for a stored path after login - if ($remembered = App::instance()->session()->pull('panel.path')) { - // convert the result to an absolute URL if available - return Panel::url($remembered); - } + $remembered = App::instance()->session()->pull('panel.path'); - return null; + // convert the result to an absolute URL if available + return $remembered ? Panel::url($remembered) : null; } /** @@ -199,6 +206,8 @@ class Home * Afterwards, we also check for permissions before the redirect happens * to avoid redirects to inaccessible Panel views. In such a case * the next best accessible view is picked from the menu. + * + * @return string */ public static function url(): string { diff --git a/kirby/src/Panel/Json.php b/kirby/src/Panel/Json.php index 2cfa895..926046e 100644 --- a/kirby/src/Panel/Json.php +++ b/kirby/src/Panel/Json.php @@ -2,11 +2,6 @@ namespace Kirby\Panel; -use Kirby\Cms\App; -use Kirby\Exception\Exception; -use Kirby\Http\Response; -use Throwable; - /** * The Json abstract response class provides * common framework for Fiber requests @@ -22,12 +17,16 @@ use Throwable; */ abstract class Json { - protected static string $key = '$response'; + protected static $key = '$response'; /** * Renders the error response with the provided message + * + * @param string $message + * @param int $code + * @return array */ - public static function error(string $message, int $code = 404): array + public static function error(string $message, int $code = 404) { return [ 'code' => $code, @@ -37,48 +36,42 @@ abstract class Json /** * Prepares the JSON response for the Panel + * + * @param mixed $data + * @param array $options + * @return mixed */ - public static function response($data, array $options = []): Response + public static function response($data, array $options = []) { - $data = static::responseData($data); + // handle redirects + if (is_a($data, 'Kirby\Panel\Redirect') === true) { + $data = [ + 'redirect' => $data->location(), + 'code' => $data->code() + ]; + + // handle Kirby exceptions + } elseif (is_a($data, 'Kirby\Exception\Exception') === true) { + $data = static::error($data->getMessage(), $data->getHttpCode()); + + // handle exceptions + } elseif (is_a($data, 'Throwable') === true) { + $data = static::error($data->getMessage(), 500); + + // only expect arrays from here on + } elseif (is_array($data) === false) { + $data = static::error('Invalid response', 500); + } + + if (empty($data) === true) { + $data = static::error('The response is empty', 404); + } // always inject the response code $data['code'] ??= 200; $data['path'] = $options['path'] ?? null; - $data['query'] = App::instance()->request()->query()->toArray(); $data['referrer'] = Panel::referrer(); return Panel::json([static::$key => $data], $data['code']); } - - public static function responseData(mixed $data): array - { - // handle redirects - if ($data instanceof Redirect) { - return [ - 'redirect' => $data->location(), - ]; - } - - // handle Kirby exceptions - if ($data instanceof Exception) { - return static::error($data->getMessage(), $data->getHttpCode()); - } - - // handle exceptions - if ($data instanceof Throwable) { - return static::error($data->getMessage(), 500); - } - - // only expect arrays from here on - if (is_array($data) === false) { - return static::error('Invalid response', 500); - } - - if (empty($data) === true) { - return static::error('The response is empty', 404); - } - - return $data; - } } diff --git a/kirby/src/Panel/Lab/Category.php b/kirby/src/Panel/Lab/Category.php deleted file mode 100644 index 4926737..0000000 --- a/kirby/src/Panel/Lab/Category.php +++ /dev/null @@ -1,134 +0,0 @@ - - * @link https://getkirby.com - * @copyright Bastian Allgeier - * @license https://getkirby.com/license - */ -class Category -{ - protected string $root; - - public function __construct( - protected string $id, - string|null $root = null, - protected array $props = [] - ) { - $this->root = $root ?? static::base() . '/' . $this->id; - - if (file_exists($this->root . '/index.php') === true) { - $this->props = array_merge( - require $this->root . '/index.php', - $this->props - ); - } - } - - public static function all(): array - { - // all core lab examples from `kirby/panel/lab` - $examples = A::map( - Dir::inventory(static::base())['children'], - fn ($props) => (new static($props['dirname']))->toArray() - ); - - // all custom lab examples from `site/lab` - $custom = static::factory('site')->toArray(); - - array_push($examples, $custom); - - return $examples; - } - - public static function base(): string - { - return App::instance()->root('panel') . '/lab'; - } - - public function example(string $id, string|null $tab = null): Example - { - return new Example(parent: $this, id: $id, tab: $tab); - } - - public function examples(): array - { - return A::map( - Dir::inventory($this->root)['children'], - fn ($props) => $this->example($props['dirname'])->toArray() - ); - } - - public static function factory(string $id) - { - return match ($id) { - 'site' => static::site(), - default => new static($id) - }; - } - - public function icon(): string - { - return $this->props['icon'] ?? 'palette'; - } - - public function id(): string - { - return $this->id; - } - - public static function installed(): bool - { - return Dir::exists(static::base()) === true; - } - - public function name(): string - { - return $this->props['name'] ?? ucfirst($this->id); - } - - public function root(): string - { - return $this->root; - } - - public static function site(): static - { - return new static( - 'site', - App::instance()->root('site') . '/lab', - [ - 'name' => 'Your examples', - 'icon' => 'live' - ] - ); - } - - public function toArray(): array - { - return [ - 'name' => $this->name(), - 'examples' => $this->examples(), - 'icon' => $this->icon(), - 'path' => Str::after( - $this->root(), - App::instance()->root('index') - ), - ]; - } -} diff --git a/kirby/src/Panel/Lab/Docs.php b/kirby/src/Panel/Lab/Docs.php deleted file mode 100644 index 44a6af0..0000000 --- a/kirby/src/Panel/Lab/Docs.php +++ /dev/null @@ -1,340 +0,0 @@ - - * @link https://getkirby.com - * @copyright Bastian Allgeier - * @license https://getkirby.com/license - */ -class Docs -{ - protected array $json; - protected App $kirby; - - public function __construct( - protected string $name - ) { - $this->kirby = App::instance(); - $this->json = $this->read(); - } - - public static function all(): array - { - $dist = static::root(); - $tmp = static::root(true); - $files = Dir::inventory($dist)['files']; - - if (Dir::exists($tmp) === true) { - $files = [...Dir::inventory($tmp)['files'], ...$files]; - } - - $docs = A::map( - $files, - function ($file) { - $component = 'k-' . Str::camelToKebab(F::name($file['filename'])); - - return [ - 'image' => [ - 'icon' => 'book', - 'back' => 'white', - ], - 'text' => $component, - 'link' => '/lab/docs/' . $component, - ]; - } - ); - - usort($docs, fn ($a, $b) => $a['text'] <=> $b['text']); - - return array_values($docs); - } - - public function deprecated(): string|null - { - return $this->kt($this->json['tags']['deprecated'][0]['description'] ?? ''); - } - - public function description(): string - { - return $this->kt($this->json['description'] ?? ''); - } - - public function docBlock(): string - { - return $this->kt($this->json['docsBlocks'][0] ?? ''); - } - - public function events(): array - { - $events = A::map( - $this->json['events'] ?? [], - fn ($event) => [ - 'name' => $event['name'], - 'description' => $this->kt($event['description'] ?? ''), - 'deprecated' => $this->kt($event['tags']['deprecated'][0]['description'] ?? ''), - 'since' => $event['tags']['since'][0]['description'] ?? null, - 'properties' => A::map( - $event['properties'] ?? [], - fn ($property) => [ - 'name' => $property['name'], - 'type' => $property['type']['names'][0] ?? '', - 'description' => $this->kt($property['description'] ?? '', true), - ] - ), - ] - ); - - usort($events, fn ($a, $b) => $a['name'] <=> $b['name']); - - return $events; - } - - public function examples(): array - { - if (empty($this->json['tags']['examples']) === false) { - return $this->json['tags']['examples']; - } - - return []; - } - - public function file(string $context): string - { - $root = match ($context) { - 'dev' => $this->kirby->root('panel') . '/tmp', - 'dist' => $this->kirby->root('panel') . '/dist/ui', - }; - - $name = Str::after($this->name, 'k-'); - $name = Str::kebabToCamel($name); - return $root . '/' . $name . '.json'; - } - - public function github(): string - { - return 'https://github.com/getkirby/kirby/tree/main/panel/' . $this->json['sourceFile']; - } - - public static function installed(): bool - { - return Dir::exists(static::root()) === true; - } - - protected function kt(string $text, bool $inline = false): string - { - return $this->kirby->kirbytext($text, [ - 'markdown' => [ - 'breaks' => false, - 'inline' => $inline, - ] - ]); - } - - public function lab(): string|null - { - $root = $this->kirby->root('panel') . '/lab'; - - foreach (glob($root . '/{,*/,*/*/,*/*/*/}index.php', GLOB_BRACE) as $example) { - $props = require $example; - - if (($props['docs'] ?? null) === $this->name) { - return Str::before(Str::after($example, $root), 'index.php'); - } - } - - return null; - } - - public function methods(): array - { - $methods = A::map( - $this->json['methods'] ?? [], - fn ($method) => [ - 'name' => $method['name'], - 'description' => $this->kt($method['description'] ?? ''), - 'deprecated' => $this->kt($method['tags']['deprecated'][0]['description'] ?? ''), - 'since' => $method['tags']['since'][0]['description'] ?? null, - 'params' => A::map( - $method['params'] ?? [], - fn ($param) => [ - 'name' => $param['name'], - 'type' => $param['type']['name'] ?? '', - 'description' => $this->kt($param['description'] ?? '', true), - ] - ), - 'returns' => $method['returns']['type']['name'] ?? null, - ] - ); - - usort($methods, fn ($a, $b) => $a['name'] <=> $b['name']); - - return $methods; - } - - public function name(): string - { - return $this->name; - } - - public function prop(string|int $key): array|null - { - $prop = $this->json['props'][$key]; - - // filter private props - if (($prop['tags']['access'][0]['description'] ?? null) === 'private') { - return null; - } - - // filter unset props - if (($type = $prop['type']['name'] ?? null) === 'null') { - return null; - } - - $default = $prop['defaultValue']['value'] ?? null; - $deprecated = $this->kt($prop['tags']['deprecated'][0]['description'] ?? ''); - - return [ - 'name' => Str::camelToKebab($prop['name']), - 'type' => $type, - 'description' => $this->kt($prop['description'] ?? ''), - 'default' => $this->propDefault($default, $type), - 'deprecated' => $deprecated, - 'example' => $prop['tags']['example'][0]['description'] ?? null, - 'required' => $prop['required'] ?? false, - 'since' => $prop['tags']['since'][0]['description'] ?? null, - 'value' => $prop['tags']['value'][0]['description'] ?? null, - 'values' => $prop['values'] ?? null, - ]; - } - - protected function propDefault( - string|null $default, - string|null $type - ): string|null { - if ($default !== null) { - // normalize longform function - if (preg_match('/function\(\) {.*return (.*);.*}/si', $default, $matches) === 1) { - return $matches[1]; - } - - // normalize object shorthand function - if (preg_match('/\(\) => \((.*)\)/si', $default, $matches) === 1) { - return $matches[1]; - } - - // normalize all other defaults from shorthand function - if (preg_match('/\(\) => (.*)/si', $default, $matches) === 1) { - return $matches[1]; - } - - return $default; - } - - // if type is boolean primarily and no default - // value has been set, add `false` as default - // for clarity - if (Str::startsWith($type, 'boolean')) { - return 'false'; - } - - return null; - } - - public function props(): array - { - $props = A::map( - array_keys($this->json['props'] ?? []), - fn ($key) => $this->prop($key) - ); - - // remove empty props - $props = array_filter($props); - - usort($props, fn ($a, $b) => $a['name'] <=> $b['name']); - - // always return an array - return array_values($props); - } - - protected function read(): array - { - $file = $this->file('dev'); - - if (file_exists($file) === false) { - $file = $this->file('dist'); - } - - return Data::read($file); - } - - public static function root(bool $tmp = false): string - { - return App::instance()->root('panel') . '/' . match ($tmp) { - true => 'tmp', - default => 'dist/ui', - }; - } - - public function since(): string|null - { - return $this->json['tags']['since'][0]['description'] ?? null; - } - - public function slots(): array - { - $slots = A::map( - $this->json['slots'] ?? [], - fn ($slot) => [ - 'name' => $slot['name'], - 'description' => $this->kt($slot['description'] ?? ''), - 'deprecated' => $this->kt($slot['tags']['deprecated'][0]['description'] ?? ''), - 'since' => $slot['tags']['since'][0]['description'] ?? null, - 'bindings' => A::map( - $slot['bindings'] ?? [], - fn ($binding) => [ - 'name' => $binding['name'], - 'type' => $binding['type']['name'] ?? '', - 'description' => $this->kt($binding['description'] ?? '', true), - ] - ), - ] - ); - - usort($slots, fn ($a, $b) => $a['name'] <=> $b['name']); - - return $slots; - } - - public function toArray(): array - { - return [ - 'component' => $this->name(), - 'deprecated' => $this->deprecated(), - 'description' => $this->description(), - 'docBlock' => $this->docBlock(), - 'events' => $this->events(), - 'examples' => $this->examples(), - 'github' => $this->github(), - 'methods' => $this->methods(), - 'props' => $this->props(), - 'since' => $this->since(), - 'slots' => $this->slots(), - ]; - } -} diff --git a/kirby/src/Panel/Lab/Example.php b/kirby/src/Panel/Lab/Example.php deleted file mode 100644 index 153bb12..0000000 --- a/kirby/src/Panel/Lab/Example.php +++ /dev/null @@ -1,296 +0,0 @@ - - * @link https://getkirby.com - * @copyright Bastian Allgeier - * @license https://getkirby.com/license - */ -class Example -{ - protected string $root; - protected string|null $tab = null; - protected array $tabs; - - public function __construct( - protected Category $parent, - protected string $id, - string|null $tab = null, - ) { - $this->root = $this->parent->root() . '/' . $this->id; - - if ($this->exists() === false) { - throw new NotFoundException('The example could not be found'); - } - - $this->tabs = $this->collectTabs(); - $this->tab = $this->collectTab($tab); - } - - public function collectTab(string|null $tab): string|null - { - if (empty($this->tabs) === true) { - return null; - } - - if (array_key_exists($tab, $this->tabs) === true) { - return $tab; - } - - return array_key_first($this->tabs); - } - - public function collectTabs(): array - { - $tabs = []; - - foreach (Dir::inventory($this->root)['children'] as $child) { - $tabs[$child['dirname']] = [ - 'name' => $child['dirname'], - 'label' => $child['slug'], - 'link' => '/lab/' . $this->parent->id() . '/' . $this->id . '/' . $child['dirname'] - ]; - } - - return $tabs; - } - - public function exists(): bool - { - return is_dir($this->root) === true; - } - - public function file(string $filename): string - { - return $this->parent->root() . '/' . $this->path() . '/' . $filename; - } - - public function id(): string - { - return $this->id; - } - - public function load(string $filename): array|null - { - if ($file = $this->file($filename)) { - return F::load($file); - } - - return null; - } - - public function module(): string - { - return $this->url() . '/index.vue'; - } - - public function path(): string - { - return match ($this->tab) { - null => $this->id, - default => $this->id . '/' . $this->tab - }; - } - - public function props(): array - { - if ($this->tab !== null) { - $props = $this->load('../index.php'); - } - - return array_replace_recursive( - $props ?? [], - $this->load('index.php') ?? [] - ); - } - - public function read(string $filename): string|null - { - $file = $this->file($filename); - - if (is_file($file) === false) { - return null; - } - - return F::read($file); - } - - public function root(): string - { - return $this->root; - } - - public function serve(): Response - { - return new Response($this->vue()['script'], 'application/javascript'); - } - - public function tab(): string|null - { - return $this->tab; - } - - public function tabs(): array - { - return $this->tabs; - } - - public function template(string $filename): string|null - { - $file = $this->file($filename); - - if (is_file($file) === false) { - return null; - } - - $data = $this->props(); - return (new Template($file))->render($data); - } - - public function title(): string - { - return basename($this->id); - } - - public function toArray(): array - { - return [ - 'image' => [ - 'icon' => $this->parent->icon(), - 'back' => 'white', - ], - 'text' => $this->title(), - 'link' => $this->url() - ]; - } - - public function url(): string - { - return '/lab/' . $this->parent->id() . '/' . $this->path(); - } - - public function vue(): array - { - // read the index.vue file (or programmabel Vue PHP file) - $file = $this->read('index.vue'); - $file ??= $this->template('index.vue.php'); - $file ??= ''; - - // extract parts - $parts['script'] = $this->vueScript($file); - $parts['template'] = $this->vueTemplate($file); - $parts['examples'] = $this->vueExamples($parts['template'], $parts['script']); - $parts['style'] = $this->vueStyle($file); - - return $parts; - } - - public function vueExamples(string|null $template, string|null $script): array - { - $template ??= ''; - $examples = []; - $scripts = []; - - if (preg_match_all('!\/\*\* \@script: (.*?)\*\/(.*?)\/\*\* \@script-end \*\/!s', $script, $matches)) { - foreach ($matches[1] as $key => $name) { - $code = $matches[2][$key]; - $code = preg_replace('!const (.*?) \=!', 'default', $code); - - $scripts[trim($name)] = $code; - } - } - - if (preg_match_all('!(.*?)<\/k-lab-example>!s', $template, $matches)) { - foreach ($matches[1] as $key => $name) { - $tail = $matches[2][$key]; - $code = $matches[3][$key]; - - $scriptId = trim(preg_replace_callback( - '!script="(.*?)"!', - fn ($match) => trim($match[1]), - $tail - )); - - $scriptBlock = $scripts[$scriptId] ?? null; - - if (empty($scriptBlock) === false) { - $js = PHP_EOL . PHP_EOL; - $js .= ''; - } else { - $js = ''; - } - - // only use the code between the @code and @code-end comments - if (preg_match('$(.*?)$s', $code, $match)) { - $code = $match[1]; - } - - if (preg_match_all('/^(\t*)\S/m', $code, $indents)) { - // get minimum indent - $indents = array_map(fn ($i) => strlen($i), $indents[1]); - $indents = min($indents); - - if (empty($js) === false) { - $indents--; - } - - // strip minimum indent from each line - $code = preg_replace('/^\t{' . $indents . '}/m', '', $code); - } - - $code = trim($code); - - if (empty($js) === false) { - $code = ''; - } - - $examples[$name] = $code . $js; - } - } - - return $examples; - } - - public function vueScript(string $file): string - { - if (preg_match('!!s', $file, $match)) { - return trim($match[1]); - } - - return 'export default {}'; - } - - public function vueStyle(string $file): string|null - { - if (preg_match('!!s', $file, $match)) { - return trim($match[1]); - } - - return null; - } - - public function vueTemplate(string $file): string|null - { - if (preg_match('!!s', $file, $match)) { - return preg_replace('!^\n!', '', $match[1]); - } - - return null; - } -} diff --git a/kirby/src/Panel/Lab/Snippet.php b/kirby/src/Panel/Lab/Snippet.php deleted file mode 100644 index 0739eb7..0000000 --- a/kirby/src/Panel/Lab/Snippet.php +++ /dev/null @@ -1,26 +0,0 @@ - - * @link https://getkirby.com - * @copyright Bastian Allgeier - * @license https://getkirby.com/license - */ -class Snippet extends BaseSnippet -{ - public static function root(): string - { - return __DIR__ . '/snippets'; - } -} diff --git a/kirby/src/Panel/Lab/Template.php b/kirby/src/Panel/Lab/Template.php deleted file mode 100644 index 71cf484..0000000 --- a/kirby/src/Panel/Lab/Template.php +++ /dev/null @@ -1,34 +0,0 @@ - - * @link https://getkirby.com - * @copyright Bastian Allgeier - * @license https://getkirby.com/license - */ -class Template extends BaseTemplate -{ - public function __construct( - public string $file - ) { - parent::__construct( - name: basename($this->file) - ); - } - - public function file(): string|null - { - return $this->file; - } -} diff --git a/kirby/src/Panel/Menu.php b/kirby/src/Panel/Menu.php deleted file mode 100644 index c1c4498..0000000 --- a/kirby/src/Panel/Menu.php +++ /dev/null @@ -1,221 +0,0 @@ - - * @link https://getkirby.com - * @copyright Bastian Allgeier - * @license https://getkirby.com/license - */ -class Menu -{ - public function __construct( - protected array $areas = [], - protected array $permissions = [], - protected string|null $current = null - ) { - } - - /** - * Returns all areas that are configured for the menu - * @internal - */ - public function areas(): array - { - // get from config option which areas should be listed in the menu - $kirby = App::instance(); - $areas = $kirby->option('panel.menu'); - - if ($areas instanceof Closure) { - $areas = $areas($kirby); - } - - // if no config is defined… - if ($areas === null) { - // ensure that some defaults are on top in the right order - $defaults = ['site', 'languages', 'users', 'system']; - // add all other areas after that - $additionals = array_diff(array_keys($this->areas), $defaults); - $areas = array_merge($defaults, $additionals); - } - - $result = []; - - foreach ($areas as $id => $area) { - // separator, keep as is in array - if ($area === '-') { - $result[] = '-'; - continue; - } - - // for a simple id, get global area definition - if (is_numeric($id) === true) { - $id = $area; - $area = $this->areas[$id] ?? null; - } - - // did not receive custom entry definition in config, - // but also is not a global area - if ($area === null) { - continue; - } - - // merge area definition (e.g. from config) - // with global area definition - if (is_array($area) === true) { - $area = array_merge( - $this->areas[$id] ?? [], - ['menu' => true], - $area - ); - $area = Panel::area($id, $area); - } - - $result[] = $area; - } - - return $result; - } - - /** - * Transforms an area definition into a menu entry - * @internal - */ - public function entry(array $area): array|false - { - // areas without access permissions get skipped entirely - if ($this->hasPermission($area['id']) === false) { - return false; - } - - // check menu setting from the area definition - $menu = $area['menu'] ?? false; - - // menu setting can be a callback - // that returns true, false or 'disabled' - if ($menu instanceof Closure) { - $menu = $menu($this->areas, $this->permissions, $this->current); - } - - // false will remove the area/entry entirely - //just like with disabled permissions - if ($menu === false) { - return false; - } - - $menu = match ($menu) { - 'disabled' => ['disabled' => true], - true => [], - default => $menu - }; - - $entry = array_merge([ - 'current' => $this->isCurrent( - $area['id'], - $area['current'] ?? null - ), - 'icon' => $area['icon'] ?? null, - 'link' => $area['link'] ?? null, - 'dialog' => $area['dialog'] ?? null, - 'drawer' => $area['drawer'] ?? null, - 'text' => I18n::translate($area['label'], $area['label']) - ], $menu); - - // unset the link (which is always added by default to an area) - // if a dialog or drawer should be opened instead - if (isset($entry['dialog']) || isset($entry['drawer'])) { - unset($entry['link']); - } - - return array_filter($entry); - } - - /** - * Returns all menu entries - */ - public function entries(): array - { - $entries = []; - $areas = $this->areas(); - - foreach ($areas as $area) { - if ($area === '-') { - $entries[] = '-'; - } elseif ($entry = $this->entry($area)) { - $entries[] = $entry; - } - } - - $entries[] = '-'; - - return array_merge($entries, $this->options()); - } - - /** - * Checks if the access permission to a specific area is granted. - * Defaults to allow access. - * @internal - */ - public function hasPermission(string $id): bool - { - return $this->permissions['access'][$id] ?? true; - } - - /** - * Whether the menu entry should receive aria-current - * @internal - */ - public function isCurrent( - string $id, - bool|Closure|null $callback = null - ): bool { - if ($callback !== null) { - if ($callback instanceof Closure) { - $callback = $callback($this->current); - } - - return $callback; - } - - return $this->current === $id; - } - - /** - * Default options entries for bottom of menu - * @internal - */ - public function options(): array - { - $options = [ - [ - 'icon' => 'edit-line', - 'dialog' => 'changes', - 'text' => I18n::translate('changes'), - ], - [ - 'current' => $this->isCurrent('account'), - 'icon' => 'account', - 'link' => 'account', - 'disabled' => $this->hasPermission('account') === false, - 'text' => I18n::translate('view.account'), - ], - [ - 'icon' => 'logout', - 'link' => 'logout', - 'text' => I18n::translate('logout') - ] - ]; - - return $options; - } -} diff --git a/kirby/src/Panel/Model.php b/kirby/src/Panel/Model.php index d0a8d88..6fc7675 100644 --- a/kirby/src/Panel/Model.php +++ b/kirby/src/Panel/Model.php @@ -2,10 +2,6 @@ namespace Kirby\Panel; -use Closure; -use Kirby\Cms\File as CmsFile; -use Kirby\Cms\ModelWithContent; -use Kirby\Filesystem\Asset; use Kirby\Form\Form; use Kirby\Http\Uri; use Kirby\Toolkit\A; @@ -22,13 +18,23 @@ use Kirby\Toolkit\A; */ abstract class Model { - public function __construct( - protected ModelWithContent $model - ) { + /** + * @var \Kirby\Cms\ModelWithContent + */ + protected $model; + + /** + * @param \Kirby\Cms\ModelWithContent $model + */ + public function __construct($model) + { + $this->model = $model; } /** * Get the content values for the model + * + * @return array */ public function content(): array { @@ -41,14 +47,20 @@ abstract class Model * @internal * * @param string $type markdown or kirbytext + * @param mixed ...$args + * @return string|null */ - public function dragTextFromCallback(string $type, ...$args): string|null + public function dragTextFromCallback(string $type, ...$args): ?string { $option = 'panel.' . $type . '.' . $this->model::CLASS_ALIAS . 'DragText'; $callback = $this->model->kirby()->option($option); - if ($callback instanceof Closure) { - return $callback($this->model, ...$args); + if ( + empty($callback) === false && + is_a($callback, 'Closure') === true && + ($dragText = $callback($this->model, ...$args)) !== null + ) { + return $dragText; } return null; @@ -62,8 +74,9 @@ abstract class Model * @internal * * @param string|null $type (`auto`|`kirbytext`|`markdown`) + * @return string */ - public function dragTextType(string|null $type = null): string + public function dragTextType(string $type = null): string { $type ??= 'auto'; @@ -79,72 +92,98 @@ abstract class Model * Returns the setup for a dropdown option * which is used in the changes dropdown * for example. + * + * @return array */ public function dropdownOption(): array { return [ - 'icon' => 'page', - 'image' => $this->image(['back' => 'black']), - 'link' => $this->url(true), - 'text' => $this->model->id(), + 'icon' => 'page', + 'link' => $this->url(), + 'text' => $this->model->id(), ]; } /** * Returns the Panel image definition + * * @internal + * + * @param string|array|false|null $settings + * @return array|null */ - public function image( - string|array|false|null $settings = [], - string $layout = 'list' - ): array|null { + public function image($settings = [], string $layout = 'list'): ?array + { // completely switched off if ($settings === false) { return null; } - // switched off from blueprint, - // only if not overwritten by $settings - $blueprint = $this->model->blueprint()->image(); - - if ($blueprint === false) { - if (empty($settings) === true) { - return null; - } - - $blueprint = null; - } - // skip image thumbnail if option // is explicitly set to show the icon if ($settings === 'icon') { - $settings = ['query' => false]; + $settings = [ + 'query' => false + ]; } elseif (is_string($settings) === true) { // convert string settings to proper array - $settings = ['query' => $settings]; + $settings = [ + 'query' => $settings + ]; } // merge with defaults and blueprint option $settings = array_merge( $this->imageDefaults(), $settings ?? [], - $blueprint ?? [], + $this->model->blueprint()->image() ?? [], ); if ($image = $this->imageSource($settings['query'] ?? null)) { // main url $settings['url'] = $image->url(); + // only create srcsets for resizable files if ($image->isResizable() === true) { - // only create srcsets for resizable files - $settings['src'] = static::imagePlaceholder(); - $settings['srcset'] = $this->imageSrcset($image, $layout, $settings); + $settings['src'] = static::imagePlaceholder(); + + switch ($layout) { + case 'cards': + $sizes = [352, 864, 1408]; + break; + case 'cardlets': + $sizes = [96, 192]; + break; + case 'list': + default: + $sizes = [38, 76]; + break; + } + + if (($settings['cover'] ?? false) === false || $layout === 'cards') { + $settings['srcset'] = $image->srcset($sizes); + } else { + $settings['srcset'] = $image->srcset([ + '1x' => [ + 'width' => $sizes[0], + 'height' => $sizes[0], + 'crop' => 'center' + ], + '2x' => [ + 'width' => $sizes[1], + 'height' => $sizes[1], + 'crop' => 'center' + ] + ]); + } } elseif ($image->isViewable() === true) { $settings['src'] = $image->url(); } } - unset($settings['query']); + if (isset($settings['query']) === true) { + unset($settings['query']); + } // resolve remaining options defined as query return A::map($settings, function ($option) { @@ -158,6 +197,8 @@ abstract class Model /** * Default settings for Panel image + * + * @return array */ protected function imageDefaults(): array { @@ -165,13 +206,17 @@ abstract class Model 'back' => 'pattern', 'color' => 'gray-500', 'cover' => false, - 'icon' => 'page' + 'icon' => 'page', + 'ratio' => '3/2', ]; } /** * Data URI placeholder string for Panel image + * * @internal + * + * @return string */ public static function imagePlaceholder(): string { @@ -180,17 +225,20 @@ abstract class Model /** * Returns the image file object based on provided query + * * @internal + * + * @param string|null $query + * @return \Kirby\Cms\File|\Kirby\Filesystem\Asset|null */ - protected function imageSource( - string|null $query = null - ): CmsFile|Asset|null { + protected function imageSource(?string $query = null) + { $image = $this->model->query($query ?? null); // validate the query result if ( - $image instanceof CmsFile || - $image instanceof Asset + is_a($image, 'Kirby\Cms\File') === true || + is_a($image, 'Kirby\Filesystem\Asset') === true ) { return $image; } @@ -198,85 +246,19 @@ abstract class Model return null; } - /** - * Provides the correct srcset string based on - * the layout and settings - * @internal - */ - protected function imageSrcset( - CmsFile|Asset $image, - string $layout, - array $settings - ): string|null { - // depending on layout type, set different sizes - // to have multiple options for the srcset attribute - $sizes = match ($layout) { - 'cards' => [352, 864, 1408], - 'cardlets' => [96, 192], - default => [38, 76] - }; - - // no additional modfications needed if `cover: false` - if (($settings['cover'] ?? false) === false) { - return $image->srcset($sizes); - } - - // for card layouts with `cover: true` provide - // crops based on the card ratio - if ($layout === 'cards') { - $ratio = explode('/', $settings['ratio'] ?? '1/1'); - $ratio = $ratio[0] / $ratio[1]; - - return $image->srcset([ - $sizes[0] . 'w' => [ - 'width' => $sizes[0], - 'height' => round($sizes[0] / $ratio), - 'crop' => true - ], - $sizes[1] . 'w' => [ - 'width' => $sizes[1], - 'height' => round($sizes[1] / $ratio), - 'crop' => true - ], - $sizes[2] . 'w' => [ - 'width' => $sizes[2], - 'height' => round($sizes[2] / $ratio), - 'crop' => true - ] - ]); - } - - // for list and cardlets with `cover: true` - // provide square crops in two resolutions - return $image->srcset([ - '1x' => [ - 'width' => $sizes[0], - 'height' => $sizes[0], - 'crop' => true - ], - '2x' => [ - 'width' => $sizes[1], - 'height' => $sizes[1], - 'crop' => true - ] - ]); - } - /** * Checks for disabled dropdown options according * to the given permissions + * + * @param string $action + * @param array $options + * @param array $permissions + * @return bool */ - public function isDisabledDropdownOption( - string $action, - array $options, - array $permissions - ): bool { + public function isDisabledDropdownOption(string $action, array $options, array $permissions): bool + { $option = $options[$action] ?? true; - - return - $permissions[$action] === false || - $option === false || - $option === 'false'; + return $permissions[$action] === false || $option === false || $option === 'false'; } /** @@ -285,9 +267,24 @@ abstract class Model * @return array|false array with lock info, * false if locking is not supported */ - public function lock(): array|false + public function lock() { - return $this->model->lock()?->toArray() ?? false; + if ($lock = $this->model->lock()) { + if ($lock->isUnlocked() === true) { + return ['state' => 'unlock']; + } + + if ($lock->isLocked() === true) { + return [ + 'state' => 'lock', + 'data' => $lock->get() + ]; + } + + return ['state' => null]; + } + + return false; } /** @@ -296,6 +293,7 @@ abstract class Model * This also checks for the lock status * * @param array $unlock An array of options that will be force-unlocked + * @return array */ public function options(array $unlock = []): array { @@ -316,12 +314,17 @@ abstract class Model /** * Returns the full path without leading slash + * + * @return string */ abstract public function path(): string; /** * Prepares the response data for page pickers * and page fields + * + * @param array|null $params + * @return array */ public function pickerData(array $params = []): array { @@ -335,14 +338,16 @@ abstract class Model 'link' => $this->url(true), 'sortable' => true, 'text' => $this->model->toSafeString($params['text'] ?? false), - 'uuid' => $this->model->uuid()?->toString() ?? $this->model->id(), ]; } /** * Returns the data array for the * view's component props + * * @internal + * + * @return array */ public function props(): array { @@ -368,34 +373,41 @@ abstract class Model } /** - * Returns link url and title - * for model (e.g. used for prev/next navigation) + * Returns link url and tooltip + * for model (e.g. used for prev/next + * navigation) + * * @internal + * + * @param string $tooltip + * @return array */ - public function toLink(string $title = 'title'): array + public function toLink(string $tooltip = 'title'): array { return [ 'link' => $this->url(true), - 'title' => $title = (string)$this->model->{$title}() + 'tooltip' => (string)$this->model->{$tooltip}() ]; } /** - * Returns link url and title + * Returns link url and tooltip * for optional sibling model and * preserves tab selection * * @internal + * + * @param \Kirby\Cms\ModelWithContent|null $model + * @param string $tooltip + * @return array */ - protected function toPrevNextLink( - ModelWithContent|null $model = null, - string $title = 'title' - ): array|null { + protected function toPrevNextLink($model = null, string $tooltip = 'title'): ?array + { if ($model === null) { return null; } - $data = $model->panel()->toLink($title); + $data = $model->panel()->toLink($tooltip); if ($tab = $model->kirby()->request()->get('tab')) { $uri = new Uri($data['link'], [ @@ -413,6 +425,9 @@ abstract class Model * in the Panel * * @internal + * + * @param bool $relative + * @return string */ public function url(bool $relative = false): string { @@ -428,6 +443,8 @@ abstract class Model * this model's Panel view * * @internal + * + * @return array */ abstract public function view(): array; } diff --git a/kirby/src/Panel/Page.php b/kirby/src/Panel/Page.php index 72c564c..9d73016 100644 --- a/kirby/src/Panel/Page.php +++ b/kirby/src/Panel/Page.php @@ -2,9 +2,6 @@ namespace Kirby\Panel; -use Kirby\Cms\File as CmsFile; -use Kirby\Cms\ModelWithContent; -use Kirby\Filesystem\Asset; use Kirby\Toolkit\I18n; /** @@ -22,21 +19,20 @@ class Page extends Model /** * @var \Kirby\Cms\Page */ - protected ModelWithContent $model; + protected $model; /** * Breadcrumb array + * + * @return array */ public function breadcrumb(): array { $parents = $this->model->parents()->flip()->merge($this->model); - - return $parents->values( - fn ($parent) => [ - 'label' => $parent->title()->toString(), - 'link' => $parent->panel()->url(true), - ] - ); + return $parents->values(fn ($parent) => [ + 'label' => $parent->title()->toString(), + 'link' => $parent->panel()->url(true), + ]); } /** @@ -47,8 +43,9 @@ class Page extends Model * * @internal * @param string|null $type (`auto`|`kirbytext`|`markdown`) + * @return string */ - public function dragText(string|null $type = null): string + public function dragText(string $type = null): string { $type = $this->dragTextType($type); @@ -56,27 +53,24 @@ class Page extends Model return $callback; } - $title = $this->model->title(); - - // type: markdown if ($type === 'markdown') { - $url = $this->model->permalink() ?? $this->model->url(); - return '[' . $title . '](' . $url . ')'; + return '[' . $this->model->title() . '](' . $this->model->url() . ')'; } - // type: kirbytext - $link = $this->model->uuid() ?? $this->model->uri(); - return '(link: ' . $link . ' text: ' . $title . ')'; + return '(link: ' . $this->model->id() . ' text: ' . $this->model->title() . ')'; } /** * Provides options for the page dropdown + * + * @param array $options + * @return array */ public function dropdown(array $options = []): array { - $page = $this->model; - $request = $page->kirby()->request(); - $defaults = $request->get(['view', 'sort', 'delete']); + $page = $this->model; + + $defaults = $page->kirby()->request()->get(['view', 'sort', 'delete']); $options = array_merge($defaults, $options); $permissions = $this->options(['preview']); @@ -107,6 +101,15 @@ class Page extends Model 'disabled' => $this->isDisabledDropdownOption('changeTitle', $options, $permissions) ]; + $result['duplicate'] = [ + 'dialog' => $url . '/duplicate', + 'icon' => 'copy', + 'text' => I18n::translate('duplicate'), + 'disabled' => $this->isDisabledDropdownOption('duplicate', $options, $permissions) + ]; + + $result[] = '-'; + $result['changeSlug'] = [ 'dialog' => [ 'url' => $url . '/changeTitle', @@ -143,23 +146,6 @@ class Page extends Model ]; $result[] = '-'; - - $result['move'] = [ - 'dialog' => $url . '/move', - 'icon' => 'parent', - 'text' => I18n::translate('page.move'), - 'disabled' => $this->isDisabledDropdownOption('move', $options, $permissions) - ]; - - $result['duplicate'] = [ - 'dialog' => $url . '/duplicate', - 'icon' => 'copy', - 'text' => I18n::translate('duplicate'), - 'disabled' => $this->isDisabledDropdownOption('duplicate', $options, $permissions) - ]; - - $result[] = '-'; - $result['delete'] = [ 'dialog' => $url . '/delete', 'icon' => 'trash', @@ -174,6 +160,8 @@ class Page extends Model * Returns the setup for a dropdown option * which is used in the changes dropdown * for example. + * + * @return array */ public function dropdownOption(): array { @@ -185,6 +173,8 @@ class Page extends Model /** * Returns the escaped Id, which is * used in the panel to make routing work properly + * + * @return string */ public function id(): string { @@ -193,6 +183,8 @@ class Page extends Model /** * Default settings for the page's Panel image + * + * @return array */ protected function imageDefaults(): array { @@ -209,11 +201,15 @@ class Page extends Model * Returns the image file object based on provided query * * @internal + * @param string|null $query + * @return \Kirby\Cms\File|\Kirby\Filesystem\Asset|null */ - protected function imageSource( - string|null $query = null - ): CmsFile|Asset|null { - $query ??= 'page.image'; + protected function imageSource(string $query = null) + { + if ($query === null) { + $query = 'page.image'; + } + return parent::imageSource($query); } @@ -221,6 +217,7 @@ class Page extends Model * Returns the full path without leading slash * * @internal + * @return string */ public function path(): string { @@ -230,6 +227,9 @@ class Page extends Model /** * Prepares the response data for page pickers * and page fields + * + * @param array|null $params + * @return array */ public function pickerData(array $params = []): array { @@ -245,12 +245,12 @@ class Page extends Model /** * The best applicable position for * the position/status dialog + * + * @return int */ public function position(): int { - return - $this->model->num() ?? - $this->model->parentModel()->children()->listed()->not($this->model)->count() + 1; + return $this->model->num() ?? $this->model->parentModel()->children()->listed()->not($this->model)->count() + 1; } /** @@ -259,6 +259,8 @@ class Page extends Model * based on blueprint definition * * @internal + * + * @return array */ public function prevNext(): array { @@ -307,7 +309,7 @@ class Page extends Model ->filter('status', $page->status()); } - return $siblings->filter('isListable', true); + return $siblings->filter('isReadable', true); }; return [ @@ -321,6 +323,8 @@ class Page extends Model * view's component props * * @internal + * + * @return array */ public function props(): array { @@ -330,7 +334,7 @@ class Page extends Model parent::props(), $this->prevNext(), [ - 'blueprint' => $page->intendedTemplate()->name(), + 'blueprint' => $this->model->intendedTemplate()->name(), 'model' => [ 'content' => $this->content(), 'id' => $page->id(), @@ -354,6 +358,8 @@ class Page extends Model * this model's Panel view * * @internal + * + * @return array */ public function view(): array { diff --git a/kirby/src/Panel/PageCreateDialog.php b/kirby/src/Panel/PageCreateDialog.php deleted file mode 100644 index 2ab9c58..0000000 --- a/kirby/src/Panel/PageCreateDialog.php +++ /dev/null @@ -1,389 +0,0 @@ - - * @link https://getkirby.com - * @copyright Bastian Allgeier - * @license https://getkirby.com/license - */ -class PageCreateDialog -{ - protected PageBlueprint $blueprint; - protected Page $model; - protected Page|Site $parent; - protected string $parentId; - protected string|null $sectionId; - protected string|null $slug; - protected string|null $template; - protected string|null $title; - protected Page|Site|User|File $view; - protected string|null $viewId; - - public static array $fieldTypes = [ - 'checkboxes', - 'date', - 'email', - 'info', - 'line', - 'link', - 'list', - 'number', - 'multiselect', - 'radio', - 'range', - 'select', - 'slug', - 'tags', - 'tel', - 'text', - 'toggles', - 'time', - 'url' - ]; - - public function __construct( - string|null $parentId, - string|null $sectionId, - string|null $template, - string|null $viewId, - - // optional - string|null $slug = null, - string|null $title = null, - ) { - $this->parentId = $parentId ?? 'site'; - $this->parent = Find::parent($this->parentId); - $this->sectionId = $sectionId; - $this->slug = $slug; - $this->template = $template; - $this->title = $title; - $this->viewId = $viewId; - $this->view = Find::parent($this->viewId ?? $this->parentId); - } - - /** - * Get the blueprint settings for the new page - */ - public function blueprint(): PageBlueprint - { - // create a temporary page object - return $this->blueprint ??= $this->model()->blueprint(); - } - - /** - * Get an array of all blueprints for the parent view - */ - public function blueprints(): array - { - return A::map( - $this->view->blueprints($this->sectionId), - function ($blueprint) { - $blueprint['name'] ??= $blueprint['value'] ?? null; - return $blueprint; - } - ); - } - - /** - * All the default fields for the dialog - */ - public function coreFields(): array - { - $fields = []; - - $title = $this->blueprint()->create()['title'] ?? null; - $slug = $this->blueprint()->create()['slug'] ?? null; - - if ($title === false || $slug === false) { - throw new InvalidArgumentException('Page create dialog: title and slug must not be false'); - } - - // title field - if ($title === null || is_array($title) === true) { - $label = $title['label'] ?? 'title'; - $fields['title'] = Field::title([ - ...$title ?? [], - 'label' => I18n::translate($label, $label), - 'required' => true, - 'preselect' => true - ]); - } - - // slug field - if ($slug === null) { - $fields['slug'] = Field::slug([ - 'required' => true, - 'sync' => 'title', - 'path' => $this->parent instanceof Page ? '/' . $this->parent->id() . '/' : '/' - ]); - } - - return [ - ...$fields, - 'parent' => Field::hidden(), - 'section' => Field::hidden(), - 'template' => Field::hidden(), - 'view' => Field::hidden(), - ]; - } - - /** - * Loads custom fields for the page type - */ - public function customFields(): array - { - $custom = []; - $ignore = ['title', 'slug', 'parent', 'template']; - $blueprint = $this->blueprint(); - $fields = $blueprint->fields(); - - foreach ($blueprint->create()['fields'] ?? [] as $name) { - if (!$field = ($fields[$name] ?? null)) { - throw new InvalidArgumentException('Unknown field "' . $name . '" in create dialog'); - } - - if (in_array($field['type'], static::$fieldTypes) === false) { - throw new InvalidArgumentException('Field type "' . $field['type'] . '" not supported in create dialog'); - } - - if (in_array($name, $ignore) === true) { - throw new InvalidArgumentException('Field name "' . $name . '" not allowed as custom field in create dialog'); - } - - // switch all fields to 1/1 - $field['width'] = '1/1'; - - // add the field to the form - $custom[$name] = $field; - } - - // create form so that field props, options etc. - // can be properly resolved - $form = new Form([ - 'fields' => $custom, - 'model' => $this->model(), - 'strict' => true - ]); - - return $form->fields()->toArray(); - } - - /** - * Loads all the fields for the dialog - */ - public function fields(): array - { - return [ - ...$this->coreFields(), - ...$this->customFields() - ]; - } - - /** - * Provides all the props for the - * dialog, including the fields and - * initial values - */ - public function load(): array - { - $blueprints = $this->blueprints(); - - $this->template ??= $blueprints[0]['name']; - - $status = $this->blueprint()->create()['status'] ?? 'draft'; - $status = $this->blueprint()->status()[$status]['label'] ?? null; - $status ??= I18n::translate('page.status.' . $status); - - $fields = $this->fields(); - $visible = array_filter( - $fields, - fn ($field) => ($field['hidden'] ?? null) !== true - ); - - // immediately submit the dialog if there is no editable field - if (count($visible) === 0 && count($blueprints) < 2) { - $input = $this->value(); - $response = $this->submit($input); - $response['redirect'] ??= $this->parent->panel()->url(true); - Panel::go($response['redirect']); - } - - return [ - 'component' => 'k-page-create-dialog', - 'props' => [ - 'blueprints' => $blueprints, - 'fields' => $fields, - 'submitButton' => I18n::template('page.create', [ - 'status' => $status - ]), - 'template' => $this->template, - 'value' => $this->value() - ] - ]; - } - - /** - * Temporary model for the page to - * be created, used to properly render - * the blueprint for fields - */ - public function model(): Page - { - return $this->model ??= Page::factory([ - 'slug' => 'new', - 'template' => $this->template, - 'model' => $this->template, - 'parent' => $this->parent instanceof Page ? $this->parent : null - ]); - } - - /** - * Generates values for title and slug - * from template strings from the blueprint - */ - public function resolveFieldTemplates(array $input): array - { - $title = $this->blueprint()->create()['title'] ?? null; - $slug = $this->blueprint()->create()['slug'] ?? null; - - // create temporary page object - // to resolve the template strings - $page = new Page([ - 'slug' => 'tmp', - 'template' => $this->template, - 'parent' => $this->model(), - 'content' => $input - ]); - - if (is_string($title)) { - $input['title'] = $page->toSafeString($title); - } - - if (is_string($slug)) { - $input['slug'] = $page->toSafeString($slug); - } - - return $input; - } - - /** - * Prepares and cleans up the input data - */ - public function sanitize(array $input): array - { - $input['title'] ??= $this->title ?? ''; - $input['slug'] ??= $this->slug ?? ''; - - $input = $this->resolveFieldTemplates($input); - $content = ['title' => trim($input['title'])]; - - foreach ($this->customFields() as $name => $field) { - $content[$name] = $input[$name] ?? null; - } - - // create temporary form to sanitize the input - // and add default values - $form = Form::for($this->model(), ['values' => $content]); - - return [ - 'content' => $form->strings(true), - 'slug' => $input['slug'], - 'template' => $this->template, - ]; - } - - /** - * Submits the dialog form and creates the new page - */ - public function submit(array $input): array - { - $input = $this->sanitize($input); - $status = $this->blueprint()->create()['status'] ?? 'draft'; - - // validate the input before creating the page - $this->validate($input, $status); - - $page = $this->parent->createChild($input); - - if ($status !== 'draft') { - // grant all permissions as the status is set in the blueprint and - // should not be treated as if the user would try to change it - $page->kirby()->impersonate( - 'kirby', - fn () => $page->changeStatus($status) - ); - } - - $payload = [ - 'event' => 'page.create' - ]; - - // add redirect, if not explicitly disabled - if (($this->blueprint()->create()['redirect'] ?? null) !== false) { - $payload['redirect'] = $page->panel()->url(true); - } - - return $payload; - } - - public function validate(array $input, string $status = 'draft'): bool - { - // basic validation - PageRules::validateTitleLength($input['content']['title']); - PageRules::validateSlugLength($input['slug']); - - // if the page is supposed to be published directly, - // ensure that all field validations are met - if ($status !== 'draft') { - // create temporary form to validate the input - $form = Form::for($this->model(), ['values' => $input['content']]); - - if ($form->isInvalid() === true) { - throw new InvalidArgumentException([ - 'key' => 'page.changeStatus.incomplete' - ]); - } - } - - return true; - } - - public function value(): array - { - $value = [ - 'parent' => $this->parentId, - 'section' => $this->sectionId, - 'slug' => $this->slug ?? '', - 'template' => $this->template, - 'title' => $this->title ?? '', - 'view' => $this->viewId, - ]; - - // add default values for custom fields - foreach ($this->customFields() as $name => $field) { - if ($default = $field['default'] ?? null) { - $value[$name] = $default; - } - } - - return $value; - } -} diff --git a/kirby/src/Panel/Panel.php b/kirby/src/Panel/Panel.php index e6f9ff6..f237478 100644 --- a/kirby/src/Panel/Panel.php +++ b/kirby/src/Panel/Panel.php @@ -2,7 +2,6 @@ namespace Kirby\Panel; -use Closure; use Kirby\Cms\App; use Kirby\Cms\Url as CmsUrl; use Kirby\Cms\User; @@ -11,7 +10,6 @@ use Kirby\Exception\NotFoundException; use Kirby\Exception\PermissionException; use Kirby\Http\Response; use Kirby\Http\Router; -use Kirby\Http\Uri; use Kirby\Http\Url; use Kirby\Toolkit\Str; use Kirby\Toolkit\Tpl; @@ -34,8 +32,12 @@ class Panel { /** * Normalize a panel area + * + * @param string $id + * @param array|string $area + * @return array */ - public static function area(string $id, array $area): array + public static function area(string $id, $area): array { $area['id'] = $id; $area['label'] ??= $id; @@ -51,6 +53,8 @@ class Panel /** * Collect all registered areas + * + * @return array */ public static function areas(): array { @@ -60,15 +64,9 @@ class Panel $areas = $kirby->load()->areas(); // the system is not ready - if ( - $system->isOk() === false || - $system->isInstalled() === false - ) { + if ($system->isOk() === false || $system->isInstalled() === false) { return [ - 'installation' => static::area( - 'installation', - $areas['installation'] - ), + 'installation' => static::area('installation', $areas['installation']), ]; } @@ -76,6 +74,7 @@ class Panel if (!$user) { return [ 'logout' => static::area('logout', $areas['logout']), + // login area last because it defines a fallback route 'login' => static::area('login', $areas['login']), ]; @@ -90,8 +89,24 @@ class Panel unset($areas['languages']); } + $menu = $kirby->option('panel.menu', [ + 'site', + 'languages', + 'users', + 'system', + ]); + $result = []; + // add the sorted areas + foreach ($menu as $id) { + if ($area = ($areas[$id] ?? null)) { + $result[$id] = static::area($id, $area); + unset($areas[$id]); + } + } + + // add the remaining areas foreach ($areas as $id => $area) { $result[$id] = static::area($id, $area); } @@ -101,11 +116,13 @@ class Panel /** * Check for access permissions + * + * @param \Kirby\Cms\User|null $user + * @param string|null $areaId + * @return bool */ - public static function firewall( - User|null $user = null, - string|null $areaId = null - ): bool { + public static function firewall(?User $user = null, ?string $areaId = null): bool + { // a user has to be logged in if ($user === null) { throw new PermissionException(['key' => 'access.panel']); @@ -141,10 +158,13 @@ class Panel /** * Redirect to a Panel url * + * @param string|null $path + * @param int $code * @throws \Kirby\Panel\Redirect + * @return void * @codeCoverageIgnore */ - public static function go(string|null $url = null, int $code = 302): void + public static function go(?string $url = null, int $code = 302): void { throw new Redirect(static::url($url), $code); } @@ -152,15 +172,17 @@ class Panel /** * Check if the given user has access to the panel * or to a given area + * + * @param \Kirby\Cms\User|null $user + * @param string|null $area + * @return bool */ - public static function hasAccess( - User|null $user = null, - string|null $area = null - ): bool { + public static function hasAccess(?User $user = null, string $area = null): bool + { try { static::firewall($user, $area); return true; - } catch (Throwable) { + } catch (Throwable $e) { return false; } } @@ -168,15 +190,15 @@ class Panel /** * Checks for a Fiber request * via get parameters or headers + * + * @return bool */ public static function isFiberRequest(): bool { $request = App::instance()->request(); if ($request->method() === 'GET') { - return - (bool)($request->get('_json') ?? - $request->header('X-Fiber')); + return (bool)($request->get('_json') ?? $request->header('X-Fiber')); } return false; @@ -185,19 +207,25 @@ class Panel /** * Returns a JSON response * for Fiber calls + * + * @param array $data + * @param int $code + * @return \Kirby\Http\Response */ - public static function json(array $data, int $code = 200): Response + public static function json(array $data, int $code = 200) { $request = App::instance()->request(); return Response::json($data, $code, $request->get('_pretty'), [ - 'X-Fiber' => 'true', + 'X-Fiber' => 'true', 'Cache-Control' => 'no-store, private' ]); } /** * Checks for a multilanguage installation + * + * @return bool */ public static function multilang(): bool { @@ -208,6 +236,8 @@ class Panel /** * Returns the referrer path if present + * + * @return string */ public static function referrer(): string { @@ -223,11 +253,15 @@ class Panel /** * Creates a Response object from the result of * a Panel route call + * + * @params mixed $result + * @params array $options + * @return \Kirby\Http\Response */ - public static function response($result, array $options = []): Response + public static function response($result, array $options = []) { // pass responses directly down to the Kirby router - if ($result instanceof Response) { + if (is_a($result, 'Kirby\Http\Response') === true) { return $result; } @@ -241,20 +275,25 @@ class Panel } // handle different response types (view, dialog, ...) - return match ($options['type'] ?? null) { - 'dialog' => Dialog::response($result, $options), - 'drawer' => Drawer::response($result, $options), - 'dropdown' => Dropdown::response($result, $options), - 'request' => Request::response($result, $options), - 'search' => Search::response($result, $options), - default => View::response($result, $options) - }; + switch ($options['type'] ?? null) { + case 'dialog': + return Dialog::response($result, $options); + case 'dropdown': + return Dropdown::response($result, $options); + case 'search': + return Search::response($result, $options); + default: + return View::response($result, $options); + } } /** * Router for the Panel views + * + * @param string $path + * @return \Kirby\Http\Response|false */ - public static function router(string|null $path = null): Response|null + public static function router(string $path = null) { $kirby = App::instance(); @@ -284,11 +323,7 @@ class Panel // call the route action to check the result try { // trigger hook - $route = $kirby->apply( - 'panel.route:before', - compact('route', 'path', 'method'), - 'route' - ); + $route = $kirby->apply('panel.route:before', compact('route', 'path', 'method'), 'route'); // check for access before executing area routes if ($auth !== false) { @@ -307,17 +342,15 @@ class Panel 'type' => $type ]); - return $kirby->apply( - 'panel.route:after', - compact('route', 'path', 'method', 'response'), - 'response' - ); + return $kirby->apply('panel.route:after', compact('route', 'path', 'method', 'response'), 'response'); }); } /** * Extract the routes from the given array * of active areas. + * + * @return array */ public static function routes(array $areas): array { @@ -342,9 +375,7 @@ class Panel static::routesForViews($areaId, $area), static::routesForSearches($areaId, $area), static::routesForDialogs($areaId, $area), - static::routesForDrawers($areaId, $area), static::routesForDropdowns($areaId, $area), - static::routesForRequests($areaId, $area), ); } @@ -365,7 +396,7 @@ class Panel // catch all route $routes[] = [ 'pattern' => '(:all)', - 'action' => fn (string $pattern) => 'Could not find Panel view for route: ' . $pattern + 'action' => fn () => 'The view could not be found' ]; return $routes; @@ -373,39 +404,36 @@ class Panel /** * Extract all routes from an area + * + * @param string $areaId + * @param array $area + * @return array */ public static function routesForDialogs(string $areaId, array $area): array { $dialogs = $area['dialogs'] ?? []; $routes = []; - foreach ($dialogs as $dialogId => $dialog) { - $routes = array_merge($routes, Dialog::routes( - id: $dialogId, - areaId: $areaId, - prefix: 'dialogs', - options: $dialog - )); - } + foreach ($dialogs as $key => $dialog) { + // create the full pattern with dialogs prefix + $pattern = 'dialogs/' . trim(($dialog['pattern'] ?? $key), '/'); - return $routes; - } + // load event + $routes[] = [ + 'pattern' => $pattern, + 'type' => 'dialog', + 'area' => $areaId, + 'action' => $dialog['load'] ?? fn () => 'The load handler for your dialog is missing' + ]; - /** - * Extract all routes from an area - */ - public static function routesForDrawers(string $areaId, array $area): array - { - $drawers = $area['drawers'] ?? []; - $routes = []; - - foreach ($drawers as $drawerId => $drawer) { - $routes = array_merge($routes, Drawer::routes( - id: $drawerId, - areaId: $areaId, - prefix: 'drawers', - options: $drawer - )); + // submit event + $routes[] = [ + 'pattern' => $pattern, + 'type' => 'dialog', + 'area' => $areaId, + 'method' => 'POST', + 'action' => $dialog['submit'] ?? fn () => 'Your dialog does not define a submit handler' + ]; } return $routes; @@ -413,34 +441,37 @@ class Panel /** * Extract all routes for dropdowns + * + * @param string $areaId + * @param array $area + * @return array */ public static function routesForDropdowns(string $areaId, array $area): array { $dropdowns = $area['dropdowns'] ?? []; $routes = []; - foreach ($dropdowns as $dropdownId => $dropdown) { - $routes = array_merge($routes, Dropdown::routes( - id: $dropdownId, - areaId: $areaId, - prefix: 'dropdowns', - options: $dropdown - )); - } + foreach ($dropdowns as $name => $dropdown) { + // Handle shortcuts for dropdowns. The name is the pattern + // and options are defined in a Closure + if (is_a($dropdown, 'Closure') === true) { + $dropdown = [ + 'pattern' => $name, + 'action' => $dropdown + ]; + } - return $routes; - } + // create the full pattern with dropdowns prefix + $pattern = 'dropdowns/' . trim(($dropdown['pattern'] ?? $name), '/'); - /** - * Extract all routes from an area - */ - public static function routesForRequests(string $areaId, array $area): array - { - $routes = $area['requests'] ?? []; - - foreach ($routes as $key => $route) { - $routes[$key]['area'] = $areaId; - $routes[$key]['type'] = 'request'; + // load event + $routes[] = [ + 'pattern' => $pattern, + 'type' => 'dropdown', + 'area' => $areaId, + 'method' => 'GET|POST', + 'action' => $dropdown['options'] ?? $dropdown['action'] + ]; } return $routes; @@ -448,6 +479,10 @@ class Panel /** * Extract all routes for searches + * + * @param string $areaId + * @param array $area + * @return array */ public static function routesForSearches(string $areaId, array $area): array { @@ -464,13 +499,9 @@ class Panel 'type' => 'search', 'area' => $areaId, 'action' => function () use ($params) { - $kirby = App::instance(); - $request = $kirby->request(); - $query = $request->get('query'); - $limit = (int)$request->get('limit', $kirby->option('panel.search.limit', 10)); - $page = (int)$request->get('page', 1); + $request = App::instance()->request(); - return $params['query']($query, $limit, $page); + return $params['query']($request->get('query')); } ]; } @@ -480,6 +511,10 @@ class Panel /** * Extract all views from an area + * + * @param string $areaId + * @param array $area + * @return array */ public static function routesForViews(string $areaId, array $area): array { @@ -489,18 +524,7 @@ class Panel foreach ($views as $view) { $view['area'] = $areaId; $view['type'] = 'view'; - - $when = $view['when'] ?? null; - unset($view['when']); - - // enable the route by default, but if there is a - // when condition closure, it must return `true` - if ( - $when instanceof Closure === false || - $when($view, $area) === true - ) { - $routes[] = $view; - } + $routes[] = $view; } return $routes; @@ -510,8 +534,10 @@ class Panel * Set the current language in multi-lang * installations based on the session or the * query language query parameter + * + * @return string|null */ - public static function setLanguage(): string|null + public static function setLanguage(): ?string { $kirby = App::instance(); @@ -544,15 +570,20 @@ class Panel /** * Set the currently active Panel translation * based on the current user or config + * + * @return string */ public static function setTranslation(): string { $kirby = App::instance(); - // use the user language for the default translation or - // fall back to the language from the config - $translation = $kirby->user()?->language() ?? - $kirby->panelLanguage(); + if ($user = $kirby->user()) { + // use the user language for the default translation + $translation = $user->language(); + } else { + // fall back to the language from the config + $translation = $kirby->panelLanguage(); + } $kirby->setCurrentTranslation($translation); @@ -562,30 +593,26 @@ class Panel /** * Creates an absolute Panel URL * independent of the Panel slug config + * + * @param string|null $url + * @return string */ - public static function url(string|null $url = null, array $options = []): string + public static function url(?string $url = null): string { + $slug = App::instance()->option('panel.slug', 'panel'); + // only touch relative paths if (Url::isAbsolute($url) === false) { - $kirby = App::instance(); - $slug = $kirby->option('panel.slug', 'panel'); - $path = trim($url, '/'); + $path = trim($url, '/'); - $baseUri = new Uri($kirby->url()); - $basePath = trim($baseUri->path()->toString(), '/'); - - // removes base path if relative path contains it - if (empty($basePath) === false && Str::startsWith($path, $basePath) === true) { - $path = Str::after($path, $basePath); - } // add the panel slug prefix if it it's not // included in the path yet - elseif (Str::startsWith($path, $slug . '/') === false) { + if (Str::startsWith($path, $slug . '/') === false) { $path = $slug . '/' . $path; } // create an absolute URL - $url = CmsUrl::to($path, $options); + $url = CmsUrl::to($path); } return $url; diff --git a/kirby/src/Panel/Plugins.php b/kirby/src/Panel/Plugins.php index f264f73..daa6ff5 100644 --- a/kirby/src/Panel/Plugins.php +++ b/kirby/src/Panel/Plugins.php @@ -23,11 +23,15 @@ class Plugins { /** * Cache of all collected plugin files + * + * @var array */ - public array|null $files = null; + public $files; /** * Collects and returns the plugin files for all plugins + * + * @return array */ public function files(): array { @@ -54,6 +58,8 @@ class Plugins /** * Returns the last modification * of the collected plugin files + * + * @return int */ public function modified(): int { @@ -69,6 +75,9 @@ class Plugins /** * Read the files from all plugins and concatenate them + * + * @param string $type + * @return string */ public function read(string $type): string { @@ -131,6 +140,9 @@ class Plugins /** * Absolute url to the cache file * This is used by the panel to link the plugins + * + * @param string $type + * @return string */ public function url(string $type): string { diff --git a/kirby/src/Panel/Redirect.php b/kirby/src/Panel/Redirect.php index d00cd6f..0c63a2e 100644 --- a/kirby/src/Panel/Redirect.php +++ b/kirby/src/Panel/Redirect.php @@ -20,6 +20,8 @@ class Redirect extends Exception { /** * Returns the HTTP code for the redirect + * + * @return int */ public function code(): int { @@ -34,6 +36,8 @@ class Redirect extends Exception /** * Returns the URL for the redirect + * + * @return string */ public function location(): string { diff --git a/kirby/src/Panel/Request.php b/kirby/src/Panel/Request.php deleted file mode 100644 index 9656d7d..0000000 --- a/kirby/src/Panel/Request.php +++ /dev/null @@ -1,24 +0,0 @@ - - * @link https://getkirby.com - * @copyright Bastian Allgeier - * @license https://getkirby.com/license - */ -class Request -{ - /** - * Renders request responses - */ - public static function response($data, array $options = []): Response - { - $data = Json::responseData($data); - return Panel::json($data, $data['code'] ?? 200); - } -} diff --git a/kirby/src/Panel/Search.php b/kirby/src/Panel/Search.php index f9b4295..20e75ae 100644 --- a/kirby/src/Panel/Search.php +++ b/kirby/src/Panel/Search.php @@ -2,8 +2,6 @@ namespace Kirby\Panel; -use Kirby\Http\Response; - /** * The Search response class handles Fiber * requests to render the JSON object for @@ -18,21 +16,18 @@ use Kirby\Http\Response; */ class Search extends Json { - protected static string $key = '$search'; + protected static $key = '$search'; - public static function response($data, array $options = []): Response + /** + * @param mixed $data + * @param array $options + * @return \Kirby\Http\Response + */ + public static function response($data, array $options = []) { - if ( - is_array($data) === true && - array_key_exists('results', $data) === false - ) { + if (is_array($data) === true) { $data = [ - 'results' => $data, - 'pagination' => [ - 'page' => 1, - 'limit' => $total = count($data), - 'total' => $total - ] + 'results' => $data ]; } diff --git a/kirby/src/Panel/Site.php b/kirby/src/Panel/Site.php index 68f7892..92f5178 100644 --- a/kirby/src/Panel/Site.php +++ b/kirby/src/Panel/Site.php @@ -2,10 +2,6 @@ namespace Kirby\Panel; -use Kirby\Cms\File as CmsFile; -use Kirby\Cms\ModelWithContent; -use Kirby\Filesystem\Asset; - /** * Provides information about the site model for the Panel * @since 3.6.0 @@ -21,12 +17,14 @@ class Site extends Model /** * @var \Kirby\Cms\Site */ - protected ModelWithContent $model; + protected $model; /** * Returns the setup for a dropdown option * which is used in the changes dropdown * for example. + * + * @return array */ public function dropdownOption(): array { @@ -40,16 +38,22 @@ class Site extends Model * Returns the image file object based on provided query * * @internal + * @param string|null $query + * @return \Kirby\Cms\File|\Kirby\Filesystem\Asset|null */ - protected function imageSource( - string|null $query = null - ): CmsFile|Asset|null { - $query ??= 'site.image'; + protected function imageSource(string $query = null) + { + if ($query === null) { + $query = 'site.image'; + } + return parent::imageSource($query); } /** * Returns the full path without leading slash + * + * @return string */ public function path(): string { @@ -61,6 +65,8 @@ class Site extends Model * view's component props * * @internal + * + * @return array */ public function props(): array { @@ -80,6 +86,8 @@ class Site extends Model * this model's Panel view * * @internal + * + * @return array */ public function view(): array { diff --git a/kirby/src/Panel/User.php b/kirby/src/Panel/User.php index e0a5149..69275ef 100644 --- a/kirby/src/Panel/User.php +++ b/kirby/src/Panel/User.php @@ -2,11 +2,7 @@ namespace Kirby\Panel; -use Kirby\Cms\File as CmsFile; -use Kirby\Cms\ModelWithContent; -use Kirby\Cms\Translation; use Kirby\Cms\Url; -use Kirby\Filesystem\Asset; use Kirby\Toolkit\I18n; /** @@ -24,10 +20,12 @@ class User extends Model /** * @var \Kirby\Cms\User */ - protected ModelWithContent $model; + protected $model; /** * Breadcrumb array + * + * @return array */ public function breadcrumb(): array { @@ -41,6 +39,9 @@ class User extends Model /** * Provides options for the user dropdown + * + * @param array $options + * @return array */ public function dropdown(array $options = []): array { @@ -73,15 +74,6 @@ class User extends Model 'disabled' => $this->isDisabledDropdownOption('changeRole', $options, $permissions) ]; - $result[] = [ - 'dialog' => $url . '/changeLanguage', - 'icon' => 'translate', - 'text' => I18n::translate('user.changeLanguage'), - 'disabled' => $this->isDisabledDropdownOption('changeLanguage', $options, $permissions) - ]; - - $result[] = '-'; - $result[] = [ 'dialog' => $url . '/changePassword', 'icon' => 'key', @@ -89,23 +81,12 @@ class User extends Model 'disabled' => $this->isDisabledDropdownOption('changePassword', $options, $permissions) ]; - if ($this->model->kirby()->system()->is2FAWithTOTP() === true) { - if ($account || $this->model->kirby()->user()->isAdmin()) { - if ($this->model->secret('totp') !== null) { - $result[] = [ - 'dialog' => $url . '/totp/disable', - 'icon' => 'qr-code', - 'text' => I18n::translate('login.totp.disable.option'), - ]; - } elseif ($account) { - $result[] = [ - 'dialog' => $url . '/totp/enable', - 'icon' => 'qr-code', - 'text' => I18n::translate('login.totp.enable.option') - ]; - } - } - } + $result[] = [ + 'dialog' => $url . '/changeLanguage', + 'icon' => 'globe', + 'text' => I18n::translate('user.changeLanguage'), + 'disabled' => $this->isDisabledDropdownOption('changeLanguage', $options, $permissions) + ]; $result[] = '-'; @@ -123,6 +104,8 @@ class User extends Model * Returns the setup for a dropdown option * which is used in the changes dropdown * for example. + * + * @return array */ public function dropdownOption(): array { @@ -132,7 +115,10 @@ class User extends Model ] + parent::dropdownOption(); } - public function home(): string|null + /** + * @return string|null + */ + public function home(): ?string { if ($home = ($this->model->blueprint()->home() ?? null)) { $url = $this->model->toString($home); @@ -144,6 +130,8 @@ class User extends Model /** * Default settings for the user's Panel image + * + * @return array */ protected function imageDefaults(): array { @@ -156,11 +144,12 @@ class User extends Model /** * Returns the image file object based on provided query - * @internal + * + * @param string|null $query + * @return \Kirby\Cms\File|\Kirby\Filesystem\Asset|null */ - protected function imageSource( - string|null $query = null - ): CmsFile|Asset|null { + protected function imageSource(string $query = null) + { if ($query === null) { return $this->model->avatar(); } @@ -170,6 +159,8 @@ class User extends Model /** * Returns the full path without leading slash + * + * @return string */ public function path(): string { @@ -183,8 +174,11 @@ class User extends Model /** * Returns prepared data for the panel user picker + * + * @param array|null $params + * @return array */ - public function pickerData(array $params = []): array + public function pickerData(array $params = null): array { $params['text'] ??= '{{ user.username }}'; @@ -199,6 +193,8 @@ class User extends Model * previous and next user * * @internal + * + * @return array */ public function prevNext(): array { @@ -215,11 +211,14 @@ class User extends Model * view's component props * * @internal + * + * @return array */ public function props(): array { $user = $this->model; $account = $user->isLoggedIn(); + $avatar = $user->avatar(); return array_merge( parent::props(), @@ -228,7 +227,7 @@ class User extends Model 'blueprint' => $this->model->role()->name(), 'model' => [ 'account' => $account, - 'avatar' => $user->avatar()?->url(), + 'avatar' => $avatar ? $avatar->url() : null, 'content' => $this->content(), 'email' => $user->email(), 'id' => $user->id(), @@ -245,8 +244,10 @@ class User extends Model /** * Returns the Translation object * for the selected Panel language + * + * @return \Kirby\Cms\Translation */ - public function translation(): Translation + public function translation() { $kirby = $this->model->kirby(); $lang = $this->model->language(); @@ -258,6 +259,8 @@ class User extends Model * this model's Panel view * * @internal + * + * @return array */ public function view(): array { diff --git a/kirby/src/Panel/UserTotpDisableDialog.php b/kirby/src/Panel/UserTotpDisableDialog.php deleted file mode 100644 index 7050cc7..0000000 --- a/kirby/src/Panel/UserTotpDisableDialog.php +++ /dev/null @@ -1,114 +0,0 @@ - - * @link https://getkirby.com - * @copyright Bastian Allgeier - * @license https://getkirby.com/license - */ -class UserTotpDisableDialog -{ - public App $kirby; - public User $user; - - public function __construct( - string|null $id = null - ) { - $this->kirby = App::instance(); - $this->user = $id ? Find::user($id) : $this->kirby->user(); - } - - /** - * Returns the Panel dialog state when opening the dialog - */ - public function load(): array - { - $currentUser = $this->kirby->user(); - $submitBtn = [ - 'text' => I18n::translate('disable'), - 'icon' => 'protected', - 'theme' => 'negative' - ]; - - // admins can disable TOTP for other users without - // entering their password (but not for themselves) - if ( - $currentUser->isAdmin() === true && - $currentUser->is($this->user) === false - ) { - $name = $this->user->name()->or($this->user->email()); - - return [ - 'component' => 'k-remove-dialog', - 'props' => [ - 'text' => I18n::template('login.totp.disable.admin', ['user' => Escape::html($name)]), - 'submitButton' => $submitBtn, - ] - ]; - } - - // everybody else - return [ - 'component' => 'k-form-dialog', - 'props' => [ - 'fields' => [ - 'password' => [ - 'type' => 'password', - 'required' => true, - 'counter' => false, - 'label' => I18n::translate('login.totp.disable.label'), - 'help' => I18n::translate('login.totp.disable.help'), - ] - ], - 'submitButton' => $submitBtn, - ] - ]; - } - - /** - * Removes the user's TOTP secret when the dialog is submitted - */ - public function submit(): array - { - $password = $this->kirby->request()->get('password'); - - try { - if ($this->kirby->user()->is($this->user) === true) { - $this->user->validatePassword($password); - } elseif ($this->kirby->user()->isAdmin() === false) { - throw new PermissionException('You are not allowed to disable TOTP for other users'); - } - - // Remove the TOTP secret from the account - $this->user->changeTotp(null); - - return [ - 'message' => I18n::translate('login.totp.disable.success') - ]; - } catch (InvalidArgumentException $e) { - // Catch and re-throw exception so that any - // Unauthenticated exception for incorrect passwords - // does not trigger a logout - throw new InvalidArgumentException([ - 'key' => $e->getKey(), - 'data' => $e->getData(), - 'fallback' => $e->getMessage(), - 'previous' => $e - ]); - } - } -} diff --git a/kirby/src/Panel/UserTotpEnableDialog.php b/kirby/src/Panel/UserTotpEnableDialog.php deleted file mode 100644 index e2917db..0000000 --- a/kirby/src/Panel/UserTotpEnableDialog.php +++ /dev/null @@ -1,95 +0,0 @@ - - * @link https://getkirby.com - * @copyright Bastian Allgeier - * @license https://getkirby.com/license - */ -class UserTotpEnableDialog -{ - public App $kirby; - public Totp $totp; - public User $user; - - public function __construct() - { - $this->kirby = App::instance(); - $this->user = $this->kirby->user(); - } - - /** - * Returns the Panel dialog state when opening the dialog - */ - public function load(): array - { - return [ - 'component' => 'k-totp-dialog', - 'props' => [ - 'qr' => $this->qr()->toSvg(size: '100%'), - 'value' => ['secret' => $this->secret()] - ] - ]; - } - - /** - * Creates a QR code with a new TOTP secret for the user - */ - public function qr(): QrCode - { - $issuer = $this->kirby->site()->title(); - $label = $this->user->email(); - $uri = $this->totp()->uri($issuer, $label); - return new QrCode($uri); - } - - public function secret(): string - { - return $this->totp()->secret(); - } - - /** - * Changes the user's TOTP secret when the dialog is submitted - */ - public function submit(): array - { - $secret = $this->kirby->request()->get('secret'); - $confirm = $this->kirby->request()->get('confirm'); - - if ($confirm === null) { - throw new InvalidArgumentException( - ['key' => 'login.totp.confirm.missing'] - ); - } - - if ($this->totp($secret)->verify($confirm) === false) { - throw new InvalidArgumentException( - ['key' => 'login.totp.confirm.invalid'] - ); - } - - $this->user->changeTotp($secret); - - return [ - 'message' => I18n::translate('login.totp.enable.success') - ]; - } - - public function totp(string|null $secret = null): Totp - { - return $this->totp ??= new Totp($secret); - } -} diff --git a/kirby/src/Panel/View.php b/kirby/src/Panel/View.php index a2fcebc..3eb7155 100644 --- a/kirby/src/Panel/View.php +++ b/kirby/src/Panel/View.php @@ -3,11 +3,10 @@ namespace Kirby\Panel; use Kirby\Cms\App; -use Kirby\Exception\Exception; use Kirby\Http\Response; use Kirby\Toolkit\A; +use Kirby\Toolkit\I18n; use Kirby\Toolkit\Str; -use Throwable; /** * The View response class handles Fiber @@ -28,6 +27,9 @@ class View * query parameters. Requests can return only * certain data fields that way or globals can * be injected on demand. + * + * @param array $data + * @return array */ public static function apply(array $data): array { @@ -38,9 +40,7 @@ class View return static::applyOnly($data, $only); } - $globals = - $request->header('X-Fiber-Globals') ?? - $request->get('_globals'); + $globals = $request->header('X-Fiber-Globals') ?? $request->get('_globals'); if (empty($globals) === false) { return static::applyGlobals($data, $globals); @@ -55,11 +55,13 @@ class View * * A global request can be activated with the `X-Fiber-Globals` header or the * `_globals` query parameter. + * + * @param array $data + * @param string|null $globals + * @return array */ - public static function applyGlobals( - array $data, - string|null $globals = null - ): array { + public static function applyGlobals(array $data, ?string $globals = null): array + { // split globals string into an array of fields $globalKeys = Str::split($globals, ','); @@ -87,11 +89,13 @@ class View * * Such requests can fetch shared data or globals. * Globals will be loaded on demand. + * + * @param array $data + * @param string|null $only + * @return array */ - public static function applyOnly( - array $data, - string|null $only = null - ): array { + public static function applyOnly(array $data, ?string $only = null): array + { // split include string into an array of fields $onlyKeys = Str::split($only, ','); @@ -119,7 +123,9 @@ class View } // Nest dotted keys in array but ignore $translation - return A::nest($result, ['$translation']); + return A::nest($result, [ + '$translation' + ]); } /** @@ -127,6 +133,10 @@ class View * The full shared data is always sent on every JSON and * full document request unless the `X-Fiber-Only` header or * the `_only` query parameter is set. + * + * @param array $view + * @param array $options + * @return array */ public static function data(array $view = [], array $options = []): array { @@ -139,7 +149,7 @@ class View $user = $kirby->user(); // user permissions - $permissions = $user?->role()->permissions()->toArray() ?? []; + $permissions = $user ? $user->role()->permissions()->toArray() : []; // current content language $language = $kirby->language(); @@ -148,18 +158,14 @@ class View return [ '$direction' => function () use ($kirby, $multilang, $language, $user) { if ($multilang === true && $language && $user) { - $default = $kirby->defaultLanguage(); + $isDefault = $language->direction() === $kirby->defaultLanguage()->direction(); + $isFromUser = $language->code() === $user->language(); - if ( - $language->direction() !== $default->direction() && - $language->code() !== $user->language() - ) { + if ($isDefault === false && $isFromUser === false) { return $language->direction(); } } }, - '$dialog' => null, - '$drawer' => null, '$language' => function () use ($kirby, $multilang, $language) { if ($multilang === true && $language) { return [ @@ -184,20 +190,15 @@ class View return []; }, - '$menu' => function () use ($options, $permissions) { - $menu = new Menu( - $options['areas'] ?? [], - $permissions, - $options['area']['id'] ?? null - ); - return $menu->entries(); + '$menu' => function () use ($options, $permissions) { + return static::menu($options['areas'] ?? [], $permissions, $options['area']['id'] ?? null); }, '$permissions' => $permissions, - '$license' => $kirby->system()->license()->status()->value(), - '$multilang' => $multilang, - '$searches' => static::searches($options['areas'] ?? [], $permissions), - '$url' => $kirby->request()->url()->toString(), - '$user' => function () use ($user) { + '$license' => (bool)$kirby->system()->license(), + '$multilang' => $multilang, + '$searches' => static::searches($options['areas'] ?? [], $permissions), + '$url' => $kirby->request()->url()->toString(), + '$user' => function () use ($user) { if ($user) { return [ 'email' => $user->email(), @@ -215,25 +216,17 @@ class View 'breadcrumb' => [], 'code' => 200, 'path' => Str::after($kirby->path(), '/'), - 'props' => [], - 'query' => App::instance()->request()->query()->toArray(), - 'referrer' => Panel::referrer(), - 'search' => $kirby->option('panel.search.type', 'pages'), 'timestamp' => (int)(microtime(true) * 1000), + 'props' => [], + 'search' => $kirby->option('panel.search.type', 'pages') ]; - $view = array_replace_recursive( - $defaults, - $options['area'] ?? [], - $view - ); + $view = array_replace_recursive($defaults, $options['area'] ?? [], $view); // make sure that views and dialogs are gone unset( $view['dialogs'], - $view['drawers'], $view['dropdowns'], - $view['requests'], $view['searches'], $view['views'] ); @@ -246,6 +239,10 @@ class View /** * Renders the error view with provided message + * + * @param string $message + * @param int $code + * @return array */ public static function error(string $message, int $code = 404) { @@ -268,17 +265,25 @@ class View * is only requested once on the first page load. * It can be loaded partially later if needed, * but is otherwise not included in Fiber calls. + * + * @return array */ public static function globals(): array { $kirby = App::instance(); return [ - '$config' => fn () => [ - 'debug' => $kirby->option('debug', false), - 'kirbytext' => $kirby->option('panel.kirbytext', true), - 'translation' => $kirby->option('panel.language', 'en'), - ], + '$config' => function () use ($kirby) { + return [ + 'debug' => $kirby->option('debug', false), + 'kirbytext' => $kirby->option('panel.kirbytext', true), + 'search' => [ + 'limit' => $kirby->option('panel.search.limit', 10), + 'type' => $kirby->option('panel.search.type', 'pages') + ], + 'translation' => $kirby->option('panel.language', 'en'), + ]; + }, '$system' => function () use ($kirby) { $locales = []; @@ -316,23 +321,93 @@ class View ]; } + /** + * Creates the menu for the topbar + * + * @param array $areas + * @param array $permissions + * @param string|null $current + * @return array + */ + public static function menu(?array $areas = [], ?array $permissions = [], ?string $current = null): array + { + $menu = []; + + // areas + foreach ($areas as $areaId => $area) { + $access = $permissions['access'][$areaId] ?? true; + + // areas without access permissions get skipped entirely + if ($access === false) { + continue; + } + + // fetch custom menu settings from the area definition + $menuSetting = $area['menu'] ?? false; + + // menu settings can be a callback that can return true, false or disabled + if (is_a($menuSetting, 'Closure') === true) { + $menuSetting = $menuSetting($areas, $permissions, $current); + } + + // false will remove the area entirely just like with + // disabled permissions + if ($menuSetting === false) { + continue; + } + + $menu[] = [ + 'current' => $areaId === $current, + 'disabled' => $menuSetting === 'disabled', + 'icon' => $area['icon'], + 'id' => $areaId, + 'link' => $area['link'], + 'text' => $area['label'], + ]; + } + + $menu[] = '-'; + $menu[] = [ + 'current' => $current === 'account', + 'icon' => 'account', + 'id' => 'account', + 'link' => 'account', + 'disabled' => ($permissions['access']['account'] ?? false) === false, + 'text' => I18n::translate('view.account'), + ]; + $menu[] = '-'; + + // logout + $menu[] = [ + 'icon' => 'logout', + 'id' => 'logout', + 'link' => 'logout', + 'text' => I18n::translate('logout') + ]; + return $menu; + } + /** * Renders the main panel view either as * JSON response or full HTML document based * on the request header or query params + * + * @param mixed $data + * @param array $options + * @return \Kirby\Http\Response */ - public static function response($data, array $options = []): Response + public static function response($data, array $options = []) { // handle redirects - if ($data instanceof Redirect) { + if (is_a($data, 'Kirby\Panel\Redirect') === true) { return Response::redirect($data->location(), $data->code()); // handle Kirby exceptions - } elseif ($data instanceof Exception) { + } elseif (is_a($data, 'Kirby\Exception\Exception') === true) { $data = static::error($data->getMessage(), $data->getHttpCode()); // handle regular exceptions - } elseif ($data instanceof Throwable) { + } elseif (is_a($data, 'Throwable') === true) { $data = static::error($data->getMessage(), 500); // only expect arrays from here on @@ -362,21 +437,17 @@ class View return Document::response($fiber); } - public static function searches(array $areas, array $permissions): array + public static function searches(array $areas, array $permissions) { $searches = []; - foreach ($areas as $areaId => $area) { - // by default, all areas are accessible unless - // the permissions are explicitly set to false - if (($permissions['access'][$areaId] ?? true) !== false) { - foreach ($area['searches'] ?? [] as $id => $params) { - $searches[$id] = [ - 'icon' => $params['icon'] ?? 'search', - 'label' => $params['label'] ?? Str::ucfirst($id), - 'id' => $id - ]; - } + foreach ($areas as $area) { + foreach ($area['searches'] ?? [] as $id => $params) { + $searches[$id] = [ + 'icon' => $params['icon'] ?? 'search', + 'label' => $params['label'] ?? Str::ucfirst($id), + 'id' => $id + ]; } } return $searches; diff --git a/kirby/src/Parsley/Element.php b/kirby/src/Parsley/Element.php index 649c5a3..292a55a 100644 --- a/kirby/src/Parsley/Element.php +++ b/kirby/src/Parsley/Element.php @@ -21,21 +21,37 @@ use Kirby\Toolkit\Str; */ class Element { - public function __construct( - protected DOMElement $node, - protected array $marks = [] - ) { + /** + * @var array + */ + protected $marks; + + /** + * @var \DOMElement + */ + protected $node; + + /** + * @param \DOMElement $node + * @param array $marks + */ + public function __construct(DOMElement $node, array $marks = []) + { + $this->marks = $marks; + $this->node = $node; } /** * The returns the attribute value or * the given fallback if the attribute does not exist + * + * @param string $attr + * @param string|null $fallback + * @return string|null */ - public function attr( - string $attr, - string|null $fallback = null - ): string|null { - if ($this->node->hasAttribute($attr) === true) { + public function attr(string $attr, string $fallback = null): ?string + { + if ($this->node->hasAttribute($attr)) { return $this->node->getAttribute($attr) ?? $fallback; } @@ -44,6 +60,8 @@ class Element /** * Returns a list of all child elements + * + * @return \DOMNodeList */ public function children(): DOMNodeList { @@ -52,6 +70,8 @@ class Element /** * Returns an array with all class names + * + * @return array */ public function classList(): array { @@ -60,16 +80,20 @@ class Element /** * Returns the value of the class attribute + * + * @return string|null */ - public function className(): string|null + public function className(): ?string { return $this->attr('class'); } /** * Returns the original dom element + * + * @return \DOMElement */ - public function element(): DOMElement + public function element() { return $this->node; } @@ -77,6 +101,9 @@ class Element /** * Returns an array with all nested elements * that could be found for the given query + * + * @param string $query + * @return array */ public function filter(string $query): array { @@ -94,8 +121,11 @@ class Element /** * Tries to find a single nested element by * query and otherwise returns null + * + * @param string $query + * @return \Kirby\Parsley\Element|null */ - public function find(string $query): static|null + public function find(string $query) { if ($result = $this->query($query)[0]) { return new static($result); @@ -108,16 +138,17 @@ class Element * Returns the inner HTML of the element * * @param array|null $marks List of allowed marks + * @return string */ - public function innerHtml(array|null $marks = null): string + public function innerHtml(array $marks = null): string { - $marks ??= $this->marks; - $inline = new Inline($this->node, $marks); - return $inline->innerHtml(); + return (new Inline($this->node, $marks ?? $this->marks))->innerHtml(); } /** * Returns the contents as plain text + * + * @return string */ public function innerText(): string { @@ -126,31 +157,40 @@ class Element /** * Returns the full HTML for the element + * + * @param array|null $marks + * @return string */ - public function outerHtml(array|null $marks = null): string + public function outerHtml(array $marks = null): string { return $this->node->ownerDocument->saveHtml($this->node); } /** * Searches nested elements + * + * @param string $query + * @return DOMNodeList|null */ - public function query(string $query): DOMNodeList|null + public function query(string $query) { - $path = new DOMXPath($this->node->ownerDocument); - return $path->query($query, $this->node); + return (new DOMXPath($this->node->ownerDocument))->query($query, $this->node); } /** * Removes the element from the DOM + * + * @return void */ - public function remove(): void + public function remove() { $this->node->parentNode->removeChild($this->node); } /** * Returns the name of the element + * + * @return string */ public function tagName(): string { diff --git a/kirby/src/Parsley/Inline.php b/kirby/src/Parsley/Inline.php index 32e6b08..97c044f 100644 --- a/kirby/src/Parsley/Inline.php +++ b/kirby/src/Parsley/Inline.php @@ -2,10 +2,8 @@ namespace Kirby\Parsley; -use DOMElement; use DOMNode; use DOMNodeList; -use DOMText; use Kirby\Toolkit\Html; /** @@ -22,27 +20,33 @@ use Kirby\Toolkit\Html; */ class Inline { - protected string $html = ''; - protected array $marks = []; + /** + * @var string + */ + protected $html = ''; + /** + * @var array + */ + protected $marks = []; + + /** + * @param \DOMNode $node + * @param array $marks + */ public function __construct(DOMNode $node, array $marks = []) { $this->createMarkRules($marks); - - $html = static::parseNode($node, $this->marks) ?? ''; - - // only trim HTML if it doesn't consist of only spaces - if (trim($html) !== '') { - $html = trim($html); - } - - $this->html = $html; + $this->html = trim(static::parseNode($node, $this->marks) ?? ''); } /** * Loads all mark rules + * + * @param array $marks + * @return array */ - protected function createMarkRules(array $marks): array + protected function createMarkRules(array $marks) { foreach ($marks as $mark) { $this->marks[$mark['tag']] = $mark; @@ -52,22 +56,25 @@ class Inline } /** - * Get all allowed attributes for a DOMElement + * Get all allowed attributes for a DOMNode * as clean array + * + * @param DOMNode $node + * @param array $marks + * @return array */ - public static function parseAttrs( - DOMElement $node, - array $marks = [] - ): array { + public static function parseAttrs(DOMNode $node, array $marks = []): array + { $attrs = []; $mark = $marks[$node->tagName]; $defaults = $mark['defaults'] ?? []; foreach ($mark['attrs'] ?? [] as $attr) { - $attrs[$attr] = match ($node->hasAttribute($attr)) { - true => $node->getAttribute($attr), - default => $defaults[$attr] ?? null - }; + if ($node->hasAttribute($attr)) { + $attrs[$attr] = $node->getAttribute($attr); + } else { + $attrs[$attr] = $defaults[$attr] ?? null; + } } return $attrs; @@ -76,11 +83,13 @@ class Inline /** * Parses all children and creates clean HTML * for each of them. + * + * @param \DOMNodeList $children + * @param array $marks + * @return string */ - public static function parseChildren( - DOMNodeList $children, - array $marks - ): string { + public static function parseChildren(DOMNodeList $children, array $marks): string + { $html = ''; foreach ($children as $child) { $html .= static::parseNode($child, $marks); @@ -91,11 +100,12 @@ class Inline /** * Go through all child elements and create * clean inner HTML for them + * + * @param DOMNode $node + * @return string|null */ - public static function parseInnerHtml( - DOMElement $node, - array $marks = [] - ): string|null { + public static function parseInnerHtml(DOMNode $node, array $marks = []): ?string + { $html = static::parseChildren($node->childNodes, $marks); // trim the inner HTML for paragraphs @@ -113,46 +123,50 @@ class Inline /** * Converts the given node to clean HTML + * + * @param \DOMNode $node + * @param array $marks + * @return string|null */ - public static function parseNode(DOMNode $node, array $marks = []): string|null + public static function parseNode(DOMNode $node, array $marks = []): ?string { - if ($node instanceof DOMText) { + if (is_a($node, 'DOMText') === true) { return Html::encode($node->textContent); } - if ($node instanceof DOMElement) { - // unknown marks - if (array_key_exists($node->tagName, $marks) === false) { - return static::parseChildren($node->childNodes, $marks); - } - - // collect all allowed attributes - $attrs = static::parseAttrs($node, $marks); - - // close self-closing elements - if (Html::isVoid($node->tagName) === true) { - return '<' . $node->tagName . Html::attr($attrs, null, ' ') . ' />'; - } - - $innerHtml = static::parseInnerHtml($node, $marks); - - // skip empty paragraphs - if ($innerHtml === null && $node->tagName === 'p') { - return null; - } - - // create the outer html for the element - $html = '<' . $node->tagName . Html::attr($attrs, null, ' ') . '>'; - $html .= $innerHtml; - $html .= 'tagName . '>'; - return $html; + // ignore comments + if (is_a($node, 'DOMComment') === true) { + return null; } - return null; + // unknown marks + if (array_key_exists($node->tagName, $marks) === false) { + return static::parseChildren($node->childNodes, $marks); + } + + // collect all allowed attributes + $attrs = static::parseAttrs($node, $marks); + + // close self-closing elements + if (Html::isVoid($node->tagName) === true) { + return '<' . $node->tagName . Html::attr($attrs, null, ' ') . ' />'; + } + + $innerHtml = static::parseInnerHtml($node, $marks); + + // skip empty paragraphs + if ($innerHtml === null && $node->tagName === 'p') { + return null; + } + + // create the outer html for the element + return '<' . $node->tagName . Html::attr($attrs, null, ' ') . '>' . $innerHtml . 'tagName . '>'; } /** * Returns the HTML contents of the element + * + * @return string */ public function innerHtml(): string { diff --git a/kirby/src/Parsley/Parsley.php b/kirby/src/Parsley/Parsley.php index 3f2242e..d99d45e 100644 --- a/kirby/src/Parsley/Parsley.php +++ b/kirby/src/Parsley/Parsley.php @@ -2,10 +2,7 @@ namespace Kirby\Parsley; -use DOMDocument; -use DOMElement; use DOMNode; -use DOMText; use Kirby\Parsley\Schema\Plain; use Kirby\Toolkit\Dom; @@ -23,25 +20,65 @@ use Kirby\Toolkit\Dom; */ class Parsley { - protected array $blocks = []; - protected DOMDocument $doc; - protected Dom $dom; - protected array $inline = []; - protected array $marks = []; - protected array $nodes = []; - protected Schema $schema; - protected array $skip = []; + /** + * @var array + */ + protected $blocks = []; - public static bool $useXmlExtension = true; + /** + * @var \DOMDocument + */ + protected $doc; - public function __construct(string $html, Schema|null $schema = null) + /** + * @var \Kirby\Toolkit\Dom + */ + protected $dom; + + /** + * @var array + */ + protected $inline = []; + + /** + * @var array + */ + protected $marks = []; + + /** + * @var array + */ + protected $nodes = []; + + /** + * @var \Kirby\Parsley\Schema + */ + protected $schema; + + /** + * @var array + */ + protected $skip = []; + + /** + * @var bool + */ + public static $useXmlExtension = true; + + /** + * @param string $html + * @param \Kirby\Parsley\Schema|null $schema + */ + public function __construct(string $html, Schema $schema = null) { // fail gracefully if the XML extension is not installed // or should be skipped if ($this->useXmlExtension() === false) { $this->blocks[] = [ - 'type' => 'markdown', - 'content' => ['text' => $html] + 'type' => 'markdown', + 'content' => [ + 'text' => $html, + ] ]; return; } @@ -73,6 +110,8 @@ class Parsley /** * Returns all detected blocks + * + * @return array */ public function blocks(): array { @@ -81,6 +120,9 @@ class Parsley /** * Load all node rules from the schema + * + * @param array $nodes + * @return array */ public function createNodeRules(array $nodes): array { @@ -94,6 +136,9 @@ class Parsley /** * Checks if the given element contains * any other block level elements + * + * @param \DOMNode $element + * @return bool */ public function containsBlock(DOMNode $element): bool { @@ -102,10 +147,7 @@ class Parsley } foreach ($element->childNodes as $childNode) { - if ( - $this->isBlock($childNode) === true || - $this->containsBlock($childNode) - ) { + if ($this->isBlock($childNode) === true || $this->containsBlock($childNode)) { return true; } } @@ -120,8 +162,10 @@ class Parsley * if the type matches, or will be appended. * * The inline cache will be reset afterwards + * + * @return void */ - public function endInlineBlock(): void + public function endInlineBlock() { if (empty($this->inline) === true) { return; @@ -130,7 +174,7 @@ class Parsley $html = []; foreach ($this->inline as $inline) { - $node = new Inline($inline, $this->marks); + $node = new Inline($inline, $this->marks); $html[] = $node->innerHTML(); } @@ -147,8 +191,11 @@ class Parsley * Creates a fallback block type for the given * element. The element can either be a element object * or a simple HTML/plain text string + * + * @param \Kirby\Parsley\Element|string $element + * @return array|null */ - public function fallback(Element|string $element): array|null + public function fallback($element): ?array { if ($fallback = $this->schema->fallback($element)) { return $fallback; @@ -159,26 +206,32 @@ class Parsley /** * Checks if the given DOMNode is a block element + * + * @param DOMNode $element + * @return bool */ public function isBlock(DOMNode $element): bool { - if ($element instanceof DOMElement) { - return array_key_exists($element->tagName, $this->nodes) === true; + if (is_a($element, 'DOMElement') === false) { + return false; } - return false; + return array_key_exists($element->tagName, $this->nodes) === true; } /** * Checks if the given DOMNode is an inline element + * + * @param \DOMNode $element + * @return bool */ public function isInline(DOMNode $element): bool { - if ($element instanceof DOMText) { + if (is_a($element, 'DOMText') === true) { return true; } - if ($element instanceof DOMElement) { + if (is_a($element, 'DOMElement') === true) { // all spans will be treated as inline elements if ($element->tagName === 'span') { return true; @@ -199,17 +252,17 @@ class Parsley return false; } - public function mergeOrAppend(array $block): void + /** + * @param array $block + * @return void + */ + public function mergeOrAppend(array $block) { $lastIndex = count($this->blocks) - 1; $lastItem = $this->blocks[$lastIndex] ?? null; // merge with previous block - if ( - $block['type'] === 'text' && - $lastItem && - $lastItem['type'] === 'text' - ) { + if ($block['type'] === 'text' && $lastItem && $lastItem['type'] === 'text') { $this->blocks[$lastIndex]['content']['text'] .= ' ' . $block['content']['text']; // append @@ -221,6 +274,9 @@ class Parsley /** * Parses the given DOM node and tries to * convert it to a block or a list of blocks + * + * @param \DOMNode $element + * @return void */ public function parseNode(DOMNode $element): bool { @@ -232,18 +288,15 @@ class Parsley } // inline context - if ($this->isInline($element) === true) { + if ($this->isInline($element)) { $this->inline[] = $element; return true; + } else { + $this->endInlineBlock(); } - $this->endInlineBlock(); - // known block nodes if ($this->isBlock($element) === true) { - /** - * @var DOMElement $element - */ if ($parser = ($this->nodes[$element->tagName]['parse'] ?? null)) { if ($result = $parser(new Element($element, $this->marks))) { $this->blocks[] = $result; @@ -254,9 +307,6 @@ class Parsley // has only unknown children (div, etc.) if ($this->containsBlock($element) === false) { - /** - * @var DOMElement $element - */ if (in_array($element->tagName, $this->skip) === true) { return false; } @@ -289,6 +339,9 @@ class Parsley return true; } + /** + * @return bool + */ public function useXmlExtension(): bool { if (static::$useXmlExtension !== true) { diff --git a/kirby/src/Parsley/Schema.php b/kirby/src/Parsley/Schema.php index 3cf74f1..b9c1232 100644 --- a/kirby/src/Parsley/Schema.php +++ b/kirby/src/Parsley/Schema.php @@ -18,8 +18,11 @@ class Schema /** * Returns the fallback block when no * other block type can be detected + * + * @param \Kirby\Parsley\Element|string $element + * @return array|null */ - public function fallback(Element|string $element): array|null + public function fallback($element): ?array { return null; } @@ -27,6 +30,8 @@ class Schema /** * Returns a list of allowed inline marks * and their parsing rules + * + * @return array */ public function marks(): array { @@ -36,6 +41,8 @@ class Schema /** * Returns a list of allowed nodes and * their parsing rules + * + * @return array */ public function nodes(): array { @@ -45,6 +52,8 @@ class Schema /** * Returns a list of all elements that should be * skipped and not be parsed at all + * + * @return array */ public function skip(): array { diff --git a/kirby/src/Parsley/Schema/Blocks.php b/kirby/src/Parsley/Schema/Blocks.php index a72106c..d825a0e 100644 --- a/kirby/src/Parsley/Schema/Blocks.php +++ b/kirby/src/Parsley/Schema/Blocks.php @@ -2,8 +2,6 @@ namespace Kirby\Parsley\Schema; -use DOMElement; -use DOMText; use Kirby\Parsley\Element; use Kirby\Toolkit\Str; @@ -21,22 +19,22 @@ use Kirby\Toolkit\Str; */ class Blocks extends Plain { + /** + * @param \Kirby\Parsley\Element $node + * @return array + */ public function blockquote(Element $node): array { - $text = []; + $citation = null; + $text = []; // get all the text for the quote foreach ($node->children() as $child) { - if ($child instanceof DOMText) { + if (is_a($child, 'DOMText') === true) { $text[] = trim($child->textContent); } - - if ( - $child instanceof DOMElement && - $child->tagName !== 'footer' - ) { - $element = new Element($child); - $text[] = $element->innerHTML($this->marks()); + if (is_a($child, 'DOMElement') === true && $child->tagName !== 'footer') { + $text[] = (new Element($child))->innerHTML($this->marks()); } } @@ -44,7 +42,9 @@ class Blocks extends Plain $text = implode('', array_filter($text)); // get the citation from the footer - $citation = $node->find('footer')?->innerHTML($this->marks()); + if ($footer = $node->find('footer')) { + $citation = $footer->innerHTML($this->marks()); + } return [ 'content' => [ @@ -58,10 +58,13 @@ class Blocks extends Plain /** * Creates the fallback block type * if no other block can be found + * + * @param \Kirby\Parsley\Element|string $element + * @return array|null */ - public function fallback(Element|string $element): array|null + public function fallback($element): ?array { - if ($element instanceof Element) { + if (is_a($element, Element::class) === true) { $html = $element->innerHtml(); // wrap the inner HTML in a p tag if it doesn't @@ -91,6 +94,9 @@ class Blocks extends Plain /** * Converts a heading element to a heading block + * + * @param \Kirby\Parsley\Element $node + * @return array */ public function heading(Element $node): array { @@ -111,14 +117,21 @@ class Blocks extends Plain ]; } + /** + * @param \Kirby\Parsley\Element $node + * @return array + */ public function iframe(Element $node): array { - $src = $node->attr('src'); - $figcaption = $node->find('ancestor::figure[1]//figcaption'); - $caption = $figcaption?->innerHTML($this->marks()); + $caption = null; + $src = $node->attr('src'); - // avoid parsing the caption twice - $figcaption?->remove(); + if ($figcaption = $node->find('ancestor::figure[1]//figcaption')) { + $caption = $figcaption->innerHTML($this->marks()); + + // avoid parsing the caption twice + $figcaption->remove(); + } // reverse engineer video URLs if (preg_match('!player.vimeo.com\/video\/([0-9]+)!i', $src, $array) === 1) { @@ -150,14 +163,25 @@ class Blocks extends Plain ]; } + /** + * @param \Kirby\Parsley\Element $node + * @return array + */ public function img(Element $node): array { - $link = $node->find('ancestor::a')?->attr('href'); - $figcaption = $node->find('ancestor::figure[1]//figcaption'); - $caption = $figcaption?->innerHTML($this->marks()); + $caption = null; + $link = null; - // avoid parsing the caption twice - $figcaption?->remove(); + if ($figcaption = $node->find('ancestor::figure[1]//figcaption')) { + $caption = $figcaption->innerHTML($this->marks()); + + // avoid parsing the caption twice + $figcaption->remove(); + } + + if ($a = $node->find('ancestor::a')) { + $link = $a->attr('href'); + } return [ 'content' => [ @@ -173,6 +197,9 @@ class Blocks extends Plain /** * Converts a list element to HTML + * + * @param \Kirby\Parsley\Element $node + * @return string */ public function list(Element $node): string { @@ -182,30 +209,30 @@ class Blocks extends Plain $innerHtml = ''; foreach ($li->children() as $child) { - if ($child instanceof DOMText) { + if (is_a($child, 'DOMText') === true) { $innerHtml .= $child->textContent; - } elseif ($child instanceof DOMElement) { + } elseif (is_a($child, 'DOMElement') === true) { $child = new Element($child); - $list = ['ul', 'ol']; - $innerHtml .= match (in_array($child->tagName(), $list)) { - true => $this->list($child), - default => $child->innerHTML($this->marks()) - }; + + if (in_array($child->tagName(), ['ul', 'ol']) === true) { + $innerHtml .= $this->list($child); + } else { + $innerHtml .= $child->innerHTML($this->marks()); + } } } $html[] = '
    • ' . trim($innerHtml) . '
    • '; } - $outerHtml = '<' . $node->tagName() . '>'; - $outerHtml .= implode($html); - $outerHtml .= 'tagName() . '>'; - return $outerHtml; + return '<' . $node->tagName() . '>' . implode($html) . 'tagName() . '>'; } /** * Returns a list of allowed inline marks * and their parsing rules + * + * @return array */ public function marks(): array { @@ -214,7 +241,7 @@ class Blocks extends Plain 'tag' => 'a', 'attrs' => ['href', 'rel', 'target', 'title'], 'defaults' => [ - 'rel' => 'noreferrer' + 'rel' => 'noopener noreferrer' ] ], [ @@ -264,79 +291,114 @@ class Blocks extends Plain * their parsing rules * * @codeCoverageIgnore + * @return array */ public function nodes(): array { return [ [ 'tag' => 'blockquote', - 'parse' => fn (Element $node) => $this->blockquote($node) + 'parse' => function (Element $node) { + return $this->blockquote($node); + } ], [ 'tag' => 'h1', - 'parse' => fn (Element $node) => $this->heading($node) + 'parse' => function (Element $node) { + return $this->heading($node); + } ], [ 'tag' => 'h2', - 'parse' => fn (Element $node) => $this->heading($node) + 'parse' => function (Element $node) { + return $this->heading($node); + } ], [ 'tag' => 'h3', - 'parse' => fn (Element $node) => $this->heading($node) + 'parse' => function (Element $node) { + return $this->heading($node); + } ], [ 'tag' => 'h4', - 'parse' => fn (Element $node) => $this->heading($node) + 'parse' => function (Element $node) { + return $this->heading($node); + } ], [ 'tag' => 'h5', - 'parse' => fn (Element $node) => $this->heading($node) + 'parse' => function (Element $node) { + return $this->heading($node); + } ], [ 'tag' => 'h6', - 'parse' => fn (Element $node) => $this->heading($node) + 'parse' => function (Element $node) { + return $this->heading($node); + } ], [ 'tag' => 'hr', - 'parse' => fn (Element $node) => ['type' => 'line'] + 'parse' => function (Element $node) { + return [ + 'type' => 'line' + ]; + } ], [ 'tag' => 'iframe', - 'parse' => fn (Element $node) => $this->iframe($node) + 'parse' => function (Element $node) { + return $this->iframe($node); + } ], [ 'tag' => 'img', - 'parse' => fn (Element $node) => $this->img($node) + 'parse' => function (Element $node) { + return $this->img($node); + } ], [ 'tag' => 'ol', - 'parse' => fn (Element $node) => [ - 'content' => [ - 'text' => $this->list($node) - ], - 'type' => 'list', - ] + 'parse' => function (Element $node) { + return [ + 'content' => [ + 'text' => $this->list($node) + ], + 'type' => 'list', + ]; + } ], [ 'tag' => 'pre', - 'parse' => fn (Element $node) => $this->pre($node) + 'parse' => function (Element $node) { + return $this->pre($node); + } ], [ 'tag' => 'table', - 'parse' => fn (Element $node) => $this->table($node) + 'parse' => function (Element $node) { + return $this->table($node); + } ], [ 'tag' => 'ul', - 'parse' => fn (Element $node) => [ - 'content' => [ - 'text' => $this->list($node) - ], - 'type' => 'list', - ] + 'parse' => function (Element $node) { + return [ + 'content' => [ + 'text' => $this->list($node) + ], + 'type' => 'list', + ]; + } ], ]; } + /** + * @param \Kirby\Parsley\Element $node + * @return array + */ public function pre(Element $node): array { $language = 'text'; @@ -359,6 +421,10 @@ class Blocks extends Plain ]; } + /** + * @param \Kirby\Parsley\Element $node + * @return array + */ public function table(Element $node): array { return [ diff --git a/kirby/src/Parsley/Schema/Plain.php b/kirby/src/Parsley/Schema/Plain.php index 183556f..96e976a 100644 --- a/kirby/src/Parsley/Schema/Plain.php +++ b/kirby/src/Parsley/Schema/Plain.php @@ -23,10 +23,13 @@ class Plain extends Schema /** * Creates the fallback block type * if no other block can be found + * + * @param \Kirby\Parsley\Element|string $element + * @return array|null */ - public function fallback(Element|string $element): array|null + public function fallback($element): ?array { - if ($element instanceof Element) { + if (is_a($element, Element::class) === true) { $text = $element->innerText(); } elseif (is_string($element) === true) { $text = trim($element); @@ -49,6 +52,8 @@ class Plain extends Schema /** * Returns a list of all elements that * should be skipped during parsing + * + * @return array */ public function skip(): array { diff --git a/kirby/src/Query/Argument.php b/kirby/src/Query/Argument.php deleted file mode 100644 index d9ca493..0000000 --- a/kirby/src/Query/Argument.php +++ /dev/null @@ -1,117 +0,0 @@ - - * @link https://getkirby.com - * @copyright Bastian Allgeier - * @license https://opensource.org/licenses/MIT - */ -class Argument -{ - public function __construct( - public mixed $value - ) { - } - - /** - * Sanitizes argument string into actual - * PHP type/object as new Argument instance - */ - public static function factory(string $argument): static - { - $argument = trim($argument); - - // remove grouping parantheses - if ( - Str::startsWith($argument, '(') && - Str::endsWith($argument, ')') - ) { - $argument = trim(substr($argument, 1, -1)); - } - - // string with single quotes - if ( - Str::startsWith($argument, "'") && - Str::endsWith($argument, "'") - ) { - $string = substr($argument, 1, -1); - $string = str_replace("\'", "'", $string); - return new static($string); - } - - // string with double quotes - if ( - Str::startsWith($argument, '"') && - Str::endsWith($argument, '"') - ) { - $string = substr($argument, 1, -1); - $string = str_replace('\"', '"', $string); - return new static($string); - } - - // array: split and recursive sanitizing - if ( - Str::startsWith($argument, '[') && - Str::endsWith($argument, ']') - ) { - $array = substr($argument, 1, -1); - $array = Arguments::factory($array); - return new static($array); - } - - // numeric - if (is_numeric($argument) === true) { - if (strpos($argument, '.') === false) { - return new static((int)$argument); - } - - return new static((float)$argument); - } - - // Closure - if (Str::startsWith($argument, '() =>')) { - $query = Str::after($argument, '() =>'); - $query = trim($query); - return new static(fn () => $query); - } - - return new static(match ($argument) { - 'null' => null, - 'true' => true, - 'false' => false, - - // resolve parameter for objects and methods itself - default => new Query($argument) - }); - } - - /** - * Return the argument value and - * resolves nested objects to scaler types - */ - public function resolve(array|object $data = []): mixed - { - // don't resolve the Closure immediately, instead - // resolve it to the sub-query and create a new Closure - // that resolves the sub-query with the same data set once called - if ($this->value instanceof Closure) { - $query = ($this->value)(); - return fn () => static::factory($query)->resolve($data); - } - - if (is_object($this->value) === true) { - return $this->value->resolve($data); - } - - return $this->value; - } -} diff --git a/kirby/src/Query/Arguments.php b/kirby/src/Query/Arguments.php deleted file mode 100644 index c78dd22..0000000 --- a/kirby/src/Query/Arguments.php +++ /dev/null @@ -1,59 +0,0 @@ - - * @link https://getkirby.com - * @copyright Bastian Allgeier - * @license https://opensource.org/licenses/MIT - */ -class Arguments extends Collection -{ - // skip all matches inside of parantheses - public const NO_PNTH = '\([^)]+\)(*SKIP)(*FAIL)'; - // skip all matches inside of square brackets - public const NO_SQBR = '\[[^]]+\](*SKIP)(*FAIL)'; - // skip all matches inside of double quotes - public const NO_DLQU = '\"(?:[^"\\\\]|\\\\.)*\"(*SKIP)(*FAIL)'; - // skip all matches inside of single quotes - public const NO_SLQU = '\'(?:[^\'\\\\]|\\\\.)*\'(*SKIP)(*FAIL)'; - // skip all matches inside of any of the above skip groups - public const OUTSIDE = - self::NO_PNTH . '|' . self::NO_SQBR . '|' . - self::NO_DLQU . '|' . self::NO_SLQU; - - /** - * Splits list of arguments into individual - * Argument instances while respecting skip groups - */ - public static function factory(string $arguments): static - { - $arguments = A::map( - // split by comma, but not inside skip groups - preg_split('!,|' . self::OUTSIDE . '!', $arguments), - fn ($argument) => Argument::factory($argument) - ); - - return new static($arguments); - } - - /** - * Resolve each argument, so that they can - * passed together to the actual method call - */ - public function resolve(array|object $data = []): array - { - return A::map( - $this->data, - fn ($argument) => $argument->resolve($data) - ); - } -} diff --git a/kirby/src/Query/Expression.php b/kirby/src/Query/Expression.php deleted file mode 100644 index f205c30..0000000 --- a/kirby/src/Query/Expression.php +++ /dev/null @@ -1,119 +0,0 @@ - - * @link https://getkirby.com - * @copyright Bastian Allgeier - * @license https://opensource.org/licenses/MIT - */ -class Expression -{ - public function __construct( - public array $parts - ) { - } - - /** - * Parses an expression string into its parts - */ - public static function factory(string $expression, Query $parent = null): static|Segments - { - // split into different expression parts and operators - $parts = static::parse($expression); - - // shortcut: if expression has only one part, directly - // continue with the segments chain - if (count($parts) === 1) { - return Segments::factory(query: $parts[0], parent: $parent); - } - - // turn all non-operator parts into an Argument - // which takes care of converting string, arrays booleans etc. - // into actual types and treats all other parts as their own queries - $parts = A::map( - $parts, - fn ($part) => - in_array($part, ['?', ':', '?:', '??']) - ? $part - : Argument::factory($part) - ); - - return new static(parts: $parts); - } - - /** - * Splits a comparison string into an array - * of expressions and operators - * @internal - */ - public static function parse(string $string): array - { - // split by multiples of `?` and `:`, but not inside skip groups - // (parantheses, quotes etc.) - return preg_split( - '/\s+([\?\:]+)\s+|' . Arguments::OUTSIDE . '/', - trim($string), - flags: PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY - ); - } - - /** - * Resolves the expression by evaluating - * the supported comparisons and consecutively - * resolving the resulting query/argument - */ - public function resolve(array|object $data = []): mixed - { - $base = null; - - foreach ($this->parts as $index => $part) { - // `a ?? b` - // if the base/previous (e.g. `a`) isn't null, - // stop the expression chain and return `a` - if ($part === '??') { - if ($base !== null) { - return $base; - } - - continue; - } - - // `a ?: b` - // if `a` isn't false, return `a`, otherwise `b` - if ($part === '?:') { - if ($base != false) { - return $base; - } - - return $this->parts[$index + 1]->resolve($data); - } - - // `a ? b : c` - // if `a` isn't false, return `b`, otherwise `c` - if ($part === '?') { - if (($this->parts[$index + 2] ?? null) !== ':') { - throw new LogicException('Query: Incomplete ternary operator (missing matching `? :`)'); - } - - if ($base != false) { - return $this->parts[$index + 1]->resolve($data); - } - - return $this->parts[$index + 3]->resolve($data); - } - - $base = $part->resolve($data); - } - - return $base; - } -} diff --git a/kirby/src/Query/Query.php b/kirby/src/Query/Query.php deleted file mode 100644 index ab6381c..0000000 --- a/kirby/src/Query/Query.php +++ /dev/null @@ -1,142 +0,0 @@ -, - * Nico Hoffmann - * @link https://getkirby.com - * @copyright Bastian Allgeier - * @license https://opensource.org/licenses/MIT - */ -class Query -{ - /** - * Default data entries - */ - public static array $entries = []; - - /** - * Creates a new Query object - */ - public function __construct( - public string|null $query = null - ) { - if ($query !== null) { - $this->query = trim($query); - } - } - - /** - * Creates a new Query object - */ - public static function factory(string|null $query): static - { - return new static(query: $query); - } - - /** - * Method to help classes that extend Query - * to intercept a segment's result. - */ - public function intercept(mixed $result): mixed - { - return $result; - } - - /** - * Returns the query result if anything - * can be found, otherwise returns null - * - * @throws \Kirby\Exception\BadMethodCallException If an invalid method is accessed by the query - */ - public function resolve(array|object $data = []): mixed - { - if (empty($this->query) === true) { - return $data; - } - - // merge data with default entries - if (is_array($data) === true) { - $data = array_merge(static::$entries, $data); - } - - // direct data array access via key - if ( - is_array($data) === true && - array_key_exists($this->query, $data) === true - ) { - $value = $data[$this->query]; - - if ($value instanceof Closure) { - $value = $value(); - } - - return $value; - } - - // loop through all segments to resolve query - return Expression::factory($this->query, $this)->resolve($data); - } -} - -/** - * Default entries/functions - */ -Query::$entries['kirby'] = function (): App { - return App::instance(); -}; - -Query::$entries['collection'] = function (string $name): Collection|null { - return App::instance()->collection($name); -}; - -Query::$entries['file'] = function (string $id): File|null { - return App::instance()->file($id); -}; - -Query::$entries['page'] = function (string $id): Page|null { - return App::instance()->page($id); -}; - -Query::$entries['qr'] = function (string $data): QrCode { - return new QrCode($data); -}; - -Query::$entries['site'] = function (): Site { - return App::instance()->site(); -}; - -Query::$entries['t'] = function ( - string $key, - string|array $fallback = null, - string $locale = null -): string|null { - return I18n::translate($key, $fallback, $locale); -}; - -Query::$entries['user'] = function (string $id = null): User|null { - return App::instance()->user($id); -}; diff --git a/kirby/src/Query/Segment.php b/kirby/src/Query/Segment.php deleted file mode 100644 index 89e7574..0000000 --- a/kirby/src/Query/Segment.php +++ /dev/null @@ -1,182 +0,0 @@ - - * @link https://getkirby.com - * @copyright Bastian Allgeier - * @license https://opensource.org/licenses/MIT - */ -class Segment -{ - public function __construct( - public string $method, - public int $position, - public Arguments|null $arguments = null, - ) { - } - - /** - * Throws an exception for an access to an invalid method - * @internal - * - * @param mixed $data Variable on which the access was tried - * @param string $name Name of the method/property that was accessed - * @param string $label Type of the name (`method`, `property` or `method/property`) - * - * @throws \Kirby\Exception\BadMethodCallException - */ - public static function error(mixed $data, string $name, string $label): void - { - $type = strtolower(gettype($data)); - - if ($type === 'double') { - $type = 'float'; - } - - $nonExisting = in_array($type, ['array', 'object']) ? 'non-existing ' : ''; - - $error = 'Access to ' . $nonExisting . $label . ' "' . $name . '" on ' . $type; - - throw new BadMethodCallException($error); - } - - /** - * Parses a segment into the property/method name and its arguments - * - * @param int $position String position of the segment inside the full query - */ - public static function factory( - string $segment, - int $position = 0 - ): static { - if (Str::endsWith($segment, ')') === false) { - return new static(method: $segment, position: $position); - } - - // the args are everything inside the *outer* parentheses - $args = Str::substr($segment, Str::position($segment, '(') + 1, -1); - - return new static( - method: Str::before($segment, '('), - position: $position, - arguments: Arguments::factory($args) - ); - } - - /** - * Automatically resolves the segment depending on the - * segment position and the type of the base - * - * @param mixed $base Current value of the query chain - */ - public function resolve(mixed $base = null, array|object $data = []): mixed - { - // resolve arguments to array - $args = $this->arguments?->resolve($data) ?? []; - - // 1st segment, use $data as base - if ($this->position === 0) { - $base = $data; - } - - if (is_array($base) === true) { - return $this->resolveArray($base, $args); - } - - if (is_object($base) === true) { - return $this->resolveObject($base, $args); - } - - // trying to access further segments on a scalar/null value - static::error($base, $this->method, 'method/property'); - } - - /** - * Resolves segment by calling the corresponding array key - */ - protected function resolveArray(array $array, array $args): mixed - { - // the directly provided array takes precedence - // to look up a matching entry - if (array_key_exists($this->method, $array) === true) { - $value = $array[$this->method]; - - // if this is a Closure we can directly use it, as - // Closures from the $array should always have priority - // over the Query::$entries Closures - if ($value instanceof Closure) { - return $value(...$args); - } - - // if we have no arguments to pass, we also can directly - // use the value from the $array as it must not be different - // to the one from Query::$entries with the same name - if ($args === []) { - return $value; - } - } - - // fallback time: only if we are handling the first segment, - // we can also try to resolve the segment with an entry from the - // default Query::$entries - if ($this->position === 0) { - if (array_key_exists($this->method, Query::$entries) === true) { - return Query::$entries[$this->method](...$args); - } - } - - // if we have not been able to return anything so far, - // we just need to differntiate between two different error messages - - // this one is in case the original array contained the key, - // but was not a Closure while the segment had arguments - if ( - array_key_exists($this->method, $array) && - $args !== [] - ) { - throw new InvalidArgumentException('Cannot access array element "' . $this->method . '" with arguments'); - } - - // last, the standard error for trying to access something - // that does not exist - static::error($array, $this->method, 'property'); - } - - /** - * Resolves segment by calling the method/ - * accessing the property on the base object - */ - protected function resolveObject(object $object, array $args): mixed - { - if ( - method_exists($object, $this->method) === true || - method_exists($object, '__call') === true - ) { - return $object->{$this->method}(...$args); - } - - if ( - $args === [] && - ( - property_exists($object, $this->method) === true || - method_exists($object, '__get') === true - ) - ) { - return $object->{$this->method}; - } - - $label = ($args === []) ? 'method/property' : 'method'; - static::error($object, $this->method, $label); - } -} diff --git a/kirby/src/Query/Segments.php b/kirby/src/Query/Segments.php deleted file mode 100644 index d2af470..0000000 --- a/kirby/src/Query/Segments.php +++ /dev/null @@ -1,100 +0,0 @@ - - * @link https://getkirby.com - * @copyright Bastian Allgeier - * @license https://opensource.org/licenses/MIT - */ -class Segments extends Collection -{ - public function __construct( - array $data = [], - protected Query|null $parent = null, - ) { - parent::__construct($data); - } - - /** - * Split query string into segments by dot - * but not inside (nested) parens - */ - public static function factory(string $query, Query $parent = null): static - { - $segments = static::parse($query); - $position = 0; - - $segments = A::map( - $segments, - function ($segment) use (&$position) { - // leave connectors as they are - if (in_array($segment, ['.', '?.']) === true) { - return $segment; - } - - // turn all other parts into Segment objects - // and pass their position in the chain (ignoring connectors) - $position++; - return Segment::factory($segment, $position - 1); - } - ); - - return new static($segments, $parent); - } - - /** - * Splits the string of a segment chaing into an - * array of segments as well as conenctors (`.` or `?.`) - * @internal - */ - public static function parse(string $string): array - { - return preg_split( - '/(\??\.)|(\(([^()]+|(?2))*+\))(*SKIP)(*FAIL)/', - trim($string), - flags: PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY - ); - } - - /** - * Resolves the segments chain by looping through - * each segment call to be applied to the value of - * all previous segment calls, returning gracefully at - * `?.` when current value is `null` - */ - public function resolve(array|object $data = []) - { - $value = null; - - foreach ($this->data as $segment) { - // optional chaining: stop if current value is null - if ($segment === '?.' && $value === null) { - return null; - } - - // for regular connectors and optional chaining on non-null, - // just skip this connecting segment - if ($segment === '.' || $segment === '?.') { - continue; - } - - // offer possibility to intercept on objects - if ($value !== null) { - $value = $this->parent?->intercept($value) ?? $value; - } - - $value = $segment->resolve($value, $data); - } - - return $value; - } -} diff --git a/kirby/src/Sane/DomHandler.php b/kirby/src/Sane/DomHandler.php index 2fe2e09..810a1ce 100644 --- a/kirby/src/Sane/DomHandler.php +++ b/kirby/src/Sane/DomHandler.php @@ -16,16 +16,16 @@ use Kirby\Toolkit\Dom; * @link https://getkirby.com * @copyright Bastian Allgeier * @license https://opensource.org/licenses/MIT - * - * @SuppressWarnings(PHPMD.LongVariable) */ class DomHandler extends Handler { /** * List of all MIME types that may * be used in data URIs + * + * @var array */ - public static array $allowedDataUris = [ + public static $allowedDataUris = [ 'data:image/png', 'data:image/gif', 'data:image/jpg', @@ -41,59 +41,55 @@ class DomHandler extends Handler /** * Allowed hostnames for HTTP(S) URLs * - * @var array|true + * @var array */ - public static array|bool $allowedDomains = true; - - /** - * Whether URLs that begin with `/` should be allowed even if the - * site index URL is in a subfolder (useful when using the HTML - * `` element where the sanitized code will be rendered) - */ - public static bool $allowHostRelativeUrls = true; + public static $allowedDomains = []; /** * Names of allowed XML processing instructions + * + * @var array */ - public static array $allowedPIs = []; + public static $allowedPIs = []; /** * The document type (`'HTML'` or `'XML'`) * (to be set in child classes) + * + * @var string */ - protected static string $type = 'XML'; + protected static $type = 'XML'; /** * Sanitizes the given string * - * @param bool $isExternal Whether the string is from an external file - * that may be accessed directly + * @param string $string + * @return string * * @throws \Kirby\Exception\InvalidArgumentException If the file couldn't be parsed */ - public static function sanitize(string $string, bool $isExternal = false): string + public static function sanitize(string $string): string { $dom = static::parse($string); - $dom->sanitize(static::options($isExternal)); + $dom->sanitize(static::options()); return $dom->toString(); } /** * Validates file contents * - * @param bool $isExternal Whether the string is from an external file - * that may be accessed directly + * @param string $string + * @return void * * @throws \Kirby\Exception\InvalidArgumentException If the file couldn't be parsed * @throws \Kirby\Exception\InvalidArgumentException If the file didn't pass validation */ - public static function validate(string $string, bool $isExternal = false): void + public static function validate(string $string): void { - $dom = static::parse($string); - $errors = $dom->sanitize(static::options($isExternal)); - - // there may be multiple errors, we can only throw one of them at a time + $dom = static::parse($string); + $errors = $dom->sanitize(static::options()); if (count($errors) > 0) { + // there may be multiple errors, we can only throw one of them at a time throw $errors[0]; } } @@ -102,9 +98,10 @@ class DomHandler extends Handler * Custom callback for additional attribute sanitization * @internal * + * @param \DOMAttr $attr * @return array Array with exception objects for each modification */ - public static function sanitizeAttr(DOMAttr $attr, array $options): array + public static function sanitizeAttr(DOMAttr $attr): array { // to be extended in child classes return []; @@ -114,9 +111,10 @@ class DomHandler extends Handler * Custom callback for additional element sanitization * @internal * + * @param \DOMElement $element * @return array Array with exception objects for each modification */ - public static function sanitizeElement(DOMElement $element, array $options): array + public static function sanitizeElement(DOMElement $element): array { // to be extended in child classes return []; @@ -125,8 +123,11 @@ class DomHandler extends Handler /** * Custom callback for additional doctype validation * @internal + * + * @param \DOMDocumentType $doctype + * @return void */ - public static function validateDoctype(DOMDocumentType $doctype, array $options): void + public static function validateDoctype(DOMDocumentType $doctype): void { // to be extended in child classes } @@ -135,36 +136,29 @@ class DomHandler extends Handler * Returns the sanitization options for the handler * (to be extended in child classes) * - * @param bool $isExternal Whether the string is from an external file - * that may be accessed directly + * @return array */ - protected static function options(bool $isExternal): array + protected static function options(): array { - $options = [ - 'allowedDataUris' => static::$allowedDataUris, - 'allowedDomains' => static::$allowedDomains, - 'allowHostRelativeUrls' => static::$allowHostRelativeUrls, - 'allowedPIs' => static::$allowedPIs, - 'attrCallback' => [static::class, 'sanitizeAttr'], - 'doctypeCallback' => [static::class, 'validateDoctype'], - 'elementCallback' => [static::class, 'sanitizeElement'], + return [ + 'allowedDataUris' => static::$allowedDataUris, + 'allowedDomains' => static::$allowedDomains, + 'allowedPIs' => static::$allowedPIs, + 'attrCallback' => [static::class, 'sanitizeAttr'], + 'doctypeCallback' => [static::class, 'validateDoctype'], + 'elementCallback' => [static::class, 'sanitizeElement'], ]; - - // never allow host-relative URLs in external files as we - // cannot set a `` element for them when accessed directly - if ($isExternal === true) { - $options['allowHostRelativeUrls'] = false; - } - - return $options; } /** * Parses the given string into a `Toolkit\Dom` object * + * @param string $string + * @return \Kirby\Toolkit\Dom + * * @throws \Kirby\Exception\InvalidArgumentException If the file couldn't be parsed */ - protected static function parse(string $string): Dom + protected static function parse(string $string) { return new Dom($string, static::$type); } diff --git a/kirby/src/Sane/Handler.php b/kirby/src/Sane/Handler.php index 7dfcd98..c66bc98 100644 --- a/kirby/src/Sane/Handler.php +++ b/kirby/src/Sane/Handler.php @@ -22,53 +22,60 @@ abstract class Handler /** * Sanitizes the given string * - * @param bool $isExternal Whether the string is from an external file - * that may be accessed directly + * @param string $string + * @return string */ - abstract public static function sanitize(string $string, bool $isExternal = false): string; + abstract public static function sanitize(string $string): string; /** * Sanitizes the contents of a file by overwriting * the file with the sanitized version * + * @param string $file + * @return void + * * @throws \Kirby\Exception\Exception If the file does not exist * @throws \Kirby\Exception\Exception On other errors */ public static function sanitizeFile(string $file): void { - $content = static::readFile($file); - $sanitized = static::sanitize($content, isExternal: true); + $sanitized = static::sanitize(static::readFile($file)); F::write($file, $sanitized); } /** * Validates file contents * - * @param bool $isExternal Whether the string is from an external file - * that may be accessed directly + * @param string $string + * @return void * * @throws \Kirby\Exception\InvalidArgumentException If the file didn't pass validation * @throws \Kirby\Exception\Exception On other errors */ - abstract public static function validate(string $string, bool $isExternal = false): void; + abstract public static function validate(string $string): void; /** * Validates the contents of a file * + * @param string $file + * @return void + * * @throws \Kirby\Exception\InvalidArgumentException If the file didn't pass validation * @throws \Kirby\Exception\Exception If the file does not exist * @throws \Kirby\Exception\Exception On other errors */ public static function validateFile(string $file): void { - $content = static::readFile($file); - static::validate($content, isExternal: true); + static::validate(static::readFile($file)); } /** * Reads the contents of a file * for sanitization or validation * + * @param string $file + * @return string + * * @throws \Kirby\Exception\Exception If the file does not exist */ protected static function readFile(string $file): string diff --git a/kirby/src/Sane/Html.php b/kirby/src/Sane/Html.php index 0766e36..99823e5 100644 --- a/kirby/src/Sane/Html.php +++ b/kirby/src/Sane/Html.php @@ -17,28 +17,41 @@ class Html extends DomHandler { /** * Global list of allowed attribute prefixes + * + * @var array */ - public static array $allowedAttrPrefixes = [ + public static $allowedAttrPrefixes = [ 'aria-', 'data-', ]; /** * Global list of allowed attributes + * + * @var array */ - public static array $allowedAttrs = [ + public static $allowedAttrs = [ 'class', 'id', ]; + /** + * Allowed hostnames for HTTP(S) URLs + * + * @var array + */ + public static $allowedDomains = true; + /** * Associative array of all allowed tag names with the value * of either an array with the list of all allowed attributes * for this tag, `true` to allow any attribute from the * `allowedAttrs` list or `false` to allow the tag without * any attributes + * + * @var array */ - public static array $allowedTags = [ + public static $allowedTags = [ 'a' => ['href', 'rel', 'title', 'target'], 'abbr' => ['title'], 'b' => true, @@ -82,8 +95,10 @@ class Html extends DomHandler * * IMPORTANT: Use lower-case names here because * of the case-insensitive matching + * + * @var array */ - public static array $disallowedTags = [ + public static $disallowedTags = [ 'iframe', 'meta', 'object', @@ -93,8 +108,10 @@ class Html extends DomHandler /** * List of attributes that may contain URLs + * + * @var array */ - public static array $urlAttrs = [ + public static $urlAttrs = [ 'href', 'src', 'xlink:href', @@ -102,18 +119,19 @@ class Html extends DomHandler /** * The document type (`'HTML'` or `'XML'`) + * + * @var string */ - protected static string $type = 'HTML'; + protected static $type = 'HTML'; /** * Returns the sanitization options for the handler * - * @param bool $isExternal Whether the string is from an external file - * that may be accessed directly + * @return array */ - protected static function options(bool $isExternal): array + protected static function options(): array { - return array_merge(parent::options($isExternal), [ + return array_merge(parent::options(), [ 'allowedAttrPrefixes' => static::$allowedAttrPrefixes, 'allowedAttrs' => static::$allowedAttrs, 'allowedNamespaces' => [], diff --git a/kirby/src/Sane/Sane.php b/kirby/src/Sane/Sane.php index c079e2a..5a55ae0 100644 --- a/kirby/src/Sane/Sane.php +++ b/kirby/src/Sane/Sane.php @@ -23,8 +23,10 @@ class Sane { /** * Handler Type Aliases + * + * @var array */ - public static array $aliases = [ + public static $aliases = [ 'application/xml' => 'xml', 'image/svg' => 'svg', 'image/svg+xml' => 'svg', @@ -34,34 +36,34 @@ class Sane /** * All registered handlers + * + * @var array */ - public static array $handlers = [ - 'html' => Html::class, - 'svg' => Svg::class, - 'svgz' => Svgz::class, - 'xml' => Xml::class, + public static $handlers = [ + 'html' => 'Kirby\Sane\Html', + 'svg' => 'Kirby\Sane\Svg', + 'svgz' => 'Kirby\Sane\Svgz', + 'xml' => 'Kirby\Sane\Xml', ]; /** * Handler getter * + * @param string $type * @param bool $lazy If set to `true`, `null` is returned for undefined handlers + * @return \Kirby\Sane\Handler|null * * @throws \Kirby\Exception\NotFoundException If no handler was found and `$lazy` was set to `false` */ - public static function handler( - string $type, - bool $lazy = false - ): Handler|null { + public static function handler(string $type, bool $lazy = false) + { // normalize the type $type = mb_strtolower($type); // find a handler or alias - $handler = static::$handlers[$type] ?? null; - - if ($alias = static::$aliases[$type] ?? null) { - $handler ??= static::$handlers[$alias] ?? null; - } + $handler = static::$handlers[$type] ?? + static::$handlers[static::$aliases[$type] ?? null] ?? + null; if (empty($handler) === false && class_exists($handler) === true) { return new $handler(); @@ -78,12 +80,13 @@ class Sane * Sanitizes the given string with the specified handler * @since 3.6.0 * - * @param bool $isExternal Whether the string is from an external file - * that may be accessed directly + * @param string $string + * @param string $type + * @return string */ - public static function sanitize(string $string, string $type, bool $isExternal = false): string + public static function sanitize(string $string, string $type): string { - return static::handler($type)->sanitize($string, $isExternal); + return static::handler($type)->sanitize($string); } /** @@ -93,19 +96,19 @@ class Sane * the extension and MIME type if not specified * @since 3.6.0 * + * @param string $file * @param string|bool $typeLazy Explicit handler type string, * `true` for lazy autodetection or * `false` for normal autodetection + * @return void * * @throws \Kirby\Exception\InvalidArgumentException If the file didn't pass validation * @throws \Kirby\Exception\LogicException If more than one handler applies * @throws \Kirby\Exception\NotFoundException If the handler was not found * @throws \Kirby\Exception\Exception On other errors */ - public static function sanitizeFile( - string $file, - string|bool $typeLazy = false - ): void { + public static function sanitizeFile(string $file, $typeLazy = false): void + { if (is_string($typeLazy) === true) { static::handler($typeLazy)->sanitizeFile($file); return; @@ -134,16 +137,17 @@ class Sane /** * Validates file contents with the specified handler * - * @param bool $isExternal Whether the string is from an external file - * that may be accessed directly + * @param string $string + * @param string $type + * @return void * * @throws \Kirby\Exception\InvalidArgumentException If the file didn't pass validation * @throws \Kirby\Exception\NotFoundException If the handler was not found * @throws \Kirby\Exception\Exception On other errors */ - public static function validate(string $string, string $type, bool $isExternal = false): void + public static function validate(string $string, string $type): void { - static::handler($type)->validate($string, $isExternal); + static::handler($type)->validate($string); } /** @@ -151,26 +155,24 @@ class Sane * the sane handlers are automatically chosen by * the extension and MIME type if not specified * + * @param string $file * @param string|bool $typeLazy Explicit handler type string, * `true` for lazy autodetection or * `false` for normal autodetection + * @return void * * @throws \Kirby\Exception\InvalidArgumentException If the file didn't pass validation * @throws \Kirby\Exception\NotFoundException If the handler was not found * @throws \Kirby\Exception\Exception On other errors */ - public static function validateFile( - string $file, - string|bool $typeLazy = false - ): void { + public static function validateFile(string $file, $typeLazy = false): void + { if (is_string($typeLazy) === true) { static::handler($typeLazy)->validateFile($file); return; } - $handlers = static::handlersForFile($file, $typeLazy === true); - - foreach ($handlers as $handler) { + foreach (static::handlersForFile($file, $typeLazy === true) as $handler) { $handler->validateFile($file); } } @@ -179,13 +181,12 @@ class Sane * Returns all handler objects that apply to the given file based on * file extension and MIME type * + * @param string $file * @param bool $lazy If set to `true`, undefined handlers are skipped * @return array<\Kirby\Sane\Handler> */ - protected static function handlersForFile( - string $file, - bool $lazy = false - ): array { + protected static function handlersForFile(string $file, bool $lazy = false): array + { $handlers = $handlerClasses = []; // all values that can be used for the handler search; @@ -197,10 +198,7 @@ class Sane $handlerClass = $handler ? get_class($handler) : null; // ensure that each handler class is only returned once - if ( - $handler && - in_array($handlerClass, $handlerClasses) === false - ) { + if ($handler && in_array($handlerClass, $handlerClasses) === false) { $handlers[] = $handler; $handlerClasses[] = $handlerClass; } diff --git a/kirby/src/Sane/Svg.php b/kirby/src/Sane/Svg.php index 1a947ec..d8d8604 100644 --- a/kirby/src/Sane/Svg.php +++ b/kirby/src/Sane/Svg.php @@ -33,16 +33,20 @@ class Svg extends Xml /** * Global list of allowed attribute prefixes + * + * @var array */ - public static array $allowedAttrPrefixes = [ + public static $allowedAttrPrefixes = [ 'aria-', 'data-', ]; /** * Global list of allowed attributes + * + * @var array */ - public static array $allowedAttrs = [ + public static $allowedAttrs = [ // core attributes 'id', 'lang', @@ -262,17 +266,12 @@ class Svg extends Xml 'zoomAndPan', ]; - /** - * Allowed hostnames for HTTP(S) URLs - * - * @var array|true - */ - public static array|bool $allowedDomains = []; - /** * Associative array of all allowed namespace URIs + * + * @var array */ - public static array $allowedNamespaces = [ + public static $allowedNamespaces = [ '' => 'http://www.w3.org/2000/svg', 'xlink' => 'http://www.w3.org/1999/xlink' ]; @@ -283,8 +282,10 @@ class Svg extends Xml * for this tag, `true` to allow any attribute from the * `allowedAttrs` list or `false` to allow the tag without * any attributes + * + * @var array */ - public static array $allowedTags = [ + public static $allowedTags = [ 'a' => true, 'altGlyph' => true, 'altGlyphDef' => true, @@ -359,8 +360,10 @@ class Svg extends Xml * * IMPORTANT: Use lower-case names here because * of the case-insensitive matching + * + * @var array */ - public static array $disallowedTags = [ + public static $disallowedTags = [ 'animate', 'color-profile', 'cursor', @@ -390,9 +393,10 @@ class Svg extends Xml * Custom callback for additional attribute sanitization * @internal * + * @param \DOMAttr $attr * @return array Array with exception objects for each modification */ - public static function sanitizeAttr(DOMAttr $attr, array $options): array + public static function sanitizeAttr(DOMAttr $attr): array { $element = $attr->ownerElement; $name = $attr->name; @@ -406,13 +410,12 @@ class Svg extends Xml Str::startsWith($value, '#') === true ) { // find the target (used element) - $id = str_replace('"', '', mb_substr($value, 1)); - $path = new DOMXPath($attr->ownerDocument); - $target = $path->query('//*[@id="' . $id . '"]')->item(0); + $id = str_replace('"', '', mb_substr($value, 1)); + $target = (new DOMXPath($attr->ownerDocument))->query('//*[@id="' . $id . '"]')->item(0); // the target must not contain any other elements if ( - $target instanceof DOMElement && + is_a($target, 'DOMElement') === true && $target->getElementsByTagName('use')->count() > 0 ) { $errors[] = new InvalidArgumentException( @@ -430,16 +433,17 @@ class Svg extends Xml * Custom callback for additional element sanitization * @internal * + * @param \DOMElement $element * @return array Array with exception objects for each modification */ - public static function sanitizeElement(DOMElement $element, array $options): array + public static function sanitizeElement(DOMElement $element): array { $errors = []; // check for URLs inside * * text + * + * @param string $string + * @return string */ - public static function css(string $string): string + public static function css($string) { return static::escaper()->escapeCss($string); } /** * Get the escaper instance (and create if needed) + * + * @return \Laminas\Escaper\Escaper */ - protected static function escaper(): Escaper + protected static function escaper() { return static::$escaper ??= new Escaper('utf-8'); } @@ -85,8 +95,11 @@ class Escape * * ...ESCAPE UNTRUSTED DATA BEFORE PUTTING HERE... *
      ...ESCAPE UNTRUSTED DATA BEFORE PUTTING HERE...
      + * + * @param string $string + * @return string */ - public static function html(string $string): string + public static function html($string) { return static::escaper()->escapeHtml($string); } @@ -100,8 +113,11 @@ class Escape * * *
      + * + * @param string $string + * @return string */ - public static function js(string $string): string + public static function js($string) { return static::escaper()->escapeJs($string); } @@ -113,8 +129,11 @@ class Escape * This should not be used to escape an entire URI. * * link + * + * @param string $string + * @return string */ - public static function url(string $string): string + public static function url($string) { return rawurlencode($string); } @@ -132,8 +151,11 @@ class Escape * & is replaced with & * < is replaced with < * > is replaced with > + * + * @param string $string + * @return string */ - public static function xml(string $string): string + public static function xml($string) { return htmlspecialchars($string, ENT_QUOTES | ENT_XML1, 'UTF-8'); } diff --git a/kirby/src/Toolkit/Facade.php b/kirby/src/Toolkit/Facade.php index b1547ec..bf72974 100644 --- a/kirby/src/Toolkit/Facade.php +++ b/kirby/src/Toolkit/Facade.php @@ -17,11 +17,17 @@ abstract class Facade /** * Returns the instance that should be * available statically + * + * @return mixed */ abstract public static function instance(); /** * Proxy for all public instance calls + * + * @param string $method + * @param array $args + * @return mixed */ public static function __callStatic(string $method, array $args = null) { diff --git a/kirby/src/Toolkit/Html.php b/kirby/src/Toolkit/Html.php index 56c4ed8..c8c30d7 100644 --- a/kirby/src/Toolkit/Html.php +++ b/kirby/src/Toolkit/Html.php @@ -19,13 +19,17 @@ class Html extends Xml { /** * An internal store for an HTML entities translation table + * + * @var array */ - public static array|null $entities = null; + public static $entities; /** * List of HTML tags that can be used inline + * + * @var array */ - public static array $inlineList = [ + public static $inlineList = [ 'b', 'i', 'small', @@ -90,11 +94,10 @@ class Html extends Xml * * @param string $tag Tag name * @param array $arguments Further arguments for the Html::tag() method + * @return string */ - public static function __callStatic( - string $tag, - array $arguments = [] - ): string { + public static function __callStatic(string $tag, array $arguments = []): string + { if (static::isVoid($tag) === true) { return static::tag($tag, null, ...$arguments); } @@ -134,22 +137,13 @@ class Html extends Xml * @param string|null $after An optional string that will be appended if the result is not empty * @return string|null The generated HTML attributes string */ - public static function attr( - string|array $name, - $value = null, - string|null $before = null, - string|null $after = null - ): string|null { + public static function attr($name, $value = null, ?string $before = null, ?string $after = null): ?string + { // HTML supports boolean attributes without values if (is_array($name) === false && is_bool($value) === true) { return $value === true ? strtolower($name) : null; } - // HTML attribute names are case-insensitive - if (is_string($name) === true) { - $name = strtolower($name); - } - // all other cases can share the XML variant $attr = parent::attr($name, $value); @@ -172,6 +166,9 @@ class Html extends Xml /** * Converts lines in a string into HTML breaks + * + * @param string $string + * @return string */ public static function breaks(string $string): string { @@ -186,11 +183,8 @@ class Html extends Xml * @param array $attr Additional attributes for the tag * @return string The generated HTML */ - public static function email( - string $email, - string|array|null $text = null, - array $attr = [] - ): string { + public static function email(string $email, $text = null, array $attr = []): string + { if (empty($email) === true) { return ''; } @@ -219,15 +213,14 @@ class Html extends Xml /** * Converts a string to an HTML-safe string * + * @param string|null $string * @param bool $keepTags If true, existing tags won't be escaped * @return string The HTML string * * @psalm-suppress ParamNameMismatch */ - public static function encode( - string|null $string, - bool $keepTags = false - ): string { + public static function encode(?string $string, bool $keepTags = false): string + { if ($string === null) { return ''; } @@ -247,6 +240,8 @@ class Html extends Xml /** * Returns the entity translation table + * + * @return array */ public static function entities(): array { @@ -261,11 +256,8 @@ class Html extends Xml * @param array $attr Additional attributes for the `
      ` tag * @return string The generated HTML */ - public static function figure( - string|array $content, - string|array|null $caption = '', - array $attr = [] - ): string { + public static function figure($content, $caption = '', array $attr = []): string + { if ($caption) { $figcaption = static::tag('figcaption', $caption); @@ -287,15 +279,12 @@ class Html extends Xml * @param array $attr Additional attributes for the ` $js): ?> diff --git a/site/blueprints/fields/block_settings.yml b/site/blueprints/fields/block_settings.yml index b797573..0d1c2f5 100644 --- a/site/blueprints/fields/block_settings.yml +++ b/site/blueprints/fields/block_settings.yml @@ -1,8 +1,7 @@ fields: background: label: Hintergrund - type: color - mode: options + type: color-palette options: - "#f1edeb" - "#ff00ff" @@ -12,8 +11,7 @@ fields: - "#000000" grid: label: Raster - type: color - mode: options + type: color-palette options: - "#f1edeb" - "#ff00ff" diff --git a/site/blueprints/pages/default.yml b/site/blueprints/pages/default.yml index e1663a0..e0fa632 100644 --- a/site/blueprints/pages/default.yml +++ b/site/blueprints/pages/default.yml @@ -6,7 +6,6 @@ status: columns: main: - width: 2/3 sections: fields: type: fields diff --git a/site/plugins/color-palette/.editorconfig b/site/plugins/color-palette/.editorconfig new file mode 100644 index 0000000..edb33ca --- /dev/null +++ b/site/plugins/color-palette/.editorconfig @@ -0,0 +1,9 @@ +root = true + +[*] +indent_style = space +indent_size = 4 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true \ No newline at end of file diff --git a/site/plugins/color-palette/.gitignore b/site/plugins/color-palette/.gitignore new file mode 100644 index 0000000..217298e --- /dev/null +++ b/site/plugins/color-palette/.gitignore @@ -0,0 +1,3 @@ +.cache +node_modules +package-lock.json diff --git a/site/plugins/color-palette/README.md b/site/plugins/color-palette/README.md new file mode 100644 index 0000000..c06b092 --- /dev/null +++ b/site/plugins/color-palette/README.md @@ -0,0 +1,301 @@ +# Kirby Color-Palette + +A color palette displayed in the panel, helping you pick predefined colors / palettes. + +![screenshot-palette-cursor](https://user-images.githubusercontent.com/14079751/47902848-12a9cc80-de83-11e8-92ea-cabf5031b355.jpg) + +
      + +## Overview + +> This plugin is completely free and published under the MIT license. However, if you are using it in a commercial project and want to help me keep up with maintenance, please consider [making a donation of your choice](https://www.paypal.me/sylvainjule) or purchasing your license(s) through [my affiliate link](https://a.paddle.com/v2/click/1129/36369?link=1170). + +- [1. Installation](#1-installation) +- [2. Setup](#2-setup) +- [3. Configuration](#3-configuration) +- [4. Extract palette from an image](#4-extract-palette-from-an-image) +- [5. Template usage](#5-template-usage) +- [6. License](#6-license) +- [7. Credits](#7-credits) + +
      + +## 1. Installation + +Download and copy this repository to ```/site/plugins/color-palette``` + +Alternatively, you can install it with composer: ```composer require sylvainjule/color-palette``` + +
      + +## 2. Setup + +A basic setup looks like this: + +```yaml +palette: + label: Pick a color + type: color-palette + options: + - '#135fdc' + - '#f6917e' + - '#6a96e4' + - ... +``` + +Note that you can fill it with any CSS-valid color: + +```yaml +- '#ffffff' +- rgba(255, 255, 255, 0.5) +- rgb(255, 255, 255) +- white +``` + +## 3. Configuration + +#### 3.1. `options` (required) + +The plugin accepts both an array or a structured object. + +##### • Simple colors + +```yaml +palette: + type: color-palette + options: + - '#135fdc' + - '#f6917e' + - '#6a96e4' + - ... +``` + +##### • Structured color themes + +The field will use the first color of the object as the background-color. + +```yaml +palette: + type: color-palette + options: + blue: + background: '#135fdc' + border: '#0438c7' + text: white + orange: + background: '#f6917e' + border: '#ef6a57' + text: white + ... +``` + +You can add tooltips to structured colors: any color with the `tooltip` key will show a tooltip on hover. + +```yaml +... + options: + blue: + background: '#135fdc' + tooltip: This is a tooltip + ... +``` + +![screenshot-tooltip](https://user-images.githubusercontent.com/14079751/70157500-fbf12d00-16b5-11ea-8572-4877dbcb32e5.jpg) + + +##### • Dynamic options + +You can set dynamic options / query your options from a different field. Just make sure the `value` returns a CSS-valid color. + +For example with a structure field: + +```yaml +palette: + type: color-palette + options: query + query: + fetch: page.mycolors.toStructure + value: "{{ structureItem.color }}" + +... + +mycolors: + type: structure + fields: + color: + type: text +``` + + + +#### 3.2. `display` + +![screenshot-display](https://user-images.githubusercontent.com/14079751/47905300-117a9e80-de87-11e8-8853-5b328b993439.jpg) + +The display style of the color blocks, to pick from `single` or `duo` . Default is `single`. + +If the selected style is `duo` and the options are structured color themes, the field will use the first color of the object as the left color, and the second as the right color. + +```yaml +palette: + type: color-palette + display: single +``` + +#### 3.3. `size` + +![screenshot-size](https://user-images.githubusercontent.com/14079751/47905301-12133500-de87-11e8-85f2-6ab680cab91d.jpg) + +The size of the color blocks, to pick from `small`, `medium` or `large`. Default is `medium`. + +```yaml +palette: + type: color-palette + size: medium +``` + +#### 3.4. `unselect` + +If set to `true`, selected colors can be unselected. Default is `false`. + +```yaml +palette: + type: color-palette + unselect: false +``` + +#### 3.5. `default` + +The default value to be used if the field has no set value. Will be ignored if it doesn't match an option. Default is `false`. + +```yaml +#simple colors +palette: + type: color-palette + default: '#135fdc' + options: + - '#135fdc' + - '#f6917e' + +# structured colors +palette: + type: color-palette + default: blue + options: + blue: + background: '#135fdc' + border: '#0438c7' + orange: + background: '#f6917e' + border: '#ef6a57' +``` + +
      + +## 4. Extract palette from an image + +#### 4.1. Select manually which image to extract colors from + +You can extract a color palette from a page's image file by activating the `extractor` option. It will override the manual options, if specified. Default is `false`. + +```yaml +palette: + type: color-palette + extractor: true + # no need for options anymore +``` + +You can restrict the choices to a specific file template with the `template` option: + +```yaml +palette: + type: color-palette + extractor: true + template: cover +``` + +#### 4.2. Automatically extract colors when an image matches a template + +Alternatively, you can make use of the `autotemplate` option (do not add the above `extractor` option in this case). + +If the page has at least 1 image matching the given template (if 2+ are found, the field will use the first one), options will automatically be extracted from it on load. + +Note that **there is no realtime-sync**, the page needs to be reloaded in order for the plugin to detect a newly added image. The best way of achieving this without having to manually refresh the page is to place this field and the files section under two different tabs. + +```yaml +palette: + type: color-palette + autotemplate: cover + # no need for options anymore +``` + +#### 4.3. Limit + +In both cases, the maximum number of extracted colors can be set with the `limit` option. Default is `10`. + +```yaml +palette: + type: color-palette + extractor: true + limit: 10 +``` + +
      + +## 5. Template usage + +#### 5.1. If `options` is an array of simple colors + +The field will only store the selected color. + +```php +$selected = $page->palette(); #(Field object) +$selected = $selected->value(); #(string) +``` + +#### 5.2. If `options` is a structured color object + +The field will need to be decoded with the `yaml` method. For example, if your options look like this: + +```yaml +options: + blue: + background: '#135fdc' + border: '#0438c7' +``` + +Here's how to get the selected color: + +```php +$palette = $page->palette()->yaml(); +$background = $palette['background']; #(string) +$border = $palette['border']; #(string) +``` + +Note that in this case, the plugin automatically adds the key of the selected color, in case you'd want it to deal with custom classes, etc. + +```php +$border = $palette['key']; #(string) +``` + +#### 5.3. If the palette has been extracted from an image + +Both the selected color and the extracted palette are stored. The value of the field is an array you'll need to decode with the `yaml` method: + +```php +$palette = $page->palette()->yaml(); +$selected = $palette[0]; #selected color (string) +$palette = $palette[1]; #extracted palette (array) +``` + +
      + +## 6. License + +MIT + +
      + +## 7. Credits + +- K2 version: [Color list](https://github.com/Thiousi/kirby-color-list) by [@Thiousi](https://github.com/Thiousi) diff --git a/site/plugins/color-palette/composer.json b/site/plugins/color-palette/composer.json new file mode 100644 index 0000000..0d0833c --- /dev/null +++ b/site/plugins/color-palette/composer.json @@ -0,0 +1,19 @@ +{ + "name": "sylvainjule/color-palette", + "description": "A color palette to pick colors from for Kirby", + "type": "kirby-plugin", + "license": "MIT", + "authors": [ + { + "name": "Sylvain Julé", + "email": "contact@sylvain-jule.fr" + } + ], + "require": { + "getkirby/composer-installer": "^1.1" + }, + "extra": { + "installer-name": "color-palette" + }, + "minimum-stability": "beta" +} diff --git a/site/plugins/color-palette/index.css b/site/plugins/color-palette/index.css new file mode 100644 index 0000000..5ada79b --- /dev/null +++ b/site/plugins/color-palette/index.css @@ -0,0 +1 @@ +@charset "UTF-8";.k-color-palette-field .k-button{cursor:pointer}.k-color-palette-field .k-button-figure .k-icon{margin-right:-4px}.color-palette_input-list{display:flex;flex-wrap:wrap;padding:.75rem .75rem calc(.75rem - 6px);background:#eaeaea}.color-palette_input-list li{position:relative;transition:transform .3s ease-out;margin-bottom:6px;border:4px solid transparent}.color-palette_input-list li.small{width:28px;height:28px}.color-palette_input-list li.medium{width:38px;height:38px}.color-palette_input-list li.large{width:48px;height:48px}.color-palette_input-list li:not(:last-child){margin-right:6px}.color-palette_input-list li.active{pointer-events:none;border:4px solid #fff;outline:1px solid #ccc}.color-palette_input-list li.active.unselect{pointer-events:auto;cursor:pointer}.color-palette_input-list li:not(.active){cursor:pointer}.color-palette_input-color{width:100%;height:100%}.color-palette_input-color[data-tooltip]{position:relative;z-index:2;cursor:pointer}.color-palette_input-color[data-tooltip]:after,.color-palette_input-color[data-tooltip]:before{visibility:hidden;pointer-events:none}.color-palette_input-color[data-tooltip]:before{position:absolute;bottom:120%;left:50%;transform:translate(-50%);margin-bottom:5px;padding:7px 12px;width:auto;background-color:#000;color:#fff;content:attr(data-tooltip);text-align:center;font-size:14px;line-height:16px;white-space:pre}.color-palette_input-color[data-tooltip]:after{position:absolute;bottom:120%;left:50%;margin-left:-5px;width:0;border-top:5px solid #000;border-right:5px solid transparent;border-left:5px solid transparent;content:"";font-size:0;line-height:0}.color-palette_input-color[data-tooltip]:hover:after,.color-palette_input-color[data-tooltip]:hover:before{visibility:visible}.color-palette_empty-palette{padding:0;display:flex;align-items:center;flex-direction:row;justify-content:flex-start}.color-palette_empty-palette .k-icon{border-right:1px solid #d6d6d6;margin-bottom:0;display:flex;justify-content:center;align-items:center}.color-palette_empty-palette .k-icon svg{width:14px}.color-palette_empty-palette p{line-height:1.25rem;text-align:left}.color-palette_empty-palette.small .k-icon{width:calc(28px + 1.5rem);height:calc(28px + 1.5rem)}.color-palette_empty-palette.small p{padding:.75rem 1rem}.color-palette_empty-palette.medium .k-icon{width:calc(38px + 1.5rem);height:calc(38px + 1.5rem)}.color-palette_empty-palette.medium p{padding:.75rem 1.25rem}.color-palette_empty-palette.large .k-icon{width:calc(48px + 1.5rem);height:calc(48px + 1.5rem)}.color-palette_empty-palette.large p{padding:.75rem 1.75rem}.color-palette_empty-loading{padding:.75rem;background:#eaeaea}.color-palette_empty-loading .loader-ctn{display:flex;justify-content:center;align-items:center}.color-palette_empty-loading .loader-ctn.small{height:28px}.color-palette_empty-loading .loader-ctn.medium{height:38px}.color-palette_empty-loading .loader-ctn.large{height:48px}.color-palette_empty-loading .loader-ctn .loader{display:inline-block;overflow:hidden;height:1.3em;margin-top:-.3em;line-height:1.5em;vertical-align:text-bottom}.color-palette_empty-loading .loader-ctn .loader:after{content:"⠋\a⠙\a⠹\a⠸\a⠼\a⠴\a⠦\a⠧\a⠇\a⠏";display:inline-table;white-space:pre;text-align:left;animation:spin10 .8s steps(10) infinite}@keyframes spin10{to{transform:translateY(-15em)}} \ No newline at end of file diff --git a/site/plugins/color-palette/index.js b/site/plugins/color-palette/index.js new file mode 100644 index 0000000..9b6dee0 --- /dev/null +++ b/site/plugins/color-palette/index.js @@ -0,0 +1 @@ +(function () {function b(t){return(b="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}var a={data:function(){return{loading:!1,palette:[]}},props:{options:[Object,Array],display:String,size:String,unselect:Boolean,default:[String,Boolean],extractor:Boolean,limit:Number,uri:String,endpoints:Object,autotemplate:String,template:String,label:String,disabled:Boolean,help:String,parent:String,value:[String,Array],name:[String,Number],required:Boolean,type:String},computed:{selected:function(){return Array.isArray(this.value)?this.value[0]:this.value},extracted:function(){var t=Array.isArray(this.value)?this.value[1]:"";return this.palette.length?this.palette:t},emptyOptions:function(){return!(this.isObject(this.options)?Object.keys(this.options).length:this.options.length)&&!this.extractor},emptyOptionsPlaceholder:function(){return this.autotemplate?this.$t("palette.empty.template"):this.$t("palette.empty.options")},emptyPalette:function(){return this.extractor&&!this.extracted.length&&!this.loading},loadingPalette:function(){return this.extractor&&this.loading},colors:function(){return this.extractor?!!this.extracted.length&&this.extracted:this.isQueryOptions(this.options)?this.options.map(function(t){return t.value}):this.options}},created:function(){var t=this;!this.value&&this.default&&(Array.isArray(this.colors)&&this.colors.find(function(e){return e==t.default})?(this.value=this.default,this.input()):this.isObject(this.colors)&&Object.keys(this.colors).find(function(e){return e==t.default})&&(this.value=this.colors[this.default],this.input()))},methods:{isValue:function(t){return this.isObject(t)?this.selected==t||!!this.isObject(this.selected)&&this.isEquivalent(this.selected,t):this.selected==t},inlineStyle:function(t){return"duo"==this.display&&this.isObject(t)?"background: linear-gradient(to right, "+this.firstColor(t)+" 50%, "+this.secondColor(t)+" 50%);":"background:"+this.firstColor(t)},toTooltip:function(t){return!(!this.isObject(t)||!t.tooltip)&&t.tooltip},firstColor:function(t){return this.isString(t)?t:this.isObject(t)?t[Object.keys(t)[0]]:void 0},secondColor:function(t){return!!this.isObject(t)&&t[Object.keys(t)[1]]},isString:function(t){return"string"==typeof t},isObject:function(t){return null!=t&&"object"===b(t)},isQueryOptions:function(t){if(!t.length)return!1;var e=t[0];return this.isObject(e)&&2==Object.keys(e).length&&Object.keys(e).includes("text")&&Object.keys(e).includes("value")},isEquivalent:function(t,e){var i=Object.keys(t),n=Object.keys(e),r=i.indexOf("key");-1!==r&&i.splice(r,1);var o=n.indexOf("key");if(-1!==o&&n.splice(o,1),i.length!=n.length)return!1;for(var s=0;s0&&void 0!==arguments[0]&&arguments[0],e=arguments.length>1?arguments[1]:void 0;t&&(this.unselect&&this.isValue(t)&&(t=""),this.value=this.extractor?[t,this.extracted]:t,this.isObject(this.value)&&(this.value.key=e)),this.$emit("input",this.value)}}};if(typeof a==="function"){a=a.options}Object.assign(a,function(){var render=function(){var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c("k-field",_vm._b({staticClass:"k-color-palette-field"},"k-field",_vm.$props,false),[_c("template",{slot:"options"},[_vm.extractor?_c("k-button",{ref:"extract",attrs:{"id":_vm._uid,"icon":"palette-pipette"},on:{"click":_vm.openSelector}},[_vm._v(" "+_vm._s(_vm.$t("palette.new.palette"))+" ")]):_vm._e(),_vm._v(" "),_c("k-files-dialog",{ref:"selector",on:{"submit":_vm.processImage}})],1),_vm._v(" "),_vm.emptyOptions?_c("k-box",{staticClass:"color-palette_empty-options",attrs:{"theme":"info"}},[_vm._v(" "+_vm._s(_vm.emptyOptionsPlaceholder)+" ")]):_vm.emptyPalette?_c("k-empty",{class:["color-palette_empty-palette",_vm.size],attrs:{"layout":"custom","icon":"image"},on:{"click":_vm.openSelector}},[_vm._v(" "+_vm._s(_vm.$t("palette.empty.palette"))+" ")]):_vm.loadingPalette?_c("div",{staticClass:"color-palette_empty-loading"},[_c("div",{staticClass:"loader-ctn",class:_vm.size},[_c("div",{staticClass:"loader"})])]):_c("div",{staticClass:"color-palette_input"},[_c("ul",{staticClass:"color-palette_input-list"},_vm._l(_vm.colors,function(color,index){return _c("li",{class:[_vm.size,{"active":_vm.isValue(color)},{"unselect":_vm.unselect}],on:{"click":function($event){return _vm.input(color,index)}}},[_c("div",{staticClass:"color-palette_input-color",style:_vm.inlineStyle(color),attrs:{"data-tooltip":_vm.toTooltip(color)}})])}),0)])],2)};var staticRenderFns=[];return{render:render,staticRenderFns:staticRenderFns,_compiled:true,_scopeId:null,functional:undefined}}());document.querySelector("svg defs").innerHTML+="\n \n \n \n";panel.plugin("sylvainjule/color-palette",{fields:{"color-palette":a}});})(); \ No newline at end of file diff --git a/site/plugins/color-palette/index.php b/site/plugins/color-palette/index.php new file mode 100644 index 0000000..98db826 --- /dev/null +++ b/site/plugins/color-palette/index.php @@ -0,0 +1,18 @@ + array( + 'cache' => true, + ), + 'fields' => require_once __DIR__ . '/lib/fields.php', + 'api' => require_once __DIR__ . '/lib/api.php', + 'translations' => array( + 'en' => require_once __DIR__ . '/lib/languages/en.php', + 'de' => require_once __DIR__ . '/lib/languages/de.php', + 'fr' => require_once __DIR__ . '/lib/languages/fr.php', + ), +)); \ No newline at end of file diff --git a/site/plugins/color-palette/lib/api.php b/site/plugins/color-palette/lib/api.php new file mode 100644 index 0000000..6282718 --- /dev/null +++ b/site/plugins/color-palette/lib/api.php @@ -0,0 +1,68 @@ + array( + array( + 'pattern' => 'color-palette/get-files', + 'method' => 'GET', + 'action' => function () { + $uri = get('uri'); + $template = get('template'); + $page = kirby()->page($uri); + $files = $template !== 'undefined' ? $page->images()->template($template) : $page->images(); + $data = []; + + $thumb = array( + 'width' => 100, + 'height' => 100 + ); + + foreach ($files as $index => $file) { + $image = $file->panelImage([], $thumb); + $uuid = $file->filename(); + $data[] = array( + 'filename' => $file->filename(), + 'text' => $file->filename(), + 'link' => $file->panelUrl(true), + 'id' => $file->id(), + 'uuid' => $uuid, + 'url' => $file->url(), + 'info' => false, + 'image' => $image, + 'icon' => $file->panelIcon($image), + 'type' => $file->type(), + ); + } + + return $data; + } + ), + array( + 'pattern' => 'color-palette/extract-image-colors', + 'method' => 'GET', + 'action' => function() { + $filename = get('filename'); + $uri = get('uri'); + $limit = get('limit'); + $page = kirby()->page($uri); + $file = $page->file($filename); + + try { + $colors = SylvainJule\ColorPalette::extractColor($file, $limit); + $response = array( + 'status' => 'success', + 'colors' => $colors, + ); + return $response; + } + catch (Exception $e) { + $response = array( + 'status' => 'error', + 'message' => $e->getMessage() + ); + return $response; + } + } + ), + ) +); \ No newline at end of file diff --git a/site/plugins/color-palette/lib/color-palette.php b/site/plugins/color-palette/lib/color-palette.php new file mode 100644 index 0000000..92acdb0 --- /dev/null +++ b/site/plugins/color-palette/lib/color-palette.php @@ -0,0 +1,25 @@ +resize($size)->save(); + $root = $thumb->root(); + $palette = Palette::fromFilename($root, Color::fromHexToInt($fallbackColor)); + $extractor = new Extractor($palette); + $colors = $extractor->extract($limit); + + $toHex = function($value) { + return Color::fromIntToHex($value); + }; + $colors = array_map($toHex, $colors); + return $colors; + } + +} \ No newline at end of file diff --git a/site/plugins/color-palette/lib/fields.php b/site/plugins/color-palette/lib/fields.php new file mode 100644 index 0000000..c680f77 --- /dev/null +++ b/site/plugins/color-palette/lib/fields.php @@ -0,0 +1,79 @@ + array( + 'extends' => 'radio', + 'props' => array( + 'options' => function ($options = []) { + return $options; + }, + 'display' => function ($display = 'single') { + return $display; + }, + 'size' => function ($size = 'medium') { + return $size; + }, + 'unselect' => function ($unselect = false) { + return $unselect; + }, + 'default' => function($default = false) { + return $default; + }, + 'extractor' => function($extractor = false) { + return $extractor; + }, + 'limit' => function($limit = 10) { + return $limit; + }, + 'value' => function ($value = null) { + $yaml = Yaml::decode($value); + return count($yaml) ? $yaml : $value; + }, + 'template' > function($template = null) { + return $template; + }, + 'autotemplate' > function($autotemplate = null) { + return $autotemplate; + } + ), + 'computed' => array( + 'uri' => function() { + return $this->model()->uri(); + }, + 'parent' => function () { + return $this->model()->apiUrl(true); + }, + 'files' => function () { + return $this->model()->images(); + }, + 'options' => function() { + $options = $this->options; + $cache = kirby()->cache('sylvainjule.color-palette'); + + if($options == 'query') { + return $this->getOptions(); + } + + if($this->autotemplate) { + if($image = $this->model()->images()->template($this->autotemplate)->first()) { + if($image->filename() == $cache->get('image.filename')) { + $options = $cache->get('image.options'); + } + else { + $options = SylvainJule\ColorPalette::extractColor($image, $this->limit); + $cache->set('image.filename', $image->filename()); + $cache->set('image.options', $options); + } + } + } + return $options; + }, + 'default' => function() { + return $this->default; + }, + 'value' => function () { + return $this->value; + } + ), + ), +); diff --git a/site/plugins/color-palette/lib/languages/de.php b/site/plugins/color-palette/lib/languages/de.php new file mode 100644 index 0000000..99828b3 --- /dev/null +++ b/site/plugins/color-palette/lib/languages/de.php @@ -0,0 +1,8 @@ + 'Neue Palette', + 'palette.empty.options' => 'Bitte geben Sie Farben in den Feldoptionen an.', + 'palette.empty.template' => 'Es gibt derzeit kein Bild, aus denen Farben extrahiert werden können.', + 'palette.empty.palette' => 'Die Farbpalette ist leer. Bitte wählen Sie ein Bild aus.', +); \ No newline at end of file diff --git a/site/plugins/color-palette/lib/languages/en.php b/site/plugins/color-palette/lib/languages/en.php new file mode 100644 index 0000000..0b0deae --- /dev/null +++ b/site/plugins/color-palette/lib/languages/en.php @@ -0,0 +1,8 @@ + 'New palette', + 'palette.empty.options' => 'Please specify colors in the field blueprint.', + 'palette.empty.template' => 'There is currently no image to extract colors from.', + 'palette.empty.palette' => 'The color palette is empty. Please select an image.', +); \ No newline at end of file diff --git a/site/plugins/color-palette/lib/languages/fr.php b/site/plugins/color-palette/lib/languages/fr.php new file mode 100644 index 0000000..1aad17b --- /dev/null +++ b/site/plugins/color-palette/lib/languages/fr.php @@ -0,0 +1,8 @@ + 'Nouveau nuancier', + 'palette.empty.options' => 'Renseignez des couleurs dans votre blueprint.', + 'palette.empty.template' => 'Il n\'y a pour l\'instant aucune image à partir de laquelle extraire des couleurs.', + 'palette.empty.palette' => 'Le nuancier est vide. Sélectionnez une image pour commencer l\'extraction.', +); \ No newline at end of file diff --git a/site/plugins/color-palette/package.json b/site/plugins/color-palette/package.json new file mode 100644 index 0000000..3bec79e --- /dev/null +++ b/site/plugins/color-palette/package.json @@ -0,0 +1,25 @@ +{ + "name": "kirby-color-palette", + "version": "0.0.1", + "description": "A color palette to pick colors from for Kirby", + "main": "index.js", + "author": "Sylvain Julé", + "license": "MIT", + "scripts": { + "dev": "parcel watch src/index.js --no-source-maps -d ./", + "build": "parcel build src/index.js --no-source-maps --experimental-scope-hoisting -d ./" + }, + "posthtml": { + "recognizeSelfClosing": true + }, + "devDependencies": { + "@vue/component-compiler-utils": "^3.1.2", + "cssnano": "^4.1.10", + "sass": "^1.26.3", + "vue-template-compiler": "^2.6.11" + }, + "dependencies": { + "vue": "^2.6.11", + "vue-hot-reload-api": "^2.3.4" + } +} diff --git a/site/plugins/color-palette/src/assets/css/styles.scss b/site/plugins/color-palette/src/assets/css/styles.scss new file mode 100644 index 0000000..930a435 --- /dev/null +++ b/site/plugins/color-palette/src/assets/css/styles.scss @@ -0,0 +1,195 @@ +.k-color-palette-field { + .k-button { + cursor: pointer; + } + .k-button-figure .k-icon { + margin-right: -4px; + } +} + +.color-palette_input { + &-list { + display: flex; + flex-wrap: wrap; + padding: 0.75rem; + padding-bottom: calc(0.75rem - 6px); + background: darken(#efefef, 2%); + li { + position: relative; + transition: transform 0.3s ease-out; + margin-bottom: 6px; + border: 4px solid transparent; + + /* Size + ------------------------*/ + &.small { + width: 28px; + height: 28px; + } + &.medium { + width: 38px; + height: 38px; + } + &.large { + width: 48px; + height: 48px; + } + + &:not(:last-child) { + margin-right: 6px; + } + &.active { + pointer-events: none; + border: 4px solid white; + outline: 1px solid #cccccc; + + /* Unselect? + ------------------------*/ + &.unselect { + pointer-events: auto; + cursor: pointer; + } + } + &:not(.active) { + cursor: pointer; + } + } + } + + /* Style + ------------------------*/ + &-color { + width: 100%; + height: 100%; + &[data-tooltip] { + position: relative; + z-index: 2; + cursor: pointer; + &:before, &:after { + visibility: hidden; + pointer-events: none; + } + &:before { + position: absolute; + bottom: 120%; + left: 50%; + transform: translate(-50%); + margin-bottom: 5px; + padding: 7px 12px; + width: auto; + background-color: #000; + color: #fff; + content: attr(data-tooltip); + text-align: center; + font-size: 14px; + line-height: 16px; + white-space: pre; + } + &:after { + position: absolute; + bottom: 120%; + left: 50%; + margin-left: -5px; + width: 0; + border-top: 5px solid #000; + border-right: 5px solid transparent; + border-left: 5px solid transparent; + content: ""; + font-size: 0; + line-height: 0; + } + &:hover { + &:before, &:after { + visibility: visible; + } + } + } + } +} + +.color-palette_empty { + &-palette { + padding: 0; + display: flex; + align-items: center; + flex-direction: row; + justify-content: flex-start; + .k-icon { + border-right: 1px solid #d6d6d6; + margin-bottom: 0; + display: flex; + justify-content: center; + align-items: center; + svg { + width: 14px; + } + } + p { + line-height: 1.25rem; + text-align: left; + } + &.small { + .k-icon { + width: calc(28px + 1.5rem); + height: calc(28px + 1.5rem); + } + p { + padding: .75rem 1rem; + } + } + &.medium { + .k-icon { + width: calc(38px + 1.5rem); + height: calc(38px + 1.5rem); + } + p { + padding: .75rem 1.25rem; + } + } + &.large { + .k-icon { + width: calc(48px + 1.5rem); + height: calc(48px + 1.5rem); + } + p { + padding: .75rem 1.75rem; + } + } + } + &-loading { + padding: 0.75rem; + background: darken(#efefef, 2%); + .loader-ctn { + display: flex; + justify-content: center; + align-items: center; + &.small { + height: 28px; + } + &.medium { + height: 38px; + } + &.large { + height: 48px; + } + + .loader { + display: inline-block; + overflow: hidden; + height: 1.3em; + margin-top: -0.3em; + line-height: 1.5em; + vertical-align: text-bottom; + &::after { + content: "⠋\A⠙\A⠹\A⠸\A⠼\A⠴\A⠦\A⠧\A⠇\A⠏"; + display: inline-table; + white-space: pre; + text-align: left; + animation: spin10 0.8s steps(10) infinite; + } + } + + @keyframes spin10 { to { transform: translateY(-15.0em); } } + } + } +} diff --git a/site/plugins/color-palette/src/assets/svg/icons.js b/site/plugins/color-palette/src/assets/svg/icons.js new file mode 100644 index 0000000..f684529 --- /dev/null +++ b/site/plugins/color-palette/src/assets/svg/icons.js @@ -0,0 +1,5 @@ +document.querySelector('svg defs').innerHTML += ` + + + +`; \ No newline at end of file diff --git a/site/plugins/color-palette/src/assets/svg/pipette.svg b/site/plugins/color-palette/src/assets/svg/pipette.svg new file mode 100644 index 0000000..41af2fa --- /dev/null +++ b/site/plugins/color-palette/src/assets/svg/pipette.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/site/plugins/color-palette/src/components/field/ColorPalette.vue b/site/plugins/color-palette/src/components/field/ColorPalette.vue new file mode 100644 index 0000000..4882582 --- /dev/null +++ b/site/plugins/color-palette/src/components/field/ColorPalette.vue @@ -0,0 +1,217 @@ + + + + + diff --git a/site/plugins/color-palette/src/index.js b/site/plugins/color-palette/src/index.js new file mode 100644 index 0000000..8e145b6 --- /dev/null +++ b/site/plugins/color-palette/src/index.js @@ -0,0 +1,8 @@ +import ColorPalette from './components/field/ColorPalette.vue' +import './assets/svg/icons.js' + +panel.plugin('sylvainjule/color-palette', { + fields: { + 'color-palette': ColorPalette, + } +}); \ No newline at end of file diff --git a/site/plugins/embed/vendor/autoload.php b/site/plugins/embed/vendor/autoload.php deleted file mode 100644 index 76dcd09..0000000 --- a/site/plugins/embed/vendor/autoload.php +++ /dev/null @@ -1,25 +0,0 @@ - - * Jordi Boggiano - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Composer\Autoload; - -/** - * ClassLoader implements a PSR-0, PSR-4 and classmap class loader. - * - * $loader = new \Composer\Autoload\ClassLoader(); - * - * // register classes with namespaces - * $loader->add('Symfony\Component', __DIR__.'/component'); - * $loader->add('Symfony', __DIR__.'/framework'); - * - * // activate the autoloader - * $loader->register(); - * - * // to enable searching the include path (eg. for PEAR packages) - * $loader->setUseIncludePath(true); - * - * In this example, if you try to use a class in the Symfony\Component - * namespace or one of its children (Symfony\Component\Console for instance), - * the autoloader will first look for the class under the component/ - * directory, and it will then fallback to the framework/ directory if not - * found before giving up. - * - * This class is loosely based on the Symfony UniversalClassLoader. - * - * @author Fabien Potencier - * @author Jordi Boggiano - * @see https://www.php-fig.org/psr/psr-0/ - * @see https://www.php-fig.org/psr/psr-4/ - */ -class ClassLoader -{ - /** @var \Closure(string):void */ - private static $includeFile; - - /** @var ?string */ - private $vendorDir; - - // PSR-4 - /** - * @var array[] - * @psalm-var array> - */ - private $prefixLengthsPsr4 = array(); - /** - * @var array[] - * @psalm-var array> - */ - private $prefixDirsPsr4 = array(); - /** - * @var array[] - * @psalm-var array - */ - private $fallbackDirsPsr4 = array(); - - // PSR-0 - /** - * @var array[] - * @psalm-var array> - */ - private $prefixesPsr0 = array(); - /** - * @var array[] - * @psalm-var array - */ - private $fallbackDirsPsr0 = array(); - - /** @var bool */ - private $useIncludePath = false; - - /** - * @var string[] - * @psalm-var array - */ - private $classMap = array(); - - /** @var bool */ - private $classMapAuthoritative = false; - - /** - * @var bool[] - * @psalm-var array - */ - private $missingClasses = array(); - - /** @var ?string */ - private $apcuPrefix; - - /** - * @var self[] - */ - private static $registeredLoaders = array(); - - /** - * @param ?string $vendorDir - */ - public function __construct($vendorDir = null) - { - $this->vendorDir = $vendorDir; - self::initializeIncludeClosure(); - } - - /** - * @return string[] - */ - public function getPrefixes() - { - if (!empty($this->prefixesPsr0)) { - return call_user_func_array('array_merge', array_values($this->prefixesPsr0)); - } - - return array(); - } - - /** - * @return array[] - * @psalm-return array> - */ - public function getPrefixesPsr4() - { - return $this->prefixDirsPsr4; - } - - /** - * @return array[] - * @psalm-return array - */ - public function getFallbackDirs() - { - return $this->fallbackDirsPsr0; - } - - /** - * @return array[] - * @psalm-return array - */ - public function getFallbackDirsPsr4() - { - return $this->fallbackDirsPsr4; - } - - /** - * @return string[] Array of classname => path - * @psalm-return array - */ - public function getClassMap() - { - return $this->classMap; - } - - /** - * @param string[] $classMap Class to filename map - * @psalm-param array $classMap - * - * @return void - */ - public function addClassMap(array $classMap) - { - if ($this->classMap) { - $this->classMap = array_merge($this->classMap, $classMap); - } else { - $this->classMap = $classMap; - } - } - - /** - * Registers a set of PSR-0 directories for a given prefix, either - * appending or prepending to the ones previously set for this prefix. - * - * @param string $prefix The prefix - * @param string[]|string $paths The PSR-0 root directories - * @param bool $prepend Whether to prepend the directories - * - * @return void - */ - public function add($prefix, $paths, $prepend = false) - { - if (!$prefix) { - if ($prepend) { - $this->fallbackDirsPsr0 = array_merge( - (array) $paths, - $this->fallbackDirsPsr0 - ); - } else { - $this->fallbackDirsPsr0 = array_merge( - $this->fallbackDirsPsr0, - (array) $paths - ); - } - - return; - } - - $first = $prefix[0]; - if (!isset($this->prefixesPsr0[$first][$prefix])) { - $this->prefixesPsr0[$first][$prefix] = (array) $paths; - - return; - } - if ($prepend) { - $this->prefixesPsr0[$first][$prefix] = array_merge( - (array) $paths, - $this->prefixesPsr0[$first][$prefix] - ); - } else { - $this->prefixesPsr0[$first][$prefix] = array_merge( - $this->prefixesPsr0[$first][$prefix], - (array) $paths - ); - } - } - - /** - * Registers a set of PSR-4 directories for a given namespace, either - * appending or prepending to the ones previously set for this namespace. - * - * @param string $prefix The prefix/namespace, with trailing '\\' - * @param string[]|string $paths The PSR-4 base directories - * @param bool $prepend Whether to prepend the directories - * - * @throws \InvalidArgumentException - * - * @return void - */ - public function addPsr4($prefix, $paths, $prepend = false) - { - if (!$prefix) { - // Register directories for the root namespace. - if ($prepend) { - $this->fallbackDirsPsr4 = array_merge( - (array) $paths, - $this->fallbackDirsPsr4 - ); - } else { - $this->fallbackDirsPsr4 = array_merge( - $this->fallbackDirsPsr4, - (array) $paths - ); - } - } elseif (!isset($this->prefixDirsPsr4[$prefix])) { - // Register directories for a new namespace. - $length = strlen($prefix); - if ('\\' !== $prefix[$length - 1]) { - throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); - } - $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; - $this->prefixDirsPsr4[$prefix] = (array) $paths; - } elseif ($prepend) { - // Prepend directories for an already registered namespace. - $this->prefixDirsPsr4[$prefix] = array_merge( - (array) $paths, - $this->prefixDirsPsr4[$prefix] - ); - } else { - // Append directories for an already registered namespace. - $this->prefixDirsPsr4[$prefix] = array_merge( - $this->prefixDirsPsr4[$prefix], - (array) $paths - ); - } - } - - /** - * Registers a set of PSR-0 directories for a given prefix, - * replacing any others previously set for this prefix. - * - * @param string $prefix The prefix - * @param string[]|string $paths The PSR-0 base directories - * - * @return void - */ - public function set($prefix, $paths) - { - if (!$prefix) { - $this->fallbackDirsPsr0 = (array) $paths; - } else { - $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths; - } - } - - /** - * Registers a set of PSR-4 directories for a given namespace, - * replacing any others previously set for this namespace. - * - * @param string $prefix The prefix/namespace, with trailing '\\' - * @param string[]|string $paths The PSR-4 base directories - * - * @throws \InvalidArgumentException - * - * @return void - */ - public function setPsr4($prefix, $paths) - { - if (!$prefix) { - $this->fallbackDirsPsr4 = (array) $paths; - } else { - $length = strlen($prefix); - if ('\\' !== $prefix[$length - 1]) { - throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); - } - $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; - $this->prefixDirsPsr4[$prefix] = (array) $paths; - } - } - - /** - * Turns on searching the include path for class files. - * - * @param bool $useIncludePath - * - * @return void - */ - public function setUseIncludePath($useIncludePath) - { - $this->useIncludePath = $useIncludePath; - } - - /** - * Can be used to check if the autoloader uses the include path to check - * for classes. - * - * @return bool - */ - public function getUseIncludePath() - { - return $this->useIncludePath; - } - - /** - * Turns off searching the prefix and fallback directories for classes - * that have not been registered with the class map. - * - * @param bool $classMapAuthoritative - * - * @return void - */ - public function setClassMapAuthoritative($classMapAuthoritative) - { - $this->classMapAuthoritative = $classMapAuthoritative; - } - - /** - * Should class lookup fail if not found in the current class map? - * - * @return bool - */ - public function isClassMapAuthoritative() - { - return $this->classMapAuthoritative; - } - - /** - * APCu prefix to use to cache found/not-found classes, if the extension is enabled. - * - * @param string|null $apcuPrefix - * - * @return void - */ - public function setApcuPrefix($apcuPrefix) - { - $this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null; - } - - /** - * The APCu prefix in use, or null if APCu caching is not enabled. - * - * @return string|null - */ - public function getApcuPrefix() - { - return $this->apcuPrefix; - } - - /** - * Registers this instance as an autoloader. - * - * @param bool $prepend Whether to prepend the autoloader or not - * - * @return void - */ - public function register($prepend = false) - { - spl_autoload_register(array($this, 'loadClass'), true, $prepend); - - if (null === $this->vendorDir) { - return; - } - - if ($prepend) { - self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders; - } else { - unset(self::$registeredLoaders[$this->vendorDir]); - self::$registeredLoaders[$this->vendorDir] = $this; - } - } - - /** - * Unregisters this instance as an autoloader. - * - * @return void - */ - public function unregister() - { - spl_autoload_unregister(array($this, 'loadClass')); - - if (null !== $this->vendorDir) { - unset(self::$registeredLoaders[$this->vendorDir]); - } - } - - /** - * Loads the given class or interface. - * - * @param string $class The name of the class - * @return true|null True if loaded, null otherwise - */ - public function loadClass($class) - { - if ($file = $this->findFile($class)) { - (self::$includeFile)($file); - - return true; - } - - return null; - } - - /** - * Finds the path to the file where the class is defined. - * - * @param string $class The name of the class - * - * @return string|false The path if found, false otherwise - */ - public function findFile($class) - { - // class map lookup - if (isset($this->classMap[$class])) { - return $this->classMap[$class]; - } - if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) { - return false; - } - if (null !== $this->apcuPrefix) { - $file = apcu_fetch($this->apcuPrefix.$class, $hit); - if ($hit) { - return $file; - } - } - - $file = $this->findFileWithExtension($class, '.php'); - - // Search for Hack files if we are running on HHVM - if (false === $file && defined('HHVM_VERSION')) { - $file = $this->findFileWithExtension($class, '.hh'); - } - - if (null !== $this->apcuPrefix) { - apcu_add($this->apcuPrefix.$class, $file); - } - - if (false === $file) { - // Remember that this class does not exist. - $this->missingClasses[$class] = true; - } - - return $file; - } - - /** - * Returns the currently registered loaders indexed by their corresponding vendor directories. - * - * @return self[] - */ - public static function getRegisteredLoaders() - { - return self::$registeredLoaders; - } - - /** - * @param string $class - * @param string $ext - * @return string|false - */ - private function findFileWithExtension($class, $ext) - { - // PSR-4 lookup - $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext; - - $first = $class[0]; - if (isset($this->prefixLengthsPsr4[$first])) { - $subPath = $class; - while (false !== $lastPos = strrpos($subPath, '\\')) { - $subPath = substr($subPath, 0, $lastPos); - $search = $subPath . '\\'; - if (isset($this->prefixDirsPsr4[$search])) { - $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1); - foreach ($this->prefixDirsPsr4[$search] as $dir) { - if (file_exists($file = $dir . $pathEnd)) { - return $file; - } - } - } - } - } - - // PSR-4 fallback dirs - foreach ($this->fallbackDirsPsr4 as $dir) { - if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) { - return $file; - } - } - - // PSR-0 lookup - if (false !== $pos = strrpos($class, '\\')) { - // namespaced class name - $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1) - . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR); - } else { - // PEAR-like class name - $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext; - } - - if (isset($this->prefixesPsr0[$first])) { - foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) { - if (0 === strpos($class, $prefix)) { - foreach ($dirs as $dir) { - if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { - return $file; - } - } - } - } - } - - // PSR-0 fallback dirs - foreach ($this->fallbackDirsPsr0 as $dir) { - if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { - return $file; - } - } - - // PSR-0 include paths. - if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) { - return $file; - } - - return false; - } - - private static function initializeIncludeClosure(): void - { - if (self::$includeFile !== null) { - return; - } - - /** - * Scope isolated include. - * - * Prevents access to $this/self from included files. - * - * @param string $file - * @return void - */ - self::$includeFile = static function($file) { - include $file; - }; - } -} diff --git a/site/plugins/embed/vendor/composer/InstalledVersions.php b/site/plugins/embed/vendor/composer/InstalledVersions.php deleted file mode 100644 index c6b54af..0000000 --- a/site/plugins/embed/vendor/composer/InstalledVersions.php +++ /dev/null @@ -1,352 +0,0 @@ - - * Jordi Boggiano - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Composer; - -use Composer\Autoload\ClassLoader; -use Composer\Semver\VersionParser; - -/** - * This class is copied in every Composer installed project and available to all - * - * See also https://getcomposer.org/doc/07-runtime.md#installed-versions - * - * To require its presence, you can require `composer-runtime-api ^2.0` - * - * @final - */ -class InstalledVersions -{ - /** - * @var mixed[]|null - * @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array}|array{}|null - */ - private static $installed; - - /** - * @var bool|null - */ - private static $canGetVendors; - - /** - * @var array[] - * @psalm-var array}> - */ - private static $installedByVendor = array(); - - /** - * Returns a list of all package names which are present, either by being installed, replaced or provided - * - * @return string[] - * @psalm-return list - */ - public static function getInstalledPackages() - { - $packages = array(); - foreach (self::getInstalled() as $installed) { - $packages[] = array_keys($installed['versions']); - } - - if (1 === \count($packages)) { - return $packages[0]; - } - - return array_keys(array_flip(\call_user_func_array('array_merge', $packages))); - } - - /** - * Returns a list of all package names with a specific type e.g. 'library' - * - * @param string $type - * @return string[] - * @psalm-return list - */ - public static function getInstalledPackagesByType($type) - { - $packagesByType = array(); - - foreach (self::getInstalled() as $installed) { - foreach ($installed['versions'] as $name => $package) { - if (isset($package['type']) && $package['type'] === $type) { - $packagesByType[] = $name; - } - } - } - - return $packagesByType; - } - - /** - * Checks whether the given package is installed - * - * This also returns true if the package name is provided or replaced by another package - * - * @param string $packageName - * @param bool $includeDevRequirements - * @return bool - */ - public static function isInstalled($packageName, $includeDevRequirements = true) - { - foreach (self::getInstalled() as $installed) { - if (isset($installed['versions'][$packageName])) { - return $includeDevRequirements || empty($installed['versions'][$packageName]['dev_requirement']); - } - } - - return false; - } - - /** - * Checks whether the given package satisfies a version constraint - * - * e.g. If you want to know whether version 2.3+ of package foo/bar is installed, you would call: - * - * Composer\InstalledVersions::satisfies(new VersionParser, 'foo/bar', '^2.3') - * - * @param VersionParser $parser Install composer/semver to have access to this class and functionality - * @param string $packageName - * @param string|null $constraint A version constraint to check for, if you pass one you have to make sure composer/semver is required by your package - * @return bool - */ - public static function satisfies(VersionParser $parser, $packageName, $constraint) - { - $constraint = $parser->parseConstraints($constraint); - $provided = $parser->parseConstraints(self::getVersionRanges($packageName)); - - return $provided->matches($constraint); - } - - /** - * Returns a version constraint representing all the range(s) which are installed for a given package - * - * It is easier to use this via isInstalled() with the $constraint argument if you need to check - * whether a given version of a package is installed, and not just whether it exists - * - * @param string $packageName - * @return string Version constraint usable with composer/semver - */ - public static function getVersionRanges($packageName) - { - foreach (self::getInstalled() as $installed) { - if (!isset($installed['versions'][$packageName])) { - continue; - } - - $ranges = array(); - if (isset($installed['versions'][$packageName]['pretty_version'])) { - $ranges[] = $installed['versions'][$packageName]['pretty_version']; - } - if (array_key_exists('aliases', $installed['versions'][$packageName])) { - $ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']); - } - if (array_key_exists('replaced', $installed['versions'][$packageName])) { - $ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']); - } - if (array_key_exists('provided', $installed['versions'][$packageName])) { - $ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']); - } - - return implode(' || ', $ranges); - } - - throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); - } - - /** - * @param string $packageName - * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present - */ - public static function getVersion($packageName) - { - foreach (self::getInstalled() as $installed) { - if (!isset($installed['versions'][$packageName])) { - continue; - } - - if (!isset($installed['versions'][$packageName]['version'])) { - return null; - } - - return $installed['versions'][$packageName]['version']; - } - - throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); - } - - /** - * @param string $packageName - * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present - */ - public static function getPrettyVersion($packageName) - { - foreach (self::getInstalled() as $installed) { - if (!isset($installed['versions'][$packageName])) { - continue; - } - - if (!isset($installed['versions'][$packageName]['pretty_version'])) { - return null; - } - - return $installed['versions'][$packageName]['pretty_version']; - } - - throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); - } - - /** - * @param string $packageName - * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as reference - */ - public static function getReference($packageName) - { - foreach (self::getInstalled() as $installed) { - if (!isset($installed['versions'][$packageName])) { - continue; - } - - if (!isset($installed['versions'][$packageName]['reference'])) { - return null; - } - - return $installed['versions'][$packageName]['reference']; - } - - throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); - } - - /** - * @param string $packageName - * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as install path. Packages of type metapackages also have a null install path. - */ - public static function getInstallPath($packageName) - { - foreach (self::getInstalled() as $installed) { - if (!isset($installed['versions'][$packageName])) { - continue; - } - - return isset($installed['versions'][$packageName]['install_path']) ? $installed['versions'][$packageName]['install_path'] : null; - } - - throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); - } - - /** - * @return array - * @psalm-return array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool} - */ - public static function getRootPackage() - { - $installed = self::getInstalled(); - - return $installed[0]['root']; - } - - /** - * Returns the raw installed.php data for custom implementations - * - * @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect. - * @return array[] - * @psalm-return array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} - */ - public static function getRawData() - { - @trigger_error('getRawData only returns the first dataset loaded, which may not be what you expect. Use getAllRawData() instead which returns all datasets for all autoloaders present in the process.', E_USER_DEPRECATED); - - if (null === self::$installed) { - // only require the installed.php file if this file is loaded from its dumped location, - // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937 - if (substr(__DIR__, -8, 1) !== 'C') { - self::$installed = include __DIR__ . '/installed.php'; - } else { - self::$installed = array(); - } - } - - return self::$installed; - } - - /** - * Returns the raw data of all installed.php which are currently loaded for custom implementations - * - * @return array[] - * @psalm-return list}> - */ - public static function getAllRawData() - { - return self::getInstalled(); - } - - /** - * Lets you reload the static array from another file - * - * This is only useful for complex integrations in which a project needs to use - * this class but then also needs to execute another project's autoloader in process, - * and wants to ensure both projects have access to their version of installed.php. - * - * A typical case would be PHPUnit, where it would need to make sure it reads all - * the data it needs from this class, then call reload() with - * `require $CWD/vendor/composer/installed.php` (or similar) as input to make sure - * the project in which it runs can then also use this class safely, without - * interference between PHPUnit's dependencies and the project's dependencies. - * - * @param array[] $data A vendor/composer/installed.php data set - * @return void - * - * @psalm-param array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} $data - */ - public static function reload($data) - { - self::$installed = $data; - self::$installedByVendor = array(); - } - - /** - * @return array[] - * @psalm-return list}> - */ - private static function getInstalled() - { - if (null === self::$canGetVendors) { - self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders'); - } - - $installed = array(); - - if (self::$canGetVendors) { - foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) { - if (isset(self::$installedByVendor[$vendorDir])) { - $installed[] = self::$installedByVendor[$vendorDir]; - } elseif (is_file($vendorDir.'/composer/installed.php')) { - $installed[] = self::$installedByVendor[$vendorDir] = require $vendorDir.'/composer/installed.php'; - if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) { - self::$installed = $installed[count($installed) - 1]; - } - } - } - } - - if (null === self::$installed) { - // only require the installed.php file if this file is loaded from its dumped location, - // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937 - if (substr(__DIR__, -8, 1) !== 'C') { - self::$installed = require __DIR__ . '/installed.php'; - } else { - self::$installed = array(); - } - } - $installed[] = self::$installed; - - return $installed; - } -} diff --git a/site/plugins/embed/vendor/composer/LICENSE b/site/plugins/embed/vendor/composer/LICENSE deleted file mode 100644 index f27399a..0000000 --- a/site/plugins/embed/vendor/composer/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ - -Copyright (c) Nils Adermann, Jordi Boggiano - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is furnished -to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - diff --git a/site/plugins/embed/vendor/composer/autoload_classmap.php b/site/plugins/embed/vendor/composer/autoload_classmap.php deleted file mode 100644 index 0fb0a2c..0000000 --- a/site/plugins/embed/vendor/composer/autoload_classmap.php +++ /dev/null @@ -1,10 +0,0 @@ - $vendorDir . '/composer/InstalledVersions.php', -); diff --git a/site/plugins/embed/vendor/composer/autoload_files.php b/site/plugins/embed/vendor/composer/autoload_files.php deleted file mode 100644 index 4bbe72b..0000000 --- a/site/plugins/embed/vendor/composer/autoload_files.php +++ /dev/null @@ -1,11 +0,0 @@ - $vendorDir . '/ralouphie/getallheaders/src/getallheaders.php', - '09fc349b549513bf7f4291502426f919' => $vendorDir . '/embed/embed/src/functions.php', -); diff --git a/site/plugins/embed/vendor/composer/autoload_namespaces.php b/site/plugins/embed/vendor/composer/autoload_namespaces.php deleted file mode 100644 index c27b051..0000000 --- a/site/plugins/embed/vendor/composer/autoload_namespaces.php +++ /dev/null @@ -1,10 +0,0 @@ - array($vendorDir . '/ml/iri'), -); diff --git a/site/plugins/embed/vendor/composer/autoload_psr4.php b/site/plugins/embed/vendor/composer/autoload_psr4.php deleted file mode 100644 index 9537cce..0000000 --- a/site/plugins/embed/vendor/composer/autoload_psr4.php +++ /dev/null @@ -1,17 +0,0 @@ - array($vendorDir . '/psr/http-factory/src', $vendorDir . '/psr/http-message/src'), - 'Psr\\Http\\Client\\' => array($vendorDir . '/psr/http-client/src'), - 'ML\\JsonLD\\' => array($vendorDir . '/ml/json-ld'), - 'Kirby\\' => array($vendorDir . '/getkirby/composer-installer/src'), - 'HtmlParser\\' => array($vendorDir . '/oscarotero/html-parser/src'), - 'GuzzleHttp\\Psr7\\' => array($vendorDir . '/guzzlehttp/psr7/src'), - 'Embed\\' => array($vendorDir . '/embed/embed/src'), - 'Composer\\CaBundle\\' => array($vendorDir . '/composer/ca-bundle/src'), -); diff --git a/site/plugins/embed/vendor/composer/autoload_real.php b/site/plugins/embed/vendor/composer/autoload_real.php deleted file mode 100644 index a8a9dca..0000000 --- a/site/plugins/embed/vendor/composer/autoload_real.php +++ /dev/null @@ -1,50 +0,0 @@ -register(true); - - $filesToLoad = \Composer\Autoload\ComposerStaticInit15b4b4f6c06d13a66170930d082a8cbf::$files; - $requireFile = static function ($fileIdentifier, $file) { - if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) { - $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true; - - require $file; - } - }; - foreach ($filesToLoad as $fileIdentifier => $file) { - ($requireFile)($fileIdentifier, $file); - } - - return $loader; - } -} diff --git a/site/plugins/embed/vendor/composer/autoload_static.php b/site/plugins/embed/vendor/composer/autoload_static.php deleted file mode 100644 index c517af9..0000000 --- a/site/plugins/embed/vendor/composer/autoload_static.php +++ /dev/null @@ -1,106 +0,0 @@ - __DIR__ . '/..' . '/ralouphie/getallheaders/src/getallheaders.php', - '09fc349b549513bf7f4291502426f919' => __DIR__ . '/..' . '/embed/embed/src/functions.php', - ); - - public static $prefixLengthsPsr4 = array ( - 'P' => - array ( - 'Psr\\Http\\Message\\' => 17, - 'Psr\\Http\\Client\\' => 16, - ), - 'M' => - array ( - 'ML\\JsonLD\\' => 10, - ), - 'K' => - array ( - 'Kirby\\' => 6, - ), - 'H' => - array ( - 'HtmlParser\\' => 11, - ), - 'G' => - array ( - 'GuzzleHttp\\Psr7\\' => 16, - ), - 'E' => - array ( - 'Embed\\' => 6, - ), - 'C' => - array ( - 'Composer\\CaBundle\\' => 18, - ), - ); - - public static $prefixDirsPsr4 = array ( - 'Psr\\Http\\Message\\' => - array ( - 0 => __DIR__ . '/..' . '/psr/http-factory/src', - 1 => __DIR__ . '/..' . '/psr/http-message/src', - ), - 'Psr\\Http\\Client\\' => - array ( - 0 => __DIR__ . '/..' . '/psr/http-client/src', - ), - 'ML\\JsonLD\\' => - array ( - 0 => __DIR__ . '/..' . '/ml/json-ld', - ), - 'Kirby\\' => - array ( - 0 => __DIR__ . '/..' . '/getkirby/composer-installer/src', - ), - 'HtmlParser\\' => - array ( - 0 => __DIR__ . '/..' . '/oscarotero/html-parser/src', - ), - 'GuzzleHttp\\Psr7\\' => - array ( - 0 => __DIR__ . '/..' . '/guzzlehttp/psr7/src', - ), - 'Embed\\' => - array ( - 0 => __DIR__ . '/..' . '/embed/embed/src', - ), - 'Composer\\CaBundle\\' => - array ( - 0 => __DIR__ . '/..' . '/composer/ca-bundle/src', - ), - ); - - public static $prefixesPsr0 = array ( - 'M' => - array ( - 'ML\\IRI' => - array ( - 0 => __DIR__ . '/..' . '/ml/iri', - ), - ), - ); - - public static $classMap = array ( - 'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php', - ); - - public static function getInitializer(ClassLoader $loader) - { - return \Closure::bind(function () use ($loader) { - $loader->prefixLengthsPsr4 = ComposerStaticInit15b4b4f6c06d13a66170930d082a8cbf::$prefixLengthsPsr4; - $loader->prefixDirsPsr4 = ComposerStaticInit15b4b4f6c06d13a66170930d082a8cbf::$prefixDirsPsr4; - $loader->prefixesPsr0 = ComposerStaticInit15b4b4f6c06d13a66170930d082a8cbf::$prefixesPsr0; - $loader->classMap = ComposerStaticInit15b4b4f6c06d13a66170930d082a8cbf::$classMap; - - }, null, ClassLoader::class); - } -} diff --git a/site/plugins/embed/vendor/composer/installed.json b/site/plugins/embed/vendor/composer/installed.json deleted file mode 100644 index 3525bf3..0000000 --- a/site/plugins/embed/vendor/composer/installed.json +++ /dev/null @@ -1,718 +0,0 @@ -{ - "packages": [ - { - "name": "composer/ca-bundle", - "version": "1.3.7", - "version_normalized": "1.3.7.0", - "source": { - "type": "git", - "url": "https://github.com/composer/ca-bundle.git", - "reference": "76e46335014860eec1aa5a724799a00a2e47cc85" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/composer/ca-bundle/zipball/76e46335014860eec1aa5a724799a00a2e47cc85", - "reference": "76e46335014860eec1aa5a724799a00a2e47cc85", - "shasum": "" - }, - "require": { - "ext-openssl": "*", - "ext-pcre": "*", - "php": "^5.3.2 || ^7.0 || ^8.0" - }, - "require-dev": { - "phpstan/phpstan": "^0.12.55", - "psr/log": "^1.0", - "symfony/phpunit-bridge": "^4.2 || ^5", - "symfony/process": "^2.5 || ^3.0 || ^4.0 || ^5.0 || ^6.0" - }, - "time": "2023-08-30T09:31:38+00:00", - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.x-dev" - } - }, - "installation-source": "dist", - "autoload": { - "psr-4": { - "Composer\\CaBundle\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Jordi Boggiano", - "email": "j.boggiano@seld.be", - "homepage": "http://seld.be" - } - ], - "description": "Lets you find a path to the system CA bundle, and includes a fallback to the Mozilla CA bundle.", - "keywords": [ - "cabundle", - "cacert", - "certificate", - "ssl", - "tls" - ], - "support": { - "irc": "irc://irc.freenode.org/composer", - "issues": "https://github.com/composer/ca-bundle/issues", - "source": "https://github.com/composer/ca-bundle/tree/1.3.7" - }, - "funding": [ - { - "url": "https://packagist.com", - "type": "custom" - }, - { - "url": "https://github.com/composer", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/composer/composer", - "type": "tidelift" - } - ], - "install-path": "./ca-bundle" - }, - { - "name": "embed/embed", - "version": "v4.4.8", - "version_normalized": "4.4.8.0", - "source": { - "type": "git", - "url": "https://github.com/oscarotero/Embed.git", - "reference": "49134080764018bc6b8a2488dd1c8cc2c47d15fc" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/oscarotero/Embed/zipball/49134080764018bc6b8a2488dd1c8cc2c47d15fc", - "reference": "49134080764018bc6b8a2488dd1c8cc2c47d15fc", - "shasum": "" - }, - "require": { - "composer/ca-bundle": "^1.0", - "ext-curl": "*", - "ext-dom": "*", - "ext-json": "*", - "ext-mbstring": "*", - "ml/json-ld": "^1.1", - "oscarotero/html-parser": "^0.1.4", - "php": "^7.4|^8", - "psr/http-client": "^1.0", - "psr/http-factory": "^1.0", - "psr/http-message": "^1.0|^2.0" - }, - "require-dev": { - "brick/varexporter": "^0.3.1", - "friendsofphp/php-cs-fixer": "^2.0", - "nyholm/psr7": "^1.2", - "oscarotero/php-cs-fixer-config": "^1.0", - "phpunit/phpunit": "^9.0", - "symfony/css-selector": "^5.0" - }, - "suggest": { - "symfony/css-selector": "If you want to get elements using css selectors" - }, - "time": "2023-05-22T18:48:30+00:00", - "type": "library", - "installation-source": "dist", - "autoload": { - "files": [ - "src/functions.php" - ], - "psr-4": { - "Embed\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Oscar Otero", - "email": "oom@oscarotero.com", - "homepage": "http://oscarotero.com", - "role": "Developer" - } - ], - "description": "PHP library to retrieve page info using oembed, opengraph, etc", - "homepage": "https://github.com/oscarotero/Embed", - "keywords": [ - "embed", - "embedly", - "oembed", - "opengraph", - "twitter cards" - ], - "support": { - "email": "oom@oscarotero.com", - "issues": "https://github.com/oscarotero/Embed/issues", - "source": "https://github.com/oscarotero/Embed/tree/v4.4.8" - }, - "funding": [ - { - "url": "https://paypal.me/oscarotero", - "type": "custom" - }, - { - "url": "https://github.com/oscarotero", - "type": "github" - }, - { - "url": "https://www.patreon.com/misteroom", - "type": "patreon" - } - ], - "install-path": "../embed/embed" - }, - { - "name": "getkirby/composer-installer", - "version": "1.2.1", - "version_normalized": "1.2.1.0", - "source": { - "type": "git", - "url": "https://github.com/getkirby/composer-installer.git", - "reference": "c98ece30bfba45be7ce457e1102d1b169d922f3d" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/getkirby/composer-installer/zipball/c98ece30bfba45be7ce457e1102d1b169d922f3d", - "reference": "c98ece30bfba45be7ce457e1102d1b169d922f3d", - "shasum": "" - }, - "require": { - "composer-plugin-api": "^1.0 || ^2.0" - }, - "require-dev": { - "composer/composer": "^1.8 || ^2.0" - }, - "time": "2020-12-28T12:54:39+00:00", - "type": "composer-plugin", - "extra": { - "class": "Kirby\\ComposerInstaller\\Plugin" - }, - "installation-source": "dist", - "autoload": { - "psr-4": { - "Kirby\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "Kirby's custom Composer installer for the Kirby CMS and for Kirby plugins", - "homepage": "https://getkirby.com", - "install-path": "../getkirby/composer-installer" - }, - { - "name": "guzzlehttp/psr7", - "version": "2.6.1", - "version_normalized": "2.6.1.0", - "source": { - "type": "git", - "url": "https://github.com/guzzle/psr7.git", - "reference": "be45764272e8873c72dbe3d2edcfdfcc3bc9f727" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/guzzle/psr7/zipball/be45764272e8873c72dbe3d2edcfdfcc3bc9f727", - "reference": "be45764272e8873c72dbe3d2edcfdfcc3bc9f727", - "shasum": "" - }, - "require": { - "php": "^7.2.5 || ^8.0", - "psr/http-factory": "^1.0", - "psr/http-message": "^1.1 || ^2.0", - "ralouphie/getallheaders": "^3.0" - }, - "provide": { - "psr/http-factory-implementation": "1.0", - "psr/http-message-implementation": "1.0" - }, - "require-dev": { - "bamarni/composer-bin-plugin": "^1.8.1", - "http-interop/http-factory-tests": "^0.9", - "phpunit/phpunit": "^8.5.29 || ^9.5.23" - }, - "suggest": { - "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" - }, - "time": "2023-08-27T10:13:57+00:00", - "type": "library", - "extra": { - "bamarni-bin": { - "bin-links": true, - "forward-command": false - } - }, - "installation-source": "dist", - "autoload": { - "psr-4": { - "GuzzleHttp\\Psr7\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Graham Campbell", - "email": "hello@gjcampbell.co.uk", - "homepage": "https://github.com/GrahamCampbell" - }, - { - "name": "Michael Dowling", - "email": "mtdowling@gmail.com", - "homepage": "https://github.com/mtdowling" - }, - { - "name": "George Mponos", - "email": "gmponos@gmail.com", - "homepage": "https://github.com/gmponos" - }, - { - "name": "Tobias Nyholm", - "email": "tobias.nyholm@gmail.com", - "homepage": "https://github.com/Nyholm" - }, - { - "name": "Márk Sági-Kazár", - "email": "mark.sagikazar@gmail.com", - "homepage": "https://github.com/sagikazarmark" - }, - { - "name": "Tobias Schultze", - "email": "webmaster@tubo-world.de", - "homepage": "https://github.com/Tobion" - }, - { - "name": "Márk Sági-Kazár", - "email": "mark.sagikazar@gmail.com", - "homepage": "https://sagikazarmark.hu" - } - ], - "description": "PSR-7 message implementation that also provides common utility methods", - "keywords": [ - "http", - "message", - "psr-7", - "request", - "response", - "stream", - "uri", - "url" - ], - "support": { - "issues": "https://github.com/guzzle/psr7/issues", - "source": "https://github.com/guzzle/psr7/tree/2.6.1" - }, - "funding": [ - { - "url": "https://github.com/GrahamCampbell", - "type": "github" - }, - { - "url": "https://github.com/Nyholm", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/psr7", - "type": "tidelift" - } - ], - "install-path": "../guzzlehttp/psr7" - }, - { - "name": "ml/iri", - "version": "1.1.4", - "version_normalized": "1.1.4.0", - "target-dir": "ML/IRI", - "source": { - "type": "git", - "url": "https://github.com/lanthaler/IRI.git", - "reference": "cbd44fa913e00ea624241b38cefaa99da8d71341" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/lanthaler/IRI/zipball/cbd44fa913e00ea624241b38cefaa99da8d71341", - "reference": "cbd44fa913e00ea624241b38cefaa99da8d71341", - "shasum": "" - }, - "require": { - "lib-pcre": ">=4.0", - "php": ">=5.3.0" - }, - "time": "2014-01-21T13:43:39+00:00", - "type": "library", - "installation-source": "dist", - "autoload": { - "psr-0": { - "ML\\IRI": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Markus Lanthaler", - "email": "mail@markus-lanthaler.com", - "homepage": "http://www.markus-lanthaler.com", - "role": "Developer" - } - ], - "description": "IRI handling for PHP", - "homepage": "http://www.markus-lanthaler.com", - "keywords": [ - "URN", - "iri", - "uri", - "url" - ], - "support": { - "issues": "https://github.com/lanthaler/IRI/issues", - "source": "https://github.com/lanthaler/IRI/tree/master" - }, - "install-path": "../ml/iri/ML/IRI" - }, - { - "name": "ml/json-ld", - "version": "1.2.1", - "version_normalized": "1.2.1.0", - "source": { - "type": "git", - "url": "https://github.com/lanthaler/JsonLD.git", - "reference": "537e68e87a6bce23e57c575cd5dcac1f67ce25d8" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/lanthaler/JsonLD/zipball/537e68e87a6bce23e57c575cd5dcac1f67ce25d8", - "reference": "537e68e87a6bce23e57c575cd5dcac1f67ce25d8", - "shasum": "" - }, - "require": { - "ext-json": "*", - "ml/iri": "^1.1.1", - "php": ">=5.3.0" - }, - "require-dev": { - "json-ld/tests": "1.0", - "phpunit/phpunit": "^4" - }, - "time": "2022-09-29T08:45:17+00:00", - "type": "library", - "installation-source": "dist", - "autoload": { - "psr-4": { - "ML\\JsonLD\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Markus Lanthaler", - "email": "mail@markus-lanthaler.com", - "homepage": "http://www.markus-lanthaler.com", - "role": "Developer" - } - ], - "description": "JSON-LD Processor for PHP", - "homepage": "http://www.markus-lanthaler.com", - "keywords": [ - "JSON-LD", - "jsonld" - ], - "support": { - "issues": "https://github.com/lanthaler/JsonLD/issues", - "source": "https://github.com/lanthaler/JsonLD/tree/1.2.1" - }, - "install-path": "../ml/json-ld" - }, - { - "name": "oscarotero/html-parser", - "version": "v0.1.7", - "version_normalized": "0.1.7.0", - "source": { - "type": "git", - "url": "https://github.com/oscarotero/html-parser.git", - "reference": "0c5b619bdc7ac061f06a667d913e2af708ee3231" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/oscarotero/html-parser/zipball/0c5b619bdc7ac061f06a667d913e2af708ee3231", - "reference": "0c5b619bdc7ac061f06a667d913e2af708ee3231", - "shasum": "" - }, - "require": { - "php": "^7.2 || ^8" - }, - "require-dev": { - "friendsofphp/php-cs-fixer": "^2.11", - "phpunit/phpunit": "^8.0" - }, - "time": "2022-12-17T09:48:58+00:00", - "type": "library", - "installation-source": "dist", - "autoload": { - "psr-4": { - "HtmlParser\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Oscar Otero", - "email": "oom@oscarotero.com", - "homepage": "http://oscarotero.com", - "role": "Developer" - } - ], - "description": "Parse html strings to DOMDocument", - "homepage": "https://github.com/oscarotero/html-parser", - "keywords": [ - "dom", - "html", - "parser" - ], - "support": { - "email": "oom@oscarotero.com", - "issues": "https://github.com/oscarotero/html-parser/issues", - "source": "https://github.com/oscarotero/html-parser/tree/v0.1.7" - }, - "install-path": "../oscarotero/html-parser" - }, - { - "name": "psr/http-client", - "version": "1.0.3", - "version_normalized": "1.0.3.0", - "source": { - "type": "git", - "url": "https://github.com/php-fig/http-client.git", - "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-client/zipball/bb5906edc1c324c9a05aa0873d40117941e5fa90", - "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90", - "shasum": "" - }, - "require": { - "php": "^7.0 || ^8.0", - "psr/http-message": "^1.0 || ^2.0" - }, - "time": "2023-09-23T14:17:50+00:00", - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "installation-source": "dist", - "autoload": { - "psr-4": { - "Psr\\Http\\Client\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "https://www.php-fig.org/" - } - ], - "description": "Common interface for HTTP clients", - "homepage": "https://github.com/php-fig/http-client", - "keywords": [ - "http", - "http-client", - "psr", - "psr-18" - ], - "support": { - "source": "https://github.com/php-fig/http-client" - }, - "install-path": "../psr/http-client" - }, - { - "name": "psr/http-factory", - "version": "1.0.2", - "version_normalized": "1.0.2.0", - "source": { - "type": "git", - "url": "https://github.com/php-fig/http-factory.git", - "reference": "e616d01114759c4c489f93b099585439f795fe35" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-factory/zipball/e616d01114759c4c489f93b099585439f795fe35", - "reference": "e616d01114759c4c489f93b099585439f795fe35", - "shasum": "" - }, - "require": { - "php": ">=7.0.0", - "psr/http-message": "^1.0 || ^2.0" - }, - "time": "2023-04-10T20:10:41+00:00", - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "installation-source": "dist", - "autoload": { - "psr-4": { - "Psr\\Http\\Message\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "https://www.php-fig.org/" - } - ], - "description": "Common interfaces for PSR-7 HTTP message factories", - "keywords": [ - "factory", - "http", - "message", - "psr", - "psr-17", - "psr-7", - "request", - "response" - ], - "support": { - "source": "https://github.com/php-fig/http-factory/tree/1.0.2" - }, - "install-path": "../psr/http-factory" - }, - { - "name": "psr/http-message", - "version": "2.0", - "version_normalized": "2.0.0.0", - "source": { - "type": "git", - "url": "https://github.com/php-fig/http-message.git", - "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-message/zipball/402d35bcb92c70c026d1a6a9883f06b2ead23d71", - "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71", - "shasum": "" - }, - "require": { - "php": "^7.2 || ^8.0" - }, - "time": "2023-04-04T09:54:51+00:00", - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0.x-dev" - } - }, - "installation-source": "dist", - "autoload": { - "psr-4": { - "Psr\\Http\\Message\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "https://www.php-fig.org/" - } - ], - "description": "Common interface for HTTP messages", - "homepage": "https://github.com/php-fig/http-message", - "keywords": [ - "http", - "http-message", - "psr", - "psr-7", - "request", - "response" - ], - "support": { - "source": "https://github.com/php-fig/http-message/tree/2.0" - }, - "install-path": "../psr/http-message" - }, - { - "name": "ralouphie/getallheaders", - "version": "3.0.3", - "version_normalized": "3.0.3.0", - "source": { - "type": "git", - "url": "https://github.com/ralouphie/getallheaders.git", - "reference": "120b605dfeb996808c31b6477290a714d356e822" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", - "reference": "120b605dfeb996808c31b6477290a714d356e822", - "shasum": "" - }, - "require": { - "php": ">=5.6" - }, - "require-dev": { - "php-coveralls/php-coveralls": "^2.1", - "phpunit/phpunit": "^5 || ^6.5" - }, - "time": "2019-03-08T08:55:37+00:00", - "type": "library", - "installation-source": "dist", - "autoload": { - "files": [ - "src/getallheaders.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Ralph Khattar", - "email": "ralph.khattar@gmail.com" - } - ], - "description": "A polyfill for getallheaders.", - "support": { - "issues": "https://github.com/ralouphie/getallheaders/issues", - "source": "https://github.com/ralouphie/getallheaders/tree/develop" - }, - "install-path": "../ralouphie/getallheaders" - } - ], - "dev": true, - "dev-package-names": [] -} diff --git a/site/plugins/embed/vendor/composer/installed.php b/site/plugins/embed/vendor/composer/installed.php deleted file mode 100644 index 8704420..0000000 --- a/site/plugins/embed/vendor/composer/installed.php +++ /dev/null @@ -1,134 +0,0 @@ - array( - 'name' => 'sylvainjule/embed', - 'pretty_version' => 'dev-master', - 'version' => 'dev-master', - 'reference' => '14d933e6ae6a85ee874e90e64ab365d19ba7fa68', - 'type' => 'kirby-plugin', - 'install_path' => __DIR__ . '/../../', - 'aliases' => array(), - 'dev' => true, - ), - 'versions' => array( - 'composer/ca-bundle' => array( - 'pretty_version' => '1.3.7', - 'version' => '1.3.7.0', - 'reference' => '76e46335014860eec1aa5a724799a00a2e47cc85', - 'type' => 'library', - 'install_path' => __DIR__ . '/./ca-bundle', - 'aliases' => array(), - 'dev_requirement' => false, - ), - 'embed/embed' => array( - 'pretty_version' => 'v4.4.8', - 'version' => '4.4.8.0', - 'reference' => '49134080764018bc6b8a2488dd1c8cc2c47d15fc', - 'type' => 'library', - 'install_path' => __DIR__ . '/../embed/embed', - 'aliases' => array(), - 'dev_requirement' => false, - ), - 'getkirby/composer-installer' => array( - 'pretty_version' => '1.2.1', - 'version' => '1.2.1.0', - 'reference' => 'c98ece30bfba45be7ce457e1102d1b169d922f3d', - 'type' => 'composer-plugin', - 'install_path' => __DIR__ . '/../getkirby/composer-installer', - 'aliases' => array(), - 'dev_requirement' => false, - ), - 'guzzlehttp/psr7' => array( - 'pretty_version' => '2.6.1', - 'version' => '2.6.1.0', - 'reference' => 'be45764272e8873c72dbe3d2edcfdfcc3bc9f727', - 'type' => 'library', - 'install_path' => __DIR__ . '/../guzzlehttp/psr7', - 'aliases' => array(), - 'dev_requirement' => false, - ), - 'ml/iri' => array( - 'pretty_version' => '1.1.4', - 'version' => '1.1.4.0', - 'reference' => 'cbd44fa913e00ea624241b38cefaa99da8d71341', - 'type' => 'library', - 'install_path' => __DIR__ . '/../ml/iri/ML/IRI', - 'aliases' => array(), - 'dev_requirement' => false, - ), - 'ml/json-ld' => array( - 'pretty_version' => '1.2.1', - 'version' => '1.2.1.0', - 'reference' => '537e68e87a6bce23e57c575cd5dcac1f67ce25d8', - 'type' => 'library', - 'install_path' => __DIR__ . '/../ml/json-ld', - 'aliases' => array(), - 'dev_requirement' => false, - ), - 'oscarotero/html-parser' => array( - 'pretty_version' => 'v0.1.7', - 'version' => '0.1.7.0', - 'reference' => '0c5b619bdc7ac061f06a667d913e2af708ee3231', - 'type' => 'library', - 'install_path' => __DIR__ . '/../oscarotero/html-parser', - 'aliases' => array(), - 'dev_requirement' => false, - ), - 'psr/http-client' => array( - 'pretty_version' => '1.0.3', - 'version' => '1.0.3.0', - 'reference' => 'bb5906edc1c324c9a05aa0873d40117941e5fa90', - 'type' => 'library', - 'install_path' => __DIR__ . '/../psr/http-client', - 'aliases' => array(), - 'dev_requirement' => false, - ), - 'psr/http-factory' => array( - 'pretty_version' => '1.0.2', - 'version' => '1.0.2.0', - 'reference' => 'e616d01114759c4c489f93b099585439f795fe35', - 'type' => 'library', - 'install_path' => __DIR__ . '/../psr/http-factory', - 'aliases' => array(), - 'dev_requirement' => false, - ), - 'psr/http-factory-implementation' => array( - 'dev_requirement' => false, - 'provided' => array( - 0 => '1.0', - ), - ), - 'psr/http-message' => array( - 'pretty_version' => '2.0', - 'version' => '2.0.0.0', - 'reference' => '402d35bcb92c70c026d1a6a9883f06b2ead23d71', - 'type' => 'library', - 'install_path' => __DIR__ . '/../psr/http-message', - 'aliases' => array(), - 'dev_requirement' => false, - ), - 'psr/http-message-implementation' => array( - 'dev_requirement' => false, - 'provided' => array( - 0 => '1.0', - ), - ), - 'ralouphie/getallheaders' => array( - 'pretty_version' => '3.0.3', - 'version' => '3.0.3.0', - 'reference' => '120b605dfeb996808c31b6477290a714d356e822', - 'type' => 'library', - 'install_path' => __DIR__ . '/../ralouphie/getallheaders', - 'aliases' => array(), - 'dev_requirement' => false, - ), - 'sylvainjule/embed' => array( - 'pretty_version' => 'dev-master', - 'version' => 'dev-master', - 'reference' => '14d933e6ae6a85ee874e90e64ab365d19ba7fa68', - 'type' => 'kirby-plugin', - 'install_path' => __DIR__ . '/../../', - 'aliases' => array(), - 'dev_requirement' => false, - ), - ), -); diff --git a/site/plugins/kirby-fields-block/.gitignore b/site/plugins/kirby-fields-block/.gitignore new file mode 100644 index 0000000..cf23429 --- /dev/null +++ b/site/plugins/kirby-fields-block/.gitignore @@ -0,0 +1,12 @@ +# OS files +.DS_Store + +# npm modules +/node_modules + +# Composer files +/vendor + +# Lock Files +yarn.lock +package-lock.json \ No newline at end of file diff --git a/kirby/vendor/symfony/deprecation-contracts/LICENSE b/site/plugins/kirby-fields-block/LICENSE.md old mode 100644 new mode 100755 similarity index 87% rename from kirby/vendor/symfony/deprecation-contracts/LICENSE rename to site/plugins/kirby-fields-block/LICENSE.md index 0ed3a24..d964e1e --- a/kirby/vendor/symfony/deprecation-contracts/LICENSE +++ b/site/plugins/kirby-fields-block/LICENSE.md @@ -1,11 +1,13 @@ -Copyright (c) 2020-present Fabien Potencier +MIT License + +Copyright (c) 2021 Jon Gacnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is furnished -to do so, subject to the following conditions: +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. @@ -15,5 +17,5 @@ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/site/plugins/kirby-fields-block/README.md b/site/plugins/kirby-fields-block/README.md new file mode 100755 index 0000000..e36ccb2 --- /dev/null +++ b/site/plugins/kirby-fields-block/README.md @@ -0,0 +1,74 @@ +# Kirby Fields Block + +Kirby [block preview](https://getkirby.com/docs/reference/plugins/extensions/blocks) plugin to directly render block fields, allowing for inline editing. + + + +## Usage + +### Block definition + +When creating a custom block in your blueprints, pass `preview: fields` to utilize this plugin + +```yaml +blockname: + name: Block Name + preview: fields # required + wysiwyg: true # recommended + fields: + text: + label: Text + type: text +``` + +Setting `wysiwyg: true` prevents drawer from automatically opening when creating a new block. + +### Disable block title + +You can disable the block title bar by passing `label: false` + +```yaml +blockname: + name: Block Name + preview: fields + wysiwyg: true + label: false # disables block title bar + fields: + text: + label: Text + type: text +``` + +
      + Example + +
      + +### Collapse/Expand block + +You can collapse or expand the block preview by double clicking the block title bar. + +## Notes + +- The block `icon` will appear in the title bar. +- Currently does not support blocks with tabs. + +## Installation + +``` +composer require jg/kirby-fields-block +``` + +
      + Other installation methods + +### Download + +Download and copy this repository to `/site/plugins/kirby-fields-block`. + +### Git submodule + +``` +git submodule add https://github.com/jongacnik/kirby-fields-block.git site/plugins/kirby-fields-block +``` +
      \ No newline at end of file diff --git a/site/plugins/kirby-fields-block/composer.json b/site/plugins/kirby-fields-block/composer.json new file mode 100755 index 0000000..2981e1f --- /dev/null +++ b/site/plugins/kirby-fields-block/composer.json @@ -0,0 +1,15 @@ +{ + "name": "jg/kirby-fields-block", + "description": "Kirby Fields Block", + "type": "kirby-plugin", + "license": "MIT", + "authors": [ + { + "name": "Jon Gacnik", + "email": "jon@folderstudio.com" + } + ], + "require": { + "getkirby/composer-installer": "^1.1" + } +} \ No newline at end of file diff --git a/site/plugins/kirby-fields-block/index.css b/site/plugins/kirby-fields-block/index.css new file mode 100644 index 0000000..a5c8c55 --- /dev/null +++ b/site/plugins/kirby-fields-block/index.css @@ -0,0 +1,42 @@ + +.k-block-fields-preview { + margin: -0.75rem; + overflow: hidden; + border-radius: var(--rounded); +} +.k-block-fields-preview .k-block-title { + padding: 0.75rem; + background: #f7f7f7; +} +.k-block-fields-preview:not([data-hidden="true"]) .k-block-title { + border-bottom: 1px solid rgba(0,0,0,.1); +} +.k-block-fields-preview .k-fields-block-toggle { + margin-left: auto; + cursor: pointer; +} +.k-block-fields-preview[data-hidden="true"] .k-fields-block-toggle { + transform: scaleY(-1); +} +.k-block-fields-preview .k-form { + padding: 1.25rem 1.5rem 1.5rem 1.5rem; +} + +/** + * Reset `.k-layout-column .k-empty` overrides + */ +.k-block-fields-preview .k-empty { + position: static !important; + opacity: 1 !important; + align-items: stretch !important; + justify-content: flex-start !important; + color: #777 !important; + border: 1px dashed #ccc !important; + border-radius: 1px !important; +} +.k-block-fields-preview .k-empty[data-layout="cards"] { + justify-content: center !important; +} +.k-block-fields-preview .k-empty[data-layout="list"] .k-icon { + border-right: 1px solid rgba(0,0,0,.05) !important; +} diff --git a/site/plugins/kirby-fields-block/index.js b/site/plugins/kirby-fields-block/index.js new file mode 100644 index 0000000..f9d322f --- /dev/null +++ b/site/plugins/kirby-fields-block/index.js @@ -0,0 +1,122 @@ +(function() { + "use strict"; + const FieldsBlock_vue_vue_type_style_index_0_lang = ""; + function normalizeComponent(scriptExports, render, staticRenderFns, functionalTemplate, injectStyles, scopeId, moduleIdentifier, shadowMode) { + var options = typeof scriptExports === "function" ? scriptExports.options : scriptExports; + if (render) { + options.render = render; + options.staticRenderFns = staticRenderFns; + options._compiled = true; + } + if (functionalTemplate) { + options.functional = true; + } + if (scopeId) { + options._scopeId = "data-v-" + scopeId; + } + var hook; + if (moduleIdentifier) { + hook = function(context) { + context = context || this.$vnode && this.$vnode.ssrContext || this.parent && this.parent.$vnode && this.parent.$vnode.ssrContext; + if (!context && typeof __VUE_SSR_CONTEXT__ !== "undefined") { + context = __VUE_SSR_CONTEXT__; + } + if (injectStyles) { + injectStyles.call(this, context); + } + if (context && context._registeredComponents) { + context._registeredComponents.add(moduleIdentifier); + } + }; + options._ssrRegister = hook; + } else if (injectStyles) { + hook = shadowMode ? function() { + injectStyles.call( + this, + (options.functional ? this.parent : this).$root.$options.shadowRoot + ); + } : injectStyles; + } + if (hook) { + if (options.functional) { + options._injectStyles = hook; + var originalRender = options.render; + options.render = function renderWithStyleInjection(h, context) { + hook.call(context); + return originalRender(h, context); + }; + } else { + var existing = options.beforeCreate; + options.beforeCreate = existing ? [].concat(existing, hook) : [hook]; + } + } + return { + exports: scriptExports, + options + }; + } + const _sfc_main = { + data() { + return { + isHidden: JSON.parse(sessionStorage.getItem(`kirby.fieldsBlock.${this.$attrs.endpoints.field}.${this.$attrs.id}`)) + }; + }, + methods: { + toggle() { + this.isHidden = !this.isHidden; + sessionStorage.setItem(`kirby.fieldsBlock.${this.$attrs.endpoints.field}.${this.$attrs.id}`, this.isHidden); + }, + preventSelect(event) { + if (event.detail > 1) { + if (!event.target.closest(".k-input")) { + event.preventDefault(); + } + } + } + } + }; + var _sfc_render = function render() { + var _vm = this, _c = _vm._self._c; + return _c("div", { staticClass: "k-block-fields-preview", attrs: { "data-hidden": _vm.isHidden }, on: { "mousedown": _vm.preventSelect } }, [_vm.fieldset.label === null || _vm.fieldset.label ? _c("k-fields-block-title", { attrs: { "content": _vm.content, "fieldset": _vm.fieldset }, on: { "dblclick": _vm.toggle, "toggle": _vm.toggle } }) : _vm._e(), !_vm.isHidden ? _c("k-form", { ref: "form", attrs: { "autofocus": true, "fields": _vm.fieldset.tabs.content.fields, "value": _vm.$helper.clone(_vm.content) }, on: { "input": function($event) { + return _vm.$emit("update", $event); + } } }) : _vm._e()], 1); + }; + var _sfc_staticRenderFns = []; + _sfc_render._withStripped = true; + var __component__ = /* @__PURE__ */ normalizeComponent( + _sfc_main, + _sfc_render, + _sfc_staticRenderFns, + false, + null, + null, + null, + null + ); + __component__.options.__file = "/Users/jongacnik/Sites/_kirby/kirby-fields-block/src/FieldsBlock.vue"; + const FieldsBlock = __component__.exports; + panel.plugin("jg/fields-block", { + components: { + "k-fields-block-title": { + extends: "k-block-title", + template: ` +
      + + + {{ name }} + + + {{ label }} + + + + +
      + ` + } + }, + blocks: { + fields: FieldsBlock + } + }); +})(); diff --git a/site/plugins/kirby-fields-block/index.php b/site/plugins/kirby-fields-block/index.php new file mode 100644 index 0000000..d4615f0 --- /dev/null +++ b/site/plugins/kirby-fields-block/index.php @@ -0,0 +1,3 @@ +", + "license": "MIT", + "devDependencies": { + "kirbyup": "latest" + }, + "scripts": { + "dev": "kirbyup src/index.js --watch", + "build": "kirbyup src/index.js" + } +} diff --git a/site/plugins/kirby-fields-block/postcss.config.js b/site/plugins/kirby-fields-block/postcss.config.js new file mode 100644 index 0000000..0944644 --- /dev/null +++ b/site/plugins/kirby-fields-block/postcss.config.js @@ -0,0 +1,3 @@ +module.exports = { + plugins: { } +} \ No newline at end of file diff --git a/site/plugins/kirby-fields-block/src/FieldsBlock.vue b/site/plugins/kirby-fields-block/src/FieldsBlock.vue new file mode 100644 index 0000000..727a19c --- /dev/null +++ b/site/plugins/kirby-fields-block/src/FieldsBlock.vue @@ -0,0 +1,94 @@ + + + + + \ No newline at end of file diff --git a/site/plugins/kirby-fields-block/src/index.js b/site/plugins/kirby-fields-block/src/index.js new file mode 100644 index 0000000..53a8edd --- /dev/null +++ b/site/plugins/kirby-fields-block/src/index.js @@ -0,0 +1,26 @@ +import FieldsBlock from "./FieldsBlock.vue" + +panel.plugin("jg/fields-block", { + components: { + 'k-fields-block-title': { + extends: 'k-block-title', + template: ` +
      + + + {{ name }} + + + {{ label }} + + + + +
      + ` + } + }, + blocks: { + fields: FieldsBlock + } +}) \ No newline at end of file diff --git a/site/plugins/my-helper/index.php b/site/plugins/my-helper/index.php index 837ee19..c82d478 100644 --- a/site/plugins/my-helper/index.php +++ b/site/plugins/my-helper/index.php @@ -1,13 +1,14 @@ "white", - "#ff00ff" => "pink", - "#48bd8d" => "green", - "#8200ff" => "lila", - "#ff6700" => "orange", - "#000000" => "black", - }; + switch ($color) { + case "": + case "#f1edeb": return "white"; + case "#ff00ff": return "pink"; + case "#48bd8d": return "green"; + case "#8200ff": return "lila"; + case "#ff6700": return "orange"; + case "#000000": return "black"; + } } function bg(string $bgColor, string $gridColor): string { diff --git a/kirby/vendor/autoload.php b/vendor/autoload.php similarity index 91% rename from kirby/vendor/autoload.php rename to vendor/autoload.php index 26273e0..810ca43 100644 --- a/kirby/vendor/autoload.php +++ b/vendor/autoload.php @@ -22,4 +22,4 @@ if (PHP_VERSION_ID < 50600) { require_once __DIR__ . '/composer/autoload_real.php'; -return ComposerAutoloaderInit0bf5c8a9cfa251a218fc581ac888fe35::getLoader(); +return ComposerAutoloaderInit34ad0fcfd7efff0ce7004033b941cfcf::getLoader(); diff --git a/vendor/claviska/simpleimage/.editorconfig b/vendor/claviska/simpleimage/.editorconfig new file mode 100644 index 0000000..c6c8b36 --- /dev/null +++ b/vendor/claviska/simpleimage/.editorconfig @@ -0,0 +1,9 @@ +root = true + +[*] +indent_style = space +indent_size = 2 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true diff --git a/vendor/claviska/simpleimage/.github/FUNDING.yml b/vendor/claviska/simpleimage/.github/FUNDING.yml new file mode 100644 index 0000000..df43985 --- /dev/null +++ b/vendor/claviska/simpleimage/.github/FUNDING.yml @@ -0,0 +1,2 @@ +github: [claviska] + diff --git a/vendor/claviska/simpleimage/.gitignore b/vendor/claviska/simpleimage/.gitignore new file mode 100644 index 0000000..20c4be9 --- /dev/null +++ b/vendor/claviska/simpleimage/.gitignore @@ -0,0 +1,2 @@ +.DS_Store +test/ diff --git a/kirby/vendor/claviska/simpleimage/LICENSE.md b/vendor/claviska/simpleimage/LICENSE.md similarity index 100% rename from kirby/vendor/claviska/simpleimage/LICENSE.md rename to vendor/claviska/simpleimage/LICENSE.md diff --git a/vendor/claviska/simpleimage/README.md b/vendor/claviska/simpleimage/README.md new file mode 100644 index 0000000..9b2f13b --- /dev/null +++ b/vendor/claviska/simpleimage/README.md @@ -0,0 +1,779 @@ +# SimpleImage + +A PHP class that makes working with images as simple as possible. + +Developed and maintained by [Cory LaViska](https://github.com/claviska). + +_If this project has you loving PHP image manipulation again, please consider [sponsoring me](https://github.com/sponsors/claviska) to support its development._ + +--- + +## Overview + +```php +fromFile('image.jpg') // load image.jpg + ->autoOrient() // adjust orientation based on exif data + ->resize(320, 200) // resize to 320x200 pixels + ->flip('x') // flip horizontally + ->colorize('DarkBlue') // tint dark blue + ->border('black', 10) // add a 10 pixel black border + ->overlay('watermark.png', 'bottom right') // add a watermark image + ->toFile('new-image.png', 'image/png') // convert to PNG and save a copy to new-image.png + ->toScreen(); // output to the screen + + // And much more! 💪 +} catch(Exception $err) { + // Handle errors + echo $err->getMessage(); +} +``` + +## Requirements + +- PHP 5.6+ +- [GD extension](http://php.net/manual/en/book.image.php) + +## Features + +- Supports reading, writing, and converting GIF, JPEG, PNG, WEBP, BMP formats. +- Reads and writes files, data URIs, and image strings. +- Manipulation: crop, resize, overlay/watermark, adding TTF text +- Drawing: arc, border, dot, ellipse, line, polygon, rectangle, rounded rectangle +- Filters: blur, brighten, colorize, contrast, darken, desaturate, edge detect, emboss, invert, opacity, pixelate, sepia, sharpen, sketch +- Utilities: color adjustment, darken/lighten color, extract colors +- Properties: exif data, height/width, mime type, orientation +- Color arguments can be passed in as any CSS color (e.g. `LightBlue`), a hex color, or an RGB(A) array. +- Support for alpha-transparency (GIF, PNG, WEBP) +- Chainable methods +- Uses exceptions +- Load with Composer or manually (just one file) +- [Semantic Versioning](http://semver.org/) + +## Installation + +Install with Composer: + +``` +composer require claviska/simpleimage +``` + +Or include the library manually: + +```php + 96, 1 => 96] + +#### `getWidth()` + +Gets the image's current width. + +Returns the width as an integer. + +### Manipulation + +#### `autoOrient()` + +Rotates an image so the orientation will be correct based on its exif data. It is safe to call this method on images that don't have exif data (no changes will be made). +Returns a SimpleImage object. + +#### `bestFit($maxWidth, $maxHeight)` + +Proportionally resize the image to fit inside a specific width and height. + +- `$maxWidth`* (int) - The maximum width the image can be. +- `$maxHeight`* (int) - The maximum height the image can be. + +Returns a SimpleImage object. + +#### `crop($x1, $y1, $x2, $y2)` + +Crop the image. + +- $x1 - Top left x coordinate. +- $y1 - Top left y coordinate. +- $x2 - Bottom right x coordinate. +- $y2 - Bottom right x coordinate. + +Returns a SimpleImage object. + +#### `fitToHeight($height)` (DEPRECATED) + +Proportionally resize the image to a specific height. + +_This method was deprecated in version 3.2.2 and will be removed in version 4.0. Please use `resize(null, $height)` instead._ + +- `$height`* (int) - The height to resize the image to. + +Returns a SimpleImage object. + +#### `fitToWidth($width)` (DEPRECATED) + +Proportionally resize the image to a specific width. + +_This method was deprecated in version 3.2.2 and will be removed in version 4.0. Please use `resize($width, null)` instead._ + +- `$width`* (int) - The width to resize the image to. + +Returns a SimpleImage object. + +#### `flip($direction)` + +Flip the image horizontally or vertically. + +- `$direction`* (string) - The direction to flip: x|y|both + +Returns a SimpleImage object. + +#### `maxColors($max, $dither)` + +Reduces the image to a maximum number of colors. + +- `$max`* (int) - The maximum number of colors to use. +- `$dither` (bool) - Whether or not to use a dithering effect (default true). + +Returns a SimpleImage object. + +#### `overlay($overlay, $anchor, $opacity, $xOffset, $yOffset)` + +Place an image on top of the current image. + +- `$overlay`* (string|SimpleImage) - The image to overlay. This can be a filename, a data URI, or a SimpleImage object. +- `$anchor` (string) - The anchor point: 'center', 'top', 'bottom', 'left', 'right', 'top left', 'top right', 'bottom left', 'bottom right' (default 'center') +- `$opacity` (float) - The opacity level of the overlay 0-1 (default 1). +- `$xOffset` (int) - Horizontal offset in pixels (default 0). +- `$yOffset` (int) - Vertical offset in pixels (default 0). +- `$calculateOffsetFromEdge` (bool) - Calculate Offset referring to the edges of the image. $xOffset and $yOffset have no effect in center anchor. (default false). + +Returns a SimpleImage object. + +#### `resize($width, $height)` + +Resize an image to the specified dimensions. If only one dimension is specified, the image will be resized proportionally. + +- `$width`* (int) - The new image width. +- `$height`* (int) - The new image height. + +Returns a SimpleImage object. + +#### `resolution($res_x, $res_y)` + +Changes the resolution (DPI) of an image. + +- `$res_x`* (int) - The horizontal resolution, in DPI. +- `$res_y` (int) - The vertical resolution, in DPI. + +Returns a SimpleImage object. + +#### `rotate($angle, $backgroundColor)` + +Rotates the image. + +- `$angle`* (int) - The angle of rotation (-360 - 360). +- `$backgroundColor` (string|array) - The background color to use for the uncovered zone area after rotation (default 'transparent'). + +Returns a SimpleImage object. + +#### `text($text, $options, &$boundary)` + +Adds text to the image. + +- `$text*` (string) - The desired text. +- `$options` (array) - An array of options. + - `fontFile`* (string) - The TrueType (or compatible) font file to use. + - `size` (int) - The size of the font in pixels (default 12). + - `color` (string|array) - The text color (default black). + - `anchor` (string) - The anchor point: 'center', 'top', 'bottom', 'left', 'right', + 'top left', 'top right', 'bottom left', 'bottom right' (default 'center'). + - `xOffset` (int) - The horizontal offset in pixels (default 0). + - `yOffset` (int) - The vertical offset in pixels (default 0). + - `shadow` (array) - Text shadow params. + - `x`* (int) - Horizontal offset in pixels. + - `y`* (int) - Vertical offset in pixels. + - `color`* (string|array) - The text shadow color. + - `calculateOffsetFromEdge` (bool) - Calculate Offset referring to the edges of the image (default false). + - `baselineAlign` (bool) - Align the text font with the baseline. (default true). +- `$boundary` (array) - If passed, this variable will contain an array with coordinates that + surround the text: [x1, y1, x2, y2, width, height]. This can be used for calculating the + text's position after it gets added to the image. + +Returns a SimpleImage object. + +#### `thumbnail($width, $height, $anchor)` + +Creates a thumbnail image. This function attempts to get the image as close to the provided dimensions as possible, then crops the remaining overflow to force the desired size. Useful for generating thumbnail images. + +- `$width`* (int) - The thumbnail width. +- `$height`* (int) - The thumbnail height. +- `$anchor` (string) - The anchor point: 'center', 'top', 'bottom', 'left', 'right', 'top left', 'top right', 'bottom left', 'bottom right' (default 'center'). + +Returns a SimpleImage object. + +### Drawing + +#### `arc($x, $y, $width, $height, $start, $end, $color, $thickness)` + +Draws an arc. + +- `$x`* (int) - The x coordinate of the arc's center. +- `$y`* (int) - The y coordinate of the arc's center. +- `$width`* (int) - The width of the arc. +- `$height`* (int) - The height of the arc. +- `$start`* (int) - The start of the arc in degrees. +- `$end`* (int) - The end of the arc in degrees. +- `$color`* (string|array) - The arc color. +- `$thickness` (int|string) - Line thickness in pixels or 'filled' (default 1). + +Returns a SimpleImage object. + +#### `border($color, $thickness)` + +Draws a border around the image. + +- `$color`* (string|array) - The border color. +- `$thickness` (int) - The thickness of the border (default 1). + +Returns a SimpleImage object. + +#### `dot($x, $y, $color)` + +Draws a single pixel dot. + +- `$x`* (int) - The x coordinate of the dot. +- `$y`* (int) - The y coordinate of the dot. +- `$color`* (string|array) - The dot color. + +Returns a SimpleImage object. + +#### `ellipse($x, $y, $width, $height, $color, $thickness)` + +Draws an ellipse. + +- `$x`* (int) - The x coordinate of the center. +- `$y`* (int) - The y coordinate of the center. +- `$width`* (int) - The ellipse width. +- `$height`* (int) - The ellipse height. +- `$color`* (string|array) - The ellipse color. +- `$thickness` (int|string) - Line thickness in pixels or 'filled' (default 1). + +Returns a SimpleImage object. + +#### `fill($color)` + +Fills the image with a solid color. + +- `$color` (string|array) - The fill color. + +Returns a SimpleImage object. + +#### `line($x1, $y1, $x2, $y2, $color, $thickness)` + +Draws a line. + +- `$x1`* (int) - The x coordinate for the first point. +- `$y1`* (int) - The y coordinate for the first point. +- `$x2`* (int) - The x coordinate for the second point. +- `$y2`* (int) - The y coordinate for the second point. +- `$color` (string|array) - The line color. +- `$thickness` (int) - The line thickness (default 1). + +Returns a SimpleImage object. + +#### `polygon($vertices, $color, $thickness)` + +Draws a polygon. + +- `$vertices`* (array) - The polygon's vertices in an array of x/y arrays. Example: + ``` + [ + ['x' => x1, 'y' => y1], + ['x' => x2, 'y' => y2], + ['x' => xN, 'y' => yN] + ] + ``` +- `$color`* (string|array) - The polygon color. +- `$thickness` (int|string) - Line thickness in pixels or 'filled' (default 1). + +Returns a SimpleImage object. + +#### `rectangle($x1, $y1, $x2, $y2, $color, $thickness)` + +Draws a rectangle. + +- `$x1`* (int) - The upper left x coordinate. +- `$y1`* (int) - The upper left y coordinate. +- `$x2`* (int) - The bottom right x coordinate. +- `$y2`* (int) - The bottom right y coordinate. +- `$color`* (string|array) - The rectangle color. +- `$thickness` (int|string) - Line thickness in pixels or 'filled' (default 1). + +Returns a SimpleImage object. + +#### `roundedRectangle($x1, $y1, $x2, $y2, $radius, $color, $thickness)` + +Draws a rounded rectangle. + +- `$x1`* (int) - The upper left x coordinate. +- `$y1`* (int) - The upper left y coordinate. +- `$x2`* (int) - The bottom right x coordinate. +- `$y2`* (int) - The bottom right y coordinate. +- `$radius`* (int) - The border radius in pixels. +- `$color`* (string|array) - The rectangle color. +- `$thickness` (int|string) - Line thickness in pixels or 'filled' (default 1). + +Returns a SimpleImage object. + +### Filters + +#### `blur($type, $passes)` + +Applies the blur filter. + +- `$type` (string) - The blur algorithm to use: 'selective', 'gaussian' (default 'gaussian'). +- `$passes` (int) - The number of time to apply the filter, enhancing the effect (default 1). + +Returns a SimpleImage object. + +#### `brighten($percentage)` + +Applies the brightness filter to brighten the image. + +- `$percentage`* (int) - Percentage to brighten the image (0 - 100). + +Returns a SimpleImage object. + +#### `colorize($color)` + +Applies the colorize filter. + +- `$color`* (string|array) - The filter color. + +Returns a SimpleImage object. + +#### `contrast($percentage)` + +Applies the contrast filter. + +- `$percentage`* (int) - Percentage to adjust (-100 - 100). + +Returns a SimpleImage object. + +#### `darken($percentage)` + +Applies the brightness filter to darken the image. + +- `$percentage`* (int) - Percentage to darken the image (0 - 100). + +Returns a SimpleImage object. + +#### `desaturate()` + +Applies the desaturate (grayscale) filter. + +Returns a SimpleImage object. + +#### `duotone($lightColor, $darkColor)` + +Applies the duotone filter to the image. + +- `$lightColor`* (string|array) - The lightest color in the duotone. +- `$darkColor`* (string|array) - The darkest color in the duotone. + +Returns a SimpleImage object. + +#### `edgeDetect()` + +Applies the edge detect filter. + +Returns a SimpleImage object. + +#### `emboss()` + +Applies the emboss filter. + +Returns a SimpleImage object. + +#### `invert()` + +Inverts the image's colors. + +Returns a SimpleImage object. + +#### `opacity()` + +Changes the image's opacity level. + +- `$opacity`* (float) - The desired opacity level (0 - 1). + +Returns a SimpleImage object. + +#### `pixelate($size)` + +Applies the pixelate filter. + +- `$size` (int) - The size of the blocks in pixels (default 10). + +Returns a SimpleImage object. + +#### `sepia()` + +Simulates a sepia effect by desaturating the image and applying a sepia tone. + +Returns a SimpleImage object. + +#### `sharpen($amount)` + +Sharpens the image. + +- `$amount` (int) - Sharpening amount (1 - 100, default 50) + +Returns a SimpleImage object. + +#### `sketch()` + +Applies the mean remove filter to produce a sketch effect. + +Returns a SimpleImage object. + +### Color utilities + +#### `(static) adjustColor($color, $red, $green, $blue, $alpha)` + +Adjusts a color by increasing/decreasing red/green/blue/alpha values independently. + +- `$color`* (string|array) - The color to adjust. +- `$red`* (int) - Red adjustment (-255 - 255). +- `$green`* (int) - Green adjustment (-255 - 255). +- `$blue`* (int) - Blue adjustment (-255 - 255). +- `$alpha`* (float) - Alpha adjustment (-1 - 1). + +Returns an RGBA color array. + +#### `(static) darkenColor($color, $amount)` + +Darkens a color. + +- `$color`* (string|array) - The color to darken. +- `$amount`* (int) - Amount to darken (0 - 255). + +Returns an RGBA color array. + +#### `extractColors($count = 10, $backgroundColor = null)` + +Extracts colors from an image like a human would do.™ This method requires the third-party library \League\ColorExtractor. If you're using Composer, it will be installed for you automatically. + +- `$count` (int) - The max number of colors to extract (default 5). +- `$backgroundColor` (string|array) - By default any pixel with alpha value greater than zero will be discarded. This is because transparent colors are not perceived as is. For example, fully transparent black would be seen white on a white background. So if you want to take transparency into account, you have to specify a default background color. + +Returns an array of RGBA colors arrays. + +#### `getColorAt($x, $y)` + +Gets the RGBA value of a single pixel. + +- `$x`* (int) - The horizontal position of the pixel. +- `$y`* (int) - The vertical position of the pixel. + +Returns an RGBA color array or false if the x/y position is off the canvas. + +#### `(static) lightenColor($color, $amount)` + +Lightens a color. + +- `$color`* (string|array) - The color to lighten. +- `$amount`* (int) - Amount to darken (0 - 255). + +Returns an RGBA color array. + +#### `(static) normalizeColor($color)` + +Normalizes a hex or array color value to a well-formatted RGBA array. + +- `$color`* (string|array) - A CSS color name, hex string, or an array [red, green, blue, alpha]. + +You can pipe alpha transparency through hex strings and color names. For example: + + #fff|0.50 <-- 50% white + red|0.25 <-- 25% red + +Returns an array: [red, green, blue, alpha] + +### Exceptions + +SimpleImage throws standard exceptions when things go wrong. You should always use a try/catch block around your code to properly handle them. + +```php +getMessage(); +} +``` + +To check for specific errors, compare `$err->getCode()` to the defined error constants. + +```php +getCode() === $image::ERR_FILE_NOT_FOUND) { + echo 'File not found!'; + } else { + echo $err->getMessage(); + } +} +``` + +As a best practice, always use the defined constants instead of their integers values. The values will likely change in future versions, and WILL NOT be considered a breaking change. + +- `ERR_FILE_NOT_FOUND` - The specified file could not be found or loaded for some reason. +- `ERR_FONT_FILE` - The specified font file could not be loaded. +- `ERR_FREETYPE_NOT_ENABLED` - Freetype support is not enabled in your version of PHP. +- `ERR_GD_NOT_ENABLED` - The GD extension is not enabled in your version of PHP. +- `ERR_LIB_NOT_LOADED` - A required library has not been loaded. +- `ERR_INVALID_COLOR` - An invalid color value was passed as an argument. +- `ERR_INVALID_DATA_URI` - The specified data URI is not valid. +- `ERR_INVALID_IMAGE` - The specified image is not valid. +- `ERR_UNSUPPORTED_FORMAT` - The image format specified is not valid. +- `ERR_WEBP_NOT_ENABLED` - WEBP support is not enabled in your version of PHP. +- `ERR_WRITE` - Unable to write to the file system. +- `ERR_INVALID_FAG` - The specified flag key does not exist. + +### Useful Things To Know + +- Color arguments can be a CSS color name (e.g. `LightBlue`), a hex color string (e.g. `#0099dd`), or an RGB(A) array (e.g. `['red' => 255, 'green' => 0, 'blue' => 0, 'alpha' => 1]`). + +- When `$thickness` > 1, GD draws lines of the desired thickness from the center origin. For example, a rectangle drawn at [10, 10, 20, 20] with a thickness of 3 will actually be draw at [9, 9, 21, 21]. This is true for all shapes and is not a bug in the SimpleImage library. + +### Instance flags + +Tweak the behavior of a SimpleImage instance by setting instance flag values with the `setFlag($key, $value)` method. + +```php +$image = new \claviska\SimpleImage('image.jpeg')->setFlag("foo", "bar"); +``` + +You can also pass an associative array to the SimpleImage constructor to set instance flags. + +```php +$image = new \claviska\SimpleImage('image.jpeg', ['foo' => 'bar']); +// .. or without an $image +$image = new \claviska\SimpleImage(flags: ['foo' => 'bar']); +``` + +*Note: `setFlag()` throws an `ERR_INVALID_FLAG` exception if the key does not exist (no default value).* + +#### `sslVerify` + +Setting `sslVerify` to `false` (defaults to `true`) will make all images loaded over HTTPS forgo certificate peer validation. This is especially usefull for self-signed certificates. + +```php +$image = new \claviska\SimpleImage('https://localhost/image.jpeg', ['sslVerify' => false]); +// Would normally throw an OpenSSL exception, but is ignored with the sslVerify flag set to false. +``` + +## Differences from SimpleImage 2.x + +- Normalized color arguments (colors can be a CSS color name, hex color, or RGB(A) array). +- Normalized alpha (opacity) arguments: 0 (transparent) - 1 (opaque) +- Added text shadow to `text` method. +- Added `fromString()` method to load images from strings. +- Added `toString()` method to generate image strings. +- Added `arc` method for drawing arcs. +- Added `border` method for drawing borders. +- Added `dot` method for drawing individual pixels. +- Added `ellipse` method for drawing ellipses and circles. +- Added `line` method for drawing lines. +- Added `polygon` method for drawing polygons. +- Added `rectangle` method for drawing rectangles. +- Added `roundedRectangle` method for drawing rounded rectangles. +- Added `adjustColor` method for modifying RGBA color channels to create relative color variations. +- Added `darkenColor` method to darken a color. +- Added `extractColors` method to get the most common colors from the image. +- Added `getColorAt` method to get the RGBA values of a specific pixel. +- Added `lightenColor` method to lighten a color. +- Added `toDownload` method to force the image to download on the client's machine. +- Added `duotone` filter to create duotone images. +- Added `sharpen` method to sharpen the image. +- Changed namespace from `abeautifulsite` to `claviska`. +- Changed `create` method to `fromNew`. +- Changed `load` method to `fromFile`. +- Changed `load_base64` method to `fromDataUri`. +- Changed `output` method to `toScreen`.x +- Changed `output_base64` method to `toDataUri`. +- Changed `save` method to `toFile`. +- Changed `text` method to accept an array of options instead of tons of arguments. +- Removed text stroke from `text` method because it produced dirty results and didn't support transparency. +- Removed `smooth` method because its arguments in the PHP manual aren't documented well. +- Removed deprecated method `adaptive_resize` (use `thumbnail` instead). +- Removed `get_meta_data` (use `getExif`, `getHeight`, `getMime`, `getOrientation`, and `getWidth` instead). +- Added [.editorconfig](http://editorconfig.org/) file. Please make sure your editor supports these settings before submitting contributions. +- Switched from four spaces to two for indentations (sorry PHP-FIG!). +- Switched from underscore_methods to camelCaseMethods. +- Organized methods into groups based on function +- Removed PHPDoc comments. At this time, I don't wish to incorporate them into the library. diff --git a/kirby/vendor/claviska/simpleimage/composer.json b/vendor/claviska/simpleimage/composer.json similarity index 73% rename from kirby/vendor/claviska/simpleimage/composer.json rename to vendor/claviska/simpleimage/composer.json index 1a2a180..ab23830 100644 --- a/kirby/vendor/claviska/simpleimage/composer.json +++ b/vendor/claviska/simpleimage/composer.json @@ -3,9 +3,9 @@ "description": "A PHP class that makes working with images as simple as possible.", "license": "MIT", "require": { - "php": ">=8.0", + "php": ">=5.6.0", "ext-gd": "*", - "league/color-extractor": "0.4.*" + "league/color-extractor": "0.3.*" }, "authors": [ { @@ -18,9 +18,5 @@ "psr-0": { "claviska": "src/" } - }, - "require-dev": { - "laravel/pint": "^1.5", - "phpstan/phpstan": "^1.10" } } diff --git a/vendor/claviska/simpleimage/example/flag.png b/vendor/claviska/simpleimage/example/flag.png new file mode 100644 index 0000000000000000000000000000000000000000..04327af561077a3478c724a021e7bb6170892e75 GIT binary patch literal 7821 zcmY*;byyV6+BP92E=YqkN(s`jEU<{6^wI)KNUVUul1ukW$D(w1H==aMN_Y3t-68q$ zJLkOTd*8XPnP=vi`?>FV=AW5sCRhz32YCGKF$M+(KtWzs4gg0Iz_+s|Um@ z2UnP*vCAu%!}EWW{11;T)WOu=($>+^2FCOcud#^@+)%q!{V(@JsKh^BkgB~U^g;O_elWkpzmWgO_a7Yz-hagZ*JA#i>A$=W zse&I%@cwt(z>k&N*!3_l==v38rL|lz_fiPrp>JISOrtUNWGUZHzjIQfjA07m%i8tB z-w&aAB+b_U?ju+QxbC^j_kiq;b2f`L0lN`wm+J|LFmx8t|*P`f3P;@9(M8Ce|pToPK#IebUFuB*Pe5Bjr zKT!}66;n{obBbCe=7_tIV%F0mz=`MoS@%NYBa9E4k}BpP9Q&mZRLIGPI{kX5eF zO;sEWIQc}zS7IP&v@#tjOGRRBoZ`Nmx1>;w)#tPGx*NEswKv&?phQJ0k0?Zsow+j5 zFw`ftB|b&aLFUY_xt58SBHS>@uMKfy5q(DlXf%($esWMjRmb1hBx}nND!(-R&z1&+e6Apl@USkJNyfTTy0k^L8%|%(#6oQZnUZvr*$o^q8EkZOVvWdu@WMt2Yk9DUTU*M$}XLtSN zrDDMy#1f0Ry`zKp>|RcH*kE*uOlXqkO37@+S*!s2csh(8HT(Z;3D0g|`0UHbU-nHb z-GLsT-EVK@sjNHY#+t{k`*(cJiWk;RFB5Q>>t2hzSeM*<3dDsVikQ2cj)dR6S%G}e z$V)0WT)eBZj02sWcdJf~Ew+ap8CoQYPOFmcY$j*vDN~h8bb8LoNy!*NJjm(a_g3$! z+L}`&GQgUk%_-=u4e2WnT#jkoy|JgwDKGVMTX*%Nx0ax;a#IWwILz z4ay^(JK4^SB>_L1kTn-A7t-u5;64n|F2dKI6g!|;IJs)5!xGp9%LCJe&I3Dz5R5jM z(il_U4vhsxsGBr~l{wtv?Gmon(~Ngs<;15oj12r%@X~9JbGfPu@1jMp$9X0#s+%-a zYJ_E?Gm8liz9E=Xm8w{YNV9+z9PG2DVs%Dm&%z}XSMu5!(qY>L4)JB#-Y4PWywg>F zpGbx?V7_9u4Ek8PaAg|B5of(7pc7%lAYvsN@qxtZeOd z?S4>X4HN$k3=Tbf7LOy?(p!msloE6{3TD=e(hx{vTN7NoLU$TMX{Ge$p2W45ErAYG z*G+r8SZ16`LN-X69y$4(N!tOg8u>rcBbV~Vmbt3LpPnM^8DyNO0*AOBj-)p?;pN0G zfg!+1`aG3mcFj$?Z6bk0v1uI(d!gQjw4lX7{pdAg)B z^!mv%U{82QHrmUUiH5{HMnU)s7$hmf_3LO3*Q;oDq!S;#yMgr0!E1L;1EaCoajM%h zxVzm{FzDU79sd!sCDfS1{HWiGjSc|gnRRo^L3Xn4t_$5!o*3eg)Ayr{=mr`{LK$|_ zutcx`dTv793eUv~JUXSwc`#2{_Udc1sHwP@4P<8nc87hp*ciO^AK3I)S7` zb>ilv!l)G%2s)m_%AriOul@=K(_!Yd6EFQ-`mE^&wrYB98WSIe^aZy3{g57M5X`8N zQ_ruwrEfk8anC;B9+Jf$?}q=#mD8^cm{i-a9SWX%4PH>3j_lyKl@#jlk22c&o0RBX zn2;Y}m1ujc*bW;NkiH&Rtp*}5N{Sj_0J4plaHk04`!#AB=Y}>mgCFMcn%lT&ucdRM zg6NZroK93D^4-0n+5oFfzJYvMab=XxIhf{tXLJ^xv&WJH?bQ z*|a~{`q6^UJU}&EKJaj`w3JV2kHO*jd#mN!0!1hK)%~NgD%(36QweL5JU4331`n>H z)^WA%GZ^7xz3-Q)hwvK4o;q0k=~u6b`8bA7K!VCd5A_xjbx)SgE=5ddRw)n33RRn0 zF_1C9f7aoe5Rqk31M2{n?7ZPvu_Qio=F$7aXuTL9w*)PJ$ye{dH(ZwEZ*-Rch-s{uK5;HYHea*?wAoXIa&)V~)w_x( zD{7W25e%xs1!D^8QfJO3PCgo?EJvzKjK94f@nWj}46+{8nNQGQ&w%R${9=xPF64Kp zUOJJ!B~9DRAj*zN3;ZJ(yi3f8@D9*?S?&o_U;3KYrI_C6yQj}We`cl?et z*7HEcNO6B|Pm9sZ;WS0X=%r|)0pE}A@LZT>yyQ#TV%5$4q6>FB?R^Q!TKyM0Q-Kf) zRERHcQP0Y!vpd}HJg8D}HK_@9hx3=|r+e97oG0&8^1zeAAH)izsVn06Ggl-|Uoko) zMS=PAV9RlM0is5V{UV-X{-jRx2e)*Y#u}lIJwV_*wJ)s zKTOYhb8}2V-mG{^;^P~O5=K(;%~7rS{E-)&&8D27_ZCocsYTZPh6VlA@hrQ(Y3=#o zrdl_<-&V0Jh27@!JHIzSg0TAv!xG6dsMhet*$D41VkmB`e#~!dCDlY+@a4yy%#e`t z9#4?0kf^qf(U0ll@u7?R8o1S(S4a5wv?kGwF4erss|I@q43I3P33{du4tz5g)zB$u-aluuYF* znyFLzTlS*S)BxXWafCCb?+63Ez$<0C&SyePr7$wcr_$A^oAPs^xuB|h4y9GQyF^dZ ziOCuob?WkMI})caqG;!PRPT-0AzT-aoYC&1A5sBIF;zqH(Zb?>!AT%{5puGx6?;x5 z+;_WuJAQ*_Z({jm4HC~$ua+Vq26uB#GCqA#_nLcji(D$!kif7d4kvso4^Pzu;3}n0 zc%Bn=xqO;qOM1yNq>zd9OeSc0dQ+*1AW+L47#J1quY(zGjhpor=6g%KPSzyD=pFOP z+A1s9*xO~o)}+$B@RGH|Kc=b;Kd&3eh&U#5@#Ok_xahj$1JVJj>fR^=0Z#tAn_($U zfT#=L5tWP?fCXf&muDrKdc-DPFi6X_Hm{HUoh}@YKk;$L(28*~P;ueX#AiAN#)*XS zqqVg=b;!J`LPT*!i~0cgo@Wb0BRa_(mhG$k?1nr+i{1PAGr5pym;}1Q-*o3x)Hmt4 zJyKXZWR@z-J_sCKcIedN0kP4E0f7}#;3@U&3;J>@tVY`ieMYmS7-AN!N! z6uk&SaLK^-g>qnH`lv_NV8NKCe*7QapeYeJu4SHm@zfH`(XNU2+g2ntVw2^Euu*pU zA`O2$BdK;>lh2xLmjFZH`8ST{5UIdZ>=;-9ndFaDm0C381TR+apf6WZ4Mdo@36It{ zvt75WTTH+FMkyE(%*FHG3jXM5GqO{~ZOFJwiZSI5cTT=(%ZscDfI`srSN>^9=E63V zmu(M=bAa+AOUZlQe5vA&k9ZpR5`HT?{u!sOr0{a#Tb_>HA`zSjYA)}s7cW3B>DUCU z4gHRD^i7Jg!F#%NLGJ3A*3{l5dqxp@UeLi38aA#5Z~QPvJ^ z9zQN^O&F2B5BKb6V7qqjK;V`TnuJ~(ZJR`j+_z+G#HEQfl?sBWn4)SM-mkv;zUemz z0wp+b?OFfLXI;3)b`IFT90`*-I(Z4rj?v+2k$ivv)J+WKW2E-%rOZUi)(Oh zeKLh5f_Gq8=9{(5QyzZ8Mc>nq)+(Y##h9f*b^X(Tvi~wY__ox1H|vx2Pz0*|t=jhc z(k*AsQLqYW(nV+YNO1iT<`Um{zhKM?)oC5i;tGfyp6c|kR^pbKPO?cAd$N2) zULBnE>Py<_C!;A!5kK=coS^Ca7wi*;r=+H`zS$_2Fw@)eAut3sVQdTbAUDJ{Oit>k zPF?xLBeYc@EezZ8+4#OdrZ^l~?-Ri=pLnITz+@F&5%5@vem(0#zlJv1rZL>f)^MSD z8`{i%06G*p>15X^l{>C`JUV0}x37%1+m#RRbW;)6oAtt;cy#7Ul>F!nT*jh`H$$>r zA6h)&E!iNoEEf5DAjdI3RKa}&x*+=zIfEd0r6evhTVO=l(L~BiRb?f}aFpR#OXcaQ zcU0jiJ_hf-+5Vf`OkCuvF;kc_+G!I}znA|tP=<3_$ffyMAUB`}f4|t#jwGdl@B?G- z{2Be>-I$Oa?mHgM5cU@>(Ulu*7zA{AW?u=MfH*{1y7yTD z)wv3|G{mT$RmbE_V?(lSb9!gpf*sH7K|jWJ=%KMLiQ*B%UoQFP^W_xN8h%Z00skCp z&{j$Rs|&43uUA$^Q6B<| zYt!E#1hm)~5yIg`QRa4<_g2RZx;%vN;nq8xL~z8+Le!RAIb$&q{HSA=pb6{Zb(gXW zi)-qB$YdZ87PW6ViY#xMwlTI^oJs8ZRr+_Pq@&?9$_e&EpZ3aLW7tRut*iPRPGRxw z$qX^#$)p@xqFV&Lkm51mp3o4WlBvFcnSeOEe{#M?&F?gwmL?n#Xl-nn-}}tW1OMjJ zl?@*@i`}+N_a9y8;%yk}ohbhV-g0LQX+3FfpIVjPall9`NY!U;K*{d*`lTJWcq2Yt zaZ|bsCve7tY97qv&)XWVUAL=)?b3Gnd&E(zOy-W{P)S~#{tL$nD0l5l%urzg?^BH^ z3q3G2eeW}3W#T%N=k_rY`lO62#NiHqReerKhjDA-Xmw6Es$Jqscu|v`5YLW1ToD1nda!kaDSE%XgXX$=rK@13%4{ z(H7Jf**r?rdlCPi%qy{;VQ+69cY&}QbYgGgAZu(Agmd3=_FsHN7wjf2eq3gnqK?i5 z%<|Bz*@UgdS;a7Pqobqf6eMt6-{!b8ykhfQFVkO(^L0-2_Az=b_I{K=E0&l_hiXGV zt$ML-fxtDY56enttfZO-R_qlc4zr3s#5i`NQ03kbHL>>)1z6?n8#*_mSMgZg1tS+@ z7%tcdEO$er-E90ui~H zQ@Ty!*;}zF*QVKvs#En9HpU+M?2RSG{#RoKB!xlTCX?RSf1m)Okz$WUVnUxr#PBcn zyVSRTw*^_W0OJWS*e*q6=P*Lxp#B2wg21#e>rp8`B(eIKN-Z@*fVt1_9{r$*glM;M zJUfrGsi#fqymV|On)A30%Me?`Oft~@2vwEyZpP2L0*R*q(cD8`W93=W3Pit1xRV4vQ)kzQyRd=z#Nc)p(XzyQsd`}*hmzjNE zZ+|1FSGDy_DObOvG0FmthmRFUdJ(7^akHoF*zMerVH*nRE`D`P^?r~t$I7quT}xgL zh0wh*qw9d^qVI4=p%ln9{=0WUqHl&6AkF&HqUUhU$8 zu{0r$a~)(_>Qt&j($ii1*US|eNf#$emRT}qECU9#7G&4-8YV9orA7T>M*mzg9X_J& z0ES*u&s0RcYBa3zJ@9cxpc^OH69-5=I`D3vKlQBaa7|5~g*-f!(YM$z87iYz@^u1} zpUAp{X?ErKlY^YoW9>cfg7@s#_zjFsrda z*~-c=;oixwkFXTqavIP|86#yMfh{0!Hn(n+X3g5Wa=qS6Q@&f%sygWT^O6+DN>H8E zt;=_8T7teiOTU)tMy8nYn!H!(LqcdP(qV+Cy3MPc7wFt6AexlnRI#APN49`3ig1m+ z;GW-KPzQ|sbeb2|s!o=F)>BR4Y#!zWI6}5U%5gj>D%FL`Gnpw)Rw7Hn6fUzQD-8!a z#g9qKG0kA5^$uXF8=e|keT;Rb8M3|Rj;VzTFKi;p&M>6t_Ho=B;*?dhA=in(YClFD zVJl7}w&C#o^HBTrD$j(Z~xQ)xw*h&|uC13PDSnyy9p^0acyP2FmG+@kvs2-M_6~a5+LMtS4R= zi<;)AMI1@S6CPkrLMr;2QqtJ}ez%q2h{&KX5#;Ocm^+$8gcSNLGYxY@6k*4#46=F( zS>cj|b3Ics|IvrAn5+~LUc@x_p_=Z~F}QLKStG9BYJMVUgyKHwt%0_BNLeiCj!hbF zf1PG6XOOL&{=uLdkK+n@zVP^^4v&>st5>J6Mp%Y%QrPyIJ0&+B3B5w#_WNR5lpyzL zg7ejJwo{z@m$;L#R25L{+4fQ8o!pj#`(eZi=LuOn@tFuHaHSJ$2ii$6uXVN5QB70U zqqF2hpNaht26ivqwN6Uyn31Y`WoO`WgeRW!D?7bECc83!bl{SPb%67XjWkcb&d3FXsyY+Rr+@Mj&zmsY5uSHGGr4sPltQ40Dfk5V#SWYWyz8 zT`#qy)T{sW$T|gzww|jkpya^{W21j#PdqgIS&jhcpCMJlB}?#fs>{J8$EmecK zB<%#^%os3a+-TzkfIUJX`-3AIfm3QG2}BiaHB-Isw;NjJLlJ@5cc_3ml5_*41NY7FyRGuD5JOJ=&; z!RVC)EE1>o#3oTyq@49OM8h9jYi`dL?7!|Ykquv&jUt1$0(SCi1}}5%0mirOt>WK~ zzAitqMU@f3?W|N;yG_P+!pvvhz87tW2&A;hEQ{pN_MHmbQa9kw)u?2e%D*rb_v$ez z(ny=)*<(|tM$J%$n?$prh6^-cx)a_0$75gK3ldcO9;ceAhiN|>y6I+`exzsCKE-o& zoqq+?Cvx^9f|GOOoUAI*>`9gQ&rh&>^LfwK5m=fQ?24mrxuAp&%{QIxf z@Si&+;(BlKifmXI<8lzXutovoDw>O@PJqxc^{P8sZVt)OOLY52d-6Kk+JkEvD|*+g zowX~dB%yjQD*OZV*KS4jbcXN+aKc?->xGzan7e)FupvZWjA;AJ$ufrfCP0HVZu7PI z2NwF5MGPoVz!Q2lDwh>Ip7yebTU<(B7&^3TfNN8LAaoT}WT@Klat zq8FuO$a|;#u>;btzI5ZDI2!?wI)f)X@EA;ym!#@pu9llzXdPIv*oI|SOws-I$|1s; zo6$YzXNtTV#sADD;v7?-4ibRWhZ5{TYpbBNhJ>dHb()=|n#(MdL8c{2!QPocWUOPu z1OAQ7XwDd??xe?g+~q+y=ojMZ0>liyf=l>Qq%2^OJOg~*n^`Q-Qi0J(oa7ytkO literal 0 HcmV?d00001 diff --git a/vendor/claviska/simpleimage/example/index.php b/vendor/claviska/simpleimage/example/index.php new file mode 100644 index 0000000..ba3ae75 --- /dev/null +++ b/vendor/claviska/simpleimage/example/index.php @@ -0,0 +1,25 @@ +fromFile('parrot.jpg') // load parrot.jpg + ->autoOrient() // adjust orientation based on exif data + ->bestFit(300, 600) // proportionally resize to fit inside a 250x400 box + ->flip('x') // flip horizontally + ->colorize('DarkGreen') // tint dark green + ->border('black', 5) // add a 5 pixel black border + ->overlay('flag.png', 'bottom right') // add a watermark image + ->toScreen(); // output to the screen + +} catch(Exception $err) { + // Handle errors + echo $err->getMessage(); +} diff --git a/vendor/claviska/simpleimage/example/parrot.jpg b/vendor/claviska/simpleimage/example/parrot.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3611abce4946e8935cbb4f890bc074d32eba8686 GIT binary patch literal 56334 zcmbq)W0WRQ@8{FDZQHi(p0;gHd)l^b+kD!Xwrx+F)3#>&efNL%?0(*Rt3K7am0L+F zxydj2xAyN309jU2MiKx50sw$~Pr$!TKnMWxdq6=#K|@2q!hKI9M0j{aBur$K?}uboRLFE0>VI zN(fXI@?(XVH$Jpv&;7b1UY;?FM3Qw9N*E^!llr7niol8YJ+W;fIJ$&i{3dTJ6|5oW zJ~)7qcmxbF6#G~@ly5tK{xiBM?T#d9h(*h+X>O!eh-t`+N&AkMX1MK7sRW*Yzx@6( zhT1&pWK}mL@c{0MUAggSt$^+ZFV8U$WmJVnoBv)XBITrGC+q!y8FGIKpf1rd|Vk7E7S})P^ep zp`k4iz|25!?YuR%N!8eWu5_9gHgX3?>m8g~Jj+pW4m~$ zq)qf^nKiS=yoa|n_}1kY@YN(_qKHHJCQY)}y7{v9;SRt1q#XVO7_lb*K(6ElN`-f{ zH-xGTTMg52aBTr?5T1|-=Lcp~AcGC)bop1HQ8d$D)_%Gj;A!aBp)bx!%sNHcob+Bg z;!pI#M$~SwM1iE)>7sOz&TQXjc@u^k0AoXBjHrh?aVI zFBkIEJ=y7V*h3%`C+B85+I2ezAxMirF`wkIGYjcKe0b663M4s4%lY4(5q!A_GwON{ z>S<)?!wH7i*E#voVVC+H7Z9o`v42%V@EB$$JCcEj`xBYuta6}T`x=(9BqCViNP#@| ziRw1@OmgTS|1eSAYCu~NV`7YuixxYU@SvX>x@Y6S{%Azeyy@OL*6oUm9i~0UD%TN+ zpLbu}ab!^vs>{ZFLJL*+70_U^D!M9R&N=|m(`eL@nVFf-7~@s&MMg(HtM4I$QdKY_C1cV<2Zcu@%3yNSna{7m-fB_ z9;_!==4f84vg1Nq<=Wvgk3yO%gASH}MeLlN@4=J*U8FD0{!uG9ZDel?Z$Ga-;=2pf zM`hOO%&PP&JkDY)g5cJ~q;uR+vw% z*qt*QZavx$CK5JZ9*J^dkedR)KxsnnIRVu5$YTo&9|iF0LL>7;8y2!@CfxgnG(441 zXjiVdW88m$rlzgZg89XJkQg^sJLK%n@}@_>&ZWDlso7Z*3Ewr=&Q1&PMj&e7-&}m; zI?x`1z2p8hV6THNs`{hPA5$7Gj#+5&MbYcUH%pjrA?4v9N4D;_L-*^p(CP~rWKAv$ zr%84gSvtM8h)scpN--6&c$o7e7~qKZ`7am>>K|M9c|@2Z<`AdH#9YL%oN-2I7QlOL zIjk!xy3ry$YBop+D#p~gagJs-VQlC!dcny_PJffhHG=0rm?7JW^JYa`(i0&OpWRqr zd3*-AS8&!O9rx*l=W1Y;{mrFcCjqb>xHE8%e{=gjitgeU^|gw5Ge(gY$F_4(vc~EY z+{Q&-)d~Gy#?FBs_#b_#eH$K($qt=UkM!B#WZ>USn7+g`GbON#Z_pq66!OW^;W8RQ zZ7SL+n$0|7G)%1`aG7yh{dg|wqGZ_4EY0jd6`z`#`q&S!Obi2tG}}_p@U1*RUNTmC zrbOwaqXt+1OvnEWU6ouU*e>UoYvkh-P3hWdqxlw*g`XRYudP#Di!S8}!HRw<85zC4B^Cp1?3ULe>GJ|KvPS1ZLfw-VXDNo=`mvQ{(W1g zux20s+_fgH#T@y^>hmYXsMMJ>`~5Ka5zX~~w43ezl?BQLQH)b_uU_SXV^)*HAlWL& zLH+)T7;>1-OiC|Z*VuCTO-SB-(E? zf%^%PbU47Gq`1E3PB2=Qnyy4T;rZVcH)b06h+{+8wv4`tCz&-hCvZj(PqG^XD6;EV z478E@ZRDa|h<&F9V^`fWnE$h6rXM-VI|icp?OJ>KPR~tYuvkE+Faq6xz)|7kA+d(} z4L8Qs3nIMTJ0!2&U6uY@q~CuK9{ZoBpqR#APhaUH;LE8+r;I}!qeJ&xrl+5T)misT zXSJR0RU5o-x-(vV^>3FDeVtxXrvF*Vw%3#mXwXE+it#+Q4rR7BfKq)+(DhAfv6I(}(;>@kMTh_Xo1`F))!UMI&~WSVC+A68QCFAF z{3r=FKw4e|JU_-z8e*^&2v;q{MGvMq5qMgut z!-dsoZ-rp2&bXAH)4j48l1w?Vopmx67#I(W_eNe%wA_yME1Kec^EDs3Ma70C0%0Y% z1|u4$uAe=<8LK?p?Hd? zW<+)6y?E74u;{!)|5>ZANH=4Cy23NmaC_DzDDV%U@Oq3#9dwiqe5;m6KSsgfiIe}< z{m8nAy{9{7~2fnxkId4X=1ZXJ1>lH{G$1&fG3z=Atq#r$;lTBy#q9 zN}g{;dp+`YzPeMa_Mg(-SdnWtS2?FvEARIVU-7tZSkkO;=sR|hew^!^bV)}30~kWGKt=){nIO+tW$iR(t{x; zc`7)RSb{N3+OmnzU^n$~)6xzUbl5+MZ8qD!GlIu9vA*}{z7AH`@=EU!#8kQShb>>q zubot{!4fDIvV?EO@Zx1-+|X*WKKA>it*y1j`wyU8kGJZQn ze%!HZd~Zn8ym+%d7EheG+pY_w1VtNhiEeL74oz2RE%aTVpt;M$s}SPg&xe8a=(j zmzue*Tb5bUQCC-QomKDSh)&)$O}{)u_pygd{036XA_O-vd$`bVHMiQ3&qZ~VjnS*O zuj{BA6ymL`G-@v}g8E!ZXG@oVy!k%gp2L3UMxOvk82}E7BXg0 z?~z56o?$xMY-HttM{n)22J35E9>oyRR(!Z|5zyr8$$i`R1ji`zM)ptG?9Y>;R!{iB zje@A+c899aE4gXU-r(}8u7_RXCv5!7>)2by{6)Qyjh`8V@tu>5+!yjW_p`w(vM3(8 zkG=a6=wxiA@@KZ9`VTGX9})`rB~Bjc>a;4%`afRkJvJ~FaLQa%jVJN&@SwD;j>((< zJgP)ET000h%-R%PJruSkXo&R2D5<)*_Kv#BPQa=w2spPba)dmS5kaxC+1k1pUC?7U zPrY!shGD(edX#Og1!&i;pD-}#YlZI095g>5DV@L!ti+jbnYqsr*bN07ThuZ#)*9NC z<=qP+MG42(J_Q=VM^gn2o|a5Q==k~f-r-fxdU39)N`MHFSjG&!g$) zQSxRsA)!yaEqknev+cC%g&z{pj_T@`W$rlPi5K06wW=;rUh&03-1YbUpT5%>*(C80 zm=MdKkI5r>_iRGEzN%aFP?J&?4&8L*#be7*N?Q_mR-RNY+O*#NuM>oe3$9h_o*Zoi z531#i$JW+n!rpxET-a&fwjJ@=e$E}1DV!RdI8a>#5aM#;#h4%1hEvJI_^{*avFxGG z1#;l#FY^T7%!AyCoLWCxTdTw0%*M7aB=(2bQBuz-<;Dnk2%@Ng?)946vBq@HSV2sC zx$TGHg6?y-CDhE@Nh#YZs!LiJaa|=*v(>`)86);;@KU4@ULtwRh$T||5jI}vn6SIF z>FV$6mr{FYJ(ApE&jo)x)`GWYv@h9Nb54T@bTA~n&VM}MA+LbDz;DTRNtFRI?4TOW zfytmQp`ibcMALs;_r>(a=OOaW$;(Cn zD;nu*5A~>V>#L~ED71Wjv!XAag|)fe1|bQ#Zhvey*|iBn6? z|Ml~NV66w`*S@gP^bp}R7p5@}&HUN8R5J@DodJ)6GR&7{Ip)9*1QeDTrH3IN-zK7HGV?$$Im8 zZreqyt{XhuoAi2|yzE!jnFy;QUy{=H?Ex1Mo9EvmL7c(?1nHCvQFLILC)DaSr=4gn zpW(8L!S`JnymaxLXW&ifJ3pCR-WZBnZjVJ}ozuQg(WR%knwk`&(EaK~K9p@R;#&wd z>^Y;Fb9unJ%2DnVU(oRiPYq}B_|v7nyuH0lV($C-|TJVLxnnukfN;Iyur-e$fYN=N*}aFL|9EUX;$tcq22mFFVWL`gp}+u10|*OXE6brfR0Cp6N5QdZV){9vmbG2L`VQVoISQ zYpIiq&#na-(pw(fdAVIBSHb0J%u0xhhkmNrZo;m24F3FC^uq<#l7l#ej$X}Vqq0#{EFKydw%i0U{=#k8}^7DBpc7FzD*sEETeV?SXqK`+d2Jn z&NbH=W24iQ(7Xz=pP0hw*GJX3h6_jWCRQ%e>~q5Ie9WY3jJvNDq)}xEM$TrQl-^F# zDQs`qf>KVZE7tR-$5@xYf?%%Y}TvvSFyMtlRGmIj69C9&slzhYh zkcnC$*z3z{5*oxytw*@e0zJ_jbc;&vVa&Deb{V! z7Et$#x%SwDZ|yFGAX(BIOO@4Z@u-&s) zadnBi))?Dnw&?83zUNv%2cX}Zp*s@A^E6J z5V{=CmZvl7Vu*uLR>R~KpO1ebkYocN#$(A*nxLW@xJSfvf5T;JtdD8S(q&4$Jj#XG zo@%43-b*_ZoORW0liaAQHOL^~=(bPaaWz}^d&pgJ;67}ap+Avo@^zHo+oIaciqRla zfyH!!sCt#e{S8xgUiUt4{G``!kt|!%dXmqdUizzTz38xN?7iI3G=-}@LH*1#pIX;~ zR@N$YMV-#&xQ4K(`f^uWQE}m7)-MY8lSm2mi1wYQ!-gESjFurXJ< z08whLvQIa$7@RDwm=M$R1q2Qvohu+w6XT6d6~?`< zrI0JS=UKQM##)W27vvZuj>Y_y$x*GJa5&UGB+O@Oou!Dg2`Ct@1%`B<_=imfS0)yp zDDH{OAEb*QN_F^Ddgq+Ii(Bi|ZSrUv6XYWg5S#R!)6<^tG5$8$OV-^N6kWDg<@p0u zN?AtDtXFG(DK@Vm77Xw{I%wl4z(Z(PuX?q`AJ4)I*uwK_ueuQ2cMQ6&EKk5xd)p{p z&(QO)*0q=a_;qF9@oSZLwTZo8829|591D*RHW2sGenHd8Axf&osmy|q_rAs9I*!v&Q=&6Rc2BeN&-6su!Kg#Q=-XIox`7ARQtde z^fSEOzLci6cDv*OiSC+TYC*BZxYnxaJN1kAot%dFzY@Oy02lxS6dVE)>c5F!P~`7~ z@X>@VIJua}Wkx9ZVjQrE*J_*+6T=}ti!5haBQ-d$KSsRRAP1;lRC1M}?r`sDVfRRr zHJwdC))Z>v=Eg*O-^e9XjYsVc&7uxohkuO{23oDB!&l<2LRMBZ%R{1GL8_l%kRfHj zpyth|DSfM&^`qp83R$BLXT#Q|K0e-nE#m5dS1Kv8B$*S3UC$Vf$I^tfb{v!eCt1o? zzH;J>Vis|GML3FlhFjw((hmn1YcujuZZaXmXh+o$&D}NBi0G#{HEhU;X>XGy)qO@W z#eT#}XdMQ71L0dNuFVdwVx7jjq9TU@N$EKwW~5m$(&dZ9gpsM&$)^vaqU}hGDkGBB zt8c66mQbt<&kN-#B_=;kKgieIFv3}l@EMB&N5q?_&3^336Um;YO=veWNYGOk%31** zbM;Gy%Z^ZHo4irJl+qf_!zZfrr%EXazVbJ-qQ%QP{)OQIfJG6}Y4rPrHffkQ<-NSgC6Pb*b z!Pyb5(kFGrOK&Mv3wK+F>LI06vhw2$A}@bP4{65it)H`r1w?LjnMq}3L}?h?vhSdi zm`HQJLK{{isU<^&HIgfNV^s7lxsF<57E)qs&&z8Nm~&VvB}?gOw%N$rn)y>CNmaeS zrb$gMHDeBOm+$`Ml8-Y6$KNO6?~BP(N?msK{;^p`r_qVo!ryC)B)gSM-XW+0tHOOi*f!4~Jrvw2 z8Fj*A(+Wq2SzdpFpDhvf7w7toacJC}`;Q9y=#Uw2paYRd_};+PxNwh<+rnyYxQW>% zYHpCTws2AkSz+eM56h4Zij{|*tdyx6a+JGPJTl1Q>0sU3qmQ#>@tB3h$4{HvoFB8I z%erWKX|55=RZlzKV`afzrMBx2CfF>qCV?5a96y`IZ|ar0?(1|+@Vd84&-4Y_5n@DF zGR#f1u^)B-)$4aYY?$ra+mRa{$Kv3VFpJ(O5uR_;D8aQyFIH11u4Vd4KROTbW`I-K zs8+i7@2pngje9TSCxZMFvSOFh&B8J{BNW8|H54W&~K~ve~cd3 ze~g|Ewf2(PNGg1)bJd%%a)h|u4ptC7=jrdEkWj}OF2HbJE-8DZQ_<1_Q`E82|WOqYmm6yP^VCF`;r4wLiG*JoJ$ z;)=g-0V{>6v@&T&B9+>nI7!n>f4%C(c-0bcRAg9lBbMocXQ(a(cuRrBzG(+q6G<`| z6GJYyzcxD^71Pd$Tj6^v3f)v>*aWLA51gWv=Dop!BW~5(?clr?faBy-@5uc_O2xYu z4;vp(Mv&TBwGXgbl`NO6_g_DHSGRKy?{yT5JX<{vH|zA25#+NB`6-b~-fCqu@VCg;^w#M? z9agAJQq?BQHPL3C{9^7)J(m#8nhLgX=I6-hQQ7EPUnOmxb!inH!31J6Vp+^r8k1l_ zoABDT1Y=kED*9+*?QO3zu(_;L&4mMMR_dgx9zqtr{eEuV<~$CM-HH^WN(zc7&gZ6G zww#vBEo)FcD?%L&jZtS5{?t=_+VJlTk&9!-6;An78rw>Y#_joLBiYdOSYsXZ#Aa$p zS{w?G7Iub1NHQNo2(KrvZ9<=rx+)17DxSPaVcn}5Pi_8IgiMa+Im_)7@~+aYYHh-K@^5)Y8fGOqbr$P-0~a+4rGbGSXRI@X<)-0Kk!K`&;{-AKF+ zZaiq^1bDOjeVFD`P)~Ej81GiA)qW`9&GY@N7yfu%nbw=huQu)nicao%{?6hX$>sLO zR-3g2VgJl={IN=jkz`DF;_1Rtm@bHzq+guew*XYJ+CBNy)Z4=Y7`&EOZ}&&cs?J-ogH zlY13XIDpvXA8mVZqh2FZ&mOt6J{`bqbQol1TletfQ2E%cdkhEHHWkiiIaw{oG$^Ne zRmjOT=&A@=>Q;XsqfXmaS)RNN_)ywC>hfva9CEDrTLBvVZHmZ|zoGYUV+8mQ{Qh73 z9Rw5r295%OjEV+H%#1FKf%!iOJP0Vrd@L@u2w>^MLQAOZuBoYMI^LFr;4=5xd*?~X znj1f>sQ)d)*pQZ^0QB`vxmeR4%k-z8j8=wJvMzo9?9k!LwLxt9vBgo6F*vrr z7+24=_a{L7pl-0YZ|gxgxBzf1&bq0-v>6|$4Bm`WQv7k8RyJi(*JX8tmhlg;;`7|J zpg1c@_@p@gDUKpKoI1nA^bPc_nq2_^K}c)ix`|bzpk4y%^2{S4+PcKFD%5GHB&W$p zX4g;1BH-GxB?B`fecn6c7KpWT!7n&Asa4QrDhWyM@@ymktx)aEltFmr0ppObtd)W& z(%}?9k&{R5u2OlQyo{tqG&oU5JfVhK7-YNd%JcTTt-M?Lp$fN^aV(M~;R9s%>m3H# zF$x5Vu%1d94FG{PYo!rAF8s=La-&rPzW%bWX>)6SRHr+D7YIWUNlCP5-~$eGaB>eF zfp+*^)({ZMvj1D0z*gTI5%KvA`|eRgPQbfr)}XB?GF}zI^S)wWZYW8f&AP#9d|Q~JWzc>~X{RmRc+Q}gmsq4(3#IYCIlR+XAvz}mVVf_wL4 z)+cXbA4Ig4#n}4C0?pY@CO>-#a~a)1IzC`JIJ%BY#6ZsZ*l4n1P#q z>S7|;8uUTzaMUgO8YU2p(&D`v8=n9O-(}h}6A7}yl_ygrjsje`!%A>$Q})=8f@v8Gj8Z@I|==1p%xV^S(>#kA^4FK-lxIGdK^B{~ajm_~BlKMo!SJqOeL9fq3 zuTNFnglCJbdL9|o1hTaKy`0-_i&to{_$I7I7%Dq_^>@ ztS%A-E2PraA>MaNP?IhT*{_BboOvV`)yT|U9tw8J_@k}W(i^9&Qv(4SAZfwrR)EUT z{@UA09PgH1tzkv%38q6l$SNj=i~Iw#SmEWgt7;~oJ*Qs& zXAHqJI8pEVp*aE;UlQ4smpK}te=kq=^#-)b3_icTqv{gs#lK)@6&SeOI+U=v zTeTNn#<6I?Tt8f~+=3*mc6!G^Ul2Vr`vc4e9!Nw@8f6 zi(a;S=hR9}ye`Mr%{nF@-&L6^pSIW9ta;@V%kr0L-fw6dj!-M8P*qjcFe@{mQ44#+ zdGe%IuWfUBdPN9wW|qiP+GQ=UDV1bVnm0IswDoj0WRqG~*pH8mvPwD{aPg|BRN^o2 z%VaR9CmFs60wP;0I}DTIoMiSuv8Whz?Dnx#TtS++mx*GW3(5=qYC7r)K(EgW2X3#u zbXiuaGCfi6)Xp1}_ZBh;NHp^#sys8G3ROG!t`Ne|{{a}A{s{9O$Ssc*X702Nt1EY| zCiLnQDvj=^hJYA-J{fUmvR*s`8a>P6i*HZk;mxvWY zj>Zcw`5lzLG=(BZSVb0Ssd2${R)DogyE^s73lt%6FORl}nkW?(+=pEYK^D{Gz0 z<3+7wK6=%bD>*F~=8^|^&iLwYZTKu5AoI+;)DGsJqO&h1k z)IWgIE@g?T<)YP7DU?m!;OB6N*?q|dN=-TYB)*Sl-0s0 zj{n)4F3kj!k#279P7ev}%9Y>Awq1G~ zrvCv%R$2yCy_p{e4)i*3WXn;flx{v6ZT3DQSZ<62Vw0R$-xDY)a9 zIFc+)@C}G!|7^w#{{zq+_>7_@#`jV#S=e0GEj4iVe+3uA&+EIU8vk6qTlb0MfJ|m= zO4SiY=;K?COjKR`A#XRshQ=2$)_nUV2gd>_1pOFwT}gd#)7TN`5}LUiIX|$!a@Wu( zn_CI>3e7hUNqF0sqo#?p`fgrPltxqgU@Fiw1?P0*nH6RMDN&r!nsW)|({e~e*^5G- zGraQ)kpYFQTK3QP5klmn-*8bvOFTS<3Y=4Yok-q|nJH_r)~bAAR8eZh115Cp^^lp_ zlfLFs@kjkPPZy&Ncu`+o^n5d!W}Ry7?jj0Az`>FIBWOiFu~ArV;YZSS97gJgEe}(F z!NF6B!(Q*-{3?@UxtzsM8X2A%9IHyJ`eCkTp~;Xr+iJ37|9i{>Adv+MO&stK01^E7 z*hD?rx@ALO{1FpqtCZ`ax-+#}Z8vr7a1>4zKS_1;kxpt`W0(|1RZadu&icxTZ$Xf6V9VjL6FxFGP#!fzGA~sHJH#QC3{ee|(=Sz%=u^X2={sZ#E zc?LuX!*KZSSKpU=9Se82xzDD<9E2NJj6cD+`44a?Z+K`@q-`A1X;(E3NkL8x3k?Gr z9?_+8q*&wuc@x5s!&n|}da+>Cjm>eC}wK?<*iy_r;KVhP>DG2F+ z;CBsMx;L1kbSykpBPYai!WwxmoX$DjAVyVZWlBt{A@W5@|A)}&@k2JjNDEozC4z2J zdM(0s;t+)^8YrXSw^dYfg1E}6tx#P?pH9piZ@aCvSk|5Fb++5b;8#Q}wi{T-H(GF8 z9{J6`C=@Lvx}RZh4nK6)jDm|{9xr*@jl_wn#HlANx+|J-@72@g;e{ZrrmNkYHFjKX za&-0Go$?b7%xlaawNGC4a`M_@&0iid3c!6)!nuc=V0s!Y7_qtC+-RlF6HSJRtE!9_ zvoj?bGNOkUias5k;86#24TzYLsDiY$HVrh84j=C9*_xZ0VS-EXV;NI8#(*_IiTt>g z5yyE;iXLAGV2@piUxf-iYDJ@kC541Rux|DvsI7QLF8lQKWdG3NZHJ&sY|3Fxol|#^ z<-NA%_Blwc&lM@&)4T(xAA$UCnTJR7*=Z`Z4YfG3ds(Xrg|T#ssiw_|@vaiepU94) zGVJiok#f$bnmreumjOBr{y%1S+C9*e3tLVWbZQHY))%+@js}yB7E~fe7+FOaWREJb z+Q|5BT|z=+ShsK0{H6TM9&9vWc44Vgp@%GaTR+mH=AxWd@NO@gAGXxt>6?ydLne|5 zBfOYrc?F=8+C!l~HDFZfAUn6YXM=Ft>VXJh_6wlO1Q)MGqLND!e_}#6wTd}N>aT5C5W%*n#~ucd1a_L*VSX*b z-@GCGl~I(5wTLgvQv>!)kIXez%?=L_j1PvGAA2&e`RVr3Q)^E!^2f})%UKT+Whbcj zx#dgW!ajN6o3w7*Vd20U#8G%x0zgDVqrnL-l$9R5F%K5f4@?+rxh`rm`{X#x-koU@ zD)feZENwUOHm?_1S72?w|m(~1KiU;*E5 zuti`=QV0vHm~#rxXyeRb+8$9M^U<7xG@Iq`zSY6$L8E5Ep3|@Q<)e6z?3tMiAAV)5 zu_!)p4BAO_+5i9mX>KIEm`)BgCJL)uP*ij%?CIQwy;YDj`W^|(lKNw+m@LdsvMQTl ztxMRW>t(23HqaZ*do5c-Mo+6j7@VjXlq9NpXUm6pI$%QrYtoPJuRW2+vO;y#iWr*&jystE&*(d z7V&pVg>{7-#fdM7sE=RNKdNnlD(dKo z2JvoNN5`7Mf=33a3OwMcilFC167Eib(@V#T`OWllbv0^ntc@@4ue6J7krVwnX&T(W zr&@Oy`viSn?@wlvN?`$sMqk(|>n7^4=`MtAeFlB1*r$?dd7{I(RfZZ&Oz~q_O=g!rz}kt7}OlNeClt z90t=Qr|@7Z>8L5pnh24~!L|D!2kkoCgM|YqIWavf{b0^~(EN$dcdRLQ>)F=|tc4Z| zcJ{O3#&JJBi<{bcUU}}x*xzTcy&NCu+p$ncP1$!O&}r|8d0b~Pq=rs8GBH2U>c+J2 z1?j`>dqp~sr!R}yLZ=rA!)b6=e3CgUJ&gdVz4-^2wc%y;y{*lOrQuSDPE^Q=R@?Hv zYq`VDaedv_9WzlKpt>U(#dn4=xpj=!vl_MV;`IKe-TmTv5Vm1eymElU%z$9llv+1s z7^=N1YjynDO9p76v4r_MZxSBxb4?aCQ}CN1*IT^1N-M|csX zE8XWaiPpL_eFQ7nei@!VO)e=vyCX(rf4cnglXCIjPP$OQSH}p3w=xa^Py!2h*&KMt zhbF3tSvb2|5ylKUDZ4m~fYD*jD%lMS4+r$mGc#1_2RuT$JI|lEOFsB9Zd%5%>=r<- z#oWszt-JQ?=(qtqHrAwqw2{LGe2{tkRz*g+Dn<8t>?h|OH_Y2to|Wt9!y8W`zaGf1 z*dL0Nrr!ZFPCca^IvD44@PsD=Wy@TC`%XK46^7jT2MPW{+QOWYBZ8c){n5)RyJ+q{nkjS=B-JQ z>9+)Bc#94b9>*a%{Ra>p$BLH73$?a)JE#K|V#r<;aeTkbR+9NpQGG3NT_e~~6iq9D zT{_tWQc^n28T*XI?&!R1#wDus#`(%V2+x}nZ$x-ZK4na9xJV;5RvD}qb3{<~?8vsR zg(Qssm<-px={HNPi}T`wRO)aLOtKZV*s^(Q<47CC)?G%%lOIEdMcF5d#q*51g+rb`5>@hKfmf9`(Pr@NZ{zX`?)A>J-3TBL*LWn5<>vEW+u$^_6&M*~c;3Yv-vEg?cj~hPuk=99=B{*$ zjfrU|EL_vl<)6Us_-XEwYf}DDhZRa#Lxw`(i8O+Q4iiPDHi@O1_dqw=fAJ2N+1XQ% zC)UEZ&(v0HwmqpsUc5?eWj-YNTczKyje-{Pxhj~eJS2t(_M=^mVbzNu=K>ZQ9_66(FU@8idS*`65_LZ>rU`MdZm(t}2P#83MjS%fZiD6Zf@a6y|k`%-M>4Z`ASsI`O6X4bnhyey03 zRQ7m@uRvyu3s-!dBPXNit+5s%p`}b#c3Q)oI7pL@1FwvKe`f@Bffs6y)Ug?w09i8T zc;0G|WYg%rb96MoUCM1C3Af|?jB90mg*z_xe>-vS>ccP_vqjxovxM~|5V*LI_Y~>I}DNol>3B z05W%Y8H7Mc^E|G+lA*INQ!UE=iE{VX=SR_>YBH1Jl!fz)5*MA~m2okJK+>sW*5czR zv~@n;Cw!#J+HYWGUcVJKHmblgdQ!swwC@y~M{Rj%77y zfD|7EQ0ZE0`KVVXmfvo&5GHIsP;Xc8U|Q{o8cSR;iDxU8ws9QlLI zJDb~0%B_G!{fGwfw5g3g+-P>GeEK*b>>%xLapqY$j5-@KIf~n{Q#XH6n2tm@*hY!V zrglo`un#SIC2a|z>Ke%6`cGERkhoetM^Lg)U{l8%Z z8Dszm7$_L{cXuH;1Q;0jH=Oz1-Umhkj>>{eD)Ix3nAO-R5Q2@#Y3~+8SryXMg@RqYsc2x~f3OBHArOrV(TN-7N_oT4x)l!2;@Cwja;2@hKqI?% z8fD*rHDrD)XVN`=3oB89K;`^!f9G=bqOxZyr`q-i;&H-{?D!#T|PWNFd!yC#D| z&K*@O#nEgnhHn>}anspN{7qiwBira- zx6fjj-&;*ltl+9Zx9e-7e&>@MqxCy8GZ)d=q$lu}xfoMce>1)Ov-Rr*L5tfg%;)!dMQHK~Z04qPy4)l+#BRby=#KrCxTy97-4IhZjPN|DUSnvs`TLabKyGfvSHpZHWODZ{Pa@< zVhyrwTbA~7q+at)pYmlI##JQXJ65DWXwg%Dwn;TKt=2P4_}%)IsUdFK=QWm?QFg-! zXaE)0t)4LT)ZfxYFnLA6iM@)l=YA6IcxBm<5QM}vDk>_1?qQy)YuqXw=7@UI3=?z< zgg`K8N_=_RkWz*2qYb0c?SjE({e!cWlc!bcGgY!JnR)>ex*HmM8OK)-Zf zS4^?)0EJk3M~!a@^2*GGW_K$U(Krt(6iwmXsD6~CncxJCqWxh%P)YY)tgxB&DUD|? zt*xZ-PG)=|EFh}*n-ftNHa4-DMWmDZy-)&2!bP}%I<}Co_USk=Wfnr`y;MOg$GTso zn%JQO%-EzUr=HoLe6al>^#cjCnt4Pi$t8vcH$|sVE^eI`N@oIb@i{|*_W1Qi?Jh`%z&va@jX%LS@=i^UD+_6vBW`MR)&rwYh(ocO_+!q6 zRWS=g3)_ivu1a0}^l&A+?1;tnDt4yKMY2%e(8AIi=Ka#H6GzT#d!qU`NncUrH6WV( zm)ZS1Z&(TDuSpGp-SB>%Hq(CbTh!_nMU_0JU&k4@V|PMDBrAd>u3l$@9j-yT$5@hQ zdqecYtJgZM-YYuI0%IKIXwnYegGr3Pz*LMptJZ9C2{g<-C>-As)`CydM3 z60XNNa{vp(bf?j^G^OQalSt0q9{PR{fB00*#O`gfo@{(l4HgN644<{RoJaTm`0x-O z5`x$s3mWr@=8BfaCg&YcwP4kly%3K|uSO;8@2K#NB4=u3SM=hO#Uoc4_fRPORv^Bd z7MLt8pkp`4>s!z`h24Gn^}{6VPuA%uEemH_&-3v-hP$pU--U|nnZdrQQ}LSa^@Qi#p5P|+b^Sb;O{c^c2~X#Nr+`` zG}CEhJ3*NhA@-YbUJS+5j5X7C1d!wGh;qQ-sPXs#%Dg~_VHQ%<88s&X=YC)r)4>$+ zfeBTRQ;~co(r< zm4*i$FvtDUt|3avi*z=EBPi&fpUKWM_Mp@K<^9scNEGC0DYVeOO0A zXvm%n{hfZ5ag>Kr5Ie!y)IV_a&}g6ZNHrxThCFW7E@FNoCWsRuLYvuXE8Z|)SFtkf zN0zaz5BQ*Yaf59W-DFK1X6zt)lE`5MSIsjx5q~7xEFwW3MDh1svb7;H|Mfn5NF})1 zm;mN5v*X}m<*%!iQY=@#Fq3kKBbeh?{R*LS?HX3K3g>@L4Vks++JVhk-%V7Ylwq4e z6Y~h|BVS!i+s0+P01E`XS~Z=SorRKLP>-YCYmY>Bu-=M1{2{oKElWdr=@UQOS`zHZSuXW8r~?MB2uK&#;$chpM9431HSu6RC$V7T@|6U zC5<74I?UaTf&-TbN$}%f2R!v1+dZmUep|U;X^CM-W*6(y<@YTQsf{Z%sh%~jnv4;_ z*=yNP@;ypS|FyVjngH|2K5#uj z`sGP7%GRxR{)kJ4 zXV2uO-!+x?=9tpV;zXRoxl(0XbSZ$`=jeuVMuz(b-*Gi-7gK4=7d#UvTBSfwa;G*` z9}p9crBjXyjNQRgrfl!;&1WUfYqIx%6+LnfssQF{6*Yi)fP+lL`KFO?%qr{zwN=bZ z?FfMlK53L(9axw;JA|Ss3`I6{z+KH6miH_sCYWs+f?Y~lG@tlcFg5Ca0KxRcq47r#UoQi8pm1({&Q{NQ>CSR&>TEu1Jv?R>ss2Ob z%5+7{^n(m!>D)Jm1Sz(rA?2Woo0G^VS8v)KxX0)?tkof<#P}?G_xd>grBZ|aX2DMx zP5%H3U6gZlKvPYJ@P!|IeOirUMaiHS&m|m$gS)zP@b)}bb2ZR;P1F#L?-y2G%9iEmap>*hbE7FAYZlg-8 z4yJ5E#$YN6*evCk?Z#l7StLIunOu1%V<}g_<0<5?kdKEjU&Ff#RPWLSo?Hs_ zfUS{~^EPbxx00*cD|)- zjj`Qb6Gb{KYX1PJytcI<=uDT?p;$0{4j)C2py2wnTqbhe3V3Q%!R)XNm;2r(y+9~~ zKNkR-hNcaA`Jc@Gfed9*7z_I-?>aYyw$fvqTzh*BUsUT*pV=aAEL@M zglCHG*inVtu(-Ng?cU(#>al)|c{Chc(Wr?ZB}Sw2Roo`i!8RP<&2-PDRgcSvq$P)( za6$OKG%;*39RC1tu`F&%m|gBArpwYklz>_()A^>+!m^)i041RBH2iE?eH%j*X-iuj zFF5$4m{`0%I}40$DPxC3_~h*h!eg-2u0r6N@{{Rl+*(0;X zHM0up{{VWYJMu>$tG1sd#b8=Xi^YxFJ6|P($1(21*K3SH z<|nyhsFPK>YKLkv-{h%KXr+p!QHM`219U4eK8;4bt{Q{=!ZjTwhos=?yoE*sF_akE zqS?ALe^_Z8^ifg>H<${7vk=-U-z!KkPMGQj~8~&Gb(c=(eM3 zABgtjp(bgsK<`_etqQIk5(!manJ z*s8r9G2%{ucdB@18dy!|`}L3Lx;bchsa3{j`{1&ZCRQS`IT>zhy*h!}qk?$=mlNV) zGyvB}iVi!W5H5Cv)ZS>#oPn85blXKs67ikn0m)%7-HtkvbyUbVx}jC4q@&Wu2$h1v zxv>6@@s-0V9!G-0!<||k99wmUsv)MHlCbA4df4aq0;%R1L2>5uD4isyLkK(8j~1p^rArdsDmMN+e)wxXG-&NRlBI{D zD6|&S;yve{ZbuY%T6?0wVepj8K@xjspLc>a&UXlB0nJjTG}D5rXY&;k4>aT~zVp zpM$MRku<*1P-=Iw_oB|7>~VCQjsF1La>Q0}bL=ULP36Z|DjtTS+&vcOs~Uc#dP^8d ztB8CbbXY8|7DB57MS%R&C@b?sE}sWphZgU*_50=;jW*<_OZ)Vc{9Dax=X2_);Aul( zIzQ48tl?6%o9?&uDb6_}KV?ONU31A(YWqc8jo^X3d*Og_#9xGVcATL-1@lB_Xq9?XXK5H#U4oB}|qq9G- z56ub;vG5ADO2EXKu+@4-l|hK8L2xn{MV3D~adhS~d)6e9;x4gxr-ls|Lpg8Hs8MN6 zaMU4`oT%LAhiWA~uVK`J<2~letMb)*ZID9C05&XvY&+yrTWC`x*;5|!K3tH$287cN zh#UeM#=oD6!eN`zVrsN<2lNV^X$@<#aJgw!0DVSj#7wG`>k65S#7fNU+z8bNvG&kP z(P)OtE2B!YDg)VYcgV_`?mX}Jn{0PS($qHh8~Ub~mat}WWe{stg7f(%)G*eji>&Sw zqNhouF}`X<0o4huI?r-;yg4dWC}wcePZV8HiMpn6)Z)h|wCGbH&uAe$A`uWv3GPML zh#ZqxG`US{T;k~FN^83VF#43@?9T#ua0!@tWahb5I%4VHGjcTWPMImmjH+_>O~R9s zVo?roJgyWI;-#d4rqZqzOg;-cPpo((M+SlVqtM~y#GZ+lI_dX|>|>l=Q?T8CWm6F1 z)>*2Z2G12%sp8fqQw?MQs#kQx4rMSD!MfcB%c0L@l}5Cdg<0n@20NG97(fnHDAsdG zaOL6LgG)@?flg&SuBX!F;?sZ4U@>k1uZR3D-6^Drn`oU*a(-xyXXu;*o+-y9aS&=c zZ)T>ja{8dwmmLD>A5rfz*4QqQ+?q59D-wg~7Y@@6{{W=%SzgoLi=Ovx9X$ov&X!wtpWmg8Dw|D8%EsCg-wSf0evBHmG-ufTLcRf{54lm zt~W_lDb(HaDfM6n4wLGihYhEQbx0o;^m*#AxT<|E8kvW34z~^~Gmd<%Zvo9PH06lr zpj{-pht)=EEH)jZ`Xf{|fSjZA+DdCH4BdwU*LXQTjc3w!psb}A_FNpC+mjcv%rd)) zu~&&6NcLd{^pB5r$kxR%zZF(}R{8t9>}+(kJ0n5O100B#s{Ko!DN%8x%>=G7D#*YB2`a-zrUAWyl|t#{eH8b7(R7{5@vS2Dwu{FB;s?^6`RuH&LOiuH_p z{{TyE2q1uXBuc{^JFC;Fk{y-d-Rgx{9V=h`I*$d>OLIu@*j)lu?44C#ZdtY`ELf7ciJ?OOJA=UbEZ>sG-?!#^AA->YMTzHgEUEJBMLga`_Yh;P0`yzp;wYulM#Q`~jyT?a6TKsnYk4lokDc*_(FqgDCV< zY|>Uky5|qcRH>;xDWrzfALbf_X*#6vw$k^ttrAJF@6aaUu=Hp*N^Aqq?$;Y@)@Z@d zv#MUJ{uc6BKSp7i(l3|K#RFaV+L=Wvb`90Uo?p7fIi<8I^mpxQVR}y$FLi2=M}(|Z zQx1ENnr$&A)nQ)3=L@C^uF59OLwyA*f7 z&F=l)3Xq0jCKeme_&%PXny>6PiCD~Yol>Nn$4~zNs7$2KSS9>>yOS!8o~VjLvOX{N zOnKZJsf^%oS11P!v0b}ZR!zm8?pUGg^dar#${*n1CE*wP~ zEN6gS9s?&Dj|1g>xtst5$*>8S93v?E-KU?#e`G%KMvXI!#9fT+H{)`|dP5Xz*FFQ6 za80DfIwRoj9Mw9cx}&0lF86cpLcT4OsZ;eL*5s%V0|B3+8g-+pMv2X(aef2!D}H(L zSso`z5;=)NwHkF<#7HUZa~o4e%B5Mi))RUvZvfmZk8p!9veX_cd&yO<;?A5f#e;fr|P zZ}R^DtDl$NdU~*3m5mvm?oCao_SzWBQ)eK9ohPz5b3Bu);(8$K4%y@uBOMrQGh%@J z{8c&-&?VeTfgE|OZNFF*C`#1_Q$4{tRXQNjtJyj`m+Y`-`7X}m%SBb1II2&=VW|gi z2nA=wQ)uGXDr{q(_rZd)_L!%$#rHBxrQ(S^dkryU#Oi=16I zl?nLD;Au>D-TDO9F|B9;pg;qM-djr!##1+N%>MusWg2vx@uNaC=sEbAhdOd|@mPw^ z=%_QJrQ9y>HI!de2Ea8cbQ?TT>Si}2p$Zj`(ej>2gF)3DOYIF#H##6tMfNI_ znUm(%eu}Oe6f08_GiHQpR((kAIF#d}G}!#@lVUllk85glZih6OgvPYn-~5w?CBfZ> z*2^i6qmxH-Rq!+JNpHoMk4@(YT@Vky(DS8|iPJl)`_ z(54wpumUIVd2>{W$Svc+R>W0qcln+T=BToe6uU9I;moFiJpTYRPQ$kQ14N^rd&w6S zDw9vfc?~{k)4t&xhXl$k5qF&j?z(!JDUeUT zDs6_2t1y(a8@Tpc&0?{&oIo#eH&p3E>uF#rwG(ErBRBMGMH+Fe; zj{)GF13BK0mxkC?9*EiVOr7AU{3qnT7ALz>RjizW)ryuIF%9ueYXNhvex(NCsuflA zNI6Rf9w9pe>0ek$p;@8r{0Bn_xY91|{6k8EgS=ICIPaa|278dmC%~+m;M-RB9!bv) ztj$2UO{n2eanyC_*TkB&p63n>;Hgt?Rx~tn8)NT|U}ym6si%Ud$|Eyi@>K>cwOybV z9s3B^XBTxDFidx#%7&Xnm1H{G%qM}A=d?4w=AB95vjFpz(%^8_$GG_Na;)q-XqYT( zrM$$g5fw7?2x73#W3`ArJkzNX&MmQ7+Ul&~s8jy{VjB-7o}*jLuUqz)ftdCOA+_PQ zw!qzyFPv zie=fZ*}BO3-efQT040N7*!@-!jOdF%PYUqT1Bt2Oe69?p}{IT5-4$LDdfBQ2g{?J^a=y3fe5e z(T7R4jgIxw2Ab_|e|svSPQr^L!C)w1pH#yyVoIl6hSRLV=$x~3=#X0P0*KUgPgtik zsrI3Lqxgr+H14AT5SsQvzR&pBI4Rf{dO9amcxcm~a%*9{d48#_mluBD?oe^e=XeC$ zNrY*)G+J-_tgwIz=%~8Gxvado#sEc>oJ3DXb?{Gf8=2!xT0eC9bs7u3SvRm$s&<$> zRVRLjh**j(=siN`R54Wg zN)D0Bh}eCU6n(868y!NwW@WDAsMct8H#Nh#G^uX8VH2%~B?3C6lqt3bsK&l0n$56@ z@J^nL_Egk&A;AYh?@hJzs9IIwSyQKtd|aA`ExSC`K8?^!xvr1&j9J1Ek#w)u_;M-)MCB zE{d;4P4eagj$UXXg2QLaE+!hf2N#xybCrO85}!T_?U6vndrW@*I@v!!Sq;TyWHb8!9!LJ$Rvu;0ktB9%ghr4ly=9^X7S{)0~ z_*%_<4^dwh{JDV|M_k`Inx$UW(`SSh?*i-lLvzL9?J zYE?BH$NMb!Ttjg64{TPTd4FY7ekt{G> zG5eKybNjHTPM#j0WuXuA+hm( zst4LBKRp+n*Ld(Kw1O-~gfFzl8o%=+b>A1=M4jgp){7yDsv64R6R6^uNuoI-%8mu1 zXI}2C8PxR(D5%;(ihb)e1xG$o*|5r^Bm_vy&tC-B2!&CaT?Pw-DcQq?qTvUzj|Rj8 zvT47-rq~`SrF3|jr{gF80OPYOiSS0XCf24VtvN0HLyLUV9Zi+mGcd+q4n(E!o2Y<_X=$)l-?N>D>i%CJUoiX4igdyXgO`mP)COZ>^(=& zs@%kOIXrUn;HlT5DR!tl9HiE2 z&PDfk$#ivESaO-vEK`^R&zk8me`ge&e-)$6LJED2`k6r~*`_DCVyZiGhEc$ib&BZn zzKC%i@Gz;KH{zOuKy5KDcOD3nE;3Xg>=XOfbeUDzC}^2!ryh>;0aWpOtPN@dPkhxQ6sAxXQ^d!uCtKT81|FRW^nH)9tw%~ zQwIgUe+ZAB-?G$bX92v0N-S_Z6`?uK4sNRu+N=ej1#y(Fjit^o(R9-n3J60M`)a|u zd(&|g8`3wlA>;BX*c#5mJnpdWAHsA@#9^rra=M$w{{X{0SK6@5tQ)*;TglvhX_$(K z3`ebKJskV&_&i4iQw?48Un7#5lrfDPxQ2mK{{WG;O|4Wmt8#yX+uYq|zB@$SB$GTJSnC4WZV4dJcFtGlY z^m}o`b@bu5q40n14(@9af~oc@t!_${0TR9yAa4hgf-I`c79sN2{{Z&Y z4TWL+i zVO>nvxu2ToYXW2gs;NS~KS^Qxn_0ZVZa2}Cu{8CGPr>3kc8tO@)~E5Xst$0#m*$~a zx$qTvap!)bv13tTw&DwQV*i9WuVv%m7Q;vcWv z+SZC~RRg0{UIU&WE{cbHuD3^C{>v+;f~MMBgF#g(G1GRt@D_~2NQNl%I@U<07v>o?Qrb7=F+L+uqKR> z$&nqpZyGtN__iEQn7S6OJ~oek_f0s?osks)p64R*PK9c@9>X*%d?)r_Y-8H?Z#D%PO_oLYoJ_bIQt} zL<2Mu2a@PtmDXunq6z?9ue3d^Y4vmSS|e{1_G$6v^G*;tFU@qAN-pLV&@UaretS(U z6-sUG)fs%as%@c2fpGxv53e-TYM{ z>i+=uTmJx!%8ok>%Jj57rkz?wp#8=IDz=$|bI8HwJ!dd854oP*H^qEe zYJ1Jy9HC^p9Chrft?;rgb?pj+Fc^-N+m2)sd8o)9Mp6bt!8WL~^13%%6=5{1cG>y& zp^0Fq!M;B*n@YL4W5^&pYSOVkY%i|X2fyEMVyAzKa1ciGeu%Nah0)?VZ*}l74f<96 z{^Ap~Yi^AiM7y@_R&gUq_7+w~>KX^Ih3lTk?C7m@3iVAtj>~<%A#`;C;l+B^p|Uzw z`Kc>{09_nZhV~oztd3*(6bL}-5Eeo7x-EE+jviSO$(A3{S`exOv~zSR;zQvvzr?c9 zYQ7vD_1fmY)w^AF$k_R= zjF{7svIK+8P{!fSI-q^5IibxCXmdlF8*H5-o@DIJC!ZC%4-z_nT%zsnw7E8SyisF1T4Q(KZ+CKV1Lm?-1nBM4`YEMH6yDt*&Ae9Nc({xAgwZ&hFtP15WpI^O z0gR)FqHe<=d`;rjN~HtAyb6v>YdeP^%)IX`b!RDk%;^XyE zeh2^uaso-vYQE8rsD0eKzDmbt=3nl}wFh8a_MP@P7L|x_%vq+ejT)WK`l2%88LM^g z37D)q91X^Yh(yy3aK5sONL46Tql%^5W5b7t{nZ-X9wv#JRhS;%J{@SDrS@4_Z#6lU zaHMdSlns165yt-jD=fjFEzmmlS5oe+_Uae$4rj-^`69t3pvM$4kr(2(M#~jBIfEO0 zSNWUu>OrV}7AU6H_XJ?yVd$Mnrta-{E{_#R{x7Q3PTaFP6`u)NfcuX8lV3@X=Fm{5 zRl|p9coYkJj|5o!)Xk2qM>a==k;E-pc&zwZ*k>Ekc6RtbUu6enl%L5%)_M&HbKRXAn`YQk82 zlbjm%-Rzhj5IVJGh%(Y7comiqd^?y~UJnDaFQoAIwOOR^^CAfchf)VzfVwdgr=Y|?Lawq2el zZJN(AuJhj?C4HI>LUv0Kbq6<*O>H)ckKTmP-Pm)Eh|4o-P!-rdCR@p6uM-pX3lcK7 zq_EOa=x@Nvr-`Ip8_l|PJuS zN4J>zCOFCsDD0Bi{4yT`0f+36_C+z8vPbrJyZA!28#jYs}A%>%V+X@3Yw3$pcRy| zpd2o;l`RUECkpI4k8Q9#cqifOx|6t={{S#et%oDuZiou+@!8R0Uq+!F4kf)4$A1Ei z3`J@u+;MNoA7N#pxG9gpvFaG#1*(ZxJ_}C|Wpy&8pspJ=S)_bTA$qn>u?Oh4lohxZ zg;;oOl<)vfcDpqy%S8phG-d|BMHX3b-Y4mGG#Ip3cYsArNaWOgQRdPQ)n=s%TO3dBFn(fzRG9dErLlWv3!TvQp{{ZW4kFm0V z;ohc`4{{E{VOTXU{Z?9Jt<}1>oV4p-=&iS1o2yN*Q}CGDo4%}>kLp-=OlkrZnooM| zc&jT91R(4M9gqOnbws+~@wam?CjC(82Xl(v3tto#XSv+U^-MgTKRYc#bvN{l^HRWL zxev7bmTFILnDSjCiDB=8x>^+&ds_L8o5{|=ntT~kF#iBIUi&4e8kJ+3njQuabJ)Y~ z)CF#ZWuRPD_FZ3OEA_0b-L_e(5=EN8psv{NTjg72<7JT-LN-m*G=PX5{B}uF*Pn=} zH5hry608E$oYjH zz(R*H$}5k=Aw#8Qz|lVy){A-SX{#tIcG+GPy0;2st8A6cJ=l=YH%QFlvb-Mk1x{Zj zs-3p;*}OZIl*#9}hcBsF>p1ceu(np|V|!dxi0|3B{{ZPLba*Exy{!X4R%SHp$&N1v zN6O7YdKqRurcZLqMuRypC~C1= zuN=aVt+q#2+h8qx6c+dFy4>(tobSZjc`2x4Kz@pDti@y0?G2VzJ3zVMp||l{lgz8k zq4sLdI*mN+rS%Vb%Tvo{>F_Icz8f=w6Q~n9DHi_aWN<5_z_jXeE|&pWyhB5gYiZU0 z0LI|&ma9ExVyXWCE$4nc+2Xo7?rcSe)7X;B@e3=>Rnk`!emZ0YG@irm zlGEg?v(fl!l${QwO(%nJK+;uO^&L{7mmN>AvK1&W_bjzZ98}c|KM;4xT6w9Bm)T;V zY`Ix%O|+DDZ*0?L)QIlc3O_{SZuOz>EBKm+gxO}H;NqgEmsdSUxdk0d5_qij+7*#1 z8%?~LO7(5;QVO!&cZSGeK(AF(`U;l(!s&3XZ#JSvC4j+oCp33BTog~GDRk~12=0^{ z=`4LIpIqqkSzU^w19}`hy^zT9!#CASCy`wiA&0-}g}fEEZw0!c{wsPG>F!b#j}&dP z-B_qce#sDn$sgRU;ch>w83Fum`X>_J^#SekTl3si_QPCx1r*PY*xAF(?9AuC$S!K( zUa$I8HKV(2o#C=fE3Z>i`bzB&##Fd90qJVg`8fSyeV5Wznef$fe>7?0wc>!rQgPA7 z51NNKcl!%1=Qo)8DF?hLaSNwqKMVP6)e=;~D?_lyg3J|RMkb$n-aZ{m({ERT z=-7GiMx{|cC0k%^6W+683FJ1!IBG72P(sXLD9hp%*Q<{3y>)LD{6k8~{{W~7=UL1D z0H`$lSbBe|-*1Y_SsE2JNuOov+IY2QWURT{_~-Ig3r(8!A?;UIQ$2f+1*$E7fJA^( zi;ei~EUe!Z+dWCHe+b(O(t}!DN;O|UC1*R!VO%~Ctvt@pq6MWhG94{w;8$n8;azSw z#d`Yw0Yy|@={G;&#Qjuau!o))eOB{)R8pkw^)(H;r5(0X)8Mj~F!?8atg<(CC`!7% z%~keXEftl~4kN8~b-h!)WfGbKlBONWdbWL>xQ z-N!@O@Ix<}6zMtt042Lro^r0v=vP*4_!SlFcm)KW;<`Pbii%IjOJWpCxyvY zF>eZ-%XJ7qn27DjltK$2$BLB$z{48z5W;Qo0wv;fpu}+oVDkv4h*B3416XU$8zQl^ zZlJi0s7Eu63*eN{A#gkr>jd|SpNw+chJ+H9 znHX3tDw$PfWqB5h2+G`I#8koL++0h9JOs7_P!nh>60Cu;66MA44+OKw2q6A1g2H29 zQfYt)F%QCmWoU;)Ffka)L7xR_+_D){;tH`TM-2E9jv|c9Ok`P##qlwI7r;t^hcHnN zVb_2rn}V&Q3WSt=kAXzX1%*MI_>lfAGSQT*#-s2QnW2JRVqwhBxUT#kFie+IHf9=y zhyX(rLQ5dxZ&0!P$2LWa69jL?N`x4A0|$uW7)(q_P(w_79stTr<0{4QNg?2(^7woR zL}f*V;2rK*!XDoesbW~glIkfb3gHrE2q1w91l*G6Jfj&sd=z|%DiLHa4+Wyj9Za~0 zqQoLtCaBV6A`bvcu~QK&as|OjON3JY0F8J&J`*|PCvz>BT51pABn`nTAU6U~PeLpV zL}Zq1)HF=Wl*tRs#yRj56N%FB52!)w9_Cwu?1*DT#YIZo31ebOaM1(ALRFYb%oKtl zz7hx@D-juJhQ*?GXUYg>*{F{H0D~RGsRa@XpoFK$;sXp;CVper@C&TF2I29gY7y&# z?3dvKs6MBu9O4^Tg(=boF*uPQGWtq^4x+ek!8A+oF^ggwoP<<7RfFS32yQsi3k8Xn zEMOQi+2MP>o zcrh;+5@+*-UxN}?grpNIOcC%ciHsr=rARy&6~O?`QX&bQ0zFdT)8HC~F(O2ko|6v% zxM~izuqc5ZMM;KMh!k}a^%&|6Qn0~@_Cx50tT|H@aztuj6r^IPc<^m6!6Qadh^Whm zaY6{0qQk*hkm6p{Nzj?U1Mv>&X}(LrG9ea7FMu0>2tZWHV2VXcbb+9aLIIT$;UPCj z=Y_zlZffy{X%PX{FlwI$EV4!z5NU}t%S2F+NV7DLF=LTw6A5sL5I%Rv7-3bY?+}Kg zxg~i0`1NA|EVUcd4&cg$Ua6GcBckIk%uK`xqOM3SNC5`GfRswU1sgm9LkN+Imgc-9 z0A>Q83m~u-5!|y-lfalGN#sHj%QAu<5#UI}46wjD@DezRTq{Wk3n_sOF7cgY9JhiE zur`>h>^v)<057;@I`M)0h5jQO+ypFz!so7F)V6Up@O%)K(J8=|7UDuE4{(4bCju=Scn3{KGZSVl+`g|14z?SBhwvjZQuO&1 z#OXn;PgGYC0!ENQ5R0mxQZQ8F+huv!W=L zBH&KoJCzxNh@t-g6%iSMF-_2A7OJ$^gOu%3;{kajH0s zb8!s99uY97(J0I#gh<9%qpT`1#z%1rG0dS%kwmzpUj}0m%q#>VxPQY)p9m)5%>0hX z@F7zC6h%Vs$^%lEF9Jk_QidN?)B;%*F0l}e%NSvIGLz|2$watN@KC`qQ*X4v{LLm& z*?b9r(hwG4!xATe;7r78@T>m-g*CVbFedEATZJ(yAc`1U3B+Zc#ny-drJ!6>hzOC6 z2%aDlaR~Lplg@RfyArcGnQ}()+mt0i0+>7>5G1ghCTf_q7pU3$f+dC2xEBS?+(Wi( z+%Re$*9eRdGcm#c0D$+F^D%9T^D}tUQv{{lyv9R*7xg5lTeNJS+f+$8bBZaq5W}r>J^B;S&p@SIZDh!6J+>SrD#q;z17) z{K0oUv0eCc!|rRjif5EHae9V+0uC6{;ATkQG6PaH;v{Mcgh7He1!YT+_bGyH0TiT` zQ4PYTV{{BeAm4)`YZ)Inn1K>xjx{N2TGVrrP&FZ*` zjWf##Zd8H@3PQCj)EjYmiLYK2#-&R-?n$Dhbxdty*zu~>WMXZ@fpnxc4W_OX zv#~P;DL(QTpmDi!<{)dZV2fpYi*O92MN@`i9VGlJ!&|{Yt2D)X}5rD`t#VDo9mpn?R z+^7SGXCbc56FV{(E-7u*~EX)iiJ!;?sfSfUe&(Rxe!L4EntKa9!|YV!bl*2 z{{R6;f-y46l`3%#VeqL?ii)aYrY3=lsxMZ;h2Rk7%k@_fF%hDSU*aWR3rycqtrxP= zTTfr>hE_Xs53IK%7s~BUK663_X(xTU}n6v#1zoe1{CFydtgpIU*e! zGNpfHSLjd*g51B2JurB}2$KuZ4rj3mi&lQETKuMdsm#Y9iIN|gwBB*GHzfmpB%B~c+_DEyMG1@0yS z)JqDia?=B4Yc7xOTZ^74tAo6T7z{%wl$XJQmFZv{TN9%epY3em#}2FBbzn1dsFa#zEJ zgv#iyTDwZ-0UvIoT9MCIh!$QR#vAYoU_gW=K=D$);!hP(Ar28E6vT#6u((x$22*SS zN(+5lTqqbAgKFWS0*XH{#T~Vql&Nd6rTUug!ll2L5LR>=TlHkN^^v8punW6JsVife zexgDUz&ZCZg~@<^7>oRXgLr;OU?Iw_E;9_Et$v}Ym}@sor}tL6UzpYPb}<2R(?}#O zn_ESYLpCg>G)c!y7+VELW$q&#erp66ptoL+xu^gQ+On(H!vV;+^-5def~_1b(Ek8e z3c!b2P>r~YZ0Uz8-FOd(LLLwKqnO1IhQwS*N5NjE4)1#C0Vd8M>LVQ%;etK~NSh*ZMnu5sVBpW{22_KPd}~?Ut^e*)$N|4t<{G zc?67%TtSWTt>3}s6L$>r{ZIkGSNXk4(D`mzJCQ+{r z!Hn)IUv-#)9Wi(h1R(?dMCy8_Rwa-_2_V%}8E&HAh~lW`R2trc@>U-`#WJo4*Gwkg z*_8sm$MlHWwWU7kn0;Ksa|UcbWUE=`l|Q0e>!DwqLg-+;l_;;rAxGJ(g#{E1!VDo@ zt@ceoQg);bl*d+~tS}9Zt{5!bMFvH$YXUhhPN18HDu(OV`vfMKC27_+mr=1*F*uokE7?B^fOKTQJ(TILD?pj_5)V z{{WTnX`cwzXOtlI5)V-`+BBP4*2+GR!Ap@Vq!xfG11}SP(+hekSvS>!RHC;^o}#M1 zLZS*OcCwXIKsbaJ%#Ek+Ei*XUe)khboh84Wkpcs)KTqykE_I9ghc9dySM?CtZeSCJ1u>0PF+WvY3Z&`55e|Q)~iSM?1r9t+<~FK6(7s|iB}h5kev zKwRWMom6h%42(bbDvAfWelv2FXLzdE^O%QIm;V5CMT~b{G-Fj8ZU8Nog3NR=w1v9> zr{sdoTY`{hI=^0FFoBzd@_;1^K48F)bTE5foifv+y#xcO3kh-6WjhSDIRc@aOVnhv zTZl%vXr<;Vt?re!zI6b54yY72Wc2UqDLYV$OMo`0KIBB^FAjnC0~qcCZUf+f{{WG| z7C2OWJPai;@GZeiSlHOArS~u>8dp)&VVU~_3bP^dQaf@*lXsTOo2%-V>KLPzSbZUi ziv^FEEYN02LgWI$OFmhBGOtfmF~DdYI)bYzt$FTY$o94ShqBp4KFD3xSCW+QIw+xQ_e@F7?!dWtQ5EB>Xl0A)*m1m+EU zr}a{|oVvB1vWygPE+37gbA%da*^I<^VgsM1Du-1{KFIwoleK@(vKSue-h+zl@ef=4 zF*Dr%0J{GGqEWeEkG4vvE)L$An-Z1EaKWozYXoP-H|W+w(`0cKM6?PqyKlCIE*$B0)-yOfd26KjU2!c~LxRVQ!$zqBKQf4Ysdp!DCi+o}}M-p8+uC^R<{7QWwC* z(i?po$`!D7$hYBaF#~7-yg)<06et4}B@hcr#14PCk?Vo~0NlY*o87R$OMGHB7stDb zH0mM8*uiAWIkD`8F=ir+vT9vK?vPl8rS9+#=s}ZPflOZntG}jP1xi}wM+q~rrMvv< zQEPW-i*}$W9e<${5N*nOJqegTF)on>Dg?6=P_UsAkil!gd2N8YC}`jT&v1nc2W8rA zkM5w@LhU7TAjP5X9^6|)ifCDrW?Z9t6R27@+?E#w&>|txGN;d{yx> zKrR4Xm42^@(S#03R9Y@p0}-|DR&Vz%k*@6CU`asN$_j2Ol)p};O1E6B2V&qAkD?$1 zSXF=6+iTo?Q}+^^Jyf7#)%lw|@-nniYe1X@eJs5yGeJ=JnUSQ(PS=;}1ku2wjH-0X zn@>%{UTVPCMToGh7*FG9)zl7`Po`Vy6r1v;Tk2b8%T*IiP=z8^3iwgDJH%DP@|1vr z5{7Dwk&gE7hzjRWUXc|bdM3x(^_Hva&m zumQKwmz)lGU}aX`Ei)9OUl2V!T7iniy&Gk>*woqyeZW0D%j`Yk0kXd5{{TiT75F8= z0CNw-`$eV=LDo@u#RNGn9qTf(0NAgqmpF?b?j$i$^KsBUq{yI~4u{-M#TZmC(K>j- zhvAP`r+9uXOAiwYfW@Nz;N@7MJMTM)R`hB~fJX>)dX)_#H>X5hWm7x!Vo=(k;D13I ziTjmKL5A8vExNPc#7$JG^wvRF1sxm+S1aHT3E-me5Bv)J1(}WYEsh$9NSw^Eh^B-7 z`i;rw@*}Bb%Rqh++}%xYQNz-Hjq4O3^c~C2T!t$=heU2=*k`N}-@+ikdVlKawF=)AmcBdG}+$W*!bF zfFTMfKk#=$2>8X;qsurYssRo<)4#aqEbo`mEHmrt{`Plev82=Og}zFlHLWZ5ozswz}NM0rpyUFGGNXdC>M)C95{Sn!*Xmz8#9p8|9vE z;8-@chaa;o$ZT5_E*e}Ngw zIZWNrg^amiFD<9fa5o-XE33PU`b6~h)4 zgL5|pRN4Ok39c0nM8yK=*SO>XZK^^R3->J);x zkGaw9j^)D^K6OMg({xU^w%C$Dxe#L4v=CQH%j&R@)qAOP4&@gc9})3+n^&qyS&Y}k z6%MQU7Ywfh4+{*oFCZ}fIVa8HMpPMqto24{u+Aruwct_|VmJ4)1psPV} zrt}G|M=T240CdC=7u0b}QTm>i$Kc!{TkJRW?d_d}9bbp8BOFqx4L3vaa=|NS5I{=K zN@Xq41fz1ol)+9QVvZ4+OxDT+EHOkfKd2}a_>lfX`ZqB>soKV7z%~=oi&$0}#xn^u z0O)poFvV2qy?U4?L_lB-3W3D5x2wcpflDwUtVG!r)N=y+ZqoXtbyoI*4<-yl22zLub5S#6_zXAht zkX)MjRscd5h@B;_6S7$f+Gprllu65|fx%I@Rjt4rmD3wvQpi`_aA*wIIr5o ze#V~g{tn{mLcdJ4s)_)lT1W0bvNTE{Mq5)VP)L@qZkx>A~|L-s)OvC>4M#*;+zN=QwTTDJMZRJMvbL}yCnj{VJR#OiWv4h z#o0_~_#7oH_x{5k9;%2J0c;G9aBL{biV0~KtE3#g5S2Mm<@geqZN*icthgY=l(;yR zhQs?RXA(O5K{9TKIeMRpZYk^#`_NBrYCO9!J9`dBKnUY=NP=}s4v$=s33YCRfb;w69NkF)U zEM_JTh@D~#UWt9bK``ziOuPnrr(k_;-w|xbqnJG-1x5&B6=A|=0hj*(1Lc+7#Clen zL4PpQ45LBPwwp)uV%7VE&BPzQB97Q2(Ic3W;nMN%qCtQK+CM!oDS@h7ss6}lGW!R^ zH-4MpGuYGs^jJ^Pbu8JMnY~7QLI?-1a_EURR&VMwa|C%^NU|=(UXn(|=R1g9m@2SY z69{%jEeO<82j)65;|(XWC}Ej-MIFIAVn?|4MZ~xxi})z0Sc23rph)?GPnH8Ljb44q z++tFzPm!5g*BDMfKSX=|+OPd(Vr?GQ6hXu|;pPb-E^L(Q6f77Msr3@rxZhAEReeyt ztKZ^F<8{Fg3Sm;P`jOIVF|fOBS1cCD>L1hvhjDn3j%z7@sY*Athq;5HMY&Hy78SIA zU-dA;stA3f?}nHS(sMMb5T`%HCl?TG0h(2l(-{g!YBkvyG&d0)nC)1=5QaW+QU3tx zuiOeQD-^<;n_?GWL^y$Fi->E*aTFgQjBgI#k~~7F9E6onfI%uhgdT{Yq7`?djjAFJ zzBAo9W&z7+*cJ=BJV5F_d2;}0uGyi2TSwI1Rqy*@SRjCLpBrN`(d#P(Wf@`tziexW zC}oqGH*GVJ*H>G5~sFsaHw1Q3O!#IZjD|cXFJsBvqHhqxv0sitP2C5W$rb)T|>ZsxHqo$--tx&h@ohknw1vj zQky%11ZDpK_(Z~tEjDgmqdE~7MC{{Y1q!1iPXq5I-c2!e_o zur>l-Nm2%ecO)t`{{UbJ;@zGtEvsYgs0JLv?Wf@lVywgpwBua7~@ zw^^6d(K0;S^t<><#X1yj13|cfh%j>i^#RnRq+Wt0I8RRkYMemf;Cd&@#d6#GQje$h z^gz^jU7t(f9I(zFt3rMOcj7d``i&u>Q02$g4Sv1O8U>$0?{{ZPC9jo;YJp@pNNFGhUY@y9niW#J{0O6s) zqBGMvq7*_VDM86_^HF(Q`~mey)U?h zHYW7qaHBHzs>jj>i>6SQ6-S}Q<<=XpFvJy~9)k^p*fV2c4Aer}WoQSZG<)DczYtQj zMn8dG_u_j^a~Q%?wWxa-emW4RGWWQ6gtIJ6tV)#vXYdbzd5m~MD7YJ)(5_yQ-|M0d zHJwxM+Z#Qv{RGtlCxEz^Hie*%chU!V3kosO_y?#4Hx|ek5reo|I`Dzbk>P-vM=*OK zEh)?gYQF&qLa02;NfOah)1eY5P5{#TVEC17XLeKsfo)gg{-AJNdtJw{Bd0x@FSkux<^di5YH;Y3=GbERwF(&A=;pW=14^AK1W7p)d>q;8;zEj~S$* zK4;hFj32~qM!2cOK*~RU5vV@|Y%2sziZ7N>5LIuZ1UobNs4K3$t8o&l*NrJQwpc`2z$VT|CY$>KSNVTM1PGukL+AFj(%v(ciXI zf@49%5V&Z!Y-JZJF%Y|fj1t3g$F!|nM9eB*(GS(a?1=VDHdWNF*PL+5gb-?)KE(V; z)!0gFF$RlZ+7Lz3$72BzYh%NmtRc2wNF1xN&$CD8z=KtTx0H54I{4=`aV} zVYooliie`wJ;UoE9efkxQOX=RMyQl^WhAV^8CGk3{mLGqid4}Uj;gr^LHTkM4k>${jP8U6zWyD zdO-r^5Q`JUrls+$vIp_d5b~z6H!e9>!*%Vtus)_K>QT*W;!HAP>n&b^0=6uxUa^3c z1WqB2*e3l13W{JZ9&caFVTSw&fWUiTS;gx_dNw1>Q|TdiCop;MdI%&f0KKGSHGm&$ z5j_BDI4hV)XhUfO9KKvv=o)2Wh$c;GzM$1uV(4N8<%c+SzDa}pYnhEy{0RspjJS|w zW`&?N0EW+W6%@o+V^WBC-h87BIb+0(OJ0ACgb;z{xRrkVNr+n_npIOMxjnG3RQ5~m zI=SinV-7wg%fq4tm>{p{h^b`Bj|DE&%OKm&zlgxR!HHI&OTYQvxq0l3!2qXHb06KTge_DozD@e4q88S@t#A(B>Q#v~DV1Z+(b;!yeF1HgX~ z7J*#>82OTCGoJEYz8P#Zme8GjKvuVv+YwlYdhLo=AK4K#2(*X}V@B32e{pDKOcV;; z32BH%xvfi39kZG?XwkMWrwEsC1wM_yNa`m|#>}HtB)*r1eAC&obM76IB50h&{FZYe z21P`nc`ukyl7LHbv?2Q7+^m-J(?Jxl0`a(C0o8gjDqWy1YKsw>3!!VgL4g|>JU*$LtbNCnK$Y8YYs*$PqB3zu;l z9V+JT#es`RDT63|e{#Qbhx;%Gz@<9zqXMkUcHF(O?7cc1q9WA+LBMoIOWSRw!fdhL zK#t4cw#e`{Ha-qwmV@9*(J5|H?{g#wWfMTPs`*H;At-b0Lv_AP9Z^zLI+UMuA91hP(I4ovK@R4mTen8B<>dKkkK_5Q*rXh&@c&jCe#IBtMZ+5lchzDjek;mW$(RuKFZtOoAA;#EKOm@pLuCwI#n#s=UnoUDSXMZIst$=r%m~!nIEUgL!{%M?EMkOUj2M|YfU&Iz zpaTnD~sX|;o7pyV-}D0X*Xh6c$919Uu-Ek zje>0a<188{OiBfy_>Gd^VzB*w?Es7v9$PEc#0d1Z-ET`93U02Sg;f#pXB)}cz?(_~ zRr$+QLxwM?p3sDd8mgI0{l^dxf+_q0!{tYihw>N@BS$^4Hp#bV?svb7XSG6hjfB($ z*;r9_JXCYcX_qlogQ22f%tslD<*1DaX2i-FZD@A^aeyXOXn~~-k6^w>UWtv|sdeJh zsMr+4*($miCUuOVKAnspGKpO1!97iYMNO}%b6D0t+b*B=d!Ztc3cyrOmk+~1>B`gb z4a)9@6JDlV0a>p1r9lGey{>!ul^L~AhR3&} z{1La$xYLPO%bo~^5nLWEyV+mNN)BpX1q71*Veq*%L?9ad5UG@^F%wr_Eu@uO-4SGL z{=+bRBR>Xo@@3 z$;87kv?DQJ;sR86=P#+D%TWTLm>~CwiJ`ZoRRN_Pl9aSBR|I1*!HIV|t({1@a*^v~ z0Hkugr3T@j^%+nIkZb(gU`%%guiPVD+fZI2_yXwtA^VBtTNfPbp~s{pzBNXkaGH4~ z1y<`tg^rQGa_h4WE^~TbQlOR#lW)f)BgDmcEC9kYEt0G>!OxZ&2G7|EI1D>F{{SXCiJqSlH^=VvhaY z#6q*Q{{ToCyWeDI>opDteVsyeD78QIaM3V;f=0MJyac!FY5p?DYSo9PICpTSNl0pw zOj~)W=gA+K>BezF=!1YSJ1>$OX6*>U-q9^CAUoA7_ZNKm3}@mMQRMbqhnX38Tt88^ zx#1e|0;>XTa2)>tL>XXVg;?&|OGU_borH8&ui6c_ULg3na{mC42ygkebpigd_}P~t zXB{V@>SS0)N0EQH@fY_gU%0@&V|#)bq#*ZEGiZ*C9wjR&np{N*0Xtq)YxcF;HsC%6aX8+^^_Ag*RN-}KP{(KirR@Wif2 zMY2_u49!2OP2^8aP_sA})bX$x&=a#?k_k!G>v^upVv0t&SEk`8^@kB0LS`2@3^{9g!BU3}C?bd|le^FEFlDBG zqQU6!q(e#l770d%qv{{vw%k#34WK|D2)i&edSIQkA8ZKyUKcIsV|j1}m7lK3enCgC z`=kI^!DOx^dgMl-j29HJ${Rk+4P4^6=3?1Pi*JT#blgNW9G|h58{!&`?#aEw=^U5? z#^K$me=ze&E1_cqiXiGPm+JSuy_$@r3H^hK&8*gC z)=`B_71NEx+H%#uO!A`Hu;G>GP?sFP+?j*aFFx-H(@D!9ggpiQJNhE?UT)4!MQpM#S;Wtr8dxQ)a1Xd%cXK^7? z35qQ;+zid0kMGF*X%?|Iy-OH@mZSaW)Xb_D{j!pC%c90m0BHyNnaCQiZY7VS{^c`s zyg>R9ZVSW))FJ2`<4aH>e|eV{7XJXL@hTn|sD$Byzs-m;#SzHcqq^`${L14}h5}uc zGQ2Ma4wxqTij_WMG71inC5vfThhy0@AQ)3TFR5yrYmHa2h1{&8KdJFLj$x^3x$d6H z?S%6IE8IPxAV9(iAhSF6&e&y3h(doBu%a0k@dy~#lhKIO%q^B#Wnxt2oBx34qFq;^Eur1B0 z*2hTS%5uvjH_^$L>xxLZS*dzwwuU@W%re~f!8wW{P!t{^GCPo-U~6!XYld?g$FdVz zl;J}vR)iH0f(%PVt|FTv;zXFLH;yudhnNtYk1)#_S_Ae}>Uf@vOgD&nt$t_7!4B_N zK2rn<8{KvE;vu7ZrL`>yJxD`NGK-fm{Ivey!YuT`6Qa+8{{YyINx;=upJwKF6QT+p z$$3bm3vIRnNznE=5(^%8r)pE{e5Un?3*`hk77tmR;LusjxTZj%u-_!B$@&{FWMSHf za~0gHnVc9}W3Yjo8Sh6+pz-c3=#co15~&kzNq9nl6)nU=R*Paxss z0t3SW&jAt_$rW87a+_!Pan9l*g2OLVN@vrbh%g;tPm^-Cqly?p?-LMeMT4O&*M}*+ zJ_&lWF%%pz<$|@Q5KeN#q+{M93vq0)sriMi#YR`4Ej{)=QtnN9-w8Q@`xQf4%dgJ| z)GVm%*o?3Zudiea%$ajQ538&7v<=e_1x73!!L`ONb1|0}L*amo`G{*SgDg>0Q$x`J zRP4{jSGb<@Xle1!Y5uj2E&&KVu!>I?F#K@;01G96;xU+I(3dEL_#yqy5>zZDwEX3b%-~F4Q1NI0 z@ZCz9DCU`4Vgfpd-Li-8Olt8@xNMK)f@heEwhuwf27Q)FfqOSI9w58vuV#jAUgbdH z*hBrpyN6#e_`ls(6RG`C$Ja3~==9AnnsL+aSh}G6VHJ!NOOBa>=Rgb#ojG2XJ(ZQN z#v!n}{{V!{BA0+B+x&3Gfo{mybGsSjgKxlu{b@HUA?{Ct>V9Jz#HDvFV-`mU;*2a8 z2b{L1!GHr}mwb?P%L$dIV?rxUrY~(pS>`nsRAQb2Ra;cVwkUq1KV-8BX>iSKf`K%_ zR{&YSPRK=RBdxA~Fon%Sm7)BuVN({F3m=wgrkn-cLAH6!3M^TF66?gg`-5ep!ehT; zelGt2q5w#WN*$VIV;4cy%dW^&#(Ed&hz;Nmgn%lGDG$5(gqCxWfGjEZ8zZ{<;t9cN zG%9bCUgZoLw+_PP*9;Rs(-(z*s5FTv$s3`DKV;gnr|ZS|3QX^Xf;Gk~b7+mDmtDe^ zP~2Fy7!BOAQ}GY}*>|?YPGySAkAR7?Y$64|nPog|tbN?IFIc>A%OpkL!zzCO^pqb= zSL3YY2wJSFJ*7==Y7M8wKv&r)Q$OuY)y99n@G{Y{J#v>3b)J?9v_eD_HV^gyeZk75 z?N*PFY6j&i9o6dw35sScO4GKl?3cK|^l<`hFg>r( zY6Ier#0d{kSG<2KL?xE3aXX#S>hlM(t?nPc18hCMrb@MM(Nt8ayx%1#E~TXT33^(L z7N2oK){thbq^8i>7*ThZ!vP}!lrI;FxtcqNxFt`#Qhjjmvga}{Sj}JpuSbhv00)l&XM>KUVJ2&(LZpOoG`c% zddR|S0n)NKy6+%Ia9SBV>a4-H&7|RKF z3%QHH&D_Rn4NE2bx{1fm%4Qm8zI#@_BKQkVob@wP({{UM9xsjRzInE@GjxzU8H1M zVZ^y?x?+kbvoooBYbGO@xQgL-11EQaETzPW^8!Wef;3OKpFjGFiAfWX`iNJeF>Sh* z^`icWaVZxYM@9X(m?r?KW8KPVf810Y0rHgrD;)?5BsgC-zh(nH}t$&bVX z;ie?hn3f#e6IQl#EklJ*rT+k7HQ*aSP@{)YL2DDP$+j)$I?;_0adQI&u;yl#5;9h; z(lZ-@zmRV&EDXg#HdHsf zN9?GN0YdL4N92KYIjlwWB*5}x@i03GlxC|ey3qy_n#VC_SiM37t@kv2N=7d$Xo7>< zzMz*qpYiShqzCWy2toNV_+gAI;t%)zlsSt_Mt!-0TYmJBY0+a@d6B3-BWwA<4#*h9 z1Jg2!{iYGk6uR_7L9Y!IJcxKMuOCOVrdm@mG@Ru=x=QdyHhs2_4G zJuV`^>-$4#>oF)3g~~8MLM{Zhb5Yh_Bg=pK<``5lV53nz@|Ar%`GQbGs5BbA`Tqdq zj2C~h+`58RZ!mT9Kja4Ma-Hu!AzS(UaK>)@k)UY84VKo&vNZZIV3$^YS05xGHfM-H z>qJ`=l?F1~rF3A&a{OdUc;Fe7Acb){0_;_sv?SDt_RL32M1C?{O6;a8(iMlfR=&ZP zv(Xv*j?N>B8oMKcL4-Dff-G>VO0oUV64shi<>w7SkU`FsF@E?+ZHgh zF$86WWqpv8jk^=m4MSs^U&)G~1^ z`(UL)_?Y}d<%?WsBElVInenCWxF2NXqm<(^sDT}m-cXC-dGLAHgPEg4rreUxq(U}} ze=zVMtI|XSx<=2*6OA3 zpV^qlI)XL`;8`D|Y(&VC6t@WgYzt|eA1(=_5%xUCaQ={7T6h8wpT>q5#6t!PnTtYC zgdwtZh5mHbsr{5`i={%v<9ORrr4-wHV6{OE7tg zl;jvg3v5Mw$0qd*yRIt^w&o5lPDxf5-)H^BK}Xm)fzqGbQ0F#3)Xa|KXWJIn;tt_D z@`SX(b!NBr#3@lBHnH$aOwwpNIfc47eZ;bi-X&1Z8AX@t%-g_$6t;kU7)24__#DMd7^QO>G0aZVk5$Y% z8dEAi{{Sq=bsWCT$9Xp&Pz?53L2J4GrjNwT#4(jmczS}?V_26_cFjKKAZ>z+Xi#iu z)%3^vi?n6eO5x8p1Kp!sC+t8pY!mJy^8@uW^bms{Vp2MPxTtT8#VyO0Qr|?-4gwj( zR_YeTM{KW_CS9{CvYkijm+yjJ*~FHIf6`8_#f1y$moL@Os>K10AWo7@Q*>Z zqO$Tnp^>6}P0RcnztR(?zdJ@GtQ7sC1biU*^@!sJvd-0^iq{B>y8gnYHQ*BywL<3_ z&!V^Yh*A_67Cz-!E$!e~qK^Vp!BCw5jr|p3Yrv8z`9pE2>m>j0VS1K6T zVH1@E(z8?XKC0i6Bpku-z=39gyik58S0_m_Aqa3_nRj`%9K1*jZ1gG&lkKKp@FXCRNq(ON&#kKsAz{)k|X= zngv|UMt%VF08ePJ+(HM7hU3L1)fhSkL?l?D{i0ivwqR8<{Z2nrN=qhQhFStAs2^wP zCKoAZ2^5|yo~wu^*mOm=#4L8C)&nHOu}*AP{zqxX-6m$+{{YW1MLeE^6f>du%+Ec) zQs;1P7ae@d14X}OUAwE3qhjAub@MA@_-;afGRNEMp3p+Aq~d)J3j=^pFZV@oXMP z#ba=gAhh<(qf|aDlsTA}bEwO&L8uKBRez)%k*pnzj1FBd#7?+bHNjr9fU|;9|LN6MkGi;X3VcB?Wz-TZFtn zM9`u`?-2m$jpNjI@=WbHtCwc284ha^p6J+O#gQ$=L-QCAk5_QnPF2`7QlvAvJkv zT||AyCcr}5%Wc5N4Lj=u<6!xMtFq;Tp`R=Y5jL4(ARGCX7b#fc5x_}^frX8u zK;X(MP9{VQQKI>OY@=6_qNB2_`y&e_A&Tx^aIqgiVm<|bLShas9Zu`^MjnL_hS^cs z`ECBEq7n)r3SfM&5anQdn_66I*p%vKOtAXfJtOx%8NWnPp0J=sV_9aiOe9lZv4B=N zh&~VZMg(+NzNESC3oP%i#3Vgwan`U8+)dfAZSiGdrA}ai616TaHBN`>6N43GuxHAk$ffAUr8Cb>O(CC?eIDfMlI0G|v{fsJ>(Ts!zkBQ@? zN(O>VU;h9gmBCD#{)7vcnou7>7S(wCPyVTqpTL_^s4Z~I`c4QO*6eaC_L`j07|ykdgsh-VpOJ)}i_ux{d{l{3Q^Fc$fg z0yk^nQLb7WCF6{g&%hA}0K>q;yLp0%2zj0SY zLg;*v34SBxmpSQIJ`u_{lu8^*^$D}Y|HJ?y5dZ=L0s;d80RaI300000009C30|W&T z5)cz01{5$A|Jncu0RjO50s!o;EK4VH&2!wUrCouh-*>lyVh7 zb1Y(OixeaQN0S`6qaZghw;~UV5}M%^g+QbkY~doriv$O^e(vpSxqM6elIF4q_%pXH zQdAeARu2lQswh*~+HW}rA@4WYk}tz`GlDq{(Z| zrORkDf&&N_A0n&K`}be738K#7nh`kWve1(*YsNk}rK-0S1&J$)RLYOj64f`bShhk3 zj(x`0y8B#JPgh2-DzOrAQ}PWiK8Pp)F=C$tmS$tx#_2>gn%bQ7P_5pagvjM2$7bsM@Ce+2GBBIm${)Iq3IptfPNd&_P zqg{cis*_c$8zs{tI;#VlrXcH50mmGCs{`0KEdiBd)uhM83hcJM&uy3cYP&MgQ_-)v zLc#tjLzWf?><+Y1j9s#t-|zmrEqmRKi8v!5U5BjAQa{AMv$!F%lD8tLdOp9?hd;OKxz$q9oC?R|jA(qpUC`1bZ`LG`gD6blvVV722`MVetE+#$( zH(ofLaFrqfn@Rv6fc#voIR{#3#{RsEze0GdEZ1u5L>>W3%2fa*PTI5(l_C#|gO4AX z)jcm~>UTF^C?2hLIjfHqR?TFk)yxxOR&Zb-kB63_I9RyVn}1Jj)`ewBZnsIYuEMN< z6Uc=G1UA8t^2RF&Jh*va{KhLC&i4F*IpnUMU$4dp;t*L>22%tFKH+DuK%guhNwhH0 zP#Lu$oZCUH%dr=)JVaxKn-2w*xO;Z zIoKf0j#FoHw~Tr>$bZ!`1yG^D=ehIsE7xZ zJW)p5CEt#uA_!_+b<5Q34)b05EuP0CXh52LOs&0dVzq3ED>bU19C%+ErQGaYgBwFJ z7L1{lT{x65vQ?0XR4KlcKw(xul_fwAfGpYPZj1Ysxav<{formh?9t|aOIi86%JMSk zr7TcCl9~-duTZbo>J@N)XvEs; zGjU;208*@_Mh?FxL8Zq9=LBC?Zif*)UODHVyDQJS=MX6X0KO?*UJ#&+ORP^}H!YFt zvKvEq2cM^Xl^a}j9CaQ5NrO;j7uT*V12t}>Sy5by6a3KalQzW)J$*WW4kkrx6_+KD zT|l?rTJ*RPbsyzx?(XamQM#*9j-~*?c!2S`O@bXutb(u>16;;JF%+Gg&A}$i+}Wt%JNmCCi-v*Re<({ ziKAR-ixBcd!ydo_sVT9l>Wy6rdeIWj_cgfI!Qe(B77VlVvljPK%LGzizFbI3*sK#K zyo&mT>(tKsCd#bNID!B`Q8kupF`PIDl_0FLyj#nN9*Z`#UjYZhlRZDAcwmNbAs#gl z0|-GGyjCbexfSDCbL56rRS?S$Y$5t<0A=8aAq9BFdRZBPEsKJg!pbi!yBI{onqRg8V#XQskEUY~lCEzmu*Xycv9_LtlpO?WjvG4lQZ=A<_IE30Fba6${k(eRT3<}BMep?lIdAfjx!C# zon2XvKmWu4G!Xy-0s#UA1OWpC0Rsg90003301*QrF$542K~WPRB4IEEae)*gGLb@3 za-kI@KtsX*+5iXv0s#X*05YfC2fP4-KH!R$OGA|Jq}PANOeK%PA~-g%YRVyO{{SIX z7P(f?ozE)o3Dg>lKjdL2Q*wvm-fub$F@THaJ>h|Y9FRHcPqRoMz2|Ruf&e#wjpp<2 zd;lg`jT+;3_ki>6SlSgn!OHnqws?)e{JC_$Yr!@=a|Wtj%+E?*}~4XB7{g9SkZzrsaXpKw9X zUSBU@3U!~{V>-S}H0=QG7sLdTxQP5tUvuSOgsi`Khmalab*P-sY%?i`2UG-nr` z(5@rWb?PHY!*LkRGh)g+Zl+EKh)xQg$}Dqd(3!?`k+5oVkQuQLQoqC(nSastVJLYVuU9D z0EmSk%1*i&=x}XEQ4VyyOJlQQb>j7Ln<+-S&b(lb{{Z|<*@);uLGLk;q`RLYW5a|h z3IkZ1)B#M*ZD;=56C)C=BjU&LApJ$khU^~@<5HGSix4oPXI*0khjR`VRvT_z*y*O?3vD-t2wb?-hE}pfR>p?+8Wv@%r+OK z;kc})7$h(|8N_goapTlDG-Kp)&ewav2bkSpD%m?!dP@u}QB$?RB}F6{Jo3KKSket< zLyVBN2V)6p1H2$=C0F62%8YEzsGyc6fDt%X81bmd#F44oEX*)3Rdo>*VshlMAn6|m z8Iz#&5XP%X#PKvTHG#Azy!(f-xx{41zM2w5;xXc^&RFlr0jK(cwys}r_5{OLU=^eU z5#|hBLkiI9C)eSxXApRRm~>_pa|Z#7Uz43!?n#;h={BQy#aWn81H8s~#%yANgw6c+ zjdVmu#p*Z9>MkS-iB;f6p{b4Mku@0XKXVGV%HXPlmauiBO+OVLTSv^_)nu@M(vLA& zf$_A(k49h**@K4R`Z2IB`T;WMa`_s}Fte>1gBC<)U`PC-W5B&RI+e8$j@o$~$(DYG z^IB7&+7`!qkt(iT>&t0spTFYXZz^TuIEBTHZ^@t1@TrJtN&ue?H=Ir$EwVQrOOZ;8 zvWb^7b!5t2wz7F^DcARpn-{5o*{drvaKz!t2v9`>0U)8!_K5dJo4AaoZKUa12lwP` zLJ1&E0p+gKR2=(r)7if(Gb(WBAfR$J1N0_5T_N7dm^genMlyZ^i+}h$nAx&3u_Tg7 zCzqMjDr|326DJ9bgYp^~!{^km%gs!fPon0Ro~e?(5D76BeaRI`7yB%Np69${r2 zCX6F}C&ZY1%g-3 z0RrNI&eVzhDJsgu9e{_^SE4SofTfdt#Ob{(9U%aYs`4PA&3wwLg2lF{K{NnBh|GHk zS=oHh#wH*IQFYujM`!hTDp&KrBCtB2* z-fQWp&}z_mgUkf;v+f2j2gCY!2sv^9UnhWj2)Oul7*x^K-0t6IJ8=aLTTnI-Il1*O znNIPVh}JN|HPQoU2(i2)P;TR!xl7>okBha#RVE`8Hps5_GQ9lLR6Z7RnD=Xud_2CEmWhqg|M7|q z+<{cX7VF4W*X^)BF3fD{b70;;p`ESACAS$(KLNFB@zp|M(3#T}(U>QIwMc!wf% zp7vt;*^LS!DyKsLK!I~Ot<9+$h~&N&v(#)~voorrIq3iZCy~e>VVVzq9CSBqRegW>A4)=$7r7am@P$Q)f38$+8J%7W7B;|j3=8*(z?ly>E}yNDbn zPe2mq#Lb5#n^qgg%Eg%3gvyo6L0X>Exj(#C?+V(HwzmlfNIJ!cc$dVyDiVrAF)#&P zHK7r~wHM-KTVysWsLmga;j&}Nj03R*O#c9-i{HpH$pcI67#gY|X$JLCvA7$9-|^-dLMR;+OA`=d^%;-A5(M>gmfmg3<#Qfk zOxTDUI5j;?Xx%k>z#C{f3^?*AO&FaF^$}cn)>{SygQe8UqeZh7g+3+*1E-NF)m3dM z44_>d0fQNQ=0r#M?!B%$k~?<%V+s<@WS^0W+#{8H>NF_JWB4hB!LpEgDq*pE%>)D+gcTsb0-F8cHb3IP+&K#+)2->|6O35f zL-iRAAK?Bc&N^I>y}*lyh{=sV!~sHU&iQXNl>|AQ;%$==q32j|j*_H~)d~LCQU>Ih z3IYXO&X?)E6B(5WHcE@-@GEp!5Fu46-|hm06a32q=s}P!d{(&x&QToIm_ec{_MVe~ zb~_jiYcJj~;K`EehLQ7nnHtGsyw{izZS1HOIPM|#0YI3X^noIVcF)ACf)_MKHc~BnDPl7x$8fVSa->?EET=hGo88WxRiPQnHg8fw#d&d#PZb7AvK%-dgDOEwR z38DMLspKJ*ziE2=194+ZrMT;rNH${|W}h$E&1cK_9JUaEB4g+W{G8CA5j3ib4H2k- ze8$84giO2+3xlAQA)R|^~a{LL5)tacx>y&5|ihitkBM^Y%8=1pf-ZHfytw%nAmuLR9f|FAaw)+2$@y7TT$4; z9AyJTp_YTlFne|0CSTHvFwrtjkJCjT^Kd^9{{Yl@TiE1L3ghWfpgK#hu{V~Y8K@I! zqKF6}_=}M!jf@C@0lAb(@->0fM#QDSx~mXz94mB?Nn24ZS`f$DXQ}#s7mL9M{l*yh zd{?ED%8gX7ZlY8;^5b#;02Ty)6RU?tyRZ$;tY|^KCh?S5f{g=nPbAG|r2hb^Sls;? z(?lAuAuYVHM}j9tO6*05I#;L?8%-g_k+Bh=KNxZ6$fS2BXnv2gNMITGtX+zl`yk5V zu&@2bTgx}?zC%gkaT$M4P#78&8~Q~A*#wECx`U?bZ75g!n@*f3$(M~jgaX*hMl;kw zMu^zQ2!V~85G$ebY5~yXcozW&PTucFk6kDhui>HwT!%&tLVS$*AKnVMCjQL?)J}}~ zu(8qB)P2CH$~zmHa{k<@WKCt#{eb`kTppt1UAHD^N09)qV0`5Uzyc>nqHq5IuoDaL zSqSZ{88HLgO;5D0L~*1I{V5wVmWHqHYjfge{I}(-ySYLfd`2hmz{<+Nok+9HW5tY- zy8#ilGgBxNI`W+~5OldCU}b>y+@JP&YYC@K7)Hy5i5jT5Gya}fozjeaY|Hmhl25c} z;8oP!0B#(dKMvpY*qTe}n$*(Z0^tPBIaNzSX4EQmoG*82sr%)qme^BzvjEf%R3)iz zCIsQ~H`J_35B)QF@g`{Bv44-b0tlTPTPf}*pJ&_|xJ;N^bUS?*G4R|% zu>SxZr9dhR5Of)-6H_}&mNf0O9+{g^m58C-5Ja&BiPywGg#dFsLlT=~099WCr}onr z{{WEy!P5n>Cv8LpMH!*}rQtu!D~$bRFdijde9!Og^mxRxO8)>8KlZPbZCcB1rqfe2 zl)`F#nj6}5owwR_=L%2xik}tzr3;o>j_gUA7?{wV&tV%Ta_nxbz)Ua1eJK9`$%25b zOift!7H3uvYjRKiXT;0Ke{%zH%GarK5AiD|AF@RGwR!dl|HJ?x5dZ=L0s{d70RaI3 z00000009C30|XHT5E390Fa{L=+5iXv0|5a705H!aROxIc$0UyRuF<#HnTsHj@ ztKo)}t(!dGWuKPbnc0Am4*HerPP6V`+ZtLH)(epYKh`t|8xPcg|oZ*V9< zSgB}K){lB9Mxuo})ZXcW2xX^YEdw0TYY4S|VN@Q7Be5E40uJW-rGWC%#@;G+%Bln) z2t*)=CdnpjH=#|K=6c#*ZF^5xUn>V%=#s>ltu#NwDIg0pRL$bQz=CgJm}AX>)BgYh zav%ykYgR!7t@pSf?|Y96BSKmc@?GwBf(G-2&?G6X0C4~=~6Jt||6D@6u=g8u-}80@S&Gf>AT<5OQWM+Bf2TbXV{ z=B9l)w8prEdd|r$@7ZEc&c1^!kA7Z7xr>)u{*=Q_7E@rcDn*QD_xv^4=(U-d8O@j= zMa3wUg;PSa)0ptahxq}bz1aC#!G8p(VlEwZ{tBK7h(&8gMb!{`KVSvch}Dmsk&lk_ z;x0!Vn8<-Dt>`rQ3FZTbYpXBtSg`a>kCm5gXtbvnf^pXmD~$XA5GsH*_!`k36)3~$ zNSYv<>%QD(vx?&Is-P(jZ&21vFG*W1b(^+Hh7t0GNIP=#HSq7kO0o5=-*ve|A+0xU z3*PxnVl^z#!w5eq6?~PtTW|chm2s$|GiB#3X0uVC(`zm7Hw?sbOw$5B5Fm>=tn{+1 zP6vsqz4|s~+Lx29-*m1xVb&xtO%OpHs6qp_Z2thCfTFs*uxK)Kv6xqS+DkMLlinbj z>r6XX1!I`LrQ*1%R86sIpDW6+vhAz@or4G?86h1A!2BTxley~S<~3bt%-mlE_E{kZ zuPU(-MBLP1(DozSk#`=vZyKkq!ZK0B4Om)#1CF%b(u)0V4%oCk6@@bsg2mFAtr@;V zJthNGS-!8fn*9Sc(JW7Tj@Wpp0{IhBkF!Q*IKaD)uNYK1xz?Z*0XMQs5>H30r{l2F zD;HApdn)Z~tS2N`!MCC`03`2b5>LWl;b0lCVzF&`&^Ds-mGc*JNm^l9S@_v+LK08L zEBdGr09AEVD+!k7h_btvClfx<&;i!>0VMpnsAG20g_$j8WZvZhA;zm-Fa#n6HRei(9Gb#Bukb6Ti} ztVK6uUyYKcYwrp8=L6tPO@F3GqZ0<}P_dw)$S87VHeNNgl%7cX!N;u^un8X@>Z4PE zZS1D}T51COF)Ylf%H4yVTM$OIuJLj(FAPro2xj(MKMfX!F{M`=l(FH6&}Qgif^ceF@5(s`p|| zTo$2D5-~-(pr*`gDq|RuO>7$qsvHFZ5+NM{p1Ij31ELBMVXEw!cVzspP9G|kV&uYW zJ7?k$KtV7D8iHq&Q4DPaREMiyInl8nkfQ~02qMOP%14ZY$5aeiu{1#vvFtAx0BtQ{!A!Km!@gwFxO{Fu32oI809X$a{{ZKgqtbP~^_sTF22oX& zvbfPV+iPA^GZP@K!N~#x?~i^kYe%4VV1^R&Hn#>-E_O9nn=w-=%OROXm{u5wM_i43 zZL2k=1HBMKPFjN+YSKmp85VJCd;V)(@JxGZX9RVwPZ#{=N3|Q)#@gU$4CML-Aiz+qWl^`9u z1spR42&vIZ0S?Pp2#bp+_eAQo>JTGQ)Ykx@4oj4KBOObHV6D@(5T_F303Z$|bDU>n z6b_x$kisz#PbakDB@&ti!fwho!@}{&exOH^4ctzp!h0mE)W(g;D#1Ye^wiIpuF$ma>GG379= zf$W`3+whuo1R=0Qo^5gPi%{J+z80Qm6i)cx4JAsvD@%|-n3Q0M(M8ltrnG-0yI0I9hPp1VRo^qI_wmHf21Ibp!Vx^MUD+~fF(RKSYkH| ziOvXgjnJyYnb%&|L#MKEBoV3I0O*4SWpslrDy2GN34yXMtO>l8>D2@eYpg+3@;;dU z;)^|}Z|ML`r($okDSVrlvaai9fS%_`RGLMJ2kL^UhKDiarn%7IMDCwW!Y(_ha4=x% zvRH`+bnBlsS(^t`?^2aB9i>a%I)XIngbIvoiyBXa=K}}g>ZM=_B{*u?jnkc=Fq;!8 zt^vUYw6vQP(gnWjDT1#F#0#hx4^TQZROA=xL`o1G-3XJ`oB|EB+^^Deb2Jm!-9D>^ zYLhCj4q8NkxrOTjVq~iA0nBU-$qJyGqRnoa>!RZT%pxyhianLI$3>WyxY&pQq8vdT zaLrXWoUDgEInE{|?+Dv0f~!8DV~N*Ns8gWZ0(B%RZfR?p2s;(SfLrMS@D&`T%n(x~ z$TEvZwXxhFP5T{FgsDIPe<%W3Js#D88U` z{+9hAHPszbv%z%38?g9IWd^^~j%eQiYRDG|z;PBUViN!sQgpItZ?_N@ciTZ=w|84B z30yT!GMA|@aU`C|00118z-*f_H|&9ae-}l~IX5#2G_o?#PNXOU3EKez_b4W&>NQRbb+)n~G72TqptS9w zM8N{l$OPKuN{kOqtJ#>4CrM3pPg1LH!|erIlP%FCsYM>@W>&qmRK(<_T?(7!wP`uN zRVTO8r%(enC$gyOW!c*A165dwFca9|(*&J@I22TLse0`-3;=_Lt`qMW%2+uv=FeIZJ)E(B{TkgF_gG!d$6m@=q6N_5C%7Xf#9 zDUZvQjc#M0Q3JLy${`2wFB*Ymn$4I7Qz`)0i9(B^rp2-pFoU5^Bf5fGQ>a&+X}Zo) zQMp|#b((t~#RI6`2q}#wNrPl!5ov-tb(ra>*poL?OolcOb)ACu7AVI%n?|7nMv@c7 zKyw0Jax*6f-pQnb`whF44GM2=jWB)+29PtdnqlqGjTBTfx*5x6L6}CHi(P5BAr>@d zgXJ`hWEGi%DUuF}wP}(pMxgZQ3R%mEbbtbMVR}_6Gc@Iq zWJ?9ghsMGJZCY=0?#6>58cuyZrr!v)g`@&DR30wq8rc@QSyU0I*r&vskab?AJDu*c zO(J5@5AL5$*|d3$G%2!NBTCnBaUxM@ zEpUPf1S23cNje1jTmYiWyyckOlBuzb4{m9I2>hXx#*$RZA?+hsK!>rzP>8EhjyqX7 zhW2v^%7rGe#1l=?4(%zV$T$6*5ISkMNt6y|iFU-NRHE0rQf_)el{$4BV(OzY`zG-Y z&K?7|2XxW;t{{@lBm8nG3&NQY$D?7zTpRzuncoz^z zP0CHKZzBEI+b&bp-S}J%TsAyHHm(-*uNdr);6PGD(azsLFL1T1JVF21UMa~Cq>(pU* z)?}uPq#N#taCya1PJUD%TD1m)FVSM zy*B0pMNC#}!*;r5T20FNiy71?5P3#0@Mlv9ORaJQo?G8#Jdr@g_Dpp*HQGvOhO}5H zFFQHExL&}&O{4vafSu{*>_W`)XF#7>&n^0Ci7VbvHA{iM;ZzNP{{U;YPt4k6T-l_m zw10?(2@Q0Iu&qC3ATKzc=(%}L%*O8_8Z8hfF$%+y$ImHe4Vz%$D2g>Lw95A%m7R_o z>Ji8lnes}usyJ}X2|w{wVKKgnohmM(E?f>{6o)s4cJe%%2 z6dPH!43i*A^(a$($stPzafBl!6lVsCz&rxr36v{wG}{&qm{X0Et$7;$7Nbt>S)J(v zqafi93n_DZ5{I|pW_TM+m0&vsFQz*gD=k);-Dj%&x`$|mETH{elQ@nThuD@_uSMh+ zf)0v}MrLh@fP>RPTk=*M*mep!Cq^)EbaF8ektu?K^@KhZN@N z1c*>bi-#5T{H8w6{I29ey@h~)h-?9M0j(PeC1l{K$3sjgQ{w}O zf<&*?t7w=i?L-Mg$S2`gl_pfk3qKYQXjwRl(Yc?>FASzPLA4k=5D}roOh|CJRO-H~ znAicS#*IHJS`3S* z1HP(A3nvUaxTkuwKsvlAE@yxgt-F-kXC*-`aSEM2A&qT=os_5W{{Y5X&@5_O;FQBm zIEj{mK0*cLff8hL9_!HlAo^y&k|73Gs~_D3TNvk+k*{eH53um2r`TXyN~s&bMj~)8 zc=Cf>)_;f=PN~MQMTOVvxQ^vqe4_fT9hbSW+$T1mjYGi*Ji4K#(&ji8k}no0KZFrz zKe1QkG3?hR(l5o`k*H?J6bXnf_9Z4l# ztz)n-j$)lvtaC){SEo|q. +// +// Copyright A Beautiful Site, LLC. +// +// Source: https://github.com/claviska/SimpleImage +// +// Licensed under the MIT license +// + +namespace claviska; + +/** + * A PHP class that makes working with images as simple as possible. + */ +class SimpleImage { + + const + ERR_FILE_NOT_FOUND = 1, + ERR_FONT_FILE = 2, + ERR_FREETYPE_NOT_ENABLED = 3, + ERR_GD_NOT_ENABLED = 4, + ERR_INVALID_COLOR = 5, + ERR_INVALID_DATA_URI = 6, + ERR_INVALID_IMAGE = 7, + ERR_LIB_NOT_LOADED = 8, + ERR_UNSUPPORTED_FORMAT = 9, + ERR_WEBP_NOT_ENABLED = 10, + ERR_WRITE = 11, + ERR_INVALID_FLAG = 12; + + + protected $image; + protected $mimeType; + protected $exif; + + ////////////////////////////////////////////////////////////////////////////////////////////////// + // Magic methods + ////////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Creates a new SimpleImage object. + * + * @param string $image An image file or a data URI to load. + * @param array $flags Optional override of default flags. + * @throws \Exception Thrown if the GD library is not found; file|URI or image data is invalid. + */ + public function __construct($image = '', $flags = []) { + // Check for the required GD extension + if(extension_loaded('gd')) { + // Ignore JPEG warnings that cause imagecreatefromjpeg() to fail + ini_set('gd.jpeg_ignore_warning', 1); + } else { + throw new \Exception('Required extension GD is not loaded.', self::ERR_GD_NOT_ENABLED); + } + + // Associative array of flags. + $this->flags = [ + "sslVerify" => true // Skip SSL peer validation + ]; + + // Override default flag values. + foreach($flags as $flag => $value) { + $this->setFlag($flag, $value); + } + + // Load an image through the constructor + if(preg_match('/^data:(.*?);/', $image)) { + $this->fromDataUri($image); + } elseif($image) { + $this->fromFile($image); + } + } + + /** + * Destroys the image resource. + */ + public function __destruct() { + //Check for a valid GDimage instance + $type_check = (gettype($this->image) == "object" && get_class($this->image) == "GdImage"); + + if($this->image !== null && is_resource($this->image) && $type_check) { + imagedestroy($this->image); + } + } + + ////////////////////////////////////////////////////////////////////////////////////////////////// + // Helper functions + ////////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Set flag value. + * + * @param string $flag Name of the flag to set. + * @param boolean $value State of the flag. + * @throws \Exception Thrown if flag does not exist (no default value). + */ + public function setFlag($flag, $value) { + // Throw if flag does not exist + if(!in_array($flag, array_keys($this->flags))) { + throw new \Exception('Invalid flag.', self::ERR_INVALID_FLAG); + } + + // Set flag value by name + $this->flags[$flag] = $value; + } + + /** + * Get flag value. + * + * @param string $flag Name of the flag to get. + * @return boolean|null + */ + public function getFlag($flag) { + return in_array($flag, array_keys($this->flags)) ? $this->flags[$flag] : null; + } + + ////////////////////////////////////////////////////////////////////////////////////////////////// + // Loaders + ////////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Loads an image from a data URI. + * + * @param string $uri A data URI. + * @throws \Exception Thrown if URI or image data is invalid. + * @return \claviska\SimpleImage + */ + public function fromDataUri($uri) { + // Basic formatting check + preg_match('/^data:(.*?);/', $uri, $matches); + if(!count($matches)) { + throw new \Exception('Invalid data URI.', self::ERR_INVALID_DATA_URI); + } + + // Determine mime type + $this->mimeType = $matches[1]; + if(!preg_match('/^image\/(gif|jpeg|png)$/', $this->mimeType)) { + throw new \Exception( + 'Unsupported format: ' . $this->mimeType, + self::ERR_UNSUPPORTED_FORMAT + ); + } + + // Get image data + $uri = base64_decode(preg_replace('/^data:(.*?);base64,/', '', $uri)); + $this->image = imagecreatefromstring($uri); + if(!$this->image) { + throw new \Exception("Invalid image data.", self::ERR_INVALID_IMAGE); + } + + return $this; + } + + /** + * Loads an image from a file. + * + * @param string $file The image file to load. + * @param boolean $sslVerify Set to false to skip SSL validation. + * @throws \Exception Thrown if file or image data is invalid. + * @return \claviska\SimpleImage + */ + public function fromFile($file) { + // Set fopen options. + $sslVerify = $this->getFlag("sslVerify"); // Don't perform peer validation when true + $opts = [ + "ssl" => [ + "verify_peer" => $sslVerify, + "verify_peer_name" => $sslVerify + ] + ]; + + // Check if the file exists and is readable. + $file = @file_get_contents($file, false, stream_context_create($opts)); + if($file === false) { + throw new \Exception("File not found: $file", self::ERR_FILE_NOT_FOUND); + } + + // Create image object from string + $this->image = imagecreatefromstring($file); + + // Get image info + $info = @getimagesizefromstring($file); + if($info === false) { + throw new \Exception("Invalid image file: $file", self::ERR_INVALID_IMAGE); + } + $this->mimeType = $info['mime']; + + if(!$this->image) { + throw new \Exception("Unsupported format: " . $this->mimeType, self::ERR_UNSUPPORTED_FORMAT); + } + + switch($this->mimeType) { + case 'image/gif': + // Copy the gif over to a true color image to preserve its transparency. This is a + // workaround to prevent imagepalettetotruecolor() from borking transparency. + $width = imagesx($this->image); + $height = imagesx($this->image); + + $gif = imagecreatetruecolor((int) $width, (int) $height); + $alpha = imagecolorallocatealpha($gif, 0, 0, 0, 127); + imagecolortransparent($gif, $alpha); + imagefill($gif, 0, 0, $alpha); + + imagecopy($this->image, $gif, 0, 0, 0, 0, $width, $height); + imagedestroy($gif); + break; + case 'image/jpeg': + // Load exif data from JPEG images + if(function_exists('exif_read_data')) { + $this->exif = @exif_read_data("data://image/jpeg;base64," . base64_encode($file)); + } + break; + } + + // Convert pallete images to true color images + imagepalettetotruecolor($this->image); + + return $this; + } + + /** + * Creates a new image. + * + * @param integer $width The width of the image. + * @param integer $height The height of the image. + * @param string|array $color Optional fill color for the new image (default 'transparent'). + * @return \claviska\SimpleImage + */ + public function fromNew($width, $height, $color = 'transparent') { + $this->image = imagecreatetruecolor((int) $width, (int) $height); + + // Use PNG for dynamically created images because it's lossless and supports transparency + $this->mimeType = 'image/png'; + + // Fill the image with color + $this->fill($color); + + return $this; + } + + /** + * Creates a new image from a string. + * + * @param string $string The raw image data as a string. + * @example + * $string = file_get_contents('image.jpg'); + * @return \claviska\SimpleImage + */ + public function fromString($string) { + return $this->fromFile('data://;base64,' . base64_encode($string)); + } + + ////////////////////////////////////////////////////////////////////////////////////////////////// + // Savers + ////////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Generates an image. + * + * @param string $mimeType The image format to output as a mime type (defaults to the original mime type). + * @param integer $quality Image quality as a percentage (default 100). + * @throws \Exception Thrown when WEBP support is not enabled or unsupported format. + * @return array Returns an array containing the image data and mime type ['data' => '', 'mimeType' => '']. + */ + protected function generate($mimeType = null, $quality = 100) { + // Format defaults to the original mime type + $mimeType = $mimeType ?: $this->mimeType; + + // Ensure quality is a valid integer + if($quality === null) $quality = 100; + $quality = self::keepWithin((int) $quality, 0, 100); + + // Capture output + ob_start(); + + // Generate the image + switch($mimeType) { + + case 'image/gif': + imagesavealpha($this->image, true); + imagegif($this->image, null); + break; + case 'image/jpeg': + imageinterlace($this->image, true); + imagejpeg($this->image, null, $quality); + break; + case 'image/png': + imagesavealpha($this->image, true); + imagepng($this->image); + break; + case 'image/webp': + // Not all versions of PHP will have webp support enabled + if(!function_exists('imagewebp')) { + throw new \Exception( + 'WEBP support is not enabled in your version of PHP.', + self::ERR_WEBP_NOT_ENABLED + ); + } + imagesavealpha($this->image, true); + imagewebp($this->image, null, $quality); + break; + case 'image/bmp': + case 'image/x-ms-bmp': + case 'image/x-windows-bmp': + // Not all versions of PHP support bmp + if(!function_exists('imagebmp')) { + throw new \Exception( + 'BMP support is not available in your version of PHP.', + self::ERR_UNSUPPORTED_FORMAT + ); + } + imageinterlace($this->image, true); + imagebmp($this->image, null, $quality); + break; + default: + throw new \Exception('Unsupported format: ' . $mimeType, self::ERR_UNSUPPORTED_FORMAT); + } + + // Stop capturing + $data = ob_get_contents(); + ob_end_clean(); + + return [ + 'data' => $data, + 'mimeType' => $mimeType + ]; + } + + /** + * Generates a data URI. + * + * @param string $mimeType The image format to output as a mime type (defaults to the original mime type). + * @param integer $quality Image quality as a percentage (default 100). + * @return string Returns a string containing a data URI. + */ + public function toDataUri($mimeType = null, $quality = 100) { + $image = $this->generate($mimeType, $quality); + + return 'data:' . $image['mimeType'] . ';base64,' . base64_encode($image['data']); + } + + /** + * Forces the image to be downloaded to the clients machine. Must be called before any output is sent to the screen. + * + * @param string $filename The filename (without path) to send to the client (e.g. 'image.jpeg'). + * @param string $mimeType The image format to output as a mime type (defaults to the original mime type). + * @param integer $quality Image quality as a percentage (default 100). + * @return \claviska\SimpleImage + */ + public function toDownload($filename, $mimeType = null, $quality = 100) { + $image = $this->generate($mimeType, $quality); + + // Set download headers + header('Cache-Control: must-revalidate, post-check=0, pre-check=0'); + header('Content-Description: File Transfer'); + header('Content-Length: ' . strlen($image['data'])); + header('Content-Transfer-Encoding: Binary'); + header('Content-Type: application/octet-stream'); + header("Content-Disposition: attachment; filename=\"$filename\""); + + echo $image['data']; + + return $this; + } + + /** + * Writes the image to a file. + * + * @param string $file The image format to output as a mime type (defaults to the original mime type). + * @param string $mimeType Image quality as a percentage (default 100). + * @param integer $quality Image quality as a percentage (default 100). + * @throws \Exception Thrown if failed write to file. + * @return \claviska\SimpleImage + */ + public function toFile($file, $mimeType = null, $quality = 100) { + $image = $this->generate($mimeType, $quality); + + // Save the image to file + if(!file_put_contents($file, $image['data'])) { + throw new \Exception("Failed to write image to file: $file", self::ERR_WRITE); + } + + return $this; + } + + /** + * Outputs the image to the screen. Must be called before any output is sent to the screen. + * + * @param string $mimeType The image format to output as a mime type (defaults to the original mime type). + * @param integer $quality Image quality as a percentage (default 100). + * @return \claviska\SimpleImage + */ + public function toScreen($mimeType = null, $quality = 100) { + $image = $this->generate($mimeType, $quality); + + // Output the image to stdout + header('Content-Type: ' . $image['mimeType']); + echo $image['data']; + + return $this; + } + + /** + * Generates an image string. + * + * @param string $mimeType The image format to output as a mime type (defaults to the original mime type). + * @param integer $quality Image quality as a percentage (default 100). + * @return string + */ + public function toString($mimeType = null, $quality = 100) { + return $this->generate($mimeType, $quality)['data']; + } + + ////////////////////////////////////////////////////////////////////////////////////////////////// + // Utilities + ////////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Ensures a numeric value is always within the min and max range. + * + * @param integer|float $value A numeric value to test. + * @param integer|float $min The minimum allowed value. + * @param integer|float $max The maximum allowed value. + * @return integer|float + */ + protected static function keepWithin($value, $min, $max) { + if($value < $min) return $min; + if($value > $max) return $max; + return $value; + } + + /** + * Gets the image's current aspect ratio. + * + * @return float Returns the aspect ratio as a float. + */ + public function getAspectRatio() { + return $this->getWidth() / $this->getHeight(); + } + + /** + * Gets the image's exif data. + * + * @return array|NULL Returns an array of exif data or null if no data is available. + */ + public function getExif() { + return isset($this->exif) ? $this->exif : null; + } + + /** + * Gets the image's current height. + * + * @return integer + */ + public function getHeight() { + return (int) imagesy($this->image); + } + + /** + * Gets the mime type of the loaded image. + * + * @return string + */ + public function getMimeType() { + return $this->mimeType; + } + + /** + * Gets the image's current orientation. + * + * @return string One of the values: 'landscape', 'portrait', or 'square' + */ + public function getOrientation() { + $width = $this->getWidth(); + $height = $this->getHeight(); + + if($width > $height) return 'landscape'; + if($width < $height) return 'portrait'; + return 'square'; + } + + /** + * Gets the resolution of the image + * + * @return mixed The resolution as an array of integers: [96, 96] + */ + public function getResolution() { + return imageresolution($this->image); + } + + /** + * Gets the image's current width. + * + * @return integer + */ + public function getWidth() { + return (int) imagesx($this->image); + } + + ////////////////////////////////////////////////////////////////////////////////////////////////// + // Manipulation + ////////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Same as PHP's imagecopymerge, but works with transparent images. Used internally for overlay. + * + * @param resource $dstIm Destination image link resource. + * @param resource $srcIm Source image link resource. + * @param integer $dstX x-coordinate of destination point. + * @param integer $dstY y-coordinate of destination point. + * @param integer $srcX x-coordinate of source point. + * @param integer $srcY y-coordinate of source point. + * @param integer $srcW Source width. + * @param integer $srcH Source height. + * @param integer $pct + * @return boolean true if success. + */ + protected static function imageCopyMergeAlpha($dstIm, $srcIm, $dstX, $dstY, $srcX, $srcY, $srcW, $srcH, $pct) { + // Are we merging with transparency? + if($pct < 100) { + // Disable alpha blending and "colorize" the image using a transparent color + imagealphablending($srcIm, false); + imagefilter($srcIm, IMG_FILTER_COLORIZE, 0, 0, 0, 127 * ((100 - $pct) / 100)); + } + + imagecopy($dstIm, $srcIm, (int) $dstX, (int) $dstY, (int) $srcX, (int) $srcY, (int) $srcW, (int) $srcH); + + return true; + } + + /** + * Rotates an image so the orientation will be correct based on its exif data. It is safe to call + * this method on images that don't have exif data (no changes will be made). + * + * @return \claviska\SimpleImage + */ + public function autoOrient() { + $exif = $this->getExif(); + + if(!$exif || !isset($exif['Orientation'])){ + return $this; + } + + switch($exif['Orientation']) { + case 1: // Do nothing! + break; + case 2: // Flip horizontally + $this->flip('x'); + break; + case 3: // Rotate 180 degrees + $this->rotate(180); + break; + case 4: // Flip vertically + $this->flip('y'); + break; + case 5: // Rotate 90 degrees clockwise and flip vertically + $this->flip('y')->rotate(90); + break; + case 6: // Rotate 90 clockwise + $this->rotate(90); + break; + case 7: // Rotate 90 clockwise and flip horizontally + $this->flip('x')->rotate(90); + break; + case 8: // Rotate 90 counterclockwise + $this->rotate(-90); + break; + } + + return $this; + } + + /** + * Proportionally resize the image to fit inside a specific width and height. + * + * @param integer $maxWidth The maximum width the image can be. + * @param integer $maxHeight The maximum height the image can be. + * @return \claviska\SimpleImage + */ + public function bestFit($maxWidth, $maxHeight) { + // If the image already fits, there's nothing to do + if($this->getWidth() <= $maxWidth && $this->getHeight() <= $maxHeight) { + return $this; + } + + // Calculate max width or height based on orientation + if($this->getOrientation() === 'portrait') { + $height = $maxHeight; + $width = $maxHeight * $this->getAspectRatio(); + } else { + $width = $maxWidth; + $height = $maxWidth / $this->getAspectRatio(); + } + + // Reduce to max width + if($width > $maxWidth) { + $width = $maxWidth; + $height = $width / $this->getAspectRatio(); + } + + // Reduce to max height + if($height > $maxHeight) { + $height = $maxHeight; + $width = $height * $this->getAspectRatio(); + } + + return $this->resize($width, $height); + } + + /** + * Crop the image. + * + * @param integer|float $x1 Top left x coordinate. + * @param integer|float $y1 Top left y coordinate. + * @param integer|float $x2 Bottom right x coordinate. + * @param integer|float $y2 Bottom right x coordinate. + * @return \claviska\SimpleImage + */ + public function crop($x1, $y1, $x2, $y2) { + // Keep crop within image dimensions + $x1 = self::keepWithin($x1, 0, $this->getWidth()); + $x2 = self::keepWithin($x2, 0, $this->getWidth()); + $y1 = self::keepWithin($y1, 0, $this->getHeight()); + $y2 = self::keepWithin($y2, 0, $this->getHeight()); + + // Avoid using native imagecrop() because of a bug with PNG transparency + $dstW = abs($x2 - $x1); + $dstH = abs($y2 - $y1); + $newImage = imagecreatetruecolor((int) $dstW, (int) $dstH); + $transparentColor = imagecolorallocatealpha($newImage, 0, 0, 0, 127); + imagecolortransparent($newImage, $transparentColor); + imagefill($newImage, 0, 0, $transparentColor); + + // Crop it + imagecopyresampled( + $newImage, + $this->image, + 0, 0, min($x1, $x2), min($y1, $y2), + (int) $dstW, + (int) $dstH, + (int) $dstW, + (int) $dstH + ); + + // Swap out the new image + $this->image = $newImage; + + return $this; + } + + /** + * Applies a duotone filter to the image. + * + * @param string|array $lightColor The lightest color in the duotone. + * @param string|array $darkColor The darkest color in the duotone. + * @return \claviska\SimpleImage + */ + function duotone($lightColor, $darkColor) { + $lightColor = self::normalizeColor($lightColor); + $darkColor = self::normalizeColor($darkColor); + + // Calculate averages between light and dark colors + $redAvg = $lightColor['red'] - $darkColor['red']; + $greenAvg = $lightColor['green'] - $darkColor['green']; + $blueAvg = $lightColor['blue'] - $darkColor['blue']; + + // Create a matrix of all possible duotone colors based on gray values + $pixels = []; + for($i = 0; $i <= 255; $i++) { + $grayAvg = $i / 255; + $pixels['red'][$i] = $darkColor['red'] + $grayAvg * $redAvg; + $pixels['green'][$i] = $darkColor['green'] + $grayAvg * $greenAvg; + $pixels['blue'][$i] = $darkColor['blue'] + $grayAvg * $blueAvg; + } + + // Apply the filter pixel by pixel + for($x = 0; $x < $this->getWidth(); $x++) { + for($y = 0; $y < $this->getHeight(); $y++) { + $rgb = $this->getColorAt($x, $y); + $gray = min(255, round(0.299 * $rgb['red'] + 0.114 * $rgb['blue'] + 0.587 * $rgb['green'])); + $this->dot($x, $y, [ + 'red' => $pixels['red'][$gray], + 'green' => $pixels['green'][$gray], + 'blue' => $pixels['blue'][$gray] + ]); + } + } + + return $this; + } + + /** + * Proportionally resize the image to a specific height. + * + * @deprecated + * This method was deprecated in version 3.2.2 and will be removed in version 4.0. + * Please use `resize(null, $height)` instead. + * @param integer $height + * @return \claviska\SimpleImage + */ + public function fitToHeight($height) { + return $this->resize(null, $height); + } + + /** + * Proportionally resize the image to a specific width. + * + * @deprecated + * This method was deprecated in version 3.2.2 and will be removed in version 4.0. + * Please use `resize(null, $height)` instead. + * @param integer $width The width to resize the image to. + * @return \claviska\SimpleImage + */ + public function fitToWidth($width) { + return $this->resize($width, null); + } + + /** + * Flip the image horizontally or vertically. + * + * @param string $direction The direction to flip: x|y|both. + * @return \claviska\SimpleImage + */ + public function flip($direction) { + switch($direction) { + case 'x': + imageflip($this->image, IMG_FLIP_HORIZONTAL); + break; + case 'y': + imageflip($this->image, IMG_FLIP_VERTICAL); + break; + case 'both': + imageflip($this->image, IMG_FLIP_BOTH); + break; + } + + return $this; + } + + /** + * Reduces the image to a maximum number of colors. + * + * @param integer $max The maximum number of colors to use. + * @param boolean $dither Whether or not to use a dithering effect (default true). + * @return \claviska\SimpleImage + */ + public function maxColors($max, $dither = true) { + imagetruecolortopalette($this->image, $dither, max(1, $max)); + + return $this; + } + + /** + * Place an image on top of the current image. + * + * @param string|SimpleImage $overlay The image to overlay. This can be a filename, a data URI, or a SimpleImage object. + * @param string $anchor The anchor point: 'center', 'top', 'bottom', 'left', 'right', 'top left', 'top right', 'bottom left', 'bottom right' (default 'center'). + * @param float $opacity The opacity level of the overlay 0-1 (default 1). + * @param integer $xOffset Horizontal offset in pixels (default 0). + * @param integer $yOffset Vertical offset in pixels (default 0). + * @param bool $calculateOffsetFromEdge Calculate Offset referring to the edges of the image (default false). + * @return \claviska\SimpleImage + */ + public function overlay($overlay, $anchor = 'center', $opacity = 1, $xOffset = 0, $yOffset = 0, $calculateOffsetFromEdge = false) { + // Load overlay image + if(!($overlay instanceof SimpleImage)) $overlay = new SimpleImage($overlay); + + // Convert opacity + $opacity = self::keepWithin($opacity, 0, 1) * 100; + + // Get available space + $spaceX = $this->getWidth() - $overlay->getWidth(); + $spaceY = $this->getHeight() - $overlay->getHeight(); + + // Set default center + $x = ($spaceX / 2) + ($calculateOffsetFromEdge ? 0 : $xOffset); + $y = ($spaceY / 2) + ($calculateOffsetFromEdge ? 0 : $yOffset); + + // Determine if top|bottom + if (strpos($anchor, 'top') !== false) { + $y = $yOffset; + } elseif (strpos($anchor, 'bottom') !== false) { + $y = $spaceY + ($calculateOffsetFromEdge ? -$yOffset : $yOffset); + } + + // Determine if left|right + if (strpos($anchor, 'left') !== false) { + $x = $xOffset; + } elseif (strpos($anchor, 'right') !== false) { + $x = $spaceX + ($calculateOffsetFromEdge ? -$xOffset : $xOffset); + } + + // Perform the overlay + self::imageCopyMergeAlpha( + $this->image, + $overlay->image, + $x, $y, + 0, 0, + $overlay->getWidth(), + $overlay->getHeight(), + $opacity + ); + + return $this; + } + + /** + * Resize an image to the specified dimensions. If only one dimension is specified, the image will be resized proportionally. + * + * @param integer $width The new image width. + * @param integer $height The new image height. + * @return \claviska\SimpleImage + */ + public function resize($width = null, $height = null) { + // No dimentions specified + if(!$width && !$height) { + return $this; + } + + // Resize to width + if($width && !$height) { + $height = $width / $this->getAspectRatio(); + } + + // Resize to height + if(!$width && $height) { + $width = $height * $this->getAspectRatio(); + } + + // If the dimensions are the same, there's no need to resize + if($this->getWidth() === $width && $this->getHeight() === $height) { + return $this; + } + + // We can't use imagescale because it doesn't seem to preserve transparency properly. The + // workaround is to create a new truecolor image, allocate a transparent color, and copy the + // image over to it using imagecopyresampled. + $newImage = imagecreatetruecolor((int) $width, (int) $height); + $transparentColor = imagecolorallocatealpha($newImage, 0, 0, 0, 127); + imagecolortransparent($newImage, $transparentColor); + imagefill($newImage, 0, 0, $transparentColor); + imagecopyresampled( + $newImage, + $this->image, + 0, 0, 0, 0, + (int) $width, + (int) $height, + $this->getWidth(), + $this->getHeight() + ); + + // Swap out the new image + $this->image = $newImage; + + return $this; + } + + /** + * Sets an image's resolution, as per https://www.php.net/manual/en/function.imageresolution.php + * + * @param integer $res_x The horizontal resolution in DPI. + * @param integer $res_y The vertical resolution in DPI + * @return \claviska\SimpleImage + */ + public function resolution($res_x, $res_y = null) { + if(is_null($res_y)) { + imageresolution($this->image, $res_x); + } else { + imageresolution($this->image, $res_x, $res_y); + } + + return $this; + } + + /** + * Rotates the image. + * + * @param integer $angle The angle of rotation (-360 - 360). + * @param string|array $backgroundColor The background color to use for the uncovered zone area after rotation (default 'transparent'). + * @return \claviska\SimpleImage + */ + public function rotate($angle, $backgroundColor = 'transparent') { + // Rotate the image on a canvas with the desired background color + $backgroundColor = $this->allocateColor($backgroundColor); + + $this->image = imagerotate( + $this->image, + -(self::keepWithin($angle, -360, 360)), + $backgroundColor + ); + imagecolortransparent($this->image, imagecolorallocatealpha($this->image, 0, 0, 0, 127)); + + return $this; + } + + /** + * Adds text to the image. + * + * @param string $text The desired text. + * @param array $options + * An array of options. + * - fontFile* (string) - The TrueType (or compatible) font file to use. + * - size (integer) - The size of the font in pixels (default 12). + * - color (string|array) - The text color (default black). + * - anchor (string) - The anchor point: 'center', 'top', 'bottom', 'left', 'right', 'top left', 'top right', 'bottom left', 'bottom right' (default 'center'). + * - xOffset (integer) - The horizontal offset in pixels (default 0). + * - yOffset (integer) - The vertical offset in pixels (default 0). + * - shadow (array) - Text shadow params. + * - x* (integer) - Horizontal offset in pixels. + * - y* (integer) - Vertical offset in pixels. + * - color* (string|array) - The text shadow color. + * - $calculateOffsetFromEdge (bool) - Calculate offsets from the edge of the image (default false). + * - $baselineAlign (bool) - Align the text font with the baseline. (default true). + * @param array $boundary + * If passed, this variable will contain an array with coordinates that surround the text: [x1, y1, x2, y2, width, height]. + * This can be used for calculating the text's position after it gets added to the image. + * @throws \Exception + * @return \claviska\SimpleImage + */ + public function text($text, $options, &$boundary = null) { + // Check for freetype support + if(!function_exists('imagettftext')) { + throw new \Exception( + 'Freetype support is not enabled in your version of PHP.', + self::ERR_FREETYPE_NOT_ENABLED + ); + } + + // Default options + $options = array_merge([ + 'fontFile' => null, + 'size' => 12, + 'color' => 'black', + 'anchor' => 'center', + 'xOffset' => 0, + 'yOffset' => 0, + 'shadow' => null, + 'calculateOffsetFromEdge' => false, + 'baselineAlign' => true + ], $options); + + // Extract and normalize options + $fontFile = $options['fontFile']; + $size = ($options['size'] / 96) * 72; // Convert px to pt (72pt per inch, 96px per inch) + $color = $this->allocateColor($options['color']); + $anchor = $options['anchor']; + $xOffset = $options['xOffset']; + $yOffset = $options['yOffset']; + $calculateOffsetFromEdge = $options['calculateOffsetFromEdge']; + $baselineAlign = $options['baselineAlign']; + $angle = 0; + + // Calculate the bounding box dimensions + // + // Since imagettfbox() returns a bounding box from the text's baseline, we can end up with + // different heights for different strings of the same font size. For example, 'type' will often + // be taller than 'text' because the former has a descending letter. + // + // To compensate for this, we created a temporary bounding box to measure the maximum height + // that the font used can occupy. Based on this, we can adjust the text vertically so that it + // appears inside the box with a good consistency. + // + // See: https://github.com/claviska/SimpleImage/issues/165 + // + + $boxText = imagettfbbox($size, $angle, $fontFile, $text); + if(!$boxText) throw new \Exception("Unable to load font file: $fontFile", self::ERR_FONT_FILE); + + $boxWidth = abs($boxText[4] - $boxText[0]); + $boxHeight = abs($boxText[5] - $boxText[1]); + + // Calculate Offset referring to the edges of the image. + // Just invert the value for bottom|right; + if ($calculateOffsetFromEdge == true) { + if (strpos($anchor, 'bottom') !== false) $yOffset *= -1; + if (strpos($anchor, 'right') !== false) $xOffset *= -1; + } + + // Align the text font with the baseline. + // I use $yOffset to inject the vertical alignment correction value. + if ($baselineAlign == true) { + // Create a temporary box to obtain the maximum height that this font can use. + $boxFull = imagettfbbox($size, $angle, $fontFile, 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890'); + // Based on the maximum height, the text is aligned. + if (strpos($anchor, 'bottom') !== false) { + $yOffset -= $boxFull[1]; + } elseif (strpos($anchor, 'top') !== false) { + $yOffset += abs($boxFull[5]) - $boxHeight; + } else { // center + $boxFullHeight = abs($boxFull[1]) + abs($boxFull[5]); + $yOffset += ($boxFullHeight/2) - ($boxHeight/2) - abs($boxFull[1]); + } + + } else { + // Prevents fonts rendered outside the box boundary from being cut. + // Example: 'Scriptina' font, some letters invade the space of the previous or subsequent letter. + $yOffset -= $boxText[1]; + } + + // Prevents fonts rendered outside the box boundary from being cut. + // Example: 'Scriptina' font, some letters invade the space of the previous or subsequent letter. + $xOffset -= $boxText[0]; + + // Determine position + switch($anchor) { + case 'top left': + $x = $xOffset; + $y = $yOffset + $boxHeight; + break; + case 'top right': + $x = $this->getWidth() - $boxWidth + $xOffset; + $y = $yOffset + $boxHeight; + break; + case 'top': + $x = ($this->getWidth() / 2) - ($boxWidth / 2) + $xOffset; + $y = $yOffset + $boxHeight; + break; + case 'bottom left': + $x = $xOffset; + $y = $this->getHeight() + $yOffset ; + break; + case 'bottom right': + $x = $this->getWidth() - $boxWidth + $xOffset; + $y = $this->getHeight() + $yOffset; + break; + case 'bottom': + $x = ($this->getWidth() / 2) - ($boxWidth / 2) + $xOffset; + $y = $this->getHeight() + $yOffset; + break; + case 'left': + $x = $xOffset; + $y = ($this->getHeight() / 2) - (($boxHeight / 2) - $boxHeight) + $yOffset; + break; + case 'right'; + $x = $this->getWidth() - $boxWidth + $xOffset; + $y = ($this->getHeight() / 2) - (($boxHeight / 2) - $boxHeight) + $yOffset; + break; + default: // center + $x = ($this->getWidth() / 2) - ($boxWidth / 2) + $xOffset; + $y = ($this->getHeight() / 2) - (($boxHeight / 2) - $boxHeight) + $yOffset; + break; + } + $x = (int) round($x); + $y = (int) round($y); + + // Pass the boundary back by reference + $boundary = [ + 'x1' => $x + $boxText[0], + 'y1' => $y + $boxText[1] - $boxHeight, // $y is the baseline, not the top! + 'x2' => $x + $boxWidth + $boxText[0], + 'y2' => $y + $boxText[1], + 'width' => $boxWidth, + 'height' => $boxHeight + ]; + + // Text shadow + if(is_array($options['shadow'])) { + imagettftext( + $this->image, + $size, + $angle, + $x + $options['shadow']['x'], + $y + $options['shadow']['y'], + $this->allocateColor($options['shadow']['color']), + $fontFile, + $text + ); + } + + // Draw the text + imagettftext($this->image, $size, $angle, $x, $y, $color, $fontFile, $text); + + return $this; + } + + /** + * Adds text with a line break to the image. + * + * @param string $text The desired text. + * @param array $options + * An array of options. + * - fontFile* (string) - The TrueType (or compatible) font file to use. + * - size (integer) - The size of the font in pixels (default 12). + * - color (string|array) - The text color (default black). + * - anchor (string) - The anchor point: 'center', 'top', 'bottom', 'left', 'right', 'top left', 'top right', 'bottom left', 'bottom right' (default 'center'). + * - xOffset (integer) - The horizontal offset in pixels (default 0). Has no effect when anchor is 'center'. + * - yOffset (integer) - The vertical offset in pixels (default 0). Has no effect when anchor is 'center'. + * - shadow (array) - Text shadow params. + * - x* (integer) - Horizontal offset in pixels. + * - y* (integer) - Vertical offset in pixels. + * - color* (string|array) - The text shadow color. + * - $calculateOffsetFromEdge (bool) - Calculate offsets from the edge of the image (default false). + * - width (int) - Width of text box (default image width). + * - align (string) - How to align text: 'left', 'right', 'center', 'justify' (default 'left'). + * - leading (float) - Increase/decrease spacing between lines of text (default 0). + * - opacity (float) - The opacity level of the text 0-1 (default 1). + * @throws \Exception + * @return \claviska\SimpleImage + */ + public function textBox($text, $options) { + // default width of image + $maxWidth = $this->getWidth(); + // Default options + $options = array_merge([ + 'fontFile' => null, + 'size' => 12, + 'color' => 'black', + 'anchor' => 'center', + 'xOffset' => 0, + 'yOffset' => 0, + 'shadow' => null, + 'calculateOffsetFromEdge' => false, + 'width' => $maxWidth, + 'align' => 'left', + 'leading' => 0, + 'opacity' => 1 + ], $options); + + // Extract and normalize options + $fontFile = $options['fontFile']; + $fontSize = $fontSizePx = $options['size']; + $fontSize = ($fontSize / 96) * 72; // Convert px to pt (72pt per inch, 96px per inch) + $color = $options['color']; + $anchor = $options['anchor']; + $xOffset = $options['xOffset']; + $yOffset = $options['yOffset']; + $shadow = $options['shadow']; + $calculateOffsetFromEdge = $options['calculateOffsetFromEdge']; + $angle = 0; + $maxWidth = $options['width']; + $leading = $options['leading']; + $leading = self::keepWithin($leading, ($fontSizePx * -1), $leading); + $opacity = $options['opacity']; + + $align = $options['align']; + if ($align == 'right') { + $align = 'top right'; + } elseif ($align == 'center') { + $align = 'top'; + } elseif ($align == 'justify') { + $align = 'justify'; + } else { + $align = 'top left'; + } + + list($lines, $isLastLine, $lastLineHeight) = self::textSeparateLines($text, $fontFile, $fontSize, $maxWidth); + + $maxHeight = (count($lines) - 1) * ($fontSizePx * 1.2 + $leading) + $lastLineHeight; + + $imageText = new SimpleImage(); + $imageText->fromNew($maxWidth, $maxHeight); + + // Align left/center/right + if ($align <> 'justify') { + foreach ($lines as $key => $line) { + if( $align == 'top' ) $line = trim($line); // If is justify = 'center' + $imageText->text($line, array( + 'fontFile' => $fontFile, + 'size' => $fontSizePx, + 'color' => $color, + 'anchor' => $align, + 'xOffset' => 0, + 'yOffset' => $key * ($fontSizePx * 1.2 + $leading), + 'shadow' => $shadow, + 'calculateOffsetFromEdge' => true + )); + } + + // Justify + } else { + foreach ($lines as $keyLine => $line) { + // Check if there are spaces at the beginning of the sentence + $spaces = 0; + if (preg_match("/^\s+/", $line, $match)) { + // Count spaces + $spaces = strlen($match[0]); + $line = ltrim($line); + } + + // Separate words + $words = preg_split("/\s+/", $line); + // Include spaces with the first word + $words[0] = str_repeat(' ', $spaces) . $words[0]; + + // Calculates the space occupied by all words + $wordsSize = array(); + foreach ($words as $key => $word) { + $wordBox = imagettfbbox($fontSize, 0, $fontFile, $word); + $wordWidth = abs($wordBox[4] - $wordBox[0]); + $wordsSize[$key] = $wordWidth; + } + $wordsSizeTotal = array_sum($wordsSize); + + // Calculates the required space between words + $countWords = count($words); + $wordSpacing = 0; + if ($countWords > 1) { + $wordSpacing = ($maxWidth - $wordsSizeTotal) / ($countWords - 1); + $wordSpacing = round($wordSpacing, 3); + } + + $xOffsetJustify = 0; + foreach ($words as $key => $word) { + if ($isLastLine[$keyLine] == true) { + if ($key < (count($words) - 1)) continue; + $word = $line; + } + $imageText->text($word, array( + 'fontFile' => $fontFile, + 'size' => $fontSizePx, + 'color' => $color, + 'anchor' => 'top left', + 'xOffset' => $xOffsetJustify, + 'yOffset' => $keyLine * ($fontSizePx * 1.2 + $leading), + 'shadow' => $shadow, + 'calculateOffsetFromEdge' => true, + ) + ); + // Calculate offset for next word + $xOffsetJustify += $wordsSize[$key] + $wordSpacing; + } + } + } + + $this->overlay($imageText, $anchor, $opacity, $xOffset, $yOffset, $calculateOffsetFromEdge); + + return $this; + } + + /** + * Receives a text and breaks into LINES. + * + * @param integer $text + * @param string $fontFile + * @param int $fontSize + * @param int $maxWidth + * @return array + */ + private function textSeparateLines($text, $fontFile, $fontSize, $maxWidth) { + $words = self::textSeparateWords($text); + $countWords = count($words) - 1; + $lines[0] = ''; + $lineKey = 0; + $isLastLine = []; + for ($i = 0; $i < $countWords; $i++) { + $word = $words[$i]; + $isLastLine[$lineKey] = false; + if ($word === PHP_EOL) { + $isLastLine[$lineKey] = true; + $lineKey++; + $lines[$lineKey] = ''; + continue; + } + $lineBox = imagettfbbox($fontSize, 0, $fontFile, $lines[$lineKey] . $word); + if (abs($lineBox[4] - $lineBox[0]) < $maxWidth) { + $lines[$lineKey] .= $word . ' '; + } else { + $lineKey++; + $lines[$lineKey] = $word . ' '; + } + } + $isLastLine[$lineKey] = true; + // Exclude space of right + $lines = array_map('rtrim', $lines); + // Calculate height of last line + $boxFull = imagettfbbox($fontSize, 0, $fontFile, 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890'); + $lineBox = imagettfbbox($fontSize, 0, $fontFile, $lines[$lineKey]); + // Height of last line = ascender of $boxFull + descender of $lineBox + $lastLineHeight = abs($lineBox[1]) + abs($boxFull[5]); + + return array($lines, $isLastLine, $lastLineHeight); + } + + /** + * Receives a text and breaks into WORD / SPACE / NEW LINE. + * + * @param integer $text + * @return array + */ + private function textSeparateWords($text) { + // Normalizes line break + $text = preg_replace('/(\r\n|\n|\r)/', PHP_EOL, $text); + $text = explode(PHP_EOL, $text); + $newText = array(); + foreach ($text as $key => $line) { + $newText = array_merge($newText, explode(' ', $line), [PHP_EOL]); + } + + return $newText; + } + + /** + * Creates a thumbnail image. This function attempts to get the image as close to the provided + * dimensions as possible, then crops the remaining overflow to force the desired size. Useful + * for generating thumbnail images. + * + * @param integer $width The thumbnail width. + * @param integer $height The thumbnail height. + * @param string $anchor The anchor point: 'center', 'top', 'bottom', 'left', 'right', 'top left', 'top right', 'bottom left', 'bottom right' (default 'center'). + * @return \claviska\SimpleImage + */ + public function thumbnail($width, $height, $anchor = 'center') { + // Determine aspect ratios + $currentRatio = $this->getHeight() / $this->getWidth(); + $targetRatio = $height / $width; + + // Fit to height/width + if($targetRatio > $currentRatio) { + $this->resize(null, $height); + } else { + $this->resize($width, null); + } + + switch($anchor) { + case 'top': + $x1 = floor(($this->getWidth() / 2) - ($width / 2)); + $x2 = $width + $x1; + $y1 = 0; + $y2 = $height; + break; + case 'bottom': + $x1 = floor(($this->getWidth() / 2) - ($width / 2)); + $x2 = $width + $x1; + $y1 = $this->getHeight() - $height; + $y2 = $this->getHeight(); + break; + case 'left': + $x1 = 0; + $x2 = $width; + $y1 = floor(($this->getHeight() / 2) - ($height / 2)); + $y2 = $height + $y1; + break; + case 'right': + $x1 = $this->getWidth() - $width; + $x2 = $this->getWidth(); + $y1 = floor(($this->getHeight() / 2) - ($height / 2)); + $y2 = $height + $y1; + break; + case 'top left': + $x1 = 0; + $x2 = $width; + $y1 = 0; + $y2 = $height; + break; + case 'top right': + $x1 = $this->getWidth() - $width; + $x2 = $this->getWidth(); + $y1 = 0; + $y2 = $height; + break; + case 'bottom left': + $x1 = 0; + $x2 = $width; + $y1 = $this->getHeight() - $height; + $y2 = $this->getHeight(); + break; + case 'bottom right': + $x1 = $this->getWidth() - $width; + $x2 = $this->getWidth(); + $y1 = $this->getHeight() - $height; + $y2 = $this->getHeight(); + break; + default: + $x1 = floor(($this->getWidth() / 2) - ($width / 2)); + $x2 = $width + $x1; + $y1 = floor(($this->getHeight() / 2) - ($height / 2)); + $y2 = $height + $y1; + break; + } + + // Return the cropped thumbnail image + return $this->crop($x1, $y1, $x2, $y2); + } + + ////////////////////////////////////////////////////////////////////////////////////////////////// + // Drawing + ////////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Draws an arc. + * + * @param integer $x The x coordinate of the arc's center. + * @param integer $y The y coordinate of the arc's center. + * @param integer $width The width of the arc. + * @param integer $height The height of the arc. + * @param integer $start The start of the arc in degrees. + * @param integer $end The end of the arc in degrees. + * @param string|array $color The arc color. + * @param integer|string $thickness Line thickness in pixels or 'filled' (default 1). + * @return \claviska\SimpleImage + */ + public function arc($x, $y, $width, $height, $start, $end, $color, $thickness = 1) { + // Allocate the color + $tempColor = $this->allocateColor($color); + imagesetthickness($this->image, 1); + + // Draw an arc + if($thickness === 'filled') { + imagefilledarc($this->image, $x, $y, $width, $height, $start, $end, $tempColor, IMG_ARC_PIE); + + } else if ($thickness === 1) { + imagearc($this->image, $x, $y, $width, $height, $start, $end, $tempColor); + + } else { + // New temp image + $tempImage = new SimpleImage(); + $tempImage->fromNew($this->getWidth(), $this->getHeight(), 'transparent'); + + // Draw a large ellipse filled with $color (+$thickness pixels) + $tempColor = $tempImage->allocateColor($color); + imagefilledarc($tempImage->image, $x, $y, $width+$thickness, $height+$thickness, $start, $end, $tempColor, IMG_ARC_PIE); + + // Draw a smaller ellipse filled with red|blue (-$thickness pixels) + $tempColor = (self::normalizeColor($color)['red'] == 255) ? 'blue' : 'red'; + $tempColor = $tempImage->allocateColor($tempColor); + imagefilledarc($tempImage->image, $x, $y, $width-$thickness, $height-$thickness, $start, $end, $tempColor, IMG_ARC_PIE); + + // Replace the color of the smaller ellipse with 'transparent' + $tempImage->excludeInsideColor($x, $y, $color); + + // Apply the temp image + $this->overlay($tempImage); + } + + return $this; + } + + /** + * Draws a border around the image. + * + * @param string|array $color The border color. + * @param integer $thickness The thickness of the border (default 1). + * @return \claviska\SimpleImage + */ + public function border($color, $thickness = 1) { + $x1 = -1; + $y1 = 0; + $x2 = $this->getWidth(); + $y2 = $this->getHeight()-1; + + $color = $this->allocateColor($color); + imagesetthickness($this->image, $thickness*2); + imagerectangle($this->image, $x1, $y1, $x2, $y2, $color); + + return $this; + } + + /** + * Draws a single pixel dot. + * + * @param integer $x The x coordinate of the dot. + * @param integer $y The y coordinate of the dot. + * @param string|array $color The dot color. + * @return \claviska\SimpleImage + */ + public function dot($x, $y, $color) { + $color = $this->allocateColor($color); + imagesetpixel($this->image, $x, $y, $color); + + return $this; + } + + /** + * Draws an ellipse. + * + * @param integer $x The x coordinate of the center. + * @param integer $y The y coordinate of the center. + * @param integer $width The ellipse width. + * @param integer $height The ellipse height. + * @param string|array $color The ellipse color. + * @param integer|array $thickness Line thickness in pixels or 'filled' (default 1). + * @return \claviska\SimpleImage + */ + public function ellipse($x, $y, $width, $height, $color, $thickness = 1) { + // Allocate the color + $tempColor = $this->allocateColor($color); + imagesetthickness($this->image, 1); + + // Draw an ellipse + if($thickness === 'filled') { + imagefilledellipse($this->image, $x, $y, $width, $height, $tempColor); + + } else if ($thickness === 1) { + imageellipse($this->image, $x, $y, $width, $height, $tempColor); + + } else { + // New temp image + $tempImage = new SimpleImage(); + $tempImage->fromNew($this->getWidth(), $this->getHeight(), 'transparent'); + + // Draw a large ellipse filled with $color (+$thickness pixels) + $tempColor = $tempImage->allocateColor($color); + imagefilledellipse($tempImage->image, $x, $y, $width+$thickness, $height+$thickness, $tempColor); + + // Draw a smaller ellipse filled with red|blue (-$thickness pixels) + $tempColor = (self::normalizeColor($color)['red'] == 255) ? 'blue' : 'red'; + $tempColor = $tempImage->allocateColor($tempColor); + imagefilledellipse($tempImage->image, $x, $y, $width-$thickness, $height-$thickness, $tempColor); + + // Replace the color of the smaller ellipse with 'transparent' + $tempImage->excludeInsideColor($x, $y, $color); + + // Apply the temp image + $this->overlay($tempImage); + } + + return $this; + } + + /** + * Fills the image with a solid color. + * + * @param string|array $color The fill color. + * @return \claviska\SimpleImage + */ + public function fill($color) { + // Draw a filled rectangle over the entire image + $this->rectangle(0, 0, $this->getWidth(), $this->getHeight(), 'white', 'filled'); + + // Now flood it with the appropriate color + $color = $this->allocateColor($color); + imagefill($this->image, 0, 0, $color); + + return $this; + } + + /** + * Draws a line. + * + * @param integer $x1 The x coordinate for the first point. + * @param integer $y1 The y coordinate for the first point. + * @param integer $x2 The x coordinate for the second point. + * @param integer $y2 The y coordinate for the second point. + * @param string|array $color The line color. + * @param integer $thickness The line thickness (default 1). + * @return \claviska\SimpleImage + */ + public function line($x1, $y1, $x2, $y2, $color, $thickness = 1) { + // Allocate the color + $color = $this->allocateColor($color); + + // Draw a line + imagesetthickness($this->image, $thickness); + imageline($this->image, $x1, $y1, $x2, $y2, $color); + + return $this; + } + + /** + * Draws a polygon. + * + * @param array $vertices + * The polygon's vertices in an array of x/y arrays. + * Example: + * [ + * ['x' => x1, 'y' => y1], + * ['x' => x2, 'y' => y2], + * ['x' => xN, 'y' => yN] + * ] + * @param string|array $color The polygon color. + * @param integer|array $thickness Line thickness in pixels or 'filled' (default 1). + * @return \claviska\SimpleImage + */ + public function polygon($vertices, $color, $thickness = 1) { + // Allocate the color + $color = $this->allocateColor($color); + + // Convert [['x' => x1, 'y' => x1], ['x' => x1, 'y' => y2], ...] to [x1, y1, x2, y2, ...] + $points = []; + foreach($vertices as $vals) { + $points[] = $vals['x']; + $points[] = $vals['y']; + } + + // Draw a polygon + if($thickness === 'filled') { + imagesetthickness($this->image, 1); + imagefilledpolygon($this->image, $points, count($vertices), $color); + } else { + imagesetthickness($this->image, $thickness); + imagepolygon($this->image, $points, count($vertices), $color); + } + + return $this; + } + + /** + * Draws a rectangle. + * + * @param integer $x1 The upper left x coordinate. + * @param integer $y1 The upper left y coordinate. + * @param integer $x2 The bottom right x coordinate. + * @param integer $y2 The bottom right y coordinate. + * @param string|array $color The rectangle color. + * @param integer|array $thickness Line thickness in pixels or 'filled' (default 1). + * @return \claviska\SimpleImage + */ + public function rectangle($x1, $y1, $x2, $y2, $color, $thickness = 1) { + // Allocate the color + $color = $this->allocateColor($color); + + // Draw a rectangle + if($thickness === 'filled') { + imagesetthickness($this->image, 1); + imagefilledrectangle($this->image, $x1, $y1, $x2, $y2, $color); + } else { + imagesetthickness($this->image, $thickness); + imagerectangle($this->image, $x1, $y1, $x2, $y2, $color); + } + + return $this; + } + + /** + * Draws a rounded rectangle. + * + * @param integer $x1 The upper left x coordinate. + * @param integer $y1 The upper left y coordinate. + * @param integer $x2 The bottom right x coordinate. + * @param integer $y2 The bottom right y coordinate. + * @param integer $radius The border radius in pixels. + * @param string|array $color The rectangle color. + * @param integer|array $thickness Line thickness in pixels or 'filled' (default 1). + * @return \claviska\SimpleImage + */ + public function roundedRectangle($x1, $y1, $x2, $y2, $radius, $color, $thickness = 1) { + if($thickness === 'filled') { + // Draw the filled rectangle without edges + $this->rectangle($x1 + $radius + 1, $y1, $x2 - $radius - 1, $y2, $color, 'filled'); + $this->rectangle($x1, $y1 + $radius + 1, $x1 + $radius, $y2 - $radius - 1, $color, 'filled'); + $this->rectangle($x2 - $radius, $y1 + $radius + 1, $x2, $y2 - $radius - 1, $color, 'filled'); + + // Fill in the edges with arcs + $this->arc($x1 + $radius, $y1 + $radius, $radius * 2, $radius * 2, 180, 270, $color, 'filled'); + $this->arc($x2 - $radius, $y1 + $radius, $radius * 2, $radius * 2, 270, 360, $color, 'filled'); + $this->arc($x1 + $radius, $y2 - $radius, $radius * 2, $radius * 2, 90, 180, $color, 'filled'); + $this->arc($x2 - $radius, $y2 - $radius, $radius * 2, $radius * 2, 360, 90, $color, 'filled'); + } else { + $offset = $thickness / 2; + $x1 -= $offset; + $x2 += $offset; + $y1 -= $offset; + $y2 += $offset; + $radius = self::keepWithin($radius, 0, min(($x2 - $x1) / 2, ($y2 - $y1) / 2 ) - 1); + $radius = floor($radius); + $thickness = self::keepWithin($thickness, 1, min(($x2 - $x1) / 2, ($y2 - $y1) / 2)); + + // New temp image + $tempImage = new SimpleImage(); + $tempImage->fromNew($this->getWidth(), $this->getHeight(), 'transparent'); + + // Draw a large rectangle filled with $color + $tempImage->roundedRectangle($x1, $y1, $x2, $y2, $radius, $color,'filled'); + + // Draw a smaller rectangle filled with red|blue (-$thickness pixels on each side) + $tempColor = (self::normalizeColor($color)['red'] == 255) ? 'blue' : 'red'; + $radius = $radius - $thickness; + $radius = self::keepWithin($radius, 0, $radius); + $tempImage->roundedRectangle( + $x1 + $thickness, + $y1 + $thickness, + $x2 - $thickness, + $y2 - $thickness, + $radius, + $tempColor, + 'filled' + ); + + // Replace the color of the smaller rectangle with 'transparent' + $tempImage->excludeInsideColor(($x2 + $x1) / 2, ($y2 + $y1) / 2, $color); + + // Apply the temp image + $this->overlay($tempImage); + } + + return $this; + } + + /** + * Exclude inside color. + * Used for roundedRectangle(), ellipse() and arc() + * + * @param number $x certer x of rectangle. + * @param number $y certer y of rectangle. + * @param string|array $borderColor The color of border. + */ + private function excludeInsideColor($x, $y, $borderColor) { + $borderColor = $this->allocateColor($borderColor); + $transparent = $this->allocateColor('transparent'); + imagefilltoborder($this->image, $x, $y, $borderColor, $transparent); + return $this; + } + + ////////////////////////////////////////////////////////////////////////////////////////////////// + // Filters + ////////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Applies the blur filter. + * + * @param string $type The blur algorithm to use: 'selective', 'gaussian' (default 'gaussian'). + * @param number $passes The number of time to apply the filter, enhancing the effect (default 1). + * @return \claviska\SimpleImage + */ + public function blur($type = 'selective', $passes = 1) { + $filter = $type === 'gaussian' ? IMG_FILTER_GAUSSIAN_BLUR : IMG_FILTER_SELECTIVE_BLUR; + + for($i = 0; $i < $passes; $i++) { + imagefilter($this->image, $filter); + } + + return $this; + } + + /** + * Applies the brightness filter to brighten the image. + * + * @param integer $percentage Percentage to brighten the image (0 - 100). + * @return \claviska\SimpleImage + */ + public function brighten($percentage) { + $percentage = self::keepWithin(255 * $percentage / 100, 0, 255); + + imagefilter($this->image, IMG_FILTER_BRIGHTNESS, $percentage); + + return $this; + } + + /** + * Applies the colorize filter. + * + * @param string|array $color The filter color. + * @return \claviska\SimpleImage + */ + public function colorize($color) { + $color = self::normalizeColor($color); + + imagefilter( + $this->image, + IMG_FILTER_COLORIZE, + $color['red'], + $color['green'], + $color['blue'], + 127 - ($color['alpha'] * 127) + ); + + return $this; + } + + /** + * Applies the contrast filter. + * + * @param integer $percentage Percentage to adjust (-100 - 100). + * @return \claviska\SimpleImage + */ + public function contrast($percentage) { + imagefilter($this->image, IMG_FILTER_CONTRAST, self::keepWithin($percentage, -100, 100)); + + return $this; + } + + /** + * Applies the brightness filter to darken the image. + * + * @param integer $percentage Percentage to darken the image (0 - 100). + * @return \claviska\SimpleImage + */ + public function darken($percentage) { + $percentage = self::keepWithin(255 * $percentage / 100, 0, 255); + + imagefilter($this->image, IMG_FILTER_BRIGHTNESS, -$percentage); + + return $this; + } + + /** + * Applies the desaturate (grayscale) filter. + * + * @return \claviska\SimpleImage + */ + public function desaturate() { + imagefilter($this->image, IMG_FILTER_GRAYSCALE); + + return $this; + } + + /** + * Applies the edge detect filter. + * + * @return \claviska\SimpleImage + */ + public function edgeDetect() { + imagefilter($this->image, IMG_FILTER_EDGEDETECT); + + return $this; + } + + /** + * Applies the emboss filter. + * + * @return \claviska\SimpleImage + */ + public function emboss() { + imagefilter($this->image, IMG_FILTER_EMBOSS); + + return $this; + } + + /** + * Inverts the image's colors. + * + * @return \claviska\SimpleImage + */ + public function invert() { + imagefilter($this->image, IMG_FILTER_NEGATE); + + return $this; + } + + /** + * Changes the image's opacity level. + * + * @param float $opacity The desired opacity level (0 - 1). + * @return \claviska\SimpleImage + */ + public function opacity($opacity) { + // Create a transparent image + $newImage = new SimpleImage(); + $newImage->fromNew($this->getWidth(), $this->getHeight()); + + // Copy the current image (with opacity) onto the transparent image + self::imageCopyMergeAlpha( + $newImage->image, + $this->image, + 0, 0, + 0, 0, + $this->getWidth(), + $this->getHeight(), + self::keepWithin($opacity, 0, 1) * 100 + ); + + return $this; + } + + /** + * Applies the pixelate filter. + * + * @param integer $size The size of the blocks in pixels (default 10). + * @return \claviska\SimpleImage + */ + public function pixelate($size = 10) { + imagefilter($this->image, IMG_FILTER_PIXELATE, $size, true); + + return $this; + } + + /** + * Simulates a sepia effect by desaturating the image and applying a sepia tone. + * + * @return \claviska\SimpleImage + */ + public function sepia() { + imagefilter($this->image, IMG_FILTER_GRAYSCALE); + imagefilter($this->image, IMG_FILTER_COLORIZE, 70, 35, 0); + + return $this; + } + + /** + * Sharpens the image. + * + * @param integer $amount Sharpening amount (default 50). + * @return \claviska\SimpleImage + */ + public function sharpen($amount = 50) { + // Normalize amount + $amount = max(1, min(100, $amount)) / 100; + + $sharpen = [ + [-1, -1, -1], + [-1, 8 / $amount, -1], + [-1, -1, -1], + ]; + $divisor = array_sum(array_map('array_sum', $sharpen)); + + imageconvolution($this->image, $sharpen, $divisor, 0); + + return $this; + } + + /** + * Applies the mean remove filter to produce a sketch effect. + * + * @return \claviska\SimpleImage + */ + public function sketch() { + imagefilter($this->image, IMG_FILTER_MEAN_REMOVAL); + + return $this; + } + + ////////////////////////////////////////////////////////////////////////////////////////////////// + // Color utilities + ////////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Converts a "friendly color" into a color identifier for use with GD's image functions. + * + * @param string|array $color The color to allocate. + * @return integer + */ + protected function allocateColor($color) { + $color = self::normalizeColor($color); + + // Was this color already allocated? + $index = imagecolorexactalpha( + $this->image, + $color['red'], + $color['green'], + $color['blue'], + (int) (127 - ($color['alpha'] * 127)) + ); + if($index > -1) { + // Yes, return this color index + return $index; + } + + // Allocate a new color index + return imagecolorallocatealpha( + $this->image, + $color['red'], + $color['green'], + $color['blue'], + 127 - ($color['alpha'] * 127) + ); + } + + /** + * Adjusts a color by increasing/decreasing red/green/blue/alpha values independently. + * + * @param string|array $color The color to adjust. + * @param integer $red Red adjustment (-255 - 255). + * @param integer $green Green adjustment (-255 - 255). + * @param integer $blue Blue adjustment (-255 - 255). + * @param integer $alpha Alpha adjustment (-1 - 1). + * @return integer[] An RGBA color array. + */ + public static function adjustColor($color, $red, $green, $blue, $alpha) { + // Normalize to RGBA + $color = self::normalizeColor($color); + + // Adjust each channel + return self::normalizeColor([ + 'red' => $color['red'] + $red, + 'green' => $color['green'] + $green, + 'blue' => $color['blue'] + $blue, + 'alpha' => $color['alpha'] + $alpha + ]); + } + + /** + * Darkens a color. + * + * @param string|array $color The color to darken. + * @param integer $amount Amount to darken (0 - 255). + * @return integer[] An RGBA color array. + */ + public static function darkenColor($color, $amount) { + return self::adjustColor($color, -$amount, -$amount, -$amount, 0); + } + + /** + * Extracts colors from an image like a human would do.™ This method requires the third-party + * library \League\ColorExtractor. If you're using Composer, it will be installed for you + * automatically. + * + * @param integer $count The max number of colors to extract (default 5). + * @param string|array $backgroundColor + * By default any pixel with alpha value greater than zero will + * be discarded. This is because transparent colors are not perceived as is. For example, fully + * transparent black would be seen white on a white background. So if you want to take + * transparency into account, you have to specify a default background color. + * @throws \Exception Thrown if library \League\ColorExtractor is missing. + * @return integer[] An array of RGBA colors arrays. + */ + public function extractColors($count = 5, $backgroundColor = null) { + // Check for required library + if(!class_exists('\League\ColorExtractor\ColorExtractor')) { + throw new \Exception( + 'Required library \League\ColorExtractor is missing.', + self::ERR_LIB_NOT_LOADED + ); + } + + // Convert background color to an integer value + if($backgroundColor) { + $backgroundColor = self::normalizeColor($backgroundColor); + $backgroundColor = \League\ColorExtractor\Color::fromRgbToInt([ + 'r' => $backgroundColor['red'], + 'g' => $backgroundColor['green'], + 'b' => $backgroundColor['blue'] + ]); + } + + // Extract colors from the image + $palette = \League\ColorExtractor\Palette::fromGD($this->image, $backgroundColor); + $extractor = new \League\ColorExtractor\ColorExtractor($palette); + $colors = $extractor->extract($count); + + // Convert colors to an RGBA color array + foreach($colors as $key => $value) { + $colors[$key] = self::normalizeColor(\League\ColorExtractor\Color::fromIntToHex($value)); + } + + return $colors; + } + + /** + * Gets the RGBA value of a single pixel. + * + * @param integer $x The horizontal position of the pixel. + * @param integer $y The vertical position of the pixel. + * @return integer[] An RGBA color array or false if the x/y position is off the canvas. + */ + public function getColorAt($x, $y) { + // Coordinates must be on the canvas + if($x < 0 || $x > $this->getWidth() || $y < 0 || $y > $this->getHeight()) { + return false; + } + + // Get the color of this pixel and convert it to RGBA + $color = imagecolorat($this->image, $x, $y); + $rgba = imagecolorsforindex($this->image, $color); + $rgba['alpha'] = 127 - ($color >> 24) & 0xFF; + + return $rgba; + } + + /** + * Lightens a color. + * + * @param string|array $color The color to lighten. + * @param integer $amount Amount to lighten (0 - 255). + * @return integer[] An RGBA color array. + */ + public static function lightenColor($color, $amount) { + return self::adjustColor($color, $amount, $amount, $amount, 0); + } + + /** + * Normalizes a hex or array color value to a well-formatted RGBA array. + * + * @param string|array $color + * A CSS color name, hex string, or an array [red, green, blue, alpha]. + * You can pipe alpha transparency through hex strings and color names. For example: + * #fff|0.50 <-- 50% white + * red|0.25 <-- 25% red + * @throws \Exception Thrown if color value is invalid. + * @return array [red, green, blue, alpha]. + */ + public static function normalizeColor($color) { + // 140 CSS color names and hex values + $cssColors = [ + 'aliceblue' => '#f0f8ff', 'antiquewhite' => '#faebd7', 'aqua' => '#00ffff', + 'aquamarine' => '#7fffd4', 'azure' => '#f0ffff', 'beige' => '#f5f5dc', 'bisque' => '#ffe4c4', + 'black' => '#000000', 'blanchedalmond' => '#ffebcd', 'blue' => '#0000ff', + 'blueviolet' => '#8a2be2', 'brown' => '#a52a2a', 'burlywood' => '#deb887', + 'cadetblue' => '#5f9ea0', 'chartreuse' => '#7fff00', 'chocolate' => '#d2691e', + 'coral' => '#ff7f50', 'cornflowerblue' => '#6495ed', 'cornsilk' => '#fff8dc', + 'crimson' => '#dc143c', 'cyan' => '#00ffff', 'darkblue' => '#00008b', 'darkcyan' => '#008b8b', + 'darkgoldenrod' => '#b8860b', 'darkgray' => '#a9a9a9', 'darkgrey' => '#a9a9a9', + 'darkgreen' => '#006400', 'darkkhaki' => '#bdb76b', 'darkmagenta' => '#8b008b', + 'darkolivegreen' => '#556b2f', 'darkorange' => '#ff8c00', 'darkorchid' => '#9932cc', + 'darkred' => '#8b0000', 'darksalmon' => '#e9967a', 'darkseagreen' => '#8fbc8f', + 'darkslateblue' => '#483d8b', 'darkslategray' => '#2f4f4f', 'darkslategrey' => '#2f4f4f', + 'darkturquoise' => '#00ced1', 'darkviolet' => '#9400d3', 'deeppink' => '#ff1493', + 'deepskyblue' => '#00bfff', 'dimgray' => '#696969', 'dimgrey' => '#696969', + 'dodgerblue' => '#1e90ff', 'firebrick' => '#b22222', 'floralwhite' => '#fffaf0', + 'forestgreen' => '#228b22', 'fuchsia' => '#ff00ff', 'gainsboro' => '#dcdcdc', + 'ghostwhite' => '#f8f8ff', 'gold' => '#ffd700', 'goldenrod' => '#daa520', 'gray' => '#808080', + 'grey' => '#808080', 'green' => '#008000', 'greenyellow' => '#adff2f', + 'honeydew' => '#f0fff0', 'hotpink' => '#ff69b4', 'indianred ' => '#cd5c5c', + 'indigo ' => '#4b0082', 'ivory' => '#fffff0', 'khaki' => '#f0e68c', 'lavender' => '#e6e6fa', + 'lavenderblush' => '#fff0f5', 'lawngreen' => '#7cfc00', 'lemonchiffon' => '#fffacd', + 'lightblue' => '#add8e6', 'lightcoral' => '#f08080', 'lightcyan' => '#e0ffff', + 'lightgoldenrodyellow' => '#fafad2', 'lightgray' => '#d3d3d3', 'lightgrey' => '#d3d3d3', + 'lightgreen' => '#90ee90', 'lightpink' => '#ffb6c1', 'lightsalmon' => '#ffa07a', + 'lightseagreen' => '#20b2aa', 'lightskyblue' => '#87cefa', 'lightslategray' => '#778899', + 'lightslategrey' => '#778899', 'lightsteelblue' => '#b0c4de', 'lightyellow' => '#ffffe0', + 'lime' => '#00ff00', 'limegreen' => '#32cd32', 'linen' => '#faf0e6', 'magenta' => '#ff00ff', + 'maroon' => '#800000', 'mediumaquamarine' => '#66cdaa', 'mediumblue' => '#0000cd', + 'mediumorchid' => '#ba55d3', 'mediumpurple' => '#9370db', 'mediumseagreen' => '#3cb371', + 'mediumslateblue' => '#7b68ee', 'mediumspringgreen' => '#00fa9a', + 'mediumturquoise' => '#48d1cc', 'mediumvioletred' => '#c71585', 'midnightblue' => '#191970', + 'mintcream' => '#f5fffa', 'mistyrose' => '#ffe4e1', 'moccasin' => '#ffe4b5', + 'navajowhite' => '#ffdead', 'navy' => '#000080', 'oldlace' => '#fdf5e6', 'olive' => '#808000', + 'olivedrab' => '#6b8e23', 'orange' => '#ffa500', 'orangered' => '#ff4500', + 'orchid' => '#da70d6', 'palegoldenrod' => '#eee8aa', 'palegreen' => '#98fb98', + 'paleturquoise' => '#afeeee', 'palevioletred' => '#db7093', 'papayawhip' => '#ffefd5', + 'peachpuff' => '#ffdab9', 'peru' => '#cd853f', 'pink' => '#ffc0cb', 'plum' => '#dda0dd', + 'powderblue' => '#b0e0e6', 'purple' => '#800080', 'rebeccapurple' => '#663399', + 'red' => '#ff0000', 'rosybrown' => '#bc8f8f', 'royalblue' => '#4169e1', + 'saddlebrown' => '#8b4513', 'salmon' => '#fa8072', 'sandybrown' => '#f4a460', + 'seagreen' => '#2e8b57', 'seashell' => '#fff5ee', 'sienna' => '#a0522d', + 'silver' => '#c0c0c0', 'skyblue' => '#87ceeb', 'slateblue' => '#6a5acd', + 'slategray' => '#708090', 'slategrey' => '#708090', 'snow' => '#fffafa', + 'springgreen' => '#00ff7f', 'steelblue' => '#4682b4', 'tan' => '#d2b48c', 'teal' => '#008080', + 'thistle' => '#d8bfd8', 'tomato' => '#ff6347', 'turquoise' => '#40e0d0', + 'violet' => '#ee82ee', 'wheat' => '#f5deb3', 'white' => '#ffffff', 'whitesmoke' => '#f5f5f5', + 'yellow' => '#ffff00', 'yellowgreen' => '#9acd32' + ]; + + // Parse alpha from '#fff|.5' and 'white|.5' + if(is_string($color) && strstr($color, '|')) { + $color = explode('|', $color); + $alpha = (float) $color[1]; + $color = trim($color[0]); + } else { + $alpha = 1; + } + + // Translate CSS color names to hex values + if(is_string($color) && array_key_exists(strtolower($color), $cssColors)) { + $color = $cssColors[strtolower($color)]; + } + + // Translate transparent keyword to a transparent color + if($color === 'transparent') { + $color = ['red' => 0, 'green' => 0, 'blue' => 0, 'alpha' => 0]; + } + + // Convert hex values to RGBA + if(is_string($color)) { + // Remove # + $hex = preg_replace('/^#/', '', $color); + + // Support short and standard hex codes + if(strlen($hex) === 3) { + list($red, $green, $blue) = [ + $hex[0] . $hex[0], + $hex[1] . $hex[1], + $hex[2] . $hex[2] + ]; + } elseif(strlen($hex) === 6) { + list($red, $green, $blue) = [ + $hex[0] . $hex[1], + $hex[2] . $hex[3], + $hex[4] . $hex[5] + ]; + } else { + throw new \Exception("Invalid color value: $color", self::ERR_INVALID_COLOR); + } + + // Turn color into an array + $color = [ + 'red' => hexdec($red), + 'green' => hexdec($green), + 'blue' => hexdec($blue), + 'alpha' => $alpha + ]; + } + + // Enforce color value ranges + if(is_array($color)) { + // RGB default to 0 + $color['red'] = isset($color['red']) ? $color['red'] : 0; + $color['green'] = isset($color['green']) ? $color['green'] : 0; + $color['blue'] = isset($color['blue']) ? $color['blue'] : 0; + + // Alpha defaults to 1 + $color['alpha'] = isset($color['alpha']) ? $color['alpha'] : 1; + + return [ + 'red' => (int) self::keepWithin((int) $color['red'], 0, 255), + 'green' => (int) self::keepWithin((int) $color['green'], 0, 255), + 'blue' => (int) self::keepWithin((int) $color['blue'], 0, 255), + 'alpha' => self::keepWithin($color['alpha'], 0, 1) + ]; + } + + throw new \Exception("Invalid color value: $color", self::ERR_INVALID_COLOR); + } + +} diff --git a/kirby/vendor/composer/ClassLoader.php b/vendor/composer/ClassLoader.php similarity index 100% rename from kirby/vendor/composer/ClassLoader.php rename to vendor/composer/ClassLoader.php diff --git a/kirby/vendor/composer/InstalledVersions.php b/vendor/composer/InstalledVersions.php similarity index 100% rename from kirby/vendor/composer/InstalledVersions.php rename to vendor/composer/InstalledVersions.php diff --git a/kirby/vendor/composer/LICENSE b/vendor/composer/LICENSE similarity index 100% rename from kirby/vendor/composer/LICENSE rename to vendor/composer/LICENSE diff --git a/vendor/composer/autoload_classmap.php b/vendor/composer/autoload_classmap.php new file mode 100644 index 0000000..f74fb4b --- /dev/null +++ b/vendor/composer/autoload_classmap.php @@ -0,0 +1,507 @@ + $vendorDir . '/composer/ca-bundle/src/CaBundle.php', + 'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php', + 'Embed\\Adapters\\Archive\\Api' => $vendorDir . '/embed/embed/src/Adapters/Archive/Api.php', + 'Embed\\Adapters\\Archive\\Detectors\\AuthorName' => $vendorDir . '/embed/embed/src/Adapters/Archive/Detectors/AuthorName.php', + 'Embed\\Adapters\\Archive\\Detectors\\Code' => $vendorDir . '/embed/embed/src/Adapters/Archive/Detectors/Code.php', + 'Embed\\Adapters\\Archive\\Detectors\\Description' => $vendorDir . '/embed/embed/src/Adapters/Archive/Detectors/Description.php', + 'Embed\\Adapters\\Archive\\Detectors\\ProviderName' => $vendorDir . '/embed/embed/src/Adapters/Archive/Detectors/ProviderName.php', + 'Embed\\Adapters\\Archive\\Detectors\\PublishedTime' => $vendorDir . '/embed/embed/src/Adapters/Archive/Detectors/PublishedTime.php', + 'Embed\\Adapters\\Archive\\Detectors\\Title' => $vendorDir . '/embed/embed/src/Adapters/Archive/Detectors/Title.php', + 'Embed\\Adapters\\Archive\\Extractor' => $vendorDir . '/embed/embed/src/Adapters/Archive/Extractor.php', + 'Embed\\Adapters\\Bandcamp\\Detectors\\ProviderName' => $vendorDir . '/embed/embed/src/Adapters/Bandcamp/Detectors/ProviderName.php', + 'Embed\\Adapters\\Bandcamp\\Extractor' => $vendorDir . '/embed/embed/src/Adapters/Bandcamp/Extractor.php', + 'Embed\\Adapters\\CadenaSer\\Detectors\\Code' => $vendorDir . '/embed/embed/src/Adapters/CadenaSer/Detectors/Code.php', + 'Embed\\Adapters\\CadenaSer\\Extractor' => $vendorDir . '/embed/embed/src/Adapters/CadenaSer/Extractor.php', + 'Embed\\Adapters\\Facebook\\Detectors\\Title' => $vendorDir . '/embed/embed/src/Adapters/Facebook/Detectors/Title.php', + 'Embed\\Adapters\\Facebook\\Extractor' => $vendorDir . '/embed/embed/src/Adapters/Facebook/Extractor.php', + 'Embed\\Adapters\\Facebook\\OEmbed' => $vendorDir . '/embed/embed/src/Adapters/Facebook/OEmbed.php', + 'Embed\\Adapters\\Flickr\\Detectors\\Code' => $vendorDir . '/embed/embed/src/Adapters/Flickr/Detectors/Code.php', + 'Embed\\Adapters\\Flickr\\Extractor' => $vendorDir . '/embed/embed/src/Adapters/Flickr/Extractor.php', + 'Embed\\Adapters\\Gist\\Api' => $vendorDir . '/embed/embed/src/Adapters/Gist/Api.php', + 'Embed\\Adapters\\Gist\\Detectors\\AuthorName' => $vendorDir . '/embed/embed/src/Adapters/Gist/Detectors/AuthorName.php', + 'Embed\\Adapters\\Gist\\Detectors\\AuthorUrl' => $vendorDir . '/embed/embed/src/Adapters/Gist/Detectors/AuthorUrl.php', + 'Embed\\Adapters\\Gist\\Detectors\\Code' => $vendorDir . '/embed/embed/src/Adapters/Gist/Detectors/Code.php', + 'Embed\\Adapters\\Gist\\Detectors\\PublishedTime' => $vendorDir . '/embed/embed/src/Adapters/Gist/Detectors/PublishedTime.php', + 'Embed\\Adapters\\Gist\\Extractor' => $vendorDir . '/embed/embed/src/Adapters/Gist/Extractor.php', + 'Embed\\Adapters\\Github\\Detectors\\Code' => $vendorDir . '/embed/embed/src/Adapters/Github/Detectors/Code.php', + 'Embed\\Adapters\\Github\\Extractor' => $vendorDir . '/embed/embed/src/Adapters/Github/Extractor.php', + 'Embed\\Adapters\\Ideone\\Detectors\\Code' => $vendorDir . '/embed/embed/src/Adapters/Ideone/Detectors/Code.php', + 'Embed\\Adapters\\Ideone\\Extractor' => $vendorDir . '/embed/embed/src/Adapters/Ideone/Extractor.php', + 'Embed\\Adapters\\ImageShack\\Api' => $vendorDir . '/embed/embed/src/Adapters/ImageShack/Api.php', + 'Embed\\Adapters\\ImageShack\\Detectors\\AuthorName' => $vendorDir . '/embed/embed/src/Adapters/ImageShack/Detectors/AuthorName.php', + 'Embed\\Adapters\\ImageShack\\Detectors\\AuthorUrl' => $vendorDir . '/embed/embed/src/Adapters/ImageShack/Detectors/AuthorUrl.php', + 'Embed\\Adapters\\ImageShack\\Detectors\\Description' => $vendorDir . '/embed/embed/src/Adapters/ImageShack/Detectors/Description.php', + 'Embed\\Adapters\\ImageShack\\Detectors\\Image' => $vendorDir . '/embed/embed/src/Adapters/ImageShack/Detectors/Image.php', + 'Embed\\Adapters\\ImageShack\\Detectors\\ProviderName' => $vendorDir . '/embed/embed/src/Adapters/ImageShack/Detectors/ProviderName.php', + 'Embed\\Adapters\\ImageShack\\Detectors\\PublishedTime' => $vendorDir . '/embed/embed/src/Adapters/ImageShack/Detectors/PublishedTime.php', + 'Embed\\Adapters\\ImageShack\\Detectors\\Title' => $vendorDir . '/embed/embed/src/Adapters/ImageShack/Detectors/Title.php', + 'Embed\\Adapters\\ImageShack\\Extractor' => $vendorDir . '/embed/embed/src/Adapters/ImageShack/Extractor.php', + 'Embed\\Adapters\\Instagram\\Extractor' => $vendorDir . '/embed/embed/src/Adapters/Instagram/Extractor.php', + 'Embed\\Adapters\\Instagram\\OEmbed' => $vendorDir . '/embed/embed/src/Adapters/Instagram/OEmbed.php', + 'Embed\\Adapters\\Pinterest\\Detectors\\Code' => $vendorDir . '/embed/embed/src/Adapters/Pinterest/Detectors/Code.php', + 'Embed\\Adapters\\Pinterest\\Extractor' => $vendorDir . '/embed/embed/src/Adapters/Pinterest/Extractor.php', + 'Embed\\Adapters\\Sassmeister\\Detectors\\Code' => $vendorDir . '/embed/embed/src/Adapters/Sassmeister/Detectors/Code.php', + 'Embed\\Adapters\\Sassmeister\\Extractor' => $vendorDir . '/embed/embed/src/Adapters/Sassmeister/Extractor.php', + 'Embed\\Adapters\\Slides\\Detectors\\Code' => $vendorDir . '/embed/embed/src/Adapters/Slides/Detectors/Code.php', + 'Embed\\Adapters\\Slides\\Extractor' => $vendorDir . '/embed/embed/src/Adapters/Slides/Extractor.php', + 'Embed\\Adapters\\Snipplr\\Detectors\\Code' => $vendorDir . '/embed/embed/src/Adapters/Snipplr/Detectors/Code.php', + 'Embed\\Adapters\\Snipplr\\Extractor' => $vendorDir . '/embed/embed/src/Adapters/Snipplr/Extractor.php', + 'Embed\\Adapters\\Twitch\\Detectors\\Code' => $vendorDir . '/embed/embed/src/Adapters/Twitch/Detectors/Code.php', + 'Embed\\Adapters\\Twitch\\Extractor' => $vendorDir . '/embed/embed/src/Adapters/Twitch/Extractor.php', + 'Embed\\Adapters\\Twitter\\Api' => $vendorDir . '/embed/embed/src/Adapters/Twitter/Api.php', + 'Embed\\Adapters\\Twitter\\Detectors\\AuthorName' => $vendorDir . '/embed/embed/src/Adapters/Twitter/Detectors/AuthorName.php', + 'Embed\\Adapters\\Twitter\\Detectors\\AuthorUrl' => $vendorDir . '/embed/embed/src/Adapters/Twitter/Detectors/AuthorUrl.php', + 'Embed\\Adapters\\Twitter\\Detectors\\Description' => $vendorDir . '/embed/embed/src/Adapters/Twitter/Detectors/Description.php', + 'Embed\\Adapters\\Twitter\\Detectors\\Image' => $vendorDir . '/embed/embed/src/Adapters/Twitter/Detectors/Image.php', + 'Embed\\Adapters\\Twitter\\Detectors\\ProviderName' => $vendorDir . '/embed/embed/src/Adapters/Twitter/Detectors/ProviderName.php', + 'Embed\\Adapters\\Twitter\\Detectors\\PublishedTime' => $vendorDir . '/embed/embed/src/Adapters/Twitter/Detectors/PublishedTime.php', + 'Embed\\Adapters\\Twitter\\Detectors\\Title' => $vendorDir . '/embed/embed/src/Adapters/Twitter/Detectors/Title.php', + 'Embed\\Adapters\\Twitter\\Extractor' => $vendorDir . '/embed/embed/src/Adapters/Twitter/Extractor.php', + 'Embed\\Adapters\\Wikipedia\\Api' => $vendorDir . '/embed/embed/src/Adapters/Wikipedia/Api.php', + 'Embed\\Adapters\\Wikipedia\\Detectors\\Description' => $vendorDir . '/embed/embed/src/Adapters/Wikipedia/Detectors/Description.php', + 'Embed\\Adapters\\Wikipedia\\Detectors\\Title' => $vendorDir . '/embed/embed/src/Adapters/Wikipedia/Detectors/Title.php', + 'Embed\\Adapters\\Wikipedia\\Extractor' => $vendorDir . '/embed/embed/src/Adapters/Wikipedia/Extractor.php', + 'Embed\\Adapters\\Youtube\\Detectors\\Feeds' => $vendorDir . '/embed/embed/src/Adapters/Youtube/Detectors/Feeds.php', + 'Embed\\Adapters\\Youtube\\Extractor' => $vendorDir . '/embed/embed/src/Adapters/Youtube/Extractor.php', + 'Embed\\ApiTrait' => $vendorDir . '/embed/embed/src/ApiTrait.php', + 'Embed\\Detectors\\AuthorName' => $vendorDir . '/embed/embed/src/Detectors/AuthorName.php', + 'Embed\\Detectors\\AuthorUrl' => $vendorDir . '/embed/embed/src/Detectors/AuthorUrl.php', + 'Embed\\Detectors\\Cms' => $vendorDir . '/embed/embed/src/Detectors/Cms.php', + 'Embed\\Detectors\\Code' => $vendorDir . '/embed/embed/src/Detectors/Code.php', + 'Embed\\Detectors\\Description' => $vendorDir . '/embed/embed/src/Detectors/Description.php', + 'Embed\\Detectors\\Detector' => $vendorDir . '/embed/embed/src/Detectors/Detector.php', + 'Embed\\Detectors\\Favicon' => $vendorDir . '/embed/embed/src/Detectors/Favicon.php', + 'Embed\\Detectors\\Feeds' => $vendorDir . '/embed/embed/src/Detectors/Feeds.php', + 'Embed\\Detectors\\Icon' => $vendorDir . '/embed/embed/src/Detectors/Icon.php', + 'Embed\\Detectors\\Image' => $vendorDir . '/embed/embed/src/Detectors/Image.php', + 'Embed\\Detectors\\Keywords' => $vendorDir . '/embed/embed/src/Detectors/Keywords.php', + 'Embed\\Detectors\\Language' => $vendorDir . '/embed/embed/src/Detectors/Language.php', + 'Embed\\Detectors\\Languages' => $vendorDir . '/embed/embed/src/Detectors/Languages.php', + 'Embed\\Detectors\\License' => $vendorDir . '/embed/embed/src/Detectors/License.php', + 'Embed\\Detectors\\ProviderName' => $vendorDir . '/embed/embed/src/Detectors/ProviderName.php', + 'Embed\\Detectors\\ProviderUrl' => $vendorDir . '/embed/embed/src/Detectors/ProviderUrl.php', + 'Embed\\Detectors\\PublishedTime' => $vendorDir . '/embed/embed/src/Detectors/PublishedTime.php', + 'Embed\\Detectors\\Redirect' => $vendorDir . '/embed/embed/src/Detectors/Redirect.php', + 'Embed\\Detectors\\Title' => $vendorDir . '/embed/embed/src/Detectors/Title.php', + 'Embed\\Detectors\\Url' => $vendorDir . '/embed/embed/src/Detectors/Url.php', + 'Embed\\Document' => $vendorDir . '/embed/embed/src/Document.php', + 'Embed\\Embed' => $vendorDir . '/embed/embed/src/Embed.php', + 'Embed\\EmbedCode' => $vendorDir . '/embed/embed/src/EmbedCode.php', + 'Embed\\Extractor' => $vendorDir . '/embed/embed/src/Extractor.php', + 'Embed\\ExtractorFactory' => $vendorDir . '/embed/embed/src/ExtractorFactory.php', + 'Embed\\HttpApiTrait' => $vendorDir . '/embed/embed/src/HttpApiTrait.php', + 'Embed\\Http\\Crawler' => $vendorDir . '/embed/embed/src/Http/Crawler.php', + 'Embed\\Http\\CurlClient' => $vendorDir . '/embed/embed/src/Http/CurlClient.php', + 'Embed\\Http\\CurlDispatcher' => $vendorDir . '/embed/embed/src/Http/CurlDispatcher.php', + 'Embed\\Http\\FactoryDiscovery' => $vendorDir . '/embed/embed/src/Http/FactoryDiscovery.php', + 'Embed\\Http\\NetworkException' => $vendorDir . '/embed/embed/src/Http/NetworkException.php', + 'Embed\\Http\\RequestException' => $vendorDir . '/embed/embed/src/Http/RequestException.php', + 'Embed\\LinkedData' => $vendorDir . '/embed/embed/src/LinkedData.php', + 'Embed\\Metas' => $vendorDir . '/embed/embed/src/Metas.php', + 'Embed\\OEmbed' => $vendorDir . '/embed/embed/src/OEmbed.php', + 'Embed\\QueryResult' => $vendorDir . '/embed/embed/src/QueryResult.php', + 'GuzzleHttp\\Psr7\\AppendStream' => $vendorDir . '/guzzlehttp/psr7/src/AppendStream.php', + 'GuzzleHttp\\Psr7\\BufferStream' => $vendorDir . '/guzzlehttp/psr7/src/BufferStream.php', + 'GuzzleHttp\\Psr7\\CachingStream' => $vendorDir . '/guzzlehttp/psr7/src/CachingStream.php', + 'GuzzleHttp\\Psr7\\DroppingStream' => $vendorDir . '/guzzlehttp/psr7/src/DroppingStream.php', + 'GuzzleHttp\\Psr7\\Exception\\MalformedUriException' => $vendorDir . '/guzzlehttp/psr7/src/Exception/MalformedUriException.php', + 'GuzzleHttp\\Psr7\\FnStream' => $vendorDir . '/guzzlehttp/psr7/src/FnStream.php', + 'GuzzleHttp\\Psr7\\Header' => $vendorDir . '/guzzlehttp/psr7/src/Header.php', + 'GuzzleHttp\\Psr7\\HttpFactory' => $vendorDir . '/guzzlehttp/psr7/src/HttpFactory.php', + 'GuzzleHttp\\Psr7\\InflateStream' => $vendorDir . '/guzzlehttp/psr7/src/InflateStream.php', + 'GuzzleHttp\\Psr7\\LazyOpenStream' => $vendorDir . '/guzzlehttp/psr7/src/LazyOpenStream.php', + 'GuzzleHttp\\Psr7\\LimitStream' => $vendorDir . '/guzzlehttp/psr7/src/LimitStream.php', + 'GuzzleHttp\\Psr7\\Message' => $vendorDir . '/guzzlehttp/psr7/src/Message.php', + 'GuzzleHttp\\Psr7\\MessageTrait' => $vendorDir . '/guzzlehttp/psr7/src/MessageTrait.php', + 'GuzzleHttp\\Psr7\\MimeType' => $vendorDir . '/guzzlehttp/psr7/src/MimeType.php', + 'GuzzleHttp\\Psr7\\MultipartStream' => $vendorDir . '/guzzlehttp/psr7/src/MultipartStream.php', + 'GuzzleHttp\\Psr7\\NoSeekStream' => $vendorDir . '/guzzlehttp/psr7/src/NoSeekStream.php', + 'GuzzleHttp\\Psr7\\PumpStream' => $vendorDir . '/guzzlehttp/psr7/src/PumpStream.php', + 'GuzzleHttp\\Psr7\\Query' => $vendorDir . '/guzzlehttp/psr7/src/Query.php', + 'GuzzleHttp\\Psr7\\Request' => $vendorDir . '/guzzlehttp/psr7/src/Request.php', + 'GuzzleHttp\\Psr7\\Response' => $vendorDir . '/guzzlehttp/psr7/src/Response.php', + 'GuzzleHttp\\Psr7\\Rfc7230' => $vendorDir . '/guzzlehttp/psr7/src/Rfc7230.php', + 'GuzzleHttp\\Psr7\\ServerRequest' => $vendorDir . '/guzzlehttp/psr7/src/ServerRequest.php', + 'GuzzleHttp\\Psr7\\Stream' => $vendorDir . '/guzzlehttp/psr7/src/Stream.php', + 'GuzzleHttp\\Psr7\\StreamDecoratorTrait' => $vendorDir . '/guzzlehttp/psr7/src/StreamDecoratorTrait.php', + 'GuzzleHttp\\Psr7\\StreamWrapper' => $vendorDir . '/guzzlehttp/psr7/src/StreamWrapper.php', + 'GuzzleHttp\\Psr7\\UploadedFile' => $vendorDir . '/guzzlehttp/psr7/src/UploadedFile.php', + 'GuzzleHttp\\Psr7\\Uri' => $vendorDir . '/guzzlehttp/psr7/src/Uri.php', + 'GuzzleHttp\\Psr7\\UriComparator' => $vendorDir . '/guzzlehttp/psr7/src/UriComparator.php', + 'GuzzleHttp\\Psr7\\UriNormalizer' => $vendorDir . '/guzzlehttp/psr7/src/UriNormalizer.php', + 'GuzzleHttp\\Psr7\\UriResolver' => $vendorDir . '/guzzlehttp/psr7/src/UriResolver.php', + 'GuzzleHttp\\Psr7\\Utils' => $vendorDir . '/guzzlehttp/psr7/src/Utils.php', + 'HtmlParser\\Parser' => $vendorDir . '/oscarotero/html-parser/src/Parser.php', + 'Kirby\\Api\\Api' => $baseDir . '/kirby/src/Api/Api.php', + 'Kirby\\Api\\Collection' => $baseDir . '/kirby/src/Api/Collection.php', + 'Kirby\\Api\\Model' => $baseDir . '/kirby/src/Api/Model.php', + 'Kirby\\Cache\\ApcuCache' => $baseDir . '/kirby/src/Cache/ApcuCache.php', + 'Kirby\\Cache\\Cache' => $baseDir . '/kirby/src/Cache/Cache.php', + 'Kirby\\Cache\\FileCache' => $baseDir . '/kirby/src/Cache/FileCache.php', + 'Kirby\\Cache\\MemCached' => $baseDir . '/kirby/src/Cache/MemCached.php', + 'Kirby\\Cache\\MemoryCache' => $baseDir . '/kirby/src/Cache/MemoryCache.php', + 'Kirby\\Cache\\NullCache' => $baseDir . '/kirby/src/Cache/NullCache.php', + 'Kirby\\Cache\\Value' => $baseDir . '/kirby/src/Cache/Value.php', + 'Kirby\\Cms\\Api' => $baseDir . '/kirby/src/Cms/Api.php', + 'Kirby\\Cms\\App' => $baseDir . '/kirby/src/Cms/App.php', + 'Kirby\\Cms\\AppCaches' => $baseDir . '/kirby/src/Cms/AppCaches.php', + 'Kirby\\Cms\\AppErrors' => $baseDir . '/kirby/src/Cms/AppErrors.php', + 'Kirby\\Cms\\AppPlugins' => $baseDir . '/kirby/src/Cms/AppPlugins.php', + 'Kirby\\Cms\\AppTranslations' => $baseDir . '/kirby/src/Cms/AppTranslations.php', + 'Kirby\\Cms\\AppUsers' => $baseDir . '/kirby/src/Cms/AppUsers.php', + 'Kirby\\Cms\\Auth' => $baseDir . '/kirby/src/Cms/Auth.php', + 'Kirby\\Cms\\Auth\\Challenge' => $baseDir . '/kirby/src/Cms/Auth/Challenge.php', + 'Kirby\\Cms\\Auth\\EmailChallenge' => $baseDir . '/kirby/src/Cms/Auth/EmailChallenge.php', + 'Kirby\\Cms\\Auth\\Status' => $baseDir . '/kirby/src/Cms/Auth/Status.php', + 'Kirby\\Cms\\Block' => $baseDir . '/kirby/src/Cms/Block.php', + 'Kirby\\Cms\\Blocks' => $baseDir . '/kirby/src/Cms/Blocks.php', + 'Kirby\\Cms\\Blueprint' => $baseDir . '/kirby/src/Cms/Blueprint.php', + 'Kirby\\Cms\\Collection' => $baseDir . '/kirby/src/Cms/Collection.php', + 'Kirby\\Cms\\Collections' => $baseDir . '/kirby/src/Cms/Collections.php', + 'Kirby\\Cms\\Content' => $baseDir . '/kirby/src/Cms/Content.php', + 'Kirby\\Cms\\ContentLock' => $baseDir . '/kirby/src/Cms/ContentLock.php', + 'Kirby\\Cms\\ContentLocks' => $baseDir . '/kirby/src/Cms/ContentLocks.php', + 'Kirby\\Cms\\ContentTranslation' => $baseDir . '/kirby/src/Cms/ContentTranslation.php', + 'Kirby\\Cms\\Core' => $baseDir . '/kirby/src/Cms/Core.php', + 'Kirby\\Cms\\Email' => $baseDir . '/kirby/src/Cms/Email.php', + 'Kirby\\Cms\\Event' => $baseDir . '/kirby/src/Cms/Event.php', + 'Kirby\\Cms\\Field' => $baseDir . '/kirby/src/Cms/Field.php', + 'Kirby\\Cms\\Fieldset' => $baseDir . '/kirby/src/Cms/Fieldset.php', + 'Kirby\\Cms\\Fieldsets' => $baseDir . '/kirby/src/Cms/Fieldsets.php', + 'Kirby\\Cms\\File' => $baseDir . '/kirby/src/Cms/File.php', + 'Kirby\\Cms\\FileActions' => $baseDir . '/kirby/src/Cms/FileActions.php', + 'Kirby\\Cms\\FileBlueprint' => $baseDir . '/kirby/src/Cms/FileBlueprint.php', + 'Kirby\\Cms\\FileModifications' => $baseDir . '/kirby/src/Cms/FileModifications.php', + 'Kirby\\Cms\\FilePermissions' => $baseDir . '/kirby/src/Cms/FilePermissions.php', + 'Kirby\\Cms\\FilePicker' => $baseDir . '/kirby/src/Cms/FilePicker.php', + 'Kirby\\Cms\\FileRules' => $baseDir . '/kirby/src/Cms/FileRules.php', + 'Kirby\\Cms\\FileVersion' => $baseDir . '/kirby/src/Cms/FileVersion.php', + 'Kirby\\Cms\\Files' => $baseDir . '/kirby/src/Cms/Files.php', + 'Kirby\\Cms\\Find' => $baseDir . '/kirby/src/Cms/Find.php', + 'Kirby\\Cms\\HasChildren' => $baseDir . '/kirby/src/Cms/HasChildren.php', + 'Kirby\\Cms\\HasFiles' => $baseDir . '/kirby/src/Cms/HasFiles.php', + 'Kirby\\Cms\\HasMethods' => $baseDir . '/kirby/src/Cms/HasMethods.php', + 'Kirby\\Cms\\HasSiblings' => $baseDir . '/kirby/src/Cms/HasSiblings.php', + 'Kirby\\Cms\\Helpers' => $baseDir . '/kirby/src/Cms/Helpers.php', + 'Kirby\\Cms\\Html' => $baseDir . '/kirby/src/Cms/Html.php', + 'Kirby\\Cms\\Ingredients' => $baseDir . '/kirby/src/Cms/Ingredients.php', + 'Kirby\\Cms\\Item' => $baseDir . '/kirby/src/Cms/Item.php', + 'Kirby\\Cms\\Items' => $baseDir . '/kirby/src/Cms/Items.php', + 'Kirby\\Cms\\Language' => $baseDir . '/kirby/src/Cms/Language.php', + 'Kirby\\Cms\\LanguageRouter' => $baseDir . '/kirby/src/Cms/LanguageRouter.php', + 'Kirby\\Cms\\LanguageRoutes' => $baseDir . '/kirby/src/Cms/LanguageRoutes.php', + 'Kirby\\Cms\\LanguageRules' => $baseDir . '/kirby/src/Cms/LanguageRules.php', + 'Kirby\\Cms\\Languages' => $baseDir . '/kirby/src/Cms/Languages.php', + 'Kirby\\Cms\\Layout' => $baseDir . '/kirby/src/Cms/Layout.php', + 'Kirby\\Cms\\LayoutColumn' => $baseDir . '/kirby/src/Cms/LayoutColumn.php', + 'Kirby\\Cms\\LayoutColumns' => $baseDir . '/kirby/src/Cms/LayoutColumns.php', + 'Kirby\\Cms\\Layouts' => $baseDir . '/kirby/src/Cms/Layouts.php', + 'Kirby\\Cms\\Loader' => $baseDir . '/kirby/src/Cms/Loader.php', + 'Kirby\\Cms\\Media' => $baseDir . '/kirby/src/Cms/Media.php', + 'Kirby\\Cms\\Model' => $baseDir . '/kirby/src/Cms/Model.php', + 'Kirby\\Cms\\ModelPermissions' => $baseDir . '/kirby/src/Cms/ModelPermissions.php', + 'Kirby\\Cms\\ModelWithContent' => $baseDir . '/kirby/src/Cms/ModelWithContent.php', + 'Kirby\\Cms\\Nest' => $baseDir . '/kirby/src/Cms/Nest.php', + 'Kirby\\Cms\\NestCollection' => $baseDir . '/kirby/src/Cms/NestCollection.php', + 'Kirby\\Cms\\NestObject' => $baseDir . '/kirby/src/Cms/NestObject.php', + 'Kirby\\Cms\\Page' => $baseDir . '/kirby/src/Cms/Page.php', + 'Kirby\\Cms\\PageActions' => $baseDir . '/kirby/src/Cms/PageActions.php', + 'Kirby\\Cms\\PageBlueprint' => $baseDir . '/kirby/src/Cms/PageBlueprint.php', + 'Kirby\\Cms\\PagePermissions' => $baseDir . '/kirby/src/Cms/PagePermissions.php', + 'Kirby\\Cms\\PagePicker' => $baseDir . '/kirby/src/Cms/PagePicker.php', + 'Kirby\\Cms\\PageRules' => $baseDir . '/kirby/src/Cms/PageRules.php', + 'Kirby\\Cms\\PageSiblings' => $baseDir . '/kirby/src/Cms/PageSiblings.php', + 'Kirby\\Cms\\Pages' => $baseDir . '/kirby/src/Cms/Pages.php', + 'Kirby\\Cms\\Pagination' => $baseDir . '/kirby/src/Cms/Pagination.php', + 'Kirby\\Cms\\Permissions' => $baseDir . '/kirby/src/Cms/Permissions.php', + 'Kirby\\Cms\\Picker' => $baseDir . '/kirby/src/Cms/Picker.php', + 'Kirby\\Cms\\Plugin' => $baseDir . '/kirby/src/Cms/Plugin.php', + 'Kirby\\Cms\\PluginAssets' => $baseDir . '/kirby/src/Cms/PluginAssets.php', + 'Kirby\\Cms\\R' => $baseDir . '/kirby/src/Cms/R.php', + 'Kirby\\Cms\\Responder' => $baseDir . '/kirby/src/Cms/Responder.php', + 'Kirby\\Cms\\Response' => $baseDir . '/kirby/src/Cms/Response.php', + 'Kirby\\Cms\\Role' => $baseDir . '/kirby/src/Cms/Role.php', + 'Kirby\\Cms\\Roles' => $baseDir . '/kirby/src/Cms/Roles.php', + 'Kirby\\Cms\\S' => $baseDir . '/kirby/src/Cms/S.php', + 'Kirby\\Cms\\Search' => $baseDir . '/kirby/src/Cms/Search.php', + 'Kirby\\Cms\\Section' => $baseDir . '/kirby/src/Cms/Section.php', + 'Kirby\\Cms\\Site' => $baseDir . '/kirby/src/Cms/Site.php', + 'Kirby\\Cms\\SiteActions' => $baseDir . '/kirby/src/Cms/SiteActions.php', + 'Kirby\\Cms\\SiteBlueprint' => $baseDir . '/kirby/src/Cms/SiteBlueprint.php', + 'Kirby\\Cms\\SitePermissions' => $baseDir . '/kirby/src/Cms/SitePermissions.php', + 'Kirby\\Cms\\SiteRules' => $baseDir . '/kirby/src/Cms/SiteRules.php', + 'Kirby\\Cms\\Structure' => $baseDir . '/kirby/src/Cms/Structure.php', + 'Kirby\\Cms\\StructureObject' => $baseDir . '/kirby/src/Cms/StructureObject.php', + 'Kirby\\Cms\\System' => $baseDir . '/kirby/src/Cms/System.php', + 'Kirby\\Cms\\Template' => $baseDir . '/kirby/src/Cms/Template.php', + 'Kirby\\Cms\\Translation' => $baseDir . '/kirby/src/Cms/Translation.php', + 'Kirby\\Cms\\Translations' => $baseDir . '/kirby/src/Cms/Translations.php', + 'Kirby\\Cms\\Url' => $baseDir . '/kirby/src/Cms/Url.php', + 'Kirby\\Cms\\User' => $baseDir . '/kirby/src/Cms/User.php', + 'Kirby\\Cms\\UserActions' => $baseDir . '/kirby/src/Cms/UserActions.php', + 'Kirby\\Cms\\UserBlueprint' => $baseDir . '/kirby/src/Cms/UserBlueprint.php', + 'Kirby\\Cms\\UserPermissions' => $baseDir . '/kirby/src/Cms/UserPermissions.php', + 'Kirby\\Cms\\UserPicker' => $baseDir . '/kirby/src/Cms/UserPicker.php', + 'Kirby\\Cms\\UserRules' => $baseDir . '/kirby/src/Cms/UserRules.php', + 'Kirby\\Cms\\Users' => $baseDir . '/kirby/src/Cms/Users.php', + 'Kirby\\Cms\\Visitor' => $baseDir . '/kirby/src/Cms/Visitor.php', + 'Kirby\\ComposerInstaller\\CmsInstaller' => $vendorDir . '/getkirby/composer-installer/src/ComposerInstaller/CmsInstaller.php', + 'Kirby\\ComposerInstaller\\Installer' => $vendorDir . '/getkirby/composer-installer/src/ComposerInstaller/Installer.php', + 'Kirby\\ComposerInstaller\\Plugin' => $vendorDir . '/getkirby/composer-installer/src/ComposerInstaller/Plugin.php', + 'Kirby\\ComposerInstaller\\PluginInstaller' => $vendorDir . '/getkirby/composer-installer/src/ComposerInstaller/PluginInstaller.php', + 'Kirby\\Data\\Data' => $baseDir . '/kirby/src/Data/Data.php', + 'Kirby\\Data\\Handler' => $baseDir . '/kirby/src/Data/Handler.php', + 'Kirby\\Data\\Json' => $baseDir . '/kirby/src/Data/Json.php', + 'Kirby\\Data\\PHP' => $baseDir . '/kirby/src/Data/PHP.php', + 'Kirby\\Data\\Txt' => $baseDir . '/kirby/src/Data/Txt.php', + 'Kirby\\Data\\Xml' => $baseDir . '/kirby/src/Data/Xml.php', + 'Kirby\\Data\\Yaml' => $baseDir . '/kirby/src/Data/Yaml.php', + 'Kirby\\Database\\Database' => $baseDir . '/kirby/src/Database/Database.php', + 'Kirby\\Database\\Db' => $baseDir . '/kirby/src/Database/Db.php', + 'Kirby\\Database\\Query' => $baseDir . '/kirby/src/Database/Query.php', + 'Kirby\\Database\\Sql' => $baseDir . '/kirby/src/Database/Sql.php', + 'Kirby\\Database\\Sql\\Mysql' => $baseDir . '/kirby/src/Database/Sql/Mysql.php', + 'Kirby\\Database\\Sql\\Sqlite' => $baseDir . '/kirby/src/Database/Sql/Sqlite.php', + 'Kirby\\Email\\Body' => $baseDir . '/kirby/src/Email/Body.php', + 'Kirby\\Email\\Email' => $baseDir . '/kirby/src/Email/Email.php', + 'Kirby\\Email\\PHPMailer' => $baseDir . '/kirby/src/Email/PHPMailer.php', + 'Kirby\\Exception\\BadMethodCallException' => $baseDir . '/kirby/src/Exception/BadMethodCallException.php', + 'Kirby\\Exception\\DuplicateException' => $baseDir . '/kirby/src/Exception/DuplicateException.php', + 'Kirby\\Exception\\ErrorPageException' => $baseDir . '/kirby/src/Exception/ErrorPageException.php', + 'Kirby\\Exception\\Exception' => $baseDir . '/kirby/src/Exception/Exception.php', + 'Kirby\\Exception\\InvalidArgumentException' => $baseDir . '/kirby/src/Exception/InvalidArgumentException.php', + 'Kirby\\Exception\\LogicException' => $baseDir . '/kirby/src/Exception/LogicException.php', + 'Kirby\\Exception\\NotFoundException' => $baseDir . '/kirby/src/Exception/NotFoundException.php', + 'Kirby\\Exception\\PermissionException' => $baseDir . '/kirby/src/Exception/PermissionException.php', + 'Kirby\\Filesystem\\Asset' => $baseDir . '/kirby/src/Filesystem/Asset.php', + 'Kirby\\Filesystem\\Dir' => $baseDir . '/kirby/src/Filesystem/Dir.php', + 'Kirby\\Filesystem\\F' => $baseDir . '/kirby/src/Filesystem/F.php', + 'Kirby\\Filesystem\\File' => $baseDir . '/kirby/src/Filesystem/File.php', + 'Kirby\\Filesystem\\Filename' => $baseDir . '/kirby/src/Filesystem/Filename.php', + 'Kirby\\Filesystem\\IsFile' => $baseDir . '/kirby/src/Filesystem/IsFile.php', + 'Kirby\\Filesystem\\Mime' => $baseDir . '/kirby/src/Filesystem/Mime.php', + 'Kirby\\Form\\Field' => $baseDir . '/kirby/src/Form/Field.php', + 'Kirby\\Form\\FieldClass' => $baseDir . '/kirby/src/Form/FieldClass.php', + 'Kirby\\Form\\Field\\BlocksField' => $baseDir . '/kirby/src/Form/Field/BlocksField.php', + 'Kirby\\Form\\Field\\LayoutField' => $baseDir . '/kirby/src/Form/Field/LayoutField.php', + 'Kirby\\Form\\Fields' => $baseDir . '/kirby/src/Form/Fields.php', + 'Kirby\\Form\\Form' => $baseDir . '/kirby/src/Form/Form.php', + 'Kirby\\Form\\Mixin\\EmptyState' => $baseDir . '/kirby/src/Form/Mixin/EmptyState.php', + 'Kirby\\Form\\Mixin\\Max' => $baseDir . '/kirby/src/Form/Mixin/Max.php', + 'Kirby\\Form\\Mixin\\Min' => $baseDir . '/kirby/src/Form/Mixin/Min.php', + 'Kirby\\Form\\Options' => $baseDir . '/kirby/src/Form/Options.php', + 'Kirby\\Form\\OptionsApi' => $baseDir . '/kirby/src/Form/OptionsApi.php', + 'Kirby\\Form\\OptionsQuery' => $baseDir . '/kirby/src/Form/OptionsQuery.php', + 'Kirby\\Form\\Validations' => $baseDir . '/kirby/src/Form/Validations.php', + 'Kirby\\Http\\Cookie' => $baseDir . '/kirby/src/Http/Cookie.php', + 'Kirby\\Http\\Environment' => $baseDir . '/kirby/src/Http/Environment.php', + 'Kirby\\Http\\Exceptions\\NextRouteException' => $baseDir . '/kirby/src/Http/Exceptions/NextRouteException.php', + 'Kirby\\Http\\Header' => $baseDir . '/kirby/src/Http/Header.php', + 'Kirby\\Http\\Idn' => $baseDir . '/kirby/src/Http/Idn.php', + 'Kirby\\Http\\Params' => $baseDir . '/kirby/src/Http/Params.php', + 'Kirby\\Http\\Path' => $baseDir . '/kirby/src/Http/Path.php', + 'Kirby\\Http\\Query' => $baseDir . '/kirby/src/Http/Query.php', + 'Kirby\\Http\\Remote' => $baseDir . '/kirby/src/Http/Remote.php', + 'Kirby\\Http\\Request' => $baseDir . '/kirby/src/Http/Request.php', + 'Kirby\\Http\\Request\\Auth' => $baseDir . '/kirby/src/Http/Request/Auth.php', + 'Kirby\\Http\\Request\\Auth\\BasicAuth' => $baseDir . '/kirby/src/Http/Request/Auth/BasicAuth.php', + 'Kirby\\Http\\Request\\Auth\\BearerAuth' => $baseDir . '/kirby/src/Http/Request/Auth/BearerAuth.php', + 'Kirby\\Http\\Request\\Auth\\SessionAuth' => $baseDir . '/kirby/src/Http/Request/Auth/SessionAuth.php', + 'Kirby\\Http\\Request\\Body' => $baseDir . '/kirby/src/Http/Request/Body.php', + 'Kirby\\Http\\Request\\Data' => $baseDir . '/kirby/src/Http/Request/Data.php', + 'Kirby\\Http\\Request\\Files' => $baseDir . '/kirby/src/Http/Request/Files.php', + 'Kirby\\Http\\Request\\Query' => $baseDir . '/kirby/src/Http/Request/Query.php', + 'Kirby\\Http\\Response' => $baseDir . '/kirby/src/Http/Response.php', + 'Kirby\\Http\\Route' => $baseDir . '/kirby/src/Http/Route.php', + 'Kirby\\Http\\Router' => $baseDir . '/kirby/src/Http/Router.php', + 'Kirby\\Http\\Server' => $baseDir . '/kirby/src/Http/Server.php', + 'Kirby\\Http\\Uri' => $baseDir . '/kirby/src/Http/Uri.php', + 'Kirby\\Http\\Url' => $baseDir . '/kirby/src/Http/Url.php', + 'Kirby\\Http\\Visitor' => $baseDir . '/kirby/src/Http/Visitor.php', + 'Kirby\\Image\\Camera' => $baseDir . '/kirby/src/Image/Camera.php', + 'Kirby\\Image\\Darkroom' => $baseDir . '/kirby/src/Image/Darkroom.php', + 'Kirby\\Image\\Darkroom\\GdLib' => $baseDir . '/kirby/src/Image/Darkroom/GdLib.php', + 'Kirby\\Image\\Darkroom\\ImageMagick' => $baseDir . '/kirby/src/Image/Darkroom/ImageMagick.php', + 'Kirby\\Image\\Dimensions' => $baseDir . '/kirby/src/Image/Dimensions.php', + 'Kirby\\Image\\Exif' => $baseDir . '/kirby/src/Image/Exif.php', + 'Kirby\\Image\\Image' => $baseDir . '/kirby/src/Image/Image.php', + 'Kirby\\Image\\Location' => $baseDir . '/kirby/src/Image/Location.php', + 'Kirby\\Panel\\Dialog' => $baseDir . '/kirby/src/Panel/Dialog.php', + 'Kirby\\Panel\\Document' => $baseDir . '/kirby/src/Panel/Document.php', + 'Kirby\\Panel\\Dropdown' => $baseDir . '/kirby/src/Panel/Dropdown.php', + 'Kirby\\Panel\\Field' => $baseDir . '/kirby/src/Panel/Field.php', + 'Kirby\\Panel\\File' => $baseDir . '/kirby/src/Panel/File.php', + 'Kirby\\Panel\\Home' => $baseDir . '/kirby/src/Panel/Home.php', + 'Kirby\\Panel\\Json' => $baseDir . '/kirby/src/Panel/Json.php', + 'Kirby\\Panel\\Model' => $baseDir . '/kirby/src/Panel/Model.php', + 'Kirby\\Panel\\Page' => $baseDir . '/kirby/src/Panel/Page.php', + 'Kirby\\Panel\\Panel' => $baseDir . '/kirby/src/Panel/Panel.php', + 'Kirby\\Panel\\Plugins' => $baseDir . '/kirby/src/Panel/Plugins.php', + 'Kirby\\Panel\\Redirect' => $baseDir . '/kirby/src/Panel/Redirect.php', + 'Kirby\\Panel\\Search' => $baseDir . '/kirby/src/Panel/Search.php', + 'Kirby\\Panel\\Site' => $baseDir . '/kirby/src/Panel/Site.php', + 'Kirby\\Panel\\User' => $baseDir . '/kirby/src/Panel/User.php', + 'Kirby\\Panel\\View' => $baseDir . '/kirby/src/Panel/View.php', + 'Kirby\\Parsley\\Element' => $baseDir . '/kirby/src/Parsley/Element.php', + 'Kirby\\Parsley\\Inline' => $baseDir . '/kirby/src/Parsley/Inline.php', + 'Kirby\\Parsley\\Parsley' => $baseDir . '/kirby/src/Parsley/Parsley.php', + 'Kirby\\Parsley\\Schema' => $baseDir . '/kirby/src/Parsley/Schema.php', + 'Kirby\\Parsley\\Schema\\Blocks' => $baseDir . '/kirby/src/Parsley/Schema/Blocks.php', + 'Kirby\\Parsley\\Schema\\Plain' => $baseDir . '/kirby/src/Parsley/Schema/Plain.php', + 'Kirby\\Sane\\DomHandler' => $baseDir . '/kirby/src/Sane/DomHandler.php', + 'Kirby\\Sane\\Handler' => $baseDir . '/kirby/src/Sane/Handler.php', + 'Kirby\\Sane\\Html' => $baseDir . '/kirby/src/Sane/Html.php', + 'Kirby\\Sane\\Sane' => $baseDir . '/kirby/src/Sane/Sane.php', + 'Kirby\\Sane\\Svg' => $baseDir . '/kirby/src/Sane/Svg.php', + 'Kirby\\Sane\\Svgz' => $baseDir . '/kirby/src/Sane/Svgz.php', + 'Kirby\\Sane\\Xml' => $baseDir . '/kirby/src/Sane/Xml.php', + 'Kirby\\Session\\AutoSession' => $baseDir . '/kirby/src/Session/AutoSession.php', + 'Kirby\\Session\\FileSessionStore' => $baseDir . '/kirby/src/Session/FileSessionStore.php', + 'Kirby\\Session\\Session' => $baseDir . '/kirby/src/Session/Session.php', + 'Kirby\\Session\\SessionData' => $baseDir . '/kirby/src/Session/SessionData.php', + 'Kirby\\Session\\SessionStore' => $baseDir . '/kirby/src/Session/SessionStore.php', + 'Kirby\\Session\\Sessions' => $baseDir . '/kirby/src/Session/Sessions.php', + 'Kirby\\Text\\KirbyTag' => $baseDir . '/kirby/src/Text/KirbyTag.php', + 'Kirby\\Text\\KirbyTags' => $baseDir . '/kirby/src/Text/KirbyTags.php', + 'Kirby\\Text\\Markdown' => $baseDir . '/kirby/src/Text/Markdown.php', + 'Kirby\\Text\\SmartyPants' => $baseDir . '/kirby/src/Text/SmartyPants.php', + 'Kirby\\Toolkit\\A' => $baseDir . '/kirby/src/Toolkit/A.php', + 'Kirby\\Toolkit\\Collection' => $baseDir . '/kirby/src/Toolkit/Collection.php', + 'Kirby\\Toolkit\\Component' => $baseDir . '/kirby/src/Toolkit/Component.php', + 'Kirby\\Toolkit\\Config' => $baseDir . '/kirby/src/Toolkit/Config.php', + 'Kirby\\Toolkit\\Controller' => $baseDir . '/kirby/src/Toolkit/Controller.php', + 'Kirby\\Toolkit\\Date' => $baseDir . '/kirby/src/Toolkit/Date.php', + 'Kirby\\Toolkit\\Dom' => $baseDir . '/kirby/src/Toolkit/Dom.php', + 'Kirby\\Toolkit\\Escape' => $baseDir . '/kirby/src/Toolkit/Escape.php', + 'Kirby\\Toolkit\\Facade' => $baseDir . '/kirby/src/Toolkit/Facade.php', + 'Kirby\\Toolkit\\Html' => $baseDir . '/kirby/src/Toolkit/Html.php', + 'Kirby\\Toolkit\\I18n' => $baseDir . '/kirby/src/Toolkit/I18n.php', + 'Kirby\\Toolkit\\Iterator' => $baseDir . '/kirby/src/Toolkit/Iterator.php', + 'Kirby\\Toolkit\\Locale' => $baseDir . '/kirby/src/Toolkit/Locale.php', + 'Kirby\\Toolkit\\Obj' => $baseDir . '/kirby/src/Toolkit/Obj.php', + 'Kirby\\Toolkit\\Pagination' => $baseDir . '/kirby/src/Toolkit/Pagination.php', + 'Kirby\\Toolkit\\Properties' => $baseDir . '/kirby/src/Toolkit/Properties.php', + 'Kirby\\Toolkit\\Query' => $baseDir . '/kirby/src/Toolkit/Query.php', + 'Kirby\\Toolkit\\Silo' => $baseDir . '/kirby/src/Toolkit/Silo.php', + 'Kirby\\Toolkit\\Str' => $baseDir . '/kirby/src/Toolkit/Str.php', + 'Kirby\\Toolkit\\Tpl' => $baseDir . '/kirby/src/Toolkit/Tpl.php', + 'Kirby\\Toolkit\\V' => $baseDir . '/kirby/src/Toolkit/V.php', + 'Kirby\\Toolkit\\View' => $baseDir . '/kirby/src/Toolkit/View.php', + 'Kirby\\Toolkit\\Xml' => $baseDir . '/kirby/src/Toolkit/Xml.php', + 'Laminas\\Escaper\\Escaper' => $vendorDir . '/laminas/laminas-escaper/src/Escaper.php', + 'Laminas\\Escaper\\Exception\\ExceptionInterface' => $vendorDir . '/laminas/laminas-escaper/src/Exception/ExceptionInterface.php', + 'Laminas\\Escaper\\Exception\\InvalidArgumentException' => $vendorDir . '/laminas/laminas-escaper/src/Exception/InvalidArgumentException.php', + 'Laminas\\Escaper\\Exception\\RuntimeException' => $vendorDir . '/laminas/laminas-escaper/src/Exception/RuntimeException.php', + 'League\\ColorExtractor\\Color' => $vendorDir . '/league/color-extractor/src/League/ColorExtractor/Color.php', + 'League\\ColorExtractor\\ColorExtractor' => $vendorDir . '/league/color-extractor/src/League/ColorExtractor/ColorExtractor.php', + 'League\\ColorExtractor\\Palette' => $vendorDir . '/league/color-extractor/src/League/ColorExtractor/Palette.php', + 'ML\\IRI\\IRI' => $vendorDir . '/ml/iri/ML/IRI/IRI.php', + 'ML\\IRI\\Test\\IriTest' => $vendorDir . '/ml/iri/ML/IRI/Test/IriTest.php', + 'ML\\JsonLD\\DefaultDocumentFactory' => $vendorDir . '/ml/json-ld/DefaultDocumentFactory.php', + 'ML\\JsonLD\\Document' => $vendorDir . '/ml/json-ld/Document.php', + 'ML\\JsonLD\\DocumentFactoryInterface' => $vendorDir . '/ml/json-ld/DocumentFactoryInterface.php', + 'ML\\JsonLD\\DocumentInterface' => $vendorDir . '/ml/json-ld/DocumentInterface.php', + 'ML\\JsonLD\\DocumentLoaderInterface' => $vendorDir . '/ml/json-ld/DocumentLoaderInterface.php', + 'ML\\JsonLD\\Exception\\InvalidQuadException' => $vendorDir . '/ml/json-ld/Exception/InvalidQuadException.php', + 'ML\\JsonLD\\Exception\\JsonLdException' => $vendorDir . '/ml/json-ld/Exception/JsonLdException.php', + 'ML\\JsonLD\\FileGetContentsLoader' => $vendorDir . '/ml/json-ld/FileGetContentsLoader.php', + 'ML\\JsonLD\\Graph' => $vendorDir . '/ml/json-ld/Graph.php', + 'ML\\JsonLD\\GraphInterface' => $vendorDir . '/ml/json-ld/GraphInterface.php', + 'ML\\JsonLD\\JsonLD' => $vendorDir . '/ml/json-ld/JsonLD.php', + 'ML\\JsonLD\\JsonLdSerializable' => $vendorDir . '/ml/json-ld/JsonLdSerializable.php', + 'ML\\JsonLD\\LanguageTaggedString' => $vendorDir . '/ml/json-ld/LanguageTaggedString.php', + 'ML\\JsonLD\\NQuads' => $vendorDir . '/ml/json-ld/NQuads.php', + 'ML\\JsonLD\\Node' => $vendorDir . '/ml/json-ld/Node.php', + 'ML\\JsonLD\\NodeInterface' => $vendorDir . '/ml/json-ld/NodeInterface.php', + 'ML\\JsonLD\\Processor' => $vendorDir . '/ml/json-ld/Processor.php', + 'ML\\JsonLD\\Quad' => $vendorDir . '/ml/json-ld/Quad.php', + 'ML\\JsonLD\\QuadParserInterface' => $vendorDir . '/ml/json-ld/QuadParserInterface.php', + 'ML\\JsonLD\\QuadSerializerInterface' => $vendorDir . '/ml/json-ld/QuadSerializerInterface.php', + 'ML\\JsonLD\\RdfConstants' => $vendorDir . '/ml/json-ld/RdfConstants.php', + 'ML\\JsonLD\\RemoteDocument' => $vendorDir . '/ml/json-ld/RemoteDocument.php', + 'ML\\JsonLD\\Test\\DocumentTest' => $vendorDir . '/ml/json-ld/Test/DocumentTest.php', + 'ML\\JsonLD\\Test\\EarlReportGenerator' => $vendorDir . '/ml/json-ld/Test/EarlReportGenerator.php', + 'ML\\JsonLD\\Test\\FileGetContentsLoaderTest' => $vendorDir . '/ml/json-ld/Test/FileGetContentsLoaderTest.php', + 'ML\\JsonLD\\Test\\GraphTest' => $vendorDir . '/ml/json-ld/Test/GraphTest.php', + 'ML\\JsonLD\\Test\\JsonLDApiTest' => $vendorDir . '/ml/json-ld/Test/JsonLDApiTest.php', + 'ML\\JsonLD\\Test\\JsonTestCase' => $vendorDir . '/ml/json-ld/Test/JsonTestCase.php', + 'ML\\JsonLD\\Test\\NQuadsTest' => $vendorDir . '/ml/json-ld/Test/NQuadsTest.php', + 'ML\\JsonLD\\Test\\TestManifestIterator' => $vendorDir . '/ml/json-ld/Test/TestManifestIterator.php', + 'ML\\JsonLD\\Test\\ValueTest' => $vendorDir . '/ml/json-ld/Test/ValueTest.php', + 'ML\\JsonLD\\Test\\W3CTestSuiteTest' => $vendorDir . '/ml/json-ld/Test/W3CTestSuiteTest.php', + 'ML\\JsonLD\\TypedValue' => $vendorDir . '/ml/json-ld/TypedValue.php', + 'ML\\JsonLD\\Value' => $vendorDir . '/ml/json-ld/Value.php', + 'Michelf\\SmartyPants' => $vendorDir . '/michelf/php-smartypants/Michelf/SmartyPants.php', + 'Michelf\\SmartyPantsTypographer' => $vendorDir . '/michelf/php-smartypants/Michelf/SmartyPantsTypographer.php', + 'Normalizer' => $vendorDir . '/symfony/polyfill-intl-normalizer/Resources/stubs/Normalizer.php', + 'PHPMailer\\PHPMailer\\Exception' => $vendorDir . '/phpmailer/phpmailer/src/Exception.php', + 'PHPMailer\\PHPMailer\\OAuth' => $vendorDir . '/phpmailer/phpmailer/src/OAuth.php', + 'PHPMailer\\PHPMailer\\OAuthTokenProvider' => $vendorDir . '/phpmailer/phpmailer/src/OAuthTokenProvider.php', + 'PHPMailer\\PHPMailer\\PHPMailer' => $vendorDir . '/phpmailer/phpmailer/src/PHPMailer.php', + 'PHPMailer\\PHPMailer\\POP3' => $vendorDir . '/phpmailer/phpmailer/src/POP3.php', + 'PHPMailer\\PHPMailer\\SMTP' => $vendorDir . '/phpmailer/phpmailer/src/SMTP.php', + 'Parsedown' => $baseDir . '/kirby/dependencies/parsedown/Parsedown.php', + 'ParsedownExtra' => $baseDir . '/kirby/dependencies/parsedown-extra/ParsedownExtra.php', + 'Psr\\Http\\Client\\ClientExceptionInterface' => $vendorDir . '/psr/http-client/src/ClientExceptionInterface.php', + 'Psr\\Http\\Client\\ClientInterface' => $vendorDir . '/psr/http-client/src/ClientInterface.php', + 'Psr\\Http\\Client\\NetworkExceptionInterface' => $vendorDir . '/psr/http-client/src/NetworkExceptionInterface.php', + 'Psr\\Http\\Client\\RequestExceptionInterface' => $vendorDir . '/psr/http-client/src/RequestExceptionInterface.php', + 'Psr\\Http\\Message\\MessageInterface' => $vendorDir . '/psr/http-message/src/MessageInterface.php', + 'Psr\\Http\\Message\\RequestFactoryInterface' => $vendorDir . '/psr/http-factory/src/RequestFactoryInterface.php', + 'Psr\\Http\\Message\\RequestInterface' => $vendorDir . '/psr/http-message/src/RequestInterface.php', + 'Psr\\Http\\Message\\ResponseFactoryInterface' => $vendorDir . '/psr/http-factory/src/ResponseFactoryInterface.php', + 'Psr\\Http\\Message\\ResponseInterface' => $vendorDir . '/psr/http-message/src/ResponseInterface.php', + 'Psr\\Http\\Message\\ServerRequestFactoryInterface' => $vendorDir . '/psr/http-factory/src/ServerRequestFactoryInterface.php', + 'Psr\\Http\\Message\\ServerRequestInterface' => $vendorDir . '/psr/http-message/src/ServerRequestInterface.php', + 'Psr\\Http\\Message\\StreamFactoryInterface' => $vendorDir . '/psr/http-factory/src/StreamFactoryInterface.php', + 'Psr\\Http\\Message\\StreamInterface' => $vendorDir . '/psr/http-message/src/StreamInterface.php', + 'Psr\\Http\\Message\\UploadedFileFactoryInterface' => $vendorDir . '/psr/http-factory/src/UploadedFileFactoryInterface.php', + 'Psr\\Http\\Message\\UploadedFileInterface' => $vendorDir . '/psr/http-message/src/UploadedFileInterface.php', + 'Psr\\Http\\Message\\UriFactoryInterface' => $vendorDir . '/psr/http-factory/src/UriFactoryInterface.php', + 'Psr\\Http\\Message\\UriInterface' => $vendorDir . '/psr/http-message/src/UriInterface.php', + 'Psr\\Log\\AbstractLogger' => $vendorDir . '/psr/log/Psr/Log/AbstractLogger.php', + 'Psr\\Log\\InvalidArgumentException' => $vendorDir . '/psr/log/Psr/Log/InvalidArgumentException.php', + 'Psr\\Log\\LogLevel' => $vendorDir . '/psr/log/Psr/Log/LogLevel.php', + 'Psr\\Log\\LoggerAwareInterface' => $vendorDir . '/psr/log/Psr/Log/LoggerAwareInterface.php', + 'Psr\\Log\\LoggerAwareTrait' => $vendorDir . '/psr/log/Psr/Log/LoggerAwareTrait.php', + 'Psr\\Log\\LoggerInterface' => $vendorDir . '/psr/log/Psr/Log/LoggerInterface.php', + 'Psr\\Log\\LoggerTrait' => $vendorDir . '/psr/log/Psr/Log/LoggerTrait.php', + 'Psr\\Log\\NullLogger' => $vendorDir . '/psr/log/Psr/Log/NullLogger.php', + 'Psr\\Log\\Test\\DummyTest' => $vendorDir . '/psr/log/Psr/Log/Test/DummyTest.php', + 'Psr\\Log\\Test\\LoggerInterfaceTest' => $vendorDir . '/psr/log/Psr/Log/Test/LoggerInterfaceTest.php', + 'Psr\\Log\\Test\\TestLogger' => $vendorDir . '/psr/log/Psr/Log/Test/TestLogger.php', + 'Spyc' => $baseDir . '/kirby/dependencies/spyc/Spyc.php', + 'Symfony\\Polyfill\\Intl\\Idn\\Idn' => $vendorDir . '/symfony/polyfill-intl-idn/Idn.php', + 'Symfony\\Polyfill\\Intl\\Idn\\Info' => $vendorDir . '/symfony/polyfill-intl-idn/Info.php', + 'Symfony\\Polyfill\\Intl\\Idn\\Resources\\unidata\\DisallowedRanges' => $vendorDir . '/symfony/polyfill-intl-idn/Resources/unidata/DisallowedRanges.php', + 'Symfony\\Polyfill\\Intl\\Idn\\Resources\\unidata\\Regex' => $vendorDir . '/symfony/polyfill-intl-idn/Resources/unidata/Regex.php', + 'Symfony\\Polyfill\\Intl\\Normalizer\\Normalizer' => $vendorDir . '/symfony/polyfill-intl-normalizer/Normalizer.php', + 'Symfony\\Polyfill\\Mbstring\\Mbstring' => $vendorDir . '/symfony/polyfill-mbstring/Mbstring.php', + 'Whoops\\Exception\\ErrorException' => $vendorDir . '/filp/whoops/src/Whoops/Exception/ErrorException.php', + 'Whoops\\Exception\\Formatter' => $vendorDir . '/filp/whoops/src/Whoops/Exception/Formatter.php', + 'Whoops\\Exception\\Frame' => $vendorDir . '/filp/whoops/src/Whoops/Exception/Frame.php', + 'Whoops\\Exception\\FrameCollection' => $vendorDir . '/filp/whoops/src/Whoops/Exception/FrameCollection.php', + 'Whoops\\Exception\\Inspector' => $vendorDir . '/filp/whoops/src/Whoops/Exception/Inspector.php', + 'Whoops\\Handler\\CallbackHandler' => $vendorDir . '/filp/whoops/src/Whoops/Handler/CallbackHandler.php', + 'Whoops\\Handler\\Handler' => $vendorDir . '/filp/whoops/src/Whoops/Handler/Handler.php', + 'Whoops\\Handler\\HandlerInterface' => $vendorDir . '/filp/whoops/src/Whoops/Handler/HandlerInterface.php', + 'Whoops\\Handler\\JsonResponseHandler' => $vendorDir . '/filp/whoops/src/Whoops/Handler/JsonResponseHandler.php', + 'Whoops\\Handler\\PlainTextHandler' => $vendorDir . '/filp/whoops/src/Whoops/Handler/PlainTextHandler.php', + 'Whoops\\Handler\\PrettyPageHandler' => $vendorDir . '/filp/whoops/src/Whoops/Handler/PrettyPageHandler.php', + 'Whoops\\Handler\\XmlResponseHandler' => $vendorDir . '/filp/whoops/src/Whoops/Handler/XmlResponseHandler.php', + 'Whoops\\Run' => $vendorDir . '/filp/whoops/src/Whoops/Run.php', + 'Whoops\\RunInterface' => $vendorDir . '/filp/whoops/src/Whoops/RunInterface.php', + 'Whoops\\Util\\HtmlDumperOutput' => $vendorDir . '/filp/whoops/src/Whoops/Util/HtmlDumperOutput.php', + 'Whoops\\Util\\Misc' => $vendorDir . '/filp/whoops/src/Whoops/Util/Misc.php', + 'Whoops\\Util\\SystemFacade' => $vendorDir . '/filp/whoops/src/Whoops/Util/SystemFacade.php', + 'Whoops\\Util\\TemplateHelper' => $vendorDir . '/filp/whoops/src/Whoops/Util/TemplateHelper.php', + 'claviska\\SimpleImage' => $vendorDir . '/claviska/simpleimage/src/claviska/SimpleImage.php', +); diff --git a/kirby/vendor/composer/autoload_files.php b/vendor/composer/autoload_files.php similarity index 55% rename from kirby/vendor/composer/autoload_files.php rename to vendor/composer/autoload_files.php index c7ea288..46ba14c 100644 --- a/kirby/vendor/composer/autoload_files.php +++ b/vendor/composer/autoload_files.php @@ -6,11 +6,11 @@ $vendorDir = dirname(__DIR__); $baseDir = dirname($vendorDir); return array( - '6e3fae29631ef280660b3cdad06f25a8' => $vendorDir . '/symfony/deprecation-contracts/function.php', - '320cde22f66dd4f5d3fd621d3e88b98f' => $vendorDir . '/symfony/polyfill-ctype/bootstrap.php', + '7b11c4dc42b3b3023073cb14e519683c' => $vendorDir . '/ralouphie/getallheaders/src/getallheaders.php', 'e69f7f6ee287b969198c3c9d6777bd38' => $vendorDir . '/symfony/polyfill-intl-normalizer/bootstrap.php', + '09fc349b549513bf7f4291502426f919' => $vendorDir . '/embed/embed/src/functions.php', 'f598d06aa772fa33d905e87be6398fb1' => $vendorDir . '/symfony/polyfill-intl-idn/bootstrap.php', '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php', - 'f864ae44e8154e5ff6f4eec32f46d37f' => $baseDir . '/config/setup.php', - '87988fc7b1c1f093da22a1a3de972f3a' => $baseDir . '/config/helpers.php', + 'f864ae44e8154e5ff6f4eec32f46d37f' => $baseDir . '/kirby/config/setup.php', + '87988fc7b1c1f093da22a1a3de972f3a' => $baseDir . '/kirby/config/helpers.php', ); diff --git a/kirby/vendor/composer/autoload_namespaces.php b/vendor/composer/autoload_namespaces.php similarity index 84% rename from kirby/vendor/composer/autoload_namespaces.php rename to vendor/composer/autoload_namespaces.php index f67d4ab..829e7c7 100644 --- a/kirby/vendor/composer/autoload_namespaces.php +++ b/vendor/composer/autoload_namespaces.php @@ -8,4 +8,5 @@ $baseDir = dirname($vendorDir); return array( 'claviska' => array($vendorDir . '/claviska/simpleimage/src'), 'Michelf' => array($vendorDir . '/michelf/php-smartypants'), + 'ML\\IRI' => array($vendorDir . '/ml/iri'), ); diff --git a/vendor/composer/autoload_psr4.php b/vendor/composer/autoload_psr4.php new file mode 100644 index 0000000..6f58d37 --- /dev/null +++ b/vendor/composer/autoload_psr4.php @@ -0,0 +1,25 @@ + array($vendorDir . '/filp/whoops/src/Whoops'), + 'Symfony\\Polyfill\\Mbstring\\' => array($vendorDir . '/symfony/polyfill-mbstring'), + 'Symfony\\Polyfill\\Intl\\Normalizer\\' => array($vendorDir . '/symfony/polyfill-intl-normalizer'), + 'Symfony\\Polyfill\\Intl\\Idn\\' => array($vendorDir . '/symfony/polyfill-intl-idn'), + 'Psr\\Log\\' => array($vendorDir . '/psr/log/Psr/Log'), + 'Psr\\Http\\Message\\' => array($vendorDir . '/psr/http-factory/src', $vendorDir . '/psr/http-message/src'), + 'Psr\\Http\\Client\\' => array($vendorDir . '/psr/http-client/src'), + 'PHPMailer\\PHPMailer\\' => array($vendorDir . '/phpmailer/phpmailer/src'), + 'ML\\JsonLD\\' => array($vendorDir . '/ml/json-ld'), + 'Laminas\\Escaper\\' => array($vendorDir . '/laminas/laminas-escaper/src'), + 'Kirby\\' => array($baseDir . '/kirby/src', $vendorDir . '/getkirby/composer-installer/src'), + 'HtmlParser\\' => array($vendorDir . '/oscarotero/html-parser/src'), + 'GuzzleHttp\\Psr7\\' => array($vendorDir . '/guzzlehttp/psr7/src'), + 'Embed\\' => array($vendorDir . '/embed/embed/src'), + 'Composer\\CaBundle\\' => array($vendorDir . '/composer/ca-bundle/src'), + '' => array($vendorDir . '/league/color-extractor/src'), +); diff --git a/kirby/vendor/composer/autoload_real.php b/vendor/composer/autoload_real.php similarity index 65% rename from kirby/vendor/composer/autoload_real.php rename to vendor/composer/autoload_real.php index 91f75ce..1ffac3a 100644 --- a/kirby/vendor/composer/autoload_real.php +++ b/vendor/composer/autoload_real.php @@ -2,7 +2,7 @@ // autoload_real.php @generated by Composer -class ComposerAutoloaderInit0bf5c8a9cfa251a218fc581ac888fe35 +class ComposerAutoloaderInit34ad0fcfd7efff0ce7004033b941cfcf { private static $loader; @@ -22,16 +22,18 @@ class ComposerAutoloaderInit0bf5c8a9cfa251a218fc581ac888fe35 return self::$loader; } - spl_autoload_register(array('ComposerAutoloaderInit0bf5c8a9cfa251a218fc581ac888fe35', 'loadClassLoader'), true, true); + require __DIR__ . '/platform_check.php'; + + spl_autoload_register(array('ComposerAutoloaderInit34ad0fcfd7efff0ce7004033b941cfcf', 'loadClassLoader'), true, true); self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__)); - spl_autoload_unregister(array('ComposerAutoloaderInit0bf5c8a9cfa251a218fc581ac888fe35', 'loadClassLoader')); + spl_autoload_unregister(array('ComposerAutoloaderInit34ad0fcfd7efff0ce7004033b941cfcf', 'loadClassLoader')); require __DIR__ . '/autoload_static.php'; - call_user_func(\Composer\Autoload\ComposerStaticInit0bf5c8a9cfa251a218fc581ac888fe35::getInitializer($loader)); + call_user_func(\Composer\Autoload\ComposerStaticInit34ad0fcfd7efff0ce7004033b941cfcf::getInitializer($loader)); $loader->register(true); - $filesToLoad = \Composer\Autoload\ComposerStaticInit0bf5c8a9cfa251a218fc581ac888fe35::$files; + $filesToLoad = \Composer\Autoload\ComposerStaticInit34ad0fcfd7efff0ce7004033b941cfcf::$files; $requireFile = \Closure::bind(static function ($fileIdentifier, $file) { if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) { $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true; diff --git a/vendor/composer/autoload_static.php b/vendor/composer/autoload_static.php new file mode 100644 index 0000000..01f5bb1 --- /dev/null +++ b/vendor/composer/autoload_static.php @@ -0,0 +1,669 @@ + __DIR__ . '/..' . '/ralouphie/getallheaders/src/getallheaders.php', + 'e69f7f6ee287b969198c3c9d6777bd38' => __DIR__ . '/..' . '/symfony/polyfill-intl-normalizer/bootstrap.php', + '09fc349b549513bf7f4291502426f919' => __DIR__ . '/..' . '/embed/embed/src/functions.php', + 'f598d06aa772fa33d905e87be6398fb1' => __DIR__ . '/..' . '/symfony/polyfill-intl-idn/bootstrap.php', + '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php', + 'f864ae44e8154e5ff6f4eec32f46d37f' => __DIR__ . '/../..' . '/kirby/config/setup.php', + '87988fc7b1c1f093da22a1a3de972f3a' => __DIR__ . '/../..' . '/kirby/config/helpers.php', + ); + + public static $prefixLengthsPsr4 = array ( + 'W' => + array ( + 'Whoops\\' => 7, + ), + 'S' => + array ( + 'Symfony\\Polyfill\\Mbstring\\' => 26, + 'Symfony\\Polyfill\\Intl\\Normalizer\\' => 33, + 'Symfony\\Polyfill\\Intl\\Idn\\' => 26, + ), + 'P' => + array ( + 'Psr\\Log\\' => 8, + 'Psr\\Http\\Message\\' => 17, + 'Psr\\Http\\Client\\' => 16, + 'PHPMailer\\PHPMailer\\' => 20, + ), + 'M' => + array ( + 'ML\\JsonLD\\' => 10, + ), + 'L' => + array ( + 'Laminas\\Escaper\\' => 16, + ), + 'K' => + array ( + 'Kirby\\' => 6, + ), + 'H' => + array ( + 'HtmlParser\\' => 11, + ), + 'G' => + array ( + 'GuzzleHttp\\Psr7\\' => 16, + ), + 'E' => + array ( + 'Embed\\' => 6, + ), + 'C' => + array ( + 'Composer\\CaBundle\\' => 18, + ), + ); + + public static $prefixDirsPsr4 = array ( + 'Whoops\\' => + array ( + 0 => __DIR__ . '/..' . '/filp/whoops/src/Whoops', + ), + 'Symfony\\Polyfill\\Mbstring\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/polyfill-mbstring', + ), + 'Symfony\\Polyfill\\Intl\\Normalizer\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/polyfill-intl-normalizer', + ), + 'Symfony\\Polyfill\\Intl\\Idn\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/polyfill-intl-idn', + ), + 'Psr\\Log\\' => + array ( + 0 => __DIR__ . '/..' . '/psr/log/Psr/Log', + ), + 'Psr\\Http\\Message\\' => + array ( + 0 => __DIR__ . '/..' . '/psr/http-factory/src', + 1 => __DIR__ . '/..' . '/psr/http-message/src', + ), + 'Psr\\Http\\Client\\' => + array ( + 0 => __DIR__ . '/..' . '/psr/http-client/src', + ), + 'PHPMailer\\PHPMailer\\' => + array ( + 0 => __DIR__ . '/..' . '/phpmailer/phpmailer/src', + ), + 'ML\\JsonLD\\' => + array ( + 0 => __DIR__ . '/..' . '/ml/json-ld', + ), + 'Laminas\\Escaper\\' => + array ( + 0 => __DIR__ . '/..' . '/laminas/laminas-escaper/src', + ), + 'Kirby\\' => + array ( + 0 => __DIR__ . '/../..' . '/kirby/src', + 1 => __DIR__ . '/..' . '/getkirby/composer-installer/src', + ), + 'HtmlParser\\' => + array ( + 0 => __DIR__ . '/..' . '/oscarotero/html-parser/src', + ), + 'GuzzleHttp\\Psr7\\' => + array ( + 0 => __DIR__ . '/..' . '/guzzlehttp/psr7/src', + ), + 'Embed\\' => + array ( + 0 => __DIR__ . '/..' . '/embed/embed/src', + ), + 'Composer\\CaBundle\\' => + array ( + 0 => __DIR__ . '/..' . '/composer/ca-bundle/src', + ), + ); + + public static $fallbackDirsPsr4 = array ( + 0 => __DIR__ . '/..' . '/league/color-extractor/src', + ); + + public static $prefixesPsr0 = array ( + 'c' => + array ( + 'claviska' => + array ( + 0 => __DIR__ . '/..' . '/claviska/simpleimage/src', + ), + ), + 'M' => + array ( + 'Michelf' => + array ( + 0 => __DIR__ . '/..' . '/michelf/php-smartypants', + ), + 'ML\\IRI' => + array ( + 0 => __DIR__ . '/..' . '/ml/iri', + ), + ), + ); + + public static $classMap = array ( + 'Composer\\CaBundle\\CaBundle' => __DIR__ . '/..' . '/composer/ca-bundle/src/CaBundle.php', + 'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php', + 'Embed\\Adapters\\Archive\\Api' => __DIR__ . '/..' . '/embed/embed/src/Adapters/Archive/Api.php', + 'Embed\\Adapters\\Archive\\Detectors\\AuthorName' => __DIR__ . '/..' . '/embed/embed/src/Adapters/Archive/Detectors/AuthorName.php', + 'Embed\\Adapters\\Archive\\Detectors\\Code' => __DIR__ . '/..' . '/embed/embed/src/Adapters/Archive/Detectors/Code.php', + 'Embed\\Adapters\\Archive\\Detectors\\Description' => __DIR__ . '/..' . '/embed/embed/src/Adapters/Archive/Detectors/Description.php', + 'Embed\\Adapters\\Archive\\Detectors\\ProviderName' => __DIR__ . '/..' . '/embed/embed/src/Adapters/Archive/Detectors/ProviderName.php', + 'Embed\\Adapters\\Archive\\Detectors\\PublishedTime' => __DIR__ . '/..' . '/embed/embed/src/Adapters/Archive/Detectors/PublishedTime.php', + 'Embed\\Adapters\\Archive\\Detectors\\Title' => __DIR__ . '/..' . '/embed/embed/src/Adapters/Archive/Detectors/Title.php', + 'Embed\\Adapters\\Archive\\Extractor' => __DIR__ . '/..' . '/embed/embed/src/Adapters/Archive/Extractor.php', + 'Embed\\Adapters\\Bandcamp\\Detectors\\ProviderName' => __DIR__ . '/..' . '/embed/embed/src/Adapters/Bandcamp/Detectors/ProviderName.php', + 'Embed\\Adapters\\Bandcamp\\Extractor' => __DIR__ . '/..' . '/embed/embed/src/Adapters/Bandcamp/Extractor.php', + 'Embed\\Adapters\\CadenaSer\\Detectors\\Code' => __DIR__ . '/..' . '/embed/embed/src/Adapters/CadenaSer/Detectors/Code.php', + 'Embed\\Adapters\\CadenaSer\\Extractor' => __DIR__ . '/..' . '/embed/embed/src/Adapters/CadenaSer/Extractor.php', + 'Embed\\Adapters\\Facebook\\Detectors\\Title' => __DIR__ . '/..' . '/embed/embed/src/Adapters/Facebook/Detectors/Title.php', + 'Embed\\Adapters\\Facebook\\Extractor' => __DIR__ . '/..' . '/embed/embed/src/Adapters/Facebook/Extractor.php', + 'Embed\\Adapters\\Facebook\\OEmbed' => __DIR__ . '/..' . '/embed/embed/src/Adapters/Facebook/OEmbed.php', + 'Embed\\Adapters\\Flickr\\Detectors\\Code' => __DIR__ . '/..' . '/embed/embed/src/Adapters/Flickr/Detectors/Code.php', + 'Embed\\Adapters\\Flickr\\Extractor' => __DIR__ . '/..' . '/embed/embed/src/Adapters/Flickr/Extractor.php', + 'Embed\\Adapters\\Gist\\Api' => __DIR__ . '/..' . '/embed/embed/src/Adapters/Gist/Api.php', + 'Embed\\Adapters\\Gist\\Detectors\\AuthorName' => __DIR__ . '/..' . '/embed/embed/src/Adapters/Gist/Detectors/AuthorName.php', + 'Embed\\Adapters\\Gist\\Detectors\\AuthorUrl' => __DIR__ . '/..' . '/embed/embed/src/Adapters/Gist/Detectors/AuthorUrl.php', + 'Embed\\Adapters\\Gist\\Detectors\\Code' => __DIR__ . '/..' . '/embed/embed/src/Adapters/Gist/Detectors/Code.php', + 'Embed\\Adapters\\Gist\\Detectors\\PublishedTime' => __DIR__ . '/..' . '/embed/embed/src/Adapters/Gist/Detectors/PublishedTime.php', + 'Embed\\Adapters\\Gist\\Extractor' => __DIR__ . '/..' . '/embed/embed/src/Adapters/Gist/Extractor.php', + 'Embed\\Adapters\\Github\\Detectors\\Code' => __DIR__ . '/..' . '/embed/embed/src/Adapters/Github/Detectors/Code.php', + 'Embed\\Adapters\\Github\\Extractor' => __DIR__ . '/..' . '/embed/embed/src/Adapters/Github/Extractor.php', + 'Embed\\Adapters\\Ideone\\Detectors\\Code' => __DIR__ . '/..' . '/embed/embed/src/Adapters/Ideone/Detectors/Code.php', + 'Embed\\Adapters\\Ideone\\Extractor' => __DIR__ . '/..' . '/embed/embed/src/Adapters/Ideone/Extractor.php', + 'Embed\\Adapters\\ImageShack\\Api' => __DIR__ . '/..' . '/embed/embed/src/Adapters/ImageShack/Api.php', + 'Embed\\Adapters\\ImageShack\\Detectors\\AuthorName' => __DIR__ . '/..' . '/embed/embed/src/Adapters/ImageShack/Detectors/AuthorName.php', + 'Embed\\Adapters\\ImageShack\\Detectors\\AuthorUrl' => __DIR__ . '/..' . '/embed/embed/src/Adapters/ImageShack/Detectors/AuthorUrl.php', + 'Embed\\Adapters\\ImageShack\\Detectors\\Description' => __DIR__ . '/..' . '/embed/embed/src/Adapters/ImageShack/Detectors/Description.php', + 'Embed\\Adapters\\ImageShack\\Detectors\\Image' => __DIR__ . '/..' . '/embed/embed/src/Adapters/ImageShack/Detectors/Image.php', + 'Embed\\Adapters\\ImageShack\\Detectors\\ProviderName' => __DIR__ . '/..' . '/embed/embed/src/Adapters/ImageShack/Detectors/ProviderName.php', + 'Embed\\Adapters\\ImageShack\\Detectors\\PublishedTime' => __DIR__ . '/..' . '/embed/embed/src/Adapters/ImageShack/Detectors/PublishedTime.php', + 'Embed\\Adapters\\ImageShack\\Detectors\\Title' => __DIR__ . '/..' . '/embed/embed/src/Adapters/ImageShack/Detectors/Title.php', + 'Embed\\Adapters\\ImageShack\\Extractor' => __DIR__ . '/..' . '/embed/embed/src/Adapters/ImageShack/Extractor.php', + 'Embed\\Adapters\\Instagram\\Extractor' => __DIR__ . '/..' . '/embed/embed/src/Adapters/Instagram/Extractor.php', + 'Embed\\Adapters\\Instagram\\OEmbed' => __DIR__ . '/..' . '/embed/embed/src/Adapters/Instagram/OEmbed.php', + 'Embed\\Adapters\\Pinterest\\Detectors\\Code' => __DIR__ . '/..' . '/embed/embed/src/Adapters/Pinterest/Detectors/Code.php', + 'Embed\\Adapters\\Pinterest\\Extractor' => __DIR__ . '/..' . '/embed/embed/src/Adapters/Pinterest/Extractor.php', + 'Embed\\Adapters\\Sassmeister\\Detectors\\Code' => __DIR__ . '/..' . '/embed/embed/src/Adapters/Sassmeister/Detectors/Code.php', + 'Embed\\Adapters\\Sassmeister\\Extractor' => __DIR__ . '/..' . '/embed/embed/src/Adapters/Sassmeister/Extractor.php', + 'Embed\\Adapters\\Slides\\Detectors\\Code' => __DIR__ . '/..' . '/embed/embed/src/Adapters/Slides/Detectors/Code.php', + 'Embed\\Adapters\\Slides\\Extractor' => __DIR__ . '/..' . '/embed/embed/src/Adapters/Slides/Extractor.php', + 'Embed\\Adapters\\Snipplr\\Detectors\\Code' => __DIR__ . '/..' . '/embed/embed/src/Adapters/Snipplr/Detectors/Code.php', + 'Embed\\Adapters\\Snipplr\\Extractor' => __DIR__ . '/..' . '/embed/embed/src/Adapters/Snipplr/Extractor.php', + 'Embed\\Adapters\\Twitch\\Detectors\\Code' => __DIR__ . '/..' . '/embed/embed/src/Adapters/Twitch/Detectors/Code.php', + 'Embed\\Adapters\\Twitch\\Extractor' => __DIR__ . '/..' . '/embed/embed/src/Adapters/Twitch/Extractor.php', + 'Embed\\Adapters\\Twitter\\Api' => __DIR__ . '/..' . '/embed/embed/src/Adapters/Twitter/Api.php', + 'Embed\\Adapters\\Twitter\\Detectors\\AuthorName' => __DIR__ . '/..' . '/embed/embed/src/Adapters/Twitter/Detectors/AuthorName.php', + 'Embed\\Adapters\\Twitter\\Detectors\\AuthorUrl' => __DIR__ . '/..' . '/embed/embed/src/Adapters/Twitter/Detectors/AuthorUrl.php', + 'Embed\\Adapters\\Twitter\\Detectors\\Description' => __DIR__ . '/..' . '/embed/embed/src/Adapters/Twitter/Detectors/Description.php', + 'Embed\\Adapters\\Twitter\\Detectors\\Image' => __DIR__ . '/..' . '/embed/embed/src/Adapters/Twitter/Detectors/Image.php', + 'Embed\\Adapters\\Twitter\\Detectors\\ProviderName' => __DIR__ . '/..' . '/embed/embed/src/Adapters/Twitter/Detectors/ProviderName.php', + 'Embed\\Adapters\\Twitter\\Detectors\\PublishedTime' => __DIR__ . '/..' . '/embed/embed/src/Adapters/Twitter/Detectors/PublishedTime.php', + 'Embed\\Adapters\\Twitter\\Detectors\\Title' => __DIR__ . '/..' . '/embed/embed/src/Adapters/Twitter/Detectors/Title.php', + 'Embed\\Adapters\\Twitter\\Extractor' => __DIR__ . '/..' . '/embed/embed/src/Adapters/Twitter/Extractor.php', + 'Embed\\Adapters\\Wikipedia\\Api' => __DIR__ . '/..' . '/embed/embed/src/Adapters/Wikipedia/Api.php', + 'Embed\\Adapters\\Wikipedia\\Detectors\\Description' => __DIR__ . '/..' . '/embed/embed/src/Adapters/Wikipedia/Detectors/Description.php', + 'Embed\\Adapters\\Wikipedia\\Detectors\\Title' => __DIR__ . '/..' . '/embed/embed/src/Adapters/Wikipedia/Detectors/Title.php', + 'Embed\\Adapters\\Wikipedia\\Extractor' => __DIR__ . '/..' . '/embed/embed/src/Adapters/Wikipedia/Extractor.php', + 'Embed\\Adapters\\Youtube\\Detectors\\Feeds' => __DIR__ . '/..' . '/embed/embed/src/Adapters/Youtube/Detectors/Feeds.php', + 'Embed\\Adapters\\Youtube\\Extractor' => __DIR__ . '/..' . '/embed/embed/src/Adapters/Youtube/Extractor.php', + 'Embed\\ApiTrait' => __DIR__ . '/..' . '/embed/embed/src/ApiTrait.php', + 'Embed\\Detectors\\AuthorName' => __DIR__ . '/..' . '/embed/embed/src/Detectors/AuthorName.php', + 'Embed\\Detectors\\AuthorUrl' => __DIR__ . '/..' . '/embed/embed/src/Detectors/AuthorUrl.php', + 'Embed\\Detectors\\Cms' => __DIR__ . '/..' . '/embed/embed/src/Detectors/Cms.php', + 'Embed\\Detectors\\Code' => __DIR__ . '/..' . '/embed/embed/src/Detectors/Code.php', + 'Embed\\Detectors\\Description' => __DIR__ . '/..' . '/embed/embed/src/Detectors/Description.php', + 'Embed\\Detectors\\Detector' => __DIR__ . '/..' . '/embed/embed/src/Detectors/Detector.php', + 'Embed\\Detectors\\Favicon' => __DIR__ . '/..' . '/embed/embed/src/Detectors/Favicon.php', + 'Embed\\Detectors\\Feeds' => __DIR__ . '/..' . '/embed/embed/src/Detectors/Feeds.php', + 'Embed\\Detectors\\Icon' => __DIR__ . '/..' . '/embed/embed/src/Detectors/Icon.php', + 'Embed\\Detectors\\Image' => __DIR__ . '/..' . '/embed/embed/src/Detectors/Image.php', + 'Embed\\Detectors\\Keywords' => __DIR__ . '/..' . '/embed/embed/src/Detectors/Keywords.php', + 'Embed\\Detectors\\Language' => __DIR__ . '/..' . '/embed/embed/src/Detectors/Language.php', + 'Embed\\Detectors\\Languages' => __DIR__ . '/..' . '/embed/embed/src/Detectors/Languages.php', + 'Embed\\Detectors\\License' => __DIR__ . '/..' . '/embed/embed/src/Detectors/License.php', + 'Embed\\Detectors\\ProviderName' => __DIR__ . '/..' . '/embed/embed/src/Detectors/ProviderName.php', + 'Embed\\Detectors\\ProviderUrl' => __DIR__ . '/..' . '/embed/embed/src/Detectors/ProviderUrl.php', + 'Embed\\Detectors\\PublishedTime' => __DIR__ . '/..' . '/embed/embed/src/Detectors/PublishedTime.php', + 'Embed\\Detectors\\Redirect' => __DIR__ . '/..' . '/embed/embed/src/Detectors/Redirect.php', + 'Embed\\Detectors\\Title' => __DIR__ . '/..' . '/embed/embed/src/Detectors/Title.php', + 'Embed\\Detectors\\Url' => __DIR__ . '/..' . '/embed/embed/src/Detectors/Url.php', + 'Embed\\Document' => __DIR__ . '/..' . '/embed/embed/src/Document.php', + 'Embed\\Embed' => __DIR__ . '/..' . '/embed/embed/src/Embed.php', + 'Embed\\EmbedCode' => __DIR__ . '/..' . '/embed/embed/src/EmbedCode.php', + 'Embed\\Extractor' => __DIR__ . '/..' . '/embed/embed/src/Extractor.php', + 'Embed\\ExtractorFactory' => __DIR__ . '/..' . '/embed/embed/src/ExtractorFactory.php', + 'Embed\\HttpApiTrait' => __DIR__ . '/..' . '/embed/embed/src/HttpApiTrait.php', + 'Embed\\Http\\Crawler' => __DIR__ . '/..' . '/embed/embed/src/Http/Crawler.php', + 'Embed\\Http\\CurlClient' => __DIR__ . '/..' . '/embed/embed/src/Http/CurlClient.php', + 'Embed\\Http\\CurlDispatcher' => __DIR__ . '/..' . '/embed/embed/src/Http/CurlDispatcher.php', + 'Embed\\Http\\FactoryDiscovery' => __DIR__ . '/..' . '/embed/embed/src/Http/FactoryDiscovery.php', + 'Embed\\Http\\NetworkException' => __DIR__ . '/..' . '/embed/embed/src/Http/NetworkException.php', + 'Embed\\Http\\RequestException' => __DIR__ . '/..' . '/embed/embed/src/Http/RequestException.php', + 'Embed\\LinkedData' => __DIR__ . '/..' . '/embed/embed/src/LinkedData.php', + 'Embed\\Metas' => __DIR__ . '/..' . '/embed/embed/src/Metas.php', + 'Embed\\OEmbed' => __DIR__ . '/..' . '/embed/embed/src/OEmbed.php', + 'Embed\\QueryResult' => __DIR__ . '/..' . '/embed/embed/src/QueryResult.php', + 'GuzzleHttp\\Psr7\\AppendStream' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/AppendStream.php', + 'GuzzleHttp\\Psr7\\BufferStream' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/BufferStream.php', + 'GuzzleHttp\\Psr7\\CachingStream' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/CachingStream.php', + 'GuzzleHttp\\Psr7\\DroppingStream' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/DroppingStream.php', + 'GuzzleHttp\\Psr7\\Exception\\MalformedUriException' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/Exception/MalformedUriException.php', + 'GuzzleHttp\\Psr7\\FnStream' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/FnStream.php', + 'GuzzleHttp\\Psr7\\Header' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/Header.php', + 'GuzzleHttp\\Psr7\\HttpFactory' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/HttpFactory.php', + 'GuzzleHttp\\Psr7\\InflateStream' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/InflateStream.php', + 'GuzzleHttp\\Psr7\\LazyOpenStream' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/LazyOpenStream.php', + 'GuzzleHttp\\Psr7\\LimitStream' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/LimitStream.php', + 'GuzzleHttp\\Psr7\\Message' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/Message.php', + 'GuzzleHttp\\Psr7\\MessageTrait' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/MessageTrait.php', + 'GuzzleHttp\\Psr7\\MimeType' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/MimeType.php', + 'GuzzleHttp\\Psr7\\MultipartStream' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/MultipartStream.php', + 'GuzzleHttp\\Psr7\\NoSeekStream' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/NoSeekStream.php', + 'GuzzleHttp\\Psr7\\PumpStream' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/PumpStream.php', + 'GuzzleHttp\\Psr7\\Query' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/Query.php', + 'GuzzleHttp\\Psr7\\Request' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/Request.php', + 'GuzzleHttp\\Psr7\\Response' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/Response.php', + 'GuzzleHttp\\Psr7\\Rfc7230' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/Rfc7230.php', + 'GuzzleHttp\\Psr7\\ServerRequest' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/ServerRequest.php', + 'GuzzleHttp\\Psr7\\Stream' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/Stream.php', + 'GuzzleHttp\\Psr7\\StreamDecoratorTrait' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/StreamDecoratorTrait.php', + 'GuzzleHttp\\Psr7\\StreamWrapper' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/StreamWrapper.php', + 'GuzzleHttp\\Psr7\\UploadedFile' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/UploadedFile.php', + 'GuzzleHttp\\Psr7\\Uri' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/Uri.php', + 'GuzzleHttp\\Psr7\\UriComparator' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/UriComparator.php', + 'GuzzleHttp\\Psr7\\UriNormalizer' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/UriNormalizer.php', + 'GuzzleHttp\\Psr7\\UriResolver' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/UriResolver.php', + 'GuzzleHttp\\Psr7\\Utils' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/Utils.php', + 'HtmlParser\\Parser' => __DIR__ . '/..' . '/oscarotero/html-parser/src/Parser.php', + 'Kirby\\Api\\Api' => __DIR__ . '/../..' . '/kirby/src/Api/Api.php', + 'Kirby\\Api\\Collection' => __DIR__ . '/../..' . '/kirby/src/Api/Collection.php', + 'Kirby\\Api\\Model' => __DIR__ . '/../..' . '/kirby/src/Api/Model.php', + 'Kirby\\Cache\\ApcuCache' => __DIR__ . '/../..' . '/kirby/src/Cache/ApcuCache.php', + 'Kirby\\Cache\\Cache' => __DIR__ . '/../..' . '/kirby/src/Cache/Cache.php', + 'Kirby\\Cache\\FileCache' => __DIR__ . '/../..' . '/kirby/src/Cache/FileCache.php', + 'Kirby\\Cache\\MemCached' => __DIR__ . '/../..' . '/kirby/src/Cache/MemCached.php', + 'Kirby\\Cache\\MemoryCache' => __DIR__ . '/../..' . '/kirby/src/Cache/MemoryCache.php', + 'Kirby\\Cache\\NullCache' => __DIR__ . '/../..' . '/kirby/src/Cache/NullCache.php', + 'Kirby\\Cache\\Value' => __DIR__ . '/../..' . '/kirby/src/Cache/Value.php', + 'Kirby\\Cms\\Api' => __DIR__ . '/../..' . '/kirby/src/Cms/Api.php', + 'Kirby\\Cms\\App' => __DIR__ . '/../..' . '/kirby/src/Cms/App.php', + 'Kirby\\Cms\\AppCaches' => __DIR__ . '/../..' . '/kirby/src/Cms/AppCaches.php', + 'Kirby\\Cms\\AppErrors' => __DIR__ . '/../..' . '/kirby/src/Cms/AppErrors.php', + 'Kirby\\Cms\\AppPlugins' => __DIR__ . '/../..' . '/kirby/src/Cms/AppPlugins.php', + 'Kirby\\Cms\\AppTranslations' => __DIR__ . '/../..' . '/kirby/src/Cms/AppTranslations.php', + 'Kirby\\Cms\\AppUsers' => __DIR__ . '/../..' . '/kirby/src/Cms/AppUsers.php', + 'Kirby\\Cms\\Auth' => __DIR__ . '/../..' . '/kirby/src/Cms/Auth.php', + 'Kirby\\Cms\\Auth\\Challenge' => __DIR__ . '/../..' . '/kirby/src/Cms/Auth/Challenge.php', + 'Kirby\\Cms\\Auth\\EmailChallenge' => __DIR__ . '/../..' . '/kirby/src/Cms/Auth/EmailChallenge.php', + 'Kirby\\Cms\\Auth\\Status' => __DIR__ . '/../..' . '/kirby/src/Cms/Auth/Status.php', + 'Kirby\\Cms\\Block' => __DIR__ . '/../..' . '/kirby/src/Cms/Block.php', + 'Kirby\\Cms\\Blocks' => __DIR__ . '/../..' . '/kirby/src/Cms/Blocks.php', + 'Kirby\\Cms\\Blueprint' => __DIR__ . '/../..' . '/kirby/src/Cms/Blueprint.php', + 'Kirby\\Cms\\Collection' => __DIR__ . '/../..' . '/kirby/src/Cms/Collection.php', + 'Kirby\\Cms\\Collections' => __DIR__ . '/../..' . '/kirby/src/Cms/Collections.php', + 'Kirby\\Cms\\Content' => __DIR__ . '/../..' . '/kirby/src/Cms/Content.php', + 'Kirby\\Cms\\ContentLock' => __DIR__ . '/../..' . '/kirby/src/Cms/ContentLock.php', + 'Kirby\\Cms\\ContentLocks' => __DIR__ . '/../..' . '/kirby/src/Cms/ContentLocks.php', + 'Kirby\\Cms\\ContentTranslation' => __DIR__ . '/../..' . '/kirby/src/Cms/ContentTranslation.php', + 'Kirby\\Cms\\Core' => __DIR__ . '/../..' . '/kirby/src/Cms/Core.php', + 'Kirby\\Cms\\Email' => __DIR__ . '/../..' . '/kirby/src/Cms/Email.php', + 'Kirby\\Cms\\Event' => __DIR__ . '/../..' . '/kirby/src/Cms/Event.php', + 'Kirby\\Cms\\Field' => __DIR__ . '/../..' . '/kirby/src/Cms/Field.php', + 'Kirby\\Cms\\Fieldset' => __DIR__ . '/../..' . '/kirby/src/Cms/Fieldset.php', + 'Kirby\\Cms\\Fieldsets' => __DIR__ . '/../..' . '/kirby/src/Cms/Fieldsets.php', + 'Kirby\\Cms\\File' => __DIR__ . '/../..' . '/kirby/src/Cms/File.php', + 'Kirby\\Cms\\FileActions' => __DIR__ . '/../..' . '/kirby/src/Cms/FileActions.php', + 'Kirby\\Cms\\FileBlueprint' => __DIR__ . '/../..' . '/kirby/src/Cms/FileBlueprint.php', + 'Kirby\\Cms\\FileModifications' => __DIR__ . '/../..' . '/kirby/src/Cms/FileModifications.php', + 'Kirby\\Cms\\FilePermissions' => __DIR__ . '/../..' . '/kirby/src/Cms/FilePermissions.php', + 'Kirby\\Cms\\FilePicker' => __DIR__ . '/../..' . '/kirby/src/Cms/FilePicker.php', + 'Kirby\\Cms\\FileRules' => __DIR__ . '/../..' . '/kirby/src/Cms/FileRules.php', + 'Kirby\\Cms\\FileVersion' => __DIR__ . '/../..' . '/kirby/src/Cms/FileVersion.php', + 'Kirby\\Cms\\Files' => __DIR__ . '/../..' . '/kirby/src/Cms/Files.php', + 'Kirby\\Cms\\Find' => __DIR__ . '/../..' . '/kirby/src/Cms/Find.php', + 'Kirby\\Cms\\HasChildren' => __DIR__ . '/../..' . '/kirby/src/Cms/HasChildren.php', + 'Kirby\\Cms\\HasFiles' => __DIR__ . '/../..' . '/kirby/src/Cms/HasFiles.php', + 'Kirby\\Cms\\HasMethods' => __DIR__ . '/../..' . '/kirby/src/Cms/HasMethods.php', + 'Kirby\\Cms\\HasSiblings' => __DIR__ . '/../..' . '/kirby/src/Cms/HasSiblings.php', + 'Kirby\\Cms\\Helpers' => __DIR__ . '/../..' . '/kirby/src/Cms/Helpers.php', + 'Kirby\\Cms\\Html' => __DIR__ . '/../..' . '/kirby/src/Cms/Html.php', + 'Kirby\\Cms\\Ingredients' => __DIR__ . '/../..' . '/kirby/src/Cms/Ingredients.php', + 'Kirby\\Cms\\Item' => __DIR__ . '/../..' . '/kirby/src/Cms/Item.php', + 'Kirby\\Cms\\Items' => __DIR__ . '/../..' . '/kirby/src/Cms/Items.php', + 'Kirby\\Cms\\Language' => __DIR__ . '/../..' . '/kirby/src/Cms/Language.php', + 'Kirby\\Cms\\LanguageRouter' => __DIR__ . '/../..' . '/kirby/src/Cms/LanguageRouter.php', + 'Kirby\\Cms\\LanguageRoutes' => __DIR__ . '/../..' . '/kirby/src/Cms/LanguageRoutes.php', + 'Kirby\\Cms\\LanguageRules' => __DIR__ . '/../..' . '/kirby/src/Cms/LanguageRules.php', + 'Kirby\\Cms\\Languages' => __DIR__ . '/../..' . '/kirby/src/Cms/Languages.php', + 'Kirby\\Cms\\Layout' => __DIR__ . '/../..' . '/kirby/src/Cms/Layout.php', + 'Kirby\\Cms\\LayoutColumn' => __DIR__ . '/../..' . '/kirby/src/Cms/LayoutColumn.php', + 'Kirby\\Cms\\LayoutColumns' => __DIR__ . '/../..' . '/kirby/src/Cms/LayoutColumns.php', + 'Kirby\\Cms\\Layouts' => __DIR__ . '/../..' . '/kirby/src/Cms/Layouts.php', + 'Kirby\\Cms\\Loader' => __DIR__ . '/../..' . '/kirby/src/Cms/Loader.php', + 'Kirby\\Cms\\Media' => __DIR__ . '/../..' . '/kirby/src/Cms/Media.php', + 'Kirby\\Cms\\Model' => __DIR__ . '/../..' . '/kirby/src/Cms/Model.php', + 'Kirby\\Cms\\ModelPermissions' => __DIR__ . '/../..' . '/kirby/src/Cms/ModelPermissions.php', + 'Kirby\\Cms\\ModelWithContent' => __DIR__ . '/../..' . '/kirby/src/Cms/ModelWithContent.php', + 'Kirby\\Cms\\Nest' => __DIR__ . '/../..' . '/kirby/src/Cms/Nest.php', + 'Kirby\\Cms\\NestCollection' => __DIR__ . '/../..' . '/kirby/src/Cms/NestCollection.php', + 'Kirby\\Cms\\NestObject' => __DIR__ . '/../..' . '/kirby/src/Cms/NestObject.php', + 'Kirby\\Cms\\Page' => __DIR__ . '/../..' . '/kirby/src/Cms/Page.php', + 'Kirby\\Cms\\PageActions' => __DIR__ . '/../..' . '/kirby/src/Cms/PageActions.php', + 'Kirby\\Cms\\PageBlueprint' => __DIR__ . '/../..' . '/kirby/src/Cms/PageBlueprint.php', + 'Kirby\\Cms\\PagePermissions' => __DIR__ . '/../..' . '/kirby/src/Cms/PagePermissions.php', + 'Kirby\\Cms\\PagePicker' => __DIR__ . '/../..' . '/kirby/src/Cms/PagePicker.php', + 'Kirby\\Cms\\PageRules' => __DIR__ . '/../..' . '/kirby/src/Cms/PageRules.php', + 'Kirby\\Cms\\PageSiblings' => __DIR__ . '/../..' . '/kirby/src/Cms/PageSiblings.php', + 'Kirby\\Cms\\Pages' => __DIR__ . '/../..' . '/kirby/src/Cms/Pages.php', + 'Kirby\\Cms\\Pagination' => __DIR__ . '/../..' . '/kirby/src/Cms/Pagination.php', + 'Kirby\\Cms\\Permissions' => __DIR__ . '/../..' . '/kirby/src/Cms/Permissions.php', + 'Kirby\\Cms\\Picker' => __DIR__ . '/../..' . '/kirby/src/Cms/Picker.php', + 'Kirby\\Cms\\Plugin' => __DIR__ . '/../..' . '/kirby/src/Cms/Plugin.php', + 'Kirby\\Cms\\PluginAssets' => __DIR__ . '/../..' . '/kirby/src/Cms/PluginAssets.php', + 'Kirby\\Cms\\R' => __DIR__ . '/../..' . '/kirby/src/Cms/R.php', + 'Kirby\\Cms\\Responder' => __DIR__ . '/../..' . '/kirby/src/Cms/Responder.php', + 'Kirby\\Cms\\Response' => __DIR__ . '/../..' . '/kirby/src/Cms/Response.php', + 'Kirby\\Cms\\Role' => __DIR__ . '/../..' . '/kirby/src/Cms/Role.php', + 'Kirby\\Cms\\Roles' => __DIR__ . '/../..' . '/kirby/src/Cms/Roles.php', + 'Kirby\\Cms\\S' => __DIR__ . '/../..' . '/kirby/src/Cms/S.php', + 'Kirby\\Cms\\Search' => __DIR__ . '/../..' . '/kirby/src/Cms/Search.php', + 'Kirby\\Cms\\Section' => __DIR__ . '/../..' . '/kirby/src/Cms/Section.php', + 'Kirby\\Cms\\Site' => __DIR__ . '/../..' . '/kirby/src/Cms/Site.php', + 'Kirby\\Cms\\SiteActions' => __DIR__ . '/../..' . '/kirby/src/Cms/SiteActions.php', + 'Kirby\\Cms\\SiteBlueprint' => __DIR__ . '/../..' . '/kirby/src/Cms/SiteBlueprint.php', + 'Kirby\\Cms\\SitePermissions' => __DIR__ . '/../..' . '/kirby/src/Cms/SitePermissions.php', + 'Kirby\\Cms\\SiteRules' => __DIR__ . '/../..' . '/kirby/src/Cms/SiteRules.php', + 'Kirby\\Cms\\Structure' => __DIR__ . '/../..' . '/kirby/src/Cms/Structure.php', + 'Kirby\\Cms\\StructureObject' => __DIR__ . '/../..' . '/kirby/src/Cms/StructureObject.php', + 'Kirby\\Cms\\System' => __DIR__ . '/../..' . '/kirby/src/Cms/System.php', + 'Kirby\\Cms\\Template' => __DIR__ . '/../..' . '/kirby/src/Cms/Template.php', + 'Kirby\\Cms\\Translation' => __DIR__ . '/../..' . '/kirby/src/Cms/Translation.php', + 'Kirby\\Cms\\Translations' => __DIR__ . '/../..' . '/kirby/src/Cms/Translations.php', + 'Kirby\\Cms\\Url' => __DIR__ . '/../..' . '/kirby/src/Cms/Url.php', + 'Kirby\\Cms\\User' => __DIR__ . '/../..' . '/kirby/src/Cms/User.php', + 'Kirby\\Cms\\UserActions' => __DIR__ . '/../..' . '/kirby/src/Cms/UserActions.php', + 'Kirby\\Cms\\UserBlueprint' => __DIR__ . '/../..' . '/kirby/src/Cms/UserBlueprint.php', + 'Kirby\\Cms\\UserPermissions' => __DIR__ . '/../..' . '/kirby/src/Cms/UserPermissions.php', + 'Kirby\\Cms\\UserPicker' => __DIR__ . '/../..' . '/kirby/src/Cms/UserPicker.php', + 'Kirby\\Cms\\UserRules' => __DIR__ . '/../..' . '/kirby/src/Cms/UserRules.php', + 'Kirby\\Cms\\Users' => __DIR__ . '/../..' . '/kirby/src/Cms/Users.php', + 'Kirby\\Cms\\Visitor' => __DIR__ . '/../..' . '/kirby/src/Cms/Visitor.php', + 'Kirby\\ComposerInstaller\\CmsInstaller' => __DIR__ . '/..' . '/getkirby/composer-installer/src/ComposerInstaller/CmsInstaller.php', + 'Kirby\\ComposerInstaller\\Installer' => __DIR__ . '/..' . '/getkirby/composer-installer/src/ComposerInstaller/Installer.php', + 'Kirby\\ComposerInstaller\\Plugin' => __DIR__ . '/..' . '/getkirby/composer-installer/src/ComposerInstaller/Plugin.php', + 'Kirby\\ComposerInstaller\\PluginInstaller' => __DIR__ . '/..' . '/getkirby/composer-installer/src/ComposerInstaller/PluginInstaller.php', + 'Kirby\\Data\\Data' => __DIR__ . '/../..' . '/kirby/src/Data/Data.php', + 'Kirby\\Data\\Handler' => __DIR__ . '/../..' . '/kirby/src/Data/Handler.php', + 'Kirby\\Data\\Json' => __DIR__ . '/../..' . '/kirby/src/Data/Json.php', + 'Kirby\\Data\\PHP' => __DIR__ . '/../..' . '/kirby/src/Data/PHP.php', + 'Kirby\\Data\\Txt' => __DIR__ . '/../..' . '/kirby/src/Data/Txt.php', + 'Kirby\\Data\\Xml' => __DIR__ . '/../..' . '/kirby/src/Data/Xml.php', + 'Kirby\\Data\\Yaml' => __DIR__ . '/../..' . '/kirby/src/Data/Yaml.php', + 'Kirby\\Database\\Database' => __DIR__ . '/../..' . '/kirby/src/Database/Database.php', + 'Kirby\\Database\\Db' => __DIR__ . '/../..' . '/kirby/src/Database/Db.php', + 'Kirby\\Database\\Query' => __DIR__ . '/../..' . '/kirby/src/Database/Query.php', + 'Kirby\\Database\\Sql' => __DIR__ . '/../..' . '/kirby/src/Database/Sql.php', + 'Kirby\\Database\\Sql\\Mysql' => __DIR__ . '/../..' . '/kirby/src/Database/Sql/Mysql.php', + 'Kirby\\Database\\Sql\\Sqlite' => __DIR__ . '/../..' . '/kirby/src/Database/Sql/Sqlite.php', + 'Kirby\\Email\\Body' => __DIR__ . '/../..' . '/kirby/src/Email/Body.php', + 'Kirby\\Email\\Email' => __DIR__ . '/../..' . '/kirby/src/Email/Email.php', + 'Kirby\\Email\\PHPMailer' => __DIR__ . '/../..' . '/kirby/src/Email/PHPMailer.php', + 'Kirby\\Exception\\BadMethodCallException' => __DIR__ . '/../..' . '/kirby/src/Exception/BadMethodCallException.php', + 'Kirby\\Exception\\DuplicateException' => __DIR__ . '/../..' . '/kirby/src/Exception/DuplicateException.php', + 'Kirby\\Exception\\ErrorPageException' => __DIR__ . '/../..' . '/kirby/src/Exception/ErrorPageException.php', + 'Kirby\\Exception\\Exception' => __DIR__ . '/../..' . '/kirby/src/Exception/Exception.php', + 'Kirby\\Exception\\InvalidArgumentException' => __DIR__ . '/../..' . '/kirby/src/Exception/InvalidArgumentException.php', + 'Kirby\\Exception\\LogicException' => __DIR__ . '/../..' . '/kirby/src/Exception/LogicException.php', + 'Kirby\\Exception\\NotFoundException' => __DIR__ . '/../..' . '/kirby/src/Exception/NotFoundException.php', + 'Kirby\\Exception\\PermissionException' => __DIR__ . '/../..' . '/kirby/src/Exception/PermissionException.php', + 'Kirby\\Filesystem\\Asset' => __DIR__ . '/../..' . '/kirby/src/Filesystem/Asset.php', + 'Kirby\\Filesystem\\Dir' => __DIR__ . '/../..' . '/kirby/src/Filesystem/Dir.php', + 'Kirby\\Filesystem\\F' => __DIR__ . '/../..' . '/kirby/src/Filesystem/F.php', + 'Kirby\\Filesystem\\File' => __DIR__ . '/../..' . '/kirby/src/Filesystem/File.php', + 'Kirby\\Filesystem\\Filename' => __DIR__ . '/../..' . '/kirby/src/Filesystem/Filename.php', + 'Kirby\\Filesystem\\IsFile' => __DIR__ . '/../..' . '/kirby/src/Filesystem/IsFile.php', + 'Kirby\\Filesystem\\Mime' => __DIR__ . '/../..' . '/kirby/src/Filesystem/Mime.php', + 'Kirby\\Form\\Field' => __DIR__ . '/../..' . '/kirby/src/Form/Field.php', + 'Kirby\\Form\\FieldClass' => __DIR__ . '/../..' . '/kirby/src/Form/FieldClass.php', + 'Kirby\\Form\\Field\\BlocksField' => __DIR__ . '/../..' . '/kirby/src/Form/Field/BlocksField.php', + 'Kirby\\Form\\Field\\LayoutField' => __DIR__ . '/../..' . '/kirby/src/Form/Field/LayoutField.php', + 'Kirby\\Form\\Fields' => __DIR__ . '/../..' . '/kirby/src/Form/Fields.php', + 'Kirby\\Form\\Form' => __DIR__ . '/../..' . '/kirby/src/Form/Form.php', + 'Kirby\\Form\\Mixin\\EmptyState' => __DIR__ . '/../..' . '/kirby/src/Form/Mixin/EmptyState.php', + 'Kirby\\Form\\Mixin\\Max' => __DIR__ . '/../..' . '/kirby/src/Form/Mixin/Max.php', + 'Kirby\\Form\\Mixin\\Min' => __DIR__ . '/../..' . '/kirby/src/Form/Mixin/Min.php', + 'Kirby\\Form\\Options' => __DIR__ . '/../..' . '/kirby/src/Form/Options.php', + 'Kirby\\Form\\OptionsApi' => __DIR__ . '/../..' . '/kirby/src/Form/OptionsApi.php', + 'Kirby\\Form\\OptionsQuery' => __DIR__ . '/../..' . '/kirby/src/Form/OptionsQuery.php', + 'Kirby\\Form\\Validations' => __DIR__ . '/../..' . '/kirby/src/Form/Validations.php', + 'Kirby\\Http\\Cookie' => __DIR__ . '/../..' . '/kirby/src/Http/Cookie.php', + 'Kirby\\Http\\Environment' => __DIR__ . '/../..' . '/kirby/src/Http/Environment.php', + 'Kirby\\Http\\Exceptions\\NextRouteException' => __DIR__ . '/../..' . '/kirby/src/Http/Exceptions/NextRouteException.php', + 'Kirby\\Http\\Header' => __DIR__ . '/../..' . '/kirby/src/Http/Header.php', + 'Kirby\\Http\\Idn' => __DIR__ . '/../..' . '/kirby/src/Http/Idn.php', + 'Kirby\\Http\\Params' => __DIR__ . '/../..' . '/kirby/src/Http/Params.php', + 'Kirby\\Http\\Path' => __DIR__ . '/../..' . '/kirby/src/Http/Path.php', + 'Kirby\\Http\\Query' => __DIR__ . '/../..' . '/kirby/src/Http/Query.php', + 'Kirby\\Http\\Remote' => __DIR__ . '/../..' . '/kirby/src/Http/Remote.php', + 'Kirby\\Http\\Request' => __DIR__ . '/../..' . '/kirby/src/Http/Request.php', + 'Kirby\\Http\\Request\\Auth' => __DIR__ . '/../..' . '/kirby/src/Http/Request/Auth.php', + 'Kirby\\Http\\Request\\Auth\\BasicAuth' => __DIR__ . '/../..' . '/kirby/src/Http/Request/Auth/BasicAuth.php', + 'Kirby\\Http\\Request\\Auth\\BearerAuth' => __DIR__ . '/../..' . '/kirby/src/Http/Request/Auth/BearerAuth.php', + 'Kirby\\Http\\Request\\Auth\\SessionAuth' => __DIR__ . '/../..' . '/kirby/src/Http/Request/Auth/SessionAuth.php', + 'Kirby\\Http\\Request\\Body' => __DIR__ . '/../..' . '/kirby/src/Http/Request/Body.php', + 'Kirby\\Http\\Request\\Data' => __DIR__ . '/../..' . '/kirby/src/Http/Request/Data.php', + 'Kirby\\Http\\Request\\Files' => __DIR__ . '/../..' . '/kirby/src/Http/Request/Files.php', + 'Kirby\\Http\\Request\\Query' => __DIR__ . '/../..' . '/kirby/src/Http/Request/Query.php', + 'Kirby\\Http\\Response' => __DIR__ . '/../..' . '/kirby/src/Http/Response.php', + 'Kirby\\Http\\Route' => __DIR__ . '/../..' . '/kirby/src/Http/Route.php', + 'Kirby\\Http\\Router' => __DIR__ . '/../..' . '/kirby/src/Http/Router.php', + 'Kirby\\Http\\Server' => __DIR__ . '/../..' . '/kirby/src/Http/Server.php', + 'Kirby\\Http\\Uri' => __DIR__ . '/../..' . '/kirby/src/Http/Uri.php', + 'Kirby\\Http\\Url' => __DIR__ . '/../..' . '/kirby/src/Http/Url.php', + 'Kirby\\Http\\Visitor' => __DIR__ . '/../..' . '/kirby/src/Http/Visitor.php', + 'Kirby\\Image\\Camera' => __DIR__ . '/../..' . '/kirby/src/Image/Camera.php', + 'Kirby\\Image\\Darkroom' => __DIR__ . '/../..' . '/kirby/src/Image/Darkroom.php', + 'Kirby\\Image\\Darkroom\\GdLib' => __DIR__ . '/../..' . '/kirby/src/Image/Darkroom/GdLib.php', + 'Kirby\\Image\\Darkroom\\ImageMagick' => __DIR__ . '/../..' . '/kirby/src/Image/Darkroom/ImageMagick.php', + 'Kirby\\Image\\Dimensions' => __DIR__ . '/../..' . '/kirby/src/Image/Dimensions.php', + 'Kirby\\Image\\Exif' => __DIR__ . '/../..' . '/kirby/src/Image/Exif.php', + 'Kirby\\Image\\Image' => __DIR__ . '/../..' . '/kirby/src/Image/Image.php', + 'Kirby\\Image\\Location' => __DIR__ . '/../..' . '/kirby/src/Image/Location.php', + 'Kirby\\Panel\\Dialog' => __DIR__ . '/../..' . '/kirby/src/Panel/Dialog.php', + 'Kirby\\Panel\\Document' => __DIR__ . '/../..' . '/kirby/src/Panel/Document.php', + 'Kirby\\Panel\\Dropdown' => __DIR__ . '/../..' . '/kirby/src/Panel/Dropdown.php', + 'Kirby\\Panel\\Field' => __DIR__ . '/../..' . '/kirby/src/Panel/Field.php', + 'Kirby\\Panel\\File' => __DIR__ . '/../..' . '/kirby/src/Panel/File.php', + 'Kirby\\Panel\\Home' => __DIR__ . '/../..' . '/kirby/src/Panel/Home.php', + 'Kirby\\Panel\\Json' => __DIR__ . '/../..' . '/kirby/src/Panel/Json.php', + 'Kirby\\Panel\\Model' => __DIR__ . '/../..' . '/kirby/src/Panel/Model.php', + 'Kirby\\Panel\\Page' => __DIR__ . '/../..' . '/kirby/src/Panel/Page.php', + 'Kirby\\Panel\\Panel' => __DIR__ . '/../..' . '/kirby/src/Panel/Panel.php', + 'Kirby\\Panel\\Plugins' => __DIR__ . '/../..' . '/kirby/src/Panel/Plugins.php', + 'Kirby\\Panel\\Redirect' => __DIR__ . '/../..' . '/kirby/src/Panel/Redirect.php', + 'Kirby\\Panel\\Search' => __DIR__ . '/../..' . '/kirby/src/Panel/Search.php', + 'Kirby\\Panel\\Site' => __DIR__ . '/../..' . '/kirby/src/Panel/Site.php', + 'Kirby\\Panel\\User' => __DIR__ . '/../..' . '/kirby/src/Panel/User.php', + 'Kirby\\Panel\\View' => __DIR__ . '/../..' . '/kirby/src/Panel/View.php', + 'Kirby\\Parsley\\Element' => __DIR__ . '/../..' . '/kirby/src/Parsley/Element.php', + 'Kirby\\Parsley\\Inline' => __DIR__ . '/../..' . '/kirby/src/Parsley/Inline.php', + 'Kirby\\Parsley\\Parsley' => __DIR__ . '/../..' . '/kirby/src/Parsley/Parsley.php', + 'Kirby\\Parsley\\Schema' => __DIR__ . '/../..' . '/kirby/src/Parsley/Schema.php', + 'Kirby\\Parsley\\Schema\\Blocks' => __DIR__ . '/../..' . '/kirby/src/Parsley/Schema/Blocks.php', + 'Kirby\\Parsley\\Schema\\Plain' => __DIR__ . '/../..' . '/kirby/src/Parsley/Schema/Plain.php', + 'Kirby\\Sane\\DomHandler' => __DIR__ . '/../..' . '/kirby/src/Sane/DomHandler.php', + 'Kirby\\Sane\\Handler' => __DIR__ . '/../..' . '/kirby/src/Sane/Handler.php', + 'Kirby\\Sane\\Html' => __DIR__ . '/../..' . '/kirby/src/Sane/Html.php', + 'Kirby\\Sane\\Sane' => __DIR__ . '/../..' . '/kirby/src/Sane/Sane.php', + 'Kirby\\Sane\\Svg' => __DIR__ . '/../..' . '/kirby/src/Sane/Svg.php', + 'Kirby\\Sane\\Svgz' => __DIR__ . '/../..' . '/kirby/src/Sane/Svgz.php', + 'Kirby\\Sane\\Xml' => __DIR__ . '/../..' . '/kirby/src/Sane/Xml.php', + 'Kirby\\Session\\AutoSession' => __DIR__ . '/../..' . '/kirby/src/Session/AutoSession.php', + 'Kirby\\Session\\FileSessionStore' => __DIR__ . '/../..' . '/kirby/src/Session/FileSessionStore.php', + 'Kirby\\Session\\Session' => __DIR__ . '/../..' . '/kirby/src/Session/Session.php', + 'Kirby\\Session\\SessionData' => __DIR__ . '/../..' . '/kirby/src/Session/SessionData.php', + 'Kirby\\Session\\SessionStore' => __DIR__ . '/../..' . '/kirby/src/Session/SessionStore.php', + 'Kirby\\Session\\Sessions' => __DIR__ . '/../..' . '/kirby/src/Session/Sessions.php', + 'Kirby\\Text\\KirbyTag' => __DIR__ . '/../..' . '/kirby/src/Text/KirbyTag.php', + 'Kirby\\Text\\KirbyTags' => __DIR__ . '/../..' . '/kirby/src/Text/KirbyTags.php', + 'Kirby\\Text\\Markdown' => __DIR__ . '/../..' . '/kirby/src/Text/Markdown.php', + 'Kirby\\Text\\SmartyPants' => __DIR__ . '/../..' . '/kirby/src/Text/SmartyPants.php', + 'Kirby\\Toolkit\\A' => __DIR__ . '/../..' . '/kirby/src/Toolkit/A.php', + 'Kirby\\Toolkit\\Collection' => __DIR__ . '/../..' . '/kirby/src/Toolkit/Collection.php', + 'Kirby\\Toolkit\\Component' => __DIR__ . '/../..' . '/kirby/src/Toolkit/Component.php', + 'Kirby\\Toolkit\\Config' => __DIR__ . '/../..' . '/kirby/src/Toolkit/Config.php', + 'Kirby\\Toolkit\\Controller' => __DIR__ . '/../..' . '/kirby/src/Toolkit/Controller.php', + 'Kirby\\Toolkit\\Date' => __DIR__ . '/../..' . '/kirby/src/Toolkit/Date.php', + 'Kirby\\Toolkit\\Dom' => __DIR__ . '/../..' . '/kirby/src/Toolkit/Dom.php', + 'Kirby\\Toolkit\\Escape' => __DIR__ . '/../..' . '/kirby/src/Toolkit/Escape.php', + 'Kirby\\Toolkit\\Facade' => __DIR__ . '/../..' . '/kirby/src/Toolkit/Facade.php', + 'Kirby\\Toolkit\\Html' => __DIR__ . '/../..' . '/kirby/src/Toolkit/Html.php', + 'Kirby\\Toolkit\\I18n' => __DIR__ . '/../..' . '/kirby/src/Toolkit/I18n.php', + 'Kirby\\Toolkit\\Iterator' => __DIR__ . '/../..' . '/kirby/src/Toolkit/Iterator.php', + 'Kirby\\Toolkit\\Locale' => __DIR__ . '/../..' . '/kirby/src/Toolkit/Locale.php', + 'Kirby\\Toolkit\\Obj' => __DIR__ . '/../..' . '/kirby/src/Toolkit/Obj.php', + 'Kirby\\Toolkit\\Pagination' => __DIR__ . '/../..' . '/kirby/src/Toolkit/Pagination.php', + 'Kirby\\Toolkit\\Properties' => __DIR__ . '/../..' . '/kirby/src/Toolkit/Properties.php', + 'Kirby\\Toolkit\\Query' => __DIR__ . '/../..' . '/kirby/src/Toolkit/Query.php', + 'Kirby\\Toolkit\\Silo' => __DIR__ . '/../..' . '/kirby/src/Toolkit/Silo.php', + 'Kirby\\Toolkit\\Str' => __DIR__ . '/../..' . '/kirby/src/Toolkit/Str.php', + 'Kirby\\Toolkit\\Tpl' => __DIR__ . '/../..' . '/kirby/src/Toolkit/Tpl.php', + 'Kirby\\Toolkit\\V' => __DIR__ . '/../..' . '/kirby/src/Toolkit/V.php', + 'Kirby\\Toolkit\\View' => __DIR__ . '/../..' . '/kirby/src/Toolkit/View.php', + 'Kirby\\Toolkit\\Xml' => __DIR__ . '/../..' . '/kirby/src/Toolkit/Xml.php', + 'Laminas\\Escaper\\Escaper' => __DIR__ . '/..' . '/laminas/laminas-escaper/src/Escaper.php', + 'Laminas\\Escaper\\Exception\\ExceptionInterface' => __DIR__ . '/..' . '/laminas/laminas-escaper/src/Exception/ExceptionInterface.php', + 'Laminas\\Escaper\\Exception\\InvalidArgumentException' => __DIR__ . '/..' . '/laminas/laminas-escaper/src/Exception/InvalidArgumentException.php', + 'Laminas\\Escaper\\Exception\\RuntimeException' => __DIR__ . '/..' . '/laminas/laminas-escaper/src/Exception/RuntimeException.php', + 'League\\ColorExtractor\\Color' => __DIR__ . '/..' . '/league/color-extractor/src/League/ColorExtractor/Color.php', + 'League\\ColorExtractor\\ColorExtractor' => __DIR__ . '/..' . '/league/color-extractor/src/League/ColorExtractor/ColorExtractor.php', + 'League\\ColorExtractor\\Palette' => __DIR__ . '/..' . '/league/color-extractor/src/League/ColorExtractor/Palette.php', + 'ML\\IRI\\IRI' => __DIR__ . '/..' . '/ml/iri/ML/IRI/IRI.php', + 'ML\\IRI\\Test\\IriTest' => __DIR__ . '/..' . '/ml/iri/ML/IRI/Test/IriTest.php', + 'ML\\JsonLD\\DefaultDocumentFactory' => __DIR__ . '/..' . '/ml/json-ld/DefaultDocumentFactory.php', + 'ML\\JsonLD\\Document' => __DIR__ . '/..' . '/ml/json-ld/Document.php', + 'ML\\JsonLD\\DocumentFactoryInterface' => __DIR__ . '/..' . '/ml/json-ld/DocumentFactoryInterface.php', + 'ML\\JsonLD\\DocumentInterface' => __DIR__ . '/..' . '/ml/json-ld/DocumentInterface.php', + 'ML\\JsonLD\\DocumentLoaderInterface' => __DIR__ . '/..' . '/ml/json-ld/DocumentLoaderInterface.php', + 'ML\\JsonLD\\Exception\\InvalidQuadException' => __DIR__ . '/..' . '/ml/json-ld/Exception/InvalidQuadException.php', + 'ML\\JsonLD\\Exception\\JsonLdException' => __DIR__ . '/..' . '/ml/json-ld/Exception/JsonLdException.php', + 'ML\\JsonLD\\FileGetContentsLoader' => __DIR__ . '/..' . '/ml/json-ld/FileGetContentsLoader.php', + 'ML\\JsonLD\\Graph' => __DIR__ . '/..' . '/ml/json-ld/Graph.php', + 'ML\\JsonLD\\GraphInterface' => __DIR__ . '/..' . '/ml/json-ld/GraphInterface.php', + 'ML\\JsonLD\\JsonLD' => __DIR__ . '/..' . '/ml/json-ld/JsonLD.php', + 'ML\\JsonLD\\JsonLdSerializable' => __DIR__ . '/..' . '/ml/json-ld/JsonLdSerializable.php', + 'ML\\JsonLD\\LanguageTaggedString' => __DIR__ . '/..' . '/ml/json-ld/LanguageTaggedString.php', + 'ML\\JsonLD\\NQuads' => __DIR__ . '/..' . '/ml/json-ld/NQuads.php', + 'ML\\JsonLD\\Node' => __DIR__ . '/..' . '/ml/json-ld/Node.php', + 'ML\\JsonLD\\NodeInterface' => __DIR__ . '/..' . '/ml/json-ld/NodeInterface.php', + 'ML\\JsonLD\\Processor' => __DIR__ . '/..' . '/ml/json-ld/Processor.php', + 'ML\\JsonLD\\Quad' => __DIR__ . '/..' . '/ml/json-ld/Quad.php', + 'ML\\JsonLD\\QuadParserInterface' => __DIR__ . '/..' . '/ml/json-ld/QuadParserInterface.php', + 'ML\\JsonLD\\QuadSerializerInterface' => __DIR__ . '/..' . '/ml/json-ld/QuadSerializerInterface.php', + 'ML\\JsonLD\\RdfConstants' => __DIR__ . '/..' . '/ml/json-ld/RdfConstants.php', + 'ML\\JsonLD\\RemoteDocument' => __DIR__ . '/..' . '/ml/json-ld/RemoteDocument.php', + 'ML\\JsonLD\\Test\\DocumentTest' => __DIR__ . '/..' . '/ml/json-ld/Test/DocumentTest.php', + 'ML\\JsonLD\\Test\\EarlReportGenerator' => __DIR__ . '/..' . '/ml/json-ld/Test/EarlReportGenerator.php', + 'ML\\JsonLD\\Test\\FileGetContentsLoaderTest' => __DIR__ . '/..' . '/ml/json-ld/Test/FileGetContentsLoaderTest.php', + 'ML\\JsonLD\\Test\\GraphTest' => __DIR__ . '/..' . '/ml/json-ld/Test/GraphTest.php', + 'ML\\JsonLD\\Test\\JsonLDApiTest' => __DIR__ . '/..' . '/ml/json-ld/Test/JsonLDApiTest.php', + 'ML\\JsonLD\\Test\\JsonTestCase' => __DIR__ . '/..' . '/ml/json-ld/Test/JsonTestCase.php', + 'ML\\JsonLD\\Test\\NQuadsTest' => __DIR__ . '/..' . '/ml/json-ld/Test/NQuadsTest.php', + 'ML\\JsonLD\\Test\\TestManifestIterator' => __DIR__ . '/..' . '/ml/json-ld/Test/TestManifestIterator.php', + 'ML\\JsonLD\\Test\\ValueTest' => __DIR__ . '/..' . '/ml/json-ld/Test/ValueTest.php', + 'ML\\JsonLD\\Test\\W3CTestSuiteTest' => __DIR__ . '/..' . '/ml/json-ld/Test/W3CTestSuiteTest.php', + 'ML\\JsonLD\\TypedValue' => __DIR__ . '/..' . '/ml/json-ld/TypedValue.php', + 'ML\\JsonLD\\Value' => __DIR__ . '/..' . '/ml/json-ld/Value.php', + 'Michelf\\SmartyPants' => __DIR__ . '/..' . '/michelf/php-smartypants/Michelf/SmartyPants.php', + 'Michelf\\SmartyPantsTypographer' => __DIR__ . '/..' . '/michelf/php-smartypants/Michelf/SmartyPantsTypographer.php', + 'Normalizer' => __DIR__ . '/..' . '/symfony/polyfill-intl-normalizer/Resources/stubs/Normalizer.php', + 'PHPMailer\\PHPMailer\\Exception' => __DIR__ . '/..' . '/phpmailer/phpmailer/src/Exception.php', + 'PHPMailer\\PHPMailer\\OAuth' => __DIR__ . '/..' . '/phpmailer/phpmailer/src/OAuth.php', + 'PHPMailer\\PHPMailer\\OAuthTokenProvider' => __DIR__ . '/..' . '/phpmailer/phpmailer/src/OAuthTokenProvider.php', + 'PHPMailer\\PHPMailer\\PHPMailer' => __DIR__ . '/..' . '/phpmailer/phpmailer/src/PHPMailer.php', + 'PHPMailer\\PHPMailer\\POP3' => __DIR__ . '/..' . '/phpmailer/phpmailer/src/POP3.php', + 'PHPMailer\\PHPMailer\\SMTP' => __DIR__ . '/..' . '/phpmailer/phpmailer/src/SMTP.php', + 'Parsedown' => __DIR__ . '/../..' . '/kirby/dependencies/parsedown/Parsedown.php', + 'ParsedownExtra' => __DIR__ . '/../..' . '/kirby/dependencies/parsedown-extra/ParsedownExtra.php', + 'Psr\\Http\\Client\\ClientExceptionInterface' => __DIR__ . '/..' . '/psr/http-client/src/ClientExceptionInterface.php', + 'Psr\\Http\\Client\\ClientInterface' => __DIR__ . '/..' . '/psr/http-client/src/ClientInterface.php', + 'Psr\\Http\\Client\\NetworkExceptionInterface' => __DIR__ . '/..' . '/psr/http-client/src/NetworkExceptionInterface.php', + 'Psr\\Http\\Client\\RequestExceptionInterface' => __DIR__ . '/..' . '/psr/http-client/src/RequestExceptionInterface.php', + 'Psr\\Http\\Message\\MessageInterface' => __DIR__ . '/..' . '/psr/http-message/src/MessageInterface.php', + 'Psr\\Http\\Message\\RequestFactoryInterface' => __DIR__ . '/..' . '/psr/http-factory/src/RequestFactoryInterface.php', + 'Psr\\Http\\Message\\RequestInterface' => __DIR__ . '/..' . '/psr/http-message/src/RequestInterface.php', + 'Psr\\Http\\Message\\ResponseFactoryInterface' => __DIR__ . '/..' . '/psr/http-factory/src/ResponseFactoryInterface.php', + 'Psr\\Http\\Message\\ResponseInterface' => __DIR__ . '/..' . '/psr/http-message/src/ResponseInterface.php', + 'Psr\\Http\\Message\\ServerRequestFactoryInterface' => __DIR__ . '/..' . '/psr/http-factory/src/ServerRequestFactoryInterface.php', + 'Psr\\Http\\Message\\ServerRequestInterface' => __DIR__ . '/..' . '/psr/http-message/src/ServerRequestInterface.php', + 'Psr\\Http\\Message\\StreamFactoryInterface' => __DIR__ . '/..' . '/psr/http-factory/src/StreamFactoryInterface.php', + 'Psr\\Http\\Message\\StreamInterface' => __DIR__ . '/..' . '/psr/http-message/src/StreamInterface.php', + 'Psr\\Http\\Message\\UploadedFileFactoryInterface' => __DIR__ . '/..' . '/psr/http-factory/src/UploadedFileFactoryInterface.php', + 'Psr\\Http\\Message\\UploadedFileInterface' => __DIR__ . '/..' . '/psr/http-message/src/UploadedFileInterface.php', + 'Psr\\Http\\Message\\UriFactoryInterface' => __DIR__ . '/..' . '/psr/http-factory/src/UriFactoryInterface.php', + 'Psr\\Http\\Message\\UriInterface' => __DIR__ . '/..' . '/psr/http-message/src/UriInterface.php', + 'Psr\\Log\\AbstractLogger' => __DIR__ . '/..' . '/psr/log/Psr/Log/AbstractLogger.php', + 'Psr\\Log\\InvalidArgumentException' => __DIR__ . '/..' . '/psr/log/Psr/Log/InvalidArgumentException.php', + 'Psr\\Log\\LogLevel' => __DIR__ . '/..' . '/psr/log/Psr/Log/LogLevel.php', + 'Psr\\Log\\LoggerAwareInterface' => __DIR__ . '/..' . '/psr/log/Psr/Log/LoggerAwareInterface.php', + 'Psr\\Log\\LoggerAwareTrait' => __DIR__ . '/..' . '/psr/log/Psr/Log/LoggerAwareTrait.php', + 'Psr\\Log\\LoggerInterface' => __DIR__ . '/..' . '/psr/log/Psr/Log/LoggerInterface.php', + 'Psr\\Log\\LoggerTrait' => __DIR__ . '/..' . '/psr/log/Psr/Log/LoggerTrait.php', + 'Psr\\Log\\NullLogger' => __DIR__ . '/..' . '/psr/log/Psr/Log/NullLogger.php', + 'Psr\\Log\\Test\\DummyTest' => __DIR__ . '/..' . '/psr/log/Psr/Log/Test/DummyTest.php', + 'Psr\\Log\\Test\\LoggerInterfaceTest' => __DIR__ . '/..' . '/psr/log/Psr/Log/Test/LoggerInterfaceTest.php', + 'Psr\\Log\\Test\\TestLogger' => __DIR__ . '/..' . '/psr/log/Psr/Log/Test/TestLogger.php', + 'Spyc' => __DIR__ . '/../..' . '/kirby/dependencies/spyc/Spyc.php', + 'Symfony\\Polyfill\\Intl\\Idn\\Idn' => __DIR__ . '/..' . '/symfony/polyfill-intl-idn/Idn.php', + 'Symfony\\Polyfill\\Intl\\Idn\\Info' => __DIR__ . '/..' . '/symfony/polyfill-intl-idn/Info.php', + 'Symfony\\Polyfill\\Intl\\Idn\\Resources\\unidata\\DisallowedRanges' => __DIR__ . '/..' . '/symfony/polyfill-intl-idn/Resources/unidata/DisallowedRanges.php', + 'Symfony\\Polyfill\\Intl\\Idn\\Resources\\unidata\\Regex' => __DIR__ . '/..' . '/symfony/polyfill-intl-idn/Resources/unidata/Regex.php', + 'Symfony\\Polyfill\\Intl\\Normalizer\\Normalizer' => __DIR__ . '/..' . '/symfony/polyfill-intl-normalizer/Normalizer.php', + 'Symfony\\Polyfill\\Mbstring\\Mbstring' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/Mbstring.php', + 'Whoops\\Exception\\ErrorException' => __DIR__ . '/..' . '/filp/whoops/src/Whoops/Exception/ErrorException.php', + 'Whoops\\Exception\\Formatter' => __DIR__ . '/..' . '/filp/whoops/src/Whoops/Exception/Formatter.php', + 'Whoops\\Exception\\Frame' => __DIR__ . '/..' . '/filp/whoops/src/Whoops/Exception/Frame.php', + 'Whoops\\Exception\\FrameCollection' => __DIR__ . '/..' . '/filp/whoops/src/Whoops/Exception/FrameCollection.php', + 'Whoops\\Exception\\Inspector' => __DIR__ . '/..' . '/filp/whoops/src/Whoops/Exception/Inspector.php', + 'Whoops\\Handler\\CallbackHandler' => __DIR__ . '/..' . '/filp/whoops/src/Whoops/Handler/CallbackHandler.php', + 'Whoops\\Handler\\Handler' => __DIR__ . '/..' . '/filp/whoops/src/Whoops/Handler/Handler.php', + 'Whoops\\Handler\\HandlerInterface' => __DIR__ . '/..' . '/filp/whoops/src/Whoops/Handler/HandlerInterface.php', + 'Whoops\\Handler\\JsonResponseHandler' => __DIR__ . '/..' . '/filp/whoops/src/Whoops/Handler/JsonResponseHandler.php', + 'Whoops\\Handler\\PlainTextHandler' => __DIR__ . '/..' . '/filp/whoops/src/Whoops/Handler/PlainTextHandler.php', + 'Whoops\\Handler\\PrettyPageHandler' => __DIR__ . '/..' . '/filp/whoops/src/Whoops/Handler/PrettyPageHandler.php', + 'Whoops\\Handler\\XmlResponseHandler' => __DIR__ . '/..' . '/filp/whoops/src/Whoops/Handler/XmlResponseHandler.php', + 'Whoops\\Run' => __DIR__ . '/..' . '/filp/whoops/src/Whoops/Run.php', + 'Whoops\\RunInterface' => __DIR__ . '/..' . '/filp/whoops/src/Whoops/RunInterface.php', + 'Whoops\\Util\\HtmlDumperOutput' => __DIR__ . '/..' . '/filp/whoops/src/Whoops/Util/HtmlDumperOutput.php', + 'Whoops\\Util\\Misc' => __DIR__ . '/..' . '/filp/whoops/src/Whoops/Util/Misc.php', + 'Whoops\\Util\\SystemFacade' => __DIR__ . '/..' . '/filp/whoops/src/Whoops/Util/SystemFacade.php', + 'Whoops\\Util\\TemplateHelper' => __DIR__ . '/..' . '/filp/whoops/src/Whoops/Util/TemplateHelper.php', + 'claviska\\SimpleImage' => __DIR__ . '/..' . '/claviska/simpleimage/src/claviska/SimpleImage.php', + ); + + public static function getInitializer(ClassLoader $loader) + { + return \Closure::bind(function () use ($loader) { + $loader->prefixLengthsPsr4 = ComposerStaticInit34ad0fcfd7efff0ce7004033b941cfcf::$prefixLengthsPsr4; + $loader->prefixDirsPsr4 = ComposerStaticInit34ad0fcfd7efff0ce7004033b941cfcf::$prefixDirsPsr4; + $loader->fallbackDirsPsr4 = ComposerStaticInit34ad0fcfd7efff0ce7004033b941cfcf::$fallbackDirsPsr4; + $loader->prefixesPsr0 = ComposerStaticInit34ad0fcfd7efff0ce7004033b941cfcf::$prefixesPsr0; + $loader->classMap = ComposerStaticInit34ad0fcfd7efff0ce7004033b941cfcf::$classMap; + + }, null, ClassLoader::class); + } +} diff --git a/site/plugins/embed/vendor/composer/ca-bundle/LICENSE b/vendor/composer/ca-bundle/LICENSE similarity index 100% rename from site/plugins/embed/vendor/composer/ca-bundle/LICENSE rename to vendor/composer/ca-bundle/LICENSE diff --git a/site/plugins/embed/vendor/composer/ca-bundle/README.md b/vendor/composer/ca-bundle/README.md similarity index 100% rename from site/plugins/embed/vendor/composer/ca-bundle/README.md rename to vendor/composer/ca-bundle/README.md diff --git a/site/plugins/embed/vendor/composer/ca-bundle/composer.json b/vendor/composer/ca-bundle/composer.json similarity index 81% rename from site/plugins/embed/vendor/composer/ca-bundle/composer.json rename to vendor/composer/ca-bundle/composer.json index ed6a1b3..c2ed5ac 100644 --- a/site/plugins/embed/vendor/composer/ca-bundle/composer.json +++ b/vendor/composer/ca-bundle/composer.json @@ -24,13 +24,13 @@ "require": { "ext-openssl": "*", "ext-pcre": "*", - "php": "^5.3.2 || ^7.0 || ^8.0" + "php": "^7.2 || ^8.0" }, "require-dev": { "symfony/phpunit-bridge": "^4.2 || ^5", - "phpstan/phpstan": "^0.12.55", - "psr/log": "^1.0", - "symfony/process": "^2.5 || ^3.0 || ^4.0 || ^5.0 || ^6.0" + "phpstan/phpstan": "^1.10", + "psr/log": "^1.0 || ^2.0 || ^3.0", + "symfony/process": "^4.0 || ^5.0 || ^6.0 || ^7.0" }, "autoload": { "psr-4": { @@ -48,7 +48,7 @@ } }, "scripts": { - "test": "SYMFONY_PHPUNIT_REMOVE_RETURN_TYPEHINT=1 vendor/bin/simple-phpunit", + "test": "vendor/bin/simple-phpunit", "phpstan": "vendor/bin/phpstan analyse" } } diff --git a/site/plugins/embed/vendor/composer/ca-bundle/res/cacert.pem b/vendor/composer/ca-bundle/res/cacert.pem similarity index 94% rename from site/plugins/embed/vendor/composer/ca-bundle/res/cacert.pem rename to vendor/composer/ca-bundle/res/cacert.pem index 9551dfd..86d6cd8 100644 --- a/site/plugins/embed/vendor/composer/ca-bundle/res/cacert.pem +++ b/vendor/composer/ca-bundle/res/cacert.pem @@ -1,7 +1,7 @@ ## ## Bundle of CA Root Certificates ## -## Certificate data from Mozilla as of: Tue Aug 22 03:12:04 2023 GMT +## Certificate data from Mozilla as of: Tue Jul 2 03:12:04 2024 GMT ## ## This is a bundle of X.509 certificates of public Certificate Authorities ## (CA). These were automatically extracted from Mozilla's root certificates @@ -14,7 +14,7 @@ ## Just configure this file as the SSLCACertificateFile. ## ## Conversion done with mk-ca-bundle.pl version 1.29. -## SHA256: 0ff137babc6a5561a9cfbe9f29558972e5b528202681b7d3803d03a3e82922bd +## SHA256: 456ff095dde6dd73354c5c28c73d9c06f53b61a803963414cb91a1d92945cdd3 ## @@ -200,27 +200,6 @@ vGJHvOB0K7Lrfb5BG7XARsWhIstfTsEokt4YutUqKLsRixeTmJlglFwjz1onl14LBQaTNx47aTbr qZ5hHY8y2o4M1nQ+ewkk2gF3R8Q7zTSMmfXK4SVhM7JZG+Ju1zdXtg2pEto= -----END CERTIFICATE----- -Security Communication Root CA -============================== ------BEGIN CERTIFICATE----- -MIIDWjCCAkKgAwIBAgIBADANBgkqhkiG9w0BAQUFADBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMP -U0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEw -HhcNMDMwOTMwMDQyMDQ5WhcNMjMwOTMwMDQyMDQ5WjBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMP -U0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEw -ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCzs/5/022x7xZ8V6UMbXaKL0u/ZPtM7orw -8yl89f/uKuDp6bpbZCKamm8sOiZpUQWZJtzVHGpxxpp9Hp3dfGzGjGdnSj74cbAZJ6kJDKaVv0uM -DPpVmDvY6CKhS3E4eayXkmmziX7qIWgGmBSWh9JhNrxtJ1aeV+7AwFb9Ms+k2Y7CI9eNqPPYJayX -5HA49LY6tJ07lyZDo6G8SVlyTCMwhwFY9k6+HGhWZq/NQV3Is00qVUarH9oe4kA92819uZKAnDfd -DJZkndwi92SL32HeFZRSFaB9UslLqCHJxrHty8OVYNEP8Ktw+N/LTX7s1vqr2b1/VPKl6Xn62dZ2 -JChzAgMBAAGjPzA9MB0GA1UdDgQWBBSgc0mZaNyFW2XjmygvV5+9M7wHSDALBgNVHQ8EBAMCAQYw -DwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAaECpqLvkT115swW1F7NgE+vGkl3g -0dNq/vu+m22/xwVtWSDEHPC32oRYAmP6SBbvT6UL90qY8j+eG61Ha2POCEfrUj94nK9NrvjVT8+a -mCoQQTlSxN3Zmw7vkwGusi7KaEIkQmywszo+zenaSMQVy+n5Bw+SUEmK3TGXX8npN6o7WWWXlDLJ -s58+OmJYxUmtYg5xpTKqL8aJdkNAExNnPaJUJRDL8Try2frbSVa7pv6nQTXD4IhhyYjH3zYQIphZ -6rBK+1YWc26sTfcioU+tHXotRSflMMFe8toTyyVCUZVHA4xsIcx0Qu1T/zOLjw9XARYvz6buyXAi -FL39vmwLAw== ------END CERTIFICATE----- - XRamp Global CA Root ==================== -----BEGIN CERTIFICATE----- @@ -669,39 +648,6 @@ YIvDQVETI53O9zJrlAGomecsMx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7r kpeDMdmztcpHWD9f -----END CERTIFICATE----- -Autoridad de Certificacion Firmaprofesional CIF A62634068 -========================================================= ------BEGIN CERTIFICATE----- -MIIGFDCCA/ygAwIBAgIIU+w77vuySF8wDQYJKoZIhvcNAQEFBQAwUTELMAkGA1UEBhMCRVMxQjBA -BgNVBAMMOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1hcHJvZmVzaW9uYWwgQ0lGIEE2 -MjYzNDA2ODAeFw0wOTA1MjAwODM4MTVaFw0zMDEyMzEwODM4MTVaMFExCzAJBgNVBAYTAkVTMUIw -QAYDVQQDDDlBdXRvcmlkYWQgZGUgQ2VydGlmaWNhY2lvbiBGaXJtYXByb2Zlc2lvbmFsIENJRiBB -NjI2MzQwNjgwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKlmuO6vj78aI14H9M2uDD -Utd9thDIAl6zQyrET2qyyhxdKJp4ERppWVevtSBC5IsP5t9bpgOSL/UR5GLXMnE42QQMcas9UX4P -B99jBVzpv5RvwSmCwLTaUbDBPLutN0pcyvFLNg4kq7/DhHf9qFD0sefGL9ItWY16Ck6WaVICqjaY -7Pz6FIMMNx/Jkjd/14Et5cS54D40/mf0PmbR0/RAz15iNA9wBj4gGFrO93IbJWyTdBSTo3OxDqqH -ECNZXyAFGUftaI6SEspd/NYrspI8IM/hX68gvqB2f3bl7BqGYTM+53u0P6APjqK5am+5hyZvQWyI -plD9amML9ZMWGxmPsu2bm8mQ9QEM3xk9Dz44I8kvjwzRAv4bVdZO0I08r0+k8/6vKtMFnXkIoctX -MbScyJCyZ/QYFpM6/EfY0XiWMR+6KwxfXZmtY4laJCB22N/9q06mIqqdXuYnin1oKaPnirjaEbsX -LZmdEyRG98Xi2J+Of8ePdG1asuhy9azuJBCtLxTa/y2aRnFHvkLfuwHb9H/TKI8xWVvTyQKmtFLK -bpf7Q8UIJm+K9Lv9nyiqDdVF8xM6HdjAeI9BZzwelGSuewvF6NkBiDkal4ZkQdU7hwxu+g/GvUgU -vzlN1J5Bto+WHWOWk9mVBngxaJ43BjuAiUVhOSPHG0SjFeUc+JIwuwIDAQABo4HvMIHsMBIGA1Ud -EwEB/wQIMAYBAf8CAQEwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRlzeurNR4APn7VdMActHNH -DhpkLzCBpgYDVR0gBIGeMIGbMIGYBgRVHSAAMIGPMC8GCCsGAQUFBwIBFiNodHRwOi8vd3d3LmZp -cm1hcHJvZmVzaW9uYWwuY29tL2NwczBcBggrBgEFBQcCAjBQHk4AUABhAHMAZQBvACAAZABlACAA -bABhACAAQgBvAG4AYQBuAG8AdgBhACAANAA3ACAAQgBhAHIAYwBlAGwAbwBuAGEAIAAwADgAMAAx -ADcwDQYJKoZIhvcNAQEFBQADggIBABd9oPm03cXF661LJLWhAqvdpYhKsg9VSytXjDvlMd3+xDLx -51tkljYyGOylMnfX40S2wBEqgLk9am58m9Ot/MPWo+ZkKXzR4Tgegiv/J2Wv+xYVxC5xhOW1//qk -R71kMrv2JYSiJ0L1ILDCExARzRAVukKQKtJE4ZYm6zFIEv0q2skGz3QeqUvVhyj5eTSSPi5E6PaP -T481PyWzOdxjKpBrIF/EUhJOlywqrJ2X3kjyo2bbwtKDlaZmp54lD+kLM5FlClrD2VQS3a/DTg4f -Jl4N3LON7NWBcN7STyQF82xO9UxJZo3R/9ILJUFI/lGExkKvgATP0H5kSeTy36LssUzAKh3ntLFl -osS88Zj0qnAHY7S42jtM+kAiMFsRpvAFDsYCA0irhpuF3dvd6qJ2gHN99ZwExEWN57kci57q13XR -crHedUTnQn3iV2t93Jm8PYMo6oCTjcVMZcFwgbg4/EMxsvYDNEeyrPsiBsse3RdHHF9mudMaotoR -saS8I8nkvof/uZS2+F0gStRf571oe2XyFR7SOqkt6dhrJKyXWERHrVkY8SFlcN7ONGCoQPHzPKTD -KCOM/iczQ0CgFzzr6juwcqajuUpLXhZI9LK8yIySxZ2frHI2vDSANGupi5LAuBft7HZT9SQBjLMi -6Et8Vcad+qMUu2WFbm5PEn4KPJ2V ------END CERTIFICATE----- - Izenpe.com ========== -----BEGIN CERTIFICATE----- @@ -2654,36 +2600,6 @@ vLtoURMMA/cVi4RguYv/Uo7njLwcAjA8+RHUjE7AwWHCFUyqqx0LMV87HOIAl0Qx5v5zli/altP+ CAezNIm8BZ/3Hobui3A= -----END CERTIFICATE----- -GLOBALTRUST 2020 -================ ------BEGIN CERTIFICATE----- -MIIFgjCCA2qgAwIBAgILWku9WvtPilv6ZeUwDQYJKoZIhvcNAQELBQAwTTELMAkGA1UEBhMCQVQx -IzAhBgNVBAoTGmUtY29tbWVyY2UgbW9uaXRvcmluZyBHbWJIMRkwFwYDVQQDExBHTE9CQUxUUlVT -VCAyMDIwMB4XDTIwMDIxMDAwMDAwMFoXDTQwMDYxMDAwMDAwMFowTTELMAkGA1UEBhMCQVQxIzAh -BgNVBAoTGmUtY29tbWVyY2UgbW9uaXRvcmluZyBHbWJIMRkwFwYDVQQDExBHTE9CQUxUUlVTVCAy -MDIwMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAri5WrRsc7/aVj6B3GyvTY4+ETUWi -D59bRatZe1E0+eyLinjF3WuvvcTfk0Uev5E4C64OFudBc/jbu9G4UeDLgztzOG53ig9ZYybNpyrO -VPu44sB8R85gfD+yc/LAGbaKkoc1DZAoouQVBGM+uq/ufF7MpotQsjj3QWPKzv9pj2gOlTblzLmM -CcpL3TGQlsjMH/1WljTbjhzqLL6FLmPdqqmV0/0plRPwyJiT2S0WR5ARg6I6IqIoV6Lr/sCMKKCm -fecqQjuCgGOlYx8ZzHyyZqjC0203b+J+BlHZRYQfEs4kUmSFC0iAToexIiIwquuuvuAC4EDosEKA -A1GqtH6qRNdDYfOiaxaJSaSjpCuKAsR49GiKweR6NrFvG5Ybd0mN1MkGco/PU+PcF4UgStyYJ9OR -JitHHmkHr96i5OTUawuzXnzUJIBHKWk7buis/UDr2O1xcSvy6Fgd60GXIsUf1DnQJ4+H4xj04KlG -DfV0OoIu0G4skaMxXDtG6nsEEFZegB31pWXogvziB4xiRfUg3kZwhqG8k9MedKZssCz3AwyIDMvU -clOGvGBG85hqwvG/Q/lwIHfKN0F5VVJjjVsSn8VoxIidrPIwq7ejMZdnrY8XD2zHc+0klGvIg5rQ -mjdJBKuxFshsSUktq6HQjJLyQUp5ISXbY9e2nKd+Qmn7OmMCAwEAAaNjMGEwDwYDVR0TAQH/BAUw -AwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFNwuH9FhN3nkq9XVsxJxaD1qaJwiMB8GA1Ud -IwQYMBaAFNwuH9FhN3nkq9XVsxJxaD1qaJwiMA0GCSqGSIb3DQEBCwUAA4ICAQCR8EICaEDuw2jA -VC/f7GLDw56KoDEoqoOOpFaWEhCGVrqXctJUMHytGdUdaG/7FELYjQ7ztdGl4wJCXtzoRlgHNQIw -4Lx0SsFDKv/bGtCwr2zD/cuz9X9tAy5ZVp0tLTWMstZDFyySCstd6IwPS3BD0IL/qMy/pJTAvoe9 -iuOTe8aPmxadJ2W8esVCgmxcB9CpwYhgROmYhRZf+I/KARDOJcP5YBugxZfD0yyIMaK9MOzQ0MAS -8cE54+X1+NZK3TTN+2/BT+MAi1bikvcoskJ3ciNnxz8RFbLEAwW+uxF7Cr+obuf/WEPPm2eggAe2 -HcqtbepBEX4tdJP7wry+UUTF72glJ4DjyKDUEuzZpTcdN3y0kcra1LGWge9oXHYQSa9+pTeAsRxS -vTOBTI/53WXZFM2KJVj04sWDpQmQ1GwUY7VA3+vA/MRYfg0UFodUJ25W5HCEuGwyEn6CMUO+1918 -oa2u1qsgEu8KwxCMSZY13At1XrFP1U80DhEgB3VDRemjEdqso5nCtnkn4rnvyOL2NSl6dPrFf4IF -YqYK6miyeUcGbvJXqBUzxvd4Sj1Ce2t+/vdG6tHrju+IaFvowdlxfv1k7/9nR4hYJS8+hge9+6jl -gqispdNpQ80xiEmEU5LAsTkbOYMBMMTyqfrQA71yN2BWHzZ8vTmR9W0Nv3vXkg== ------END CERTIFICATE----- - ANF Secure Server Root CA ========================= -----BEGIN CERTIFICATE----- @@ -3449,3 +3365,204 @@ TFsR0PXNor6uzFFcw9VUewyu1rkGd4Di7wcaaMxZUa1+XGdrudviB0JbuAEFWDlN5LuYo7Ey7Nmj PqYO5Wue/9vsL3SD3460s6neFE3/MaNFcyT6lSnMEpcEoji2jbDwN/zIIX8/syQbPYtuzE2wFg2W HYMfRsCbvUOZ58SWLs5fyQ== -----END CERTIFICATE----- + +TrustAsia Global Root CA G3 +=========================== +-----BEGIN CERTIFICATE----- +MIIFpTCCA42gAwIBAgIUZPYOZXdhaqs7tOqFhLuxibhxkw8wDQYJKoZIhvcNAQEMBQAwWjELMAkG +A1UEBhMCQ04xJTAjBgNVBAoMHFRydXN0QXNpYSBUZWNobm9sb2dpZXMsIEluYy4xJDAiBgNVBAMM +G1RydXN0QXNpYSBHbG9iYWwgUm9vdCBDQSBHMzAeFw0yMTA1MjAwMjEwMTlaFw00NjA1MTkwMjEw +MTlaMFoxCzAJBgNVBAYTAkNOMSUwIwYDVQQKDBxUcnVzdEFzaWEgVGVjaG5vbG9naWVzLCBJbmMu +MSQwIgYDVQQDDBtUcnVzdEFzaWEgR2xvYmFsIFJvb3QgQ0EgRzMwggIiMA0GCSqGSIb3DQEBAQUA +A4ICDwAwggIKAoICAQDAMYJhkuSUGwoqZdC+BqmHO1ES6nBBruL7dOoKjbmzTNyPtxNST1QY4Sxz +lZHFZjtqz6xjbYdT8PfxObegQ2OwxANdV6nnRM7EoYNl9lA+sX4WuDqKAtCWHwDNBSHvBm3dIZwZ +Q0WhxeiAysKtQGIXBsaqvPPW5vxQfmZCHzyLpnl5hkA1nyDvP+uLRx+PjsXUjrYsyUQE49RDdT/V +P68czH5GX6zfZBCK70bwkPAPLfSIC7Epqq+FqklYqL9joDiR5rPmd2jE+SoZhLsO4fWvieylL1Ag +dB4SQXMeJNnKziyhWTXAyB1GJ2Faj/lN03J5Zh6fFZAhLf3ti1ZwA0pJPn9pMRJpxx5cynoTi+jm +9WAPzJMshH/x/Gr8m0ed262IPfN2dTPXS6TIi/n1Q1hPy8gDVI+lhXgEGvNz8teHHUGf59gXzhqc +D0r83ERoVGjiQTz+LISGNzzNPy+i2+f3VANfWdP3kXjHi3dqFuVJhZBFcnAvkV34PmVACxmZySYg +WmjBNb9Pp1Hx2BErW+Canig7CjoKH8GB5S7wprlppYiU5msTf9FkPz2ccEblooV7WIQn3MSAPmea +mseaMQ4w7OYXQJXZRe0Blqq/DPNL0WP3E1jAuPP6Z92bfW1K/zJMtSU7/xxnD4UiWQWRkUF3gdCF +TIcQcf+eQxuulXUtgQIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFEDk5PIj +7zjKsK5Xf/IhMBY027ySMB0GA1UdDgQWBBRA5OTyI+84yrCuV3/yITAWNNu8kjAOBgNVHQ8BAf8E +BAMCAQYwDQYJKoZIhvcNAQEMBQADggIBACY7UeFNOPMyGLS0XuFlXsSUT9SnYaP4wM8zAQLpw6o1 +D/GUE3d3NZ4tVlFEbuHGLige/9rsR82XRBf34EzC4Xx8MnpmyFq2XFNFV1pF1AWZLy4jVe5jaN/T +G3inEpQGAHUNcoTpLrxaatXeL1nHo+zSh2bbt1S1JKv0Q3jbSwTEb93mPmY+KfJLaHEih6D4sTNj +duMNhXJEIlU/HHzp/LgV6FL6qj6jITk1dImmasI5+njPtqzn59ZW/yOSLlALqbUHM/Q4X6RJpstl +cHboCoWASzY9M/eVVHUl2qzEc4Jl6VL1XP04lQJqaTDFHApXB64ipCz5xUG3uOyfT0gA+QEEVcys ++TIxxHWVBqB/0Y0n3bOppHKH/lmLmnp0Ft0WpWIp6zqW3IunaFnT63eROfjXy9mPX1onAX1daBli +2MjN9LdyR75bl87yraKZk62Uy5P2EgmVtqvXO9A/EcswFi55gORngS1d7XB4tmBZrOFdRWOPyN9y +aFvqHbgB8X7754qz41SgOAngPN5C8sLtLpvzHzW2NtjjgKGLzZlkD8Kqq7HK9W+eQ42EVJmzbsAS +ZthwEPEGNTNDqJwuuhQxzhB/HIbjj9LV+Hfsm6vxL2PZQl/gZ4FkkfGXL/xuJvYz+NO1+MRiqzFR +JQJ6+N1rZdVtTTDIZbpoFGWsJwt0ivKH +-----END CERTIFICATE----- + +TrustAsia Global Root CA G4 +=========================== +-----BEGIN CERTIFICATE----- +MIICVTCCAdygAwIBAgIUTyNkuI6XY57GU4HBdk7LKnQV1tcwCgYIKoZIzj0EAwMwWjELMAkGA1UE +BhMCQ04xJTAjBgNVBAoMHFRydXN0QXNpYSBUZWNobm9sb2dpZXMsIEluYy4xJDAiBgNVBAMMG1Ry +dXN0QXNpYSBHbG9iYWwgUm9vdCBDQSBHNDAeFw0yMTA1MjAwMjEwMjJaFw00NjA1MTkwMjEwMjJa +MFoxCzAJBgNVBAYTAkNOMSUwIwYDVQQKDBxUcnVzdEFzaWEgVGVjaG5vbG9naWVzLCBJbmMuMSQw +IgYDVQQDDBtUcnVzdEFzaWEgR2xvYmFsIFJvb3QgQ0EgRzQwdjAQBgcqhkjOPQIBBgUrgQQAIgNi +AATxs8045CVD5d4ZCbuBeaIVXxVjAd7Cq92zphtnS4CDr5nLrBfbK5bKfFJV4hrhPVbwLxYI+hW8 +m7tH5j/uqOFMjPXTNvk4XatwmkcN4oFBButJ+bAp3TPsUKV/eSm4IJijYzBhMA8GA1UdEwEB/wQF +MAMBAf8wHwYDVR0jBBgwFoAUpbtKl86zK3+kMd6Xg1mDpm9xy94wHQYDVR0OBBYEFKW7SpfOsyt/ +pDHel4NZg6ZvccveMA4GA1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNnADBkAjBe8usGzEkxn0AA +bbd+NvBNEU/zy4k6LHiRUKNbwMp1JvK/kF0LgoxgKJ/GcJpo5PECMFxYDlZ2z1jD1xCMuo6u47xk +dUfFVZDj/bpV6wfEU6s3qe4hsiFbYI89MvHVI5TWWA== +-----END CERTIFICATE----- + +CommScope Public Trust ECC Root-01 +================================== +-----BEGIN CERTIFICATE----- +MIICHTCCAaOgAwIBAgIUQ3CCd89NXTTxyq4yLzf39H91oJ4wCgYIKoZIzj0EAwMwTjELMAkGA1UE +BhMCVVMxEjAQBgNVBAoMCUNvbW1TY29wZTErMCkGA1UEAwwiQ29tbVNjb3BlIFB1YmxpYyBUcnVz +dCBFQ0MgUm9vdC0wMTAeFw0yMTA0MjgxNzM1NDNaFw00NjA0MjgxNzM1NDJaME4xCzAJBgNVBAYT +AlVTMRIwEAYDVQQKDAlDb21tU2NvcGUxKzApBgNVBAMMIkNvbW1TY29wZSBQdWJsaWMgVHJ1c3Qg +RUNDIFJvb3QtMDEwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAARLNumuV16ocNfQj3Rid8NeeqrltqLx +eP0CflfdkXmcbLlSiFS8LwS+uM32ENEp7LXQoMPwiXAZu1FlxUOcw5tjnSCDPgYLpkJEhRGnSjot +6dZoL0hOUysHP029uax3OVejQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G +A1UdDgQWBBSOB2LAUN3GGQYARnQE9/OufXVNMDAKBggqhkjOPQQDAwNoADBlAjEAnDPfQeMjqEI2 +Jpc1XHvr20v4qotzVRVcrHgpD7oh2MSg2NED3W3ROT3Ek2DS43KyAjB8xX6I01D1HiXo+k515liW +pDVfG2XqYZpwI7UNo5uSUm9poIyNStDuiw7LR47QjRE= +-----END CERTIFICATE----- + +CommScope Public Trust ECC Root-02 +================================== +-----BEGIN CERTIFICATE----- +MIICHDCCAaOgAwIBAgIUKP2ZYEFHpgE6yhR7H+/5aAiDXX0wCgYIKoZIzj0EAwMwTjELMAkGA1UE +BhMCVVMxEjAQBgNVBAoMCUNvbW1TY29wZTErMCkGA1UEAwwiQ29tbVNjb3BlIFB1YmxpYyBUcnVz +dCBFQ0MgUm9vdC0wMjAeFw0yMTA0MjgxNzQ0NTRaFw00NjA0MjgxNzQ0NTNaME4xCzAJBgNVBAYT +AlVTMRIwEAYDVQQKDAlDb21tU2NvcGUxKzApBgNVBAMMIkNvbW1TY29wZSBQdWJsaWMgVHJ1c3Qg +RUNDIFJvb3QtMDIwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAR4MIHoYx7l63FRD/cHB8o5mXxO1Q/M +MDALj2aTPs+9xYa9+bG3tD60B8jzljHz7aRP+KNOjSkVWLjVb3/ubCK1sK9IRQq9qEmUv4RDsNuE +SgMjGWdqb8FuvAY5N9GIIvejQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G +A1UdDgQWBBTmGHX/72DehKT1RsfeSlXjMjZ59TAKBggqhkjOPQQDAwNnADBkAjAmc0l6tqvmSfR9 +Uj/UQQSugEODZXW5hYA4O9Zv5JOGq4/nich/m35rChJVYaoR4HkCMHfoMXGsPHED1oQmHhS48zs7 +3u1Z/GtMMH9ZzkXpc2AVmkzw5l4lIhVtwodZ0LKOag== +-----END CERTIFICATE----- + +CommScope Public Trust RSA Root-01 +================================== +-----BEGIN CERTIFICATE----- +MIIFbDCCA1SgAwIBAgIUPgNJgXUWdDGOTKvVxZAplsU5EN0wDQYJKoZIhvcNAQELBQAwTjELMAkG +A1UEBhMCVVMxEjAQBgNVBAoMCUNvbW1TY29wZTErMCkGA1UEAwwiQ29tbVNjb3BlIFB1YmxpYyBU +cnVzdCBSU0EgUm9vdC0wMTAeFw0yMTA0MjgxNjQ1NTRaFw00NjA0MjgxNjQ1NTNaME4xCzAJBgNV +BAYTAlVTMRIwEAYDVQQKDAlDb21tU2NvcGUxKzApBgNVBAMMIkNvbW1TY29wZSBQdWJsaWMgVHJ1 +c3QgUlNBIFJvb3QtMDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCwSGWjDR1C45Ft +nYSkYZYSwu3D2iM0GXb26v1VWvZVAVMP8syMl0+5UMuzAURWlv2bKOx7dAvnQmtVzslhsuitQDy6 +uUEKBU8bJoWPQ7VAtYXR1HHcg0Hz9kXHgKKEUJdGzqAMxGBWBB0HW0alDrJLpA6lfO741GIDuZNq +ihS4cPgugkY4Iw50x2tBt9Apo52AsH53k2NC+zSDO3OjWiE260f6GBfZumbCk6SP/F2krfxQapWs +vCQz0b2If4b19bJzKo98rwjyGpg/qYFlP8GMicWWMJoKz/TUyDTtnS+8jTiGU+6Xn6myY5QXjQ/c +Zip8UlF1y5mO6D1cv547KI2DAg+pn3LiLCuz3GaXAEDQpFSOm117RTYm1nJD68/A6g3czhLmfTif +BSeolz7pUcZsBSjBAg/pGG3svZwG1KdJ9FQFa2ww8esD1eo9anbCyxooSU1/ZOD6K9pzg4H/kQO9 +lLvkuI6cMmPNn7togbGEW682v3fuHX/3SZtS7NJ3Wn2RnU3COS3kuoL4b/JOHg9O5j9ZpSPcPYeo +KFgo0fEbNttPxP/hjFtyjMcmAyejOQoBqsCyMWCDIqFPEgkBEa801M/XrmLTBQe0MXXgDW1XT2mH ++VepuhX2yFJtocucH+X8eKg1mp9BFM6ltM6UCBwJrVbl2rZJmkrqYxhTnCwuwwIDAQABo0IwQDAP +BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUN12mmnQywsL5x6YVEFm4 +5P3luG0wDQYJKoZIhvcNAQELBQADggIBAK+nz97/4L1CjU3lIpbfaOp9TSp90K09FlxD533Ahuh6 +NWPxzIHIxgvoLlI1pKZJkGNRrDSsBTtXAOnTYtPZKdVUvhwQkZyybf5Z/Xn36lbQnmhUQo8mUuJM +3y+Xpi/SB5io82BdS5pYV4jvguX6r2yBS5KPQJqTRlnLX3gWsWc+QgvfKNmwrZggvkN80V4aCRck +jXtdlemrwWCrWxhkgPut4AZ9HcpZuPN4KWfGVh2vtrV0KnahP/t1MJ+UXjulYPPLXAziDslg+Mkf +Foom3ecnf+slpoq9uC02EJqxWE2aaE9gVOX2RhOOiKy8IUISrcZKiX2bwdgt6ZYD9KJ0DLwAHb/W +NyVntHKLr4W96ioDj8z7PEQkguIBpQtZtjSNMgsSDesnwv1B10A8ckYpwIzqug/xBpMu95yo9GA+ +o/E4Xo4TwbM6l4c/ksp4qRyv0LAbJh6+cOx69TOY6lz/KwsETkPdY34Op054A5U+1C0wlREQKC6/ +oAI+/15Z0wUOlV9TRe9rh9VIzRamloPh37MG88EU26fsHItdkJANclHnYfkUyq+Dj7+vsQpZXdxc +1+SWrVtgHdqul7I52Qb1dgAT+GhMIbA1xNxVssnBQVocicCMb3SgazNNtQEo/a2tiRc7ppqEvOuM +6sRxJKi6KfkIsidWNTJf6jn7MZrVGczw +-----END CERTIFICATE----- + +CommScope Public Trust RSA Root-02 +================================== +-----BEGIN CERTIFICATE----- +MIIFbDCCA1SgAwIBAgIUVBa/O345lXGN0aoApYYNK496BU4wDQYJKoZIhvcNAQELBQAwTjELMAkG +A1UEBhMCVVMxEjAQBgNVBAoMCUNvbW1TY29wZTErMCkGA1UEAwwiQ29tbVNjb3BlIFB1YmxpYyBU +cnVzdCBSU0EgUm9vdC0wMjAeFw0yMTA0MjgxNzE2NDNaFw00NjA0MjgxNzE2NDJaME4xCzAJBgNV +BAYTAlVTMRIwEAYDVQQKDAlDb21tU2NvcGUxKzApBgNVBAMMIkNvbW1TY29wZSBQdWJsaWMgVHJ1 +c3QgUlNBIFJvb3QtMDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDh+g77aAASyE3V +rCLENQE7xVTlWXZjpX/rwcRqmL0yjReA61260WI9JSMZNRTpf4mnG2I81lDnNJUDMrG0kyI9p+Kx +7eZ7Ti6Hmw0zdQreqjXnfuU2mKKuJZ6VszKWpCtYHu8//mI0SFHRtI1CrWDaSWqVcN3SAOLMV2MC +e5bdSZdbkk6V0/nLKR8YSvgBKtJjCW4k6YnS5cciTNxzhkcAqg2Ijq6FfUrpuzNPDlJwnZXjfG2W +Wy09X6GDRl224yW4fKcZgBzqZUPckXk2LHR88mcGyYnJ27/aaL8j7dxrrSiDeS/sOKUNNwFnJ5rp +M9kzXzehxfCrPfp4sOcsn/Y+n2Dg70jpkEUeBVF4GiwSLFworA2iI540jwXmojPOEXcT1A6kHkIf +hs1w/tkuFT0du7jyU1fbzMZ0KZwYszZ1OC4PVKH4kh+Jlk+71O6d6Ts2QrUKOyrUZHk2EOH5kQMr +eyBUzQ0ZGshBMjTRsJnhkB4BQDa1t/qp5Xd1pCKBXbCL5CcSD1SIxtuFdOa3wNemKfrb3vOTlycE +VS8KbzfFPROvCgCpLIscgSjX74Yxqa7ybrjKaixUR9gqiC6vwQcQeKwRoi9C8DfF8rhW3Q5iLc4t +Vn5V8qdE9isy9COoR+jUKgF4z2rDN6ieZdIs5fq6M8EGRPbmz6UNp2YINIos8wIDAQABo0IwQDAP +BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUR9DnsSL/nSz12Vdgs7Gx +cJXvYXowDQYJKoZIhvcNAQELBQADggIBAIZpsU0v6Z9PIpNojuQhmaPORVMbc0RTAIFhzTHjCLqB +KCh6krm2qMhDnscTJk3C2OVVnJJdUNjCK9v+5qiXz1I6JMNlZFxHMaNlNRPDk7n3+VGXu6TwYofF +1gbTl4MgqX67tiHCpQ2EAOHyJxCDut0DgdXdaMNmEMjRdrSzbymeAPnCKfWxkxlSaRosTKCL4BWa +MS/TiJVZbuXEs1DIFAhKm4sTg7GkcrI7djNB3NyqpgdvHSQSn8h2vS/ZjvQs7rfSOBAkNlEv41xd +gSGn2rtO/+YHqP65DSdsu3BaVXoT6fEqSWnHX4dXTEN5bTpl6TBcQe7rd6VzEojov32u5cSoHw2O +HG1QAk8mGEPej1WFsQs3BWDJVTkSBKEqz3EWnzZRSb9wO55nnPt7eck5HHisd5FUmrh1CoFSl+Nm +YWvtPjgelmFV4ZFUjO2MJB+ByRCac5krFk5yAD9UG/iNuovnFNa2RU9g7Jauwy8CTl2dlklyALKr +dVwPaFsdZcJfMw8eD/A7hvWwTruc9+olBdytoptLFwG+Qt81IR2tq670v64fG9PiO/yzcnMcmyiQ +iRM9HcEARwmWmjgb3bHPDcK0RPOWlc4yOo80nOAXx17Org3bhzjlP1v9mxnhMUF6cKojawHhRUzN +lM47ni3niAIi9G7oyOzWPPO5std3eqx7 +-----END CERTIFICATE----- + +Telekom Security TLS ECC Root 2020 +================================== +-----BEGIN CERTIFICATE----- +MIICQjCCAcmgAwIBAgIQNjqWjMlcsljN0AFdxeVXADAKBggqhkjOPQQDAzBjMQswCQYDVQQGEwJE +RTEnMCUGA1UECgweRGV1dHNjaGUgVGVsZWtvbSBTZWN1cml0eSBHbWJIMSswKQYDVQQDDCJUZWxl +a29tIFNlY3VyaXR5IFRMUyBFQ0MgUm9vdCAyMDIwMB4XDTIwMDgyNTA3NDgyMFoXDTQ1MDgyNTIz +NTk1OVowYzELMAkGA1UEBhMCREUxJzAlBgNVBAoMHkRldXRzY2hlIFRlbGVrb20gU2VjdXJpdHkg +R21iSDErMCkGA1UEAwwiVGVsZWtvbSBTZWN1cml0eSBUTFMgRUNDIFJvb3QgMjAyMDB2MBAGByqG +SM49AgEGBSuBBAAiA2IABM6//leov9Wq9xCazbzREaK9Z0LMkOsVGJDZos0MKiXrPk/OtdKPD/M1 +2kOLAoC+b1EkHQ9rK8qfwm9QMuU3ILYg/4gND21Ju9sGpIeQkpT0CdDPf8iAC8GXs7s1J8nCG6NC +MEAwHQYDVR0OBBYEFONyzG6VmUex5rNhTNHLq+O6zd6fMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0P +AQH/BAQDAgEGMAoGCCqGSM49BAMDA2cAMGQCMHVSi7ekEE+uShCLsoRbQuHmKjYC2qBuGT8lv9pZ +Mo7k+5Dck2TOrbRBR2Diz6fLHgIwN0GMZt9Ba9aDAEH9L1r3ULRn0SyocddDypwnJJGDSA3PzfdU +ga/sf+Rn27iQ7t0l +-----END CERTIFICATE----- + +Telekom Security TLS RSA Root 2023 +================================== +-----BEGIN CERTIFICATE----- +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 +-----END CERTIFICATE----- + +FIRMAPROFESIONAL CA ROOT-A WEB +============================== +-----BEGIN CERTIFICATE----- +MIICejCCAgCgAwIBAgIQMZch7a+JQn81QYehZ1ZMbTAKBggqhkjOPQQDAzBuMQswCQYDVQQGEwJF +UzEcMBoGA1UECgwTRmlybWFwcm9mZXNpb25hbCBTQTEYMBYGA1UEYQwPVkFURVMtQTYyNjM0MDY4 +MScwJQYDVQQDDB5GSVJNQVBST0ZFU0lPTkFMIENBIFJPT1QtQSBXRUIwHhcNMjIwNDA2MDkwMTM2 +WhcNNDcwMzMxMDkwMTM2WjBuMQswCQYDVQQGEwJFUzEcMBoGA1UECgwTRmlybWFwcm9mZXNpb25h +bCBTQTEYMBYGA1UEYQwPVkFURVMtQTYyNjM0MDY4MScwJQYDVQQDDB5GSVJNQVBST0ZFU0lPTkFM +IENBIFJPT1QtQSBXRUIwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAARHU+osEaR3xyrq89Zfe9MEkVz6 +iMYiuYMQYneEMy3pA4jU4DP37XcsSmDq5G+tbbT4TIqk5B/K6k84Si6CcyvHZpsKjECcfIr28jlg +st7L7Ljkb+qbXbdTkBgyVcUgt5SjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUk+FD +Y1w8ndYn81LsF7Kpryz3dvgwHQYDVR0OBBYEFJPhQ2NcPJ3WJ/NS7Beyqa8s93b4MA4GA1UdDwEB +/wQEAwIBBjAKBggqhkjOPQQDAwNoADBlAjAdfKR7w4l1M+E7qUW/Runpod3JIha3RxEL2Jq68cgL +cFBTApFwhVmpHqTm6iMxoAACMQD94vizrxa5HnPEluPBMBnYfubDl94cT7iJLzPrSA8Z94dGXSaQ +pYXFuXqUPoeovQA= +-----END CERTIFICATE----- diff --git a/site/plugins/embed/vendor/composer/ca-bundle/src/CaBundle.php b/vendor/composer/ca-bundle/src/CaBundle.php similarity index 56% rename from site/plugins/embed/vendor/composer/ca-bundle/src/CaBundle.php rename to vendor/composer/ca-bundle/src/CaBundle.php index d99c00f..f6f2afe 100644 --- a/site/plugins/embed/vendor/composer/ca-bundle/src/CaBundle.php +++ b/vendor/composer/ca-bundle/src/CaBundle.php @@ -24,8 +24,6 @@ class CaBundle private static $caPath; /** @var array */ private static $caFileValidity = array(); - /** @var bool|null */ - private static $useOpensslParse; /** * Returns the system CA bundle path, or a path to the bundled one @@ -64,7 +62,7 @@ class CaBundle * @param LoggerInterface $logger optional logger for information about which CA files were loaded * @return string path to a CA bundle file or directory */ - public static function getSystemCaRootBundlePath(LoggerInterface $logger = null) + public static function getSystemCaRootBundlePath(?LoggerInterface $logger = null) { if (self::$caPath !== null) { return self::$caPath; @@ -95,6 +93,8 @@ class CaBundle '/usr/local/etc/ssl/cert.pem', // FreeBSD 10.x '/usr/local/etc/openssl/cert.pem', // OS X homebrew, openssl package '/usr/local/etc/openssl@1.1/cert.pem', // OS X homebrew, openssl@1.1 package + '/opt/homebrew/etc/openssl@3/cert.pem', // macOS silicon homebrew, openssl@3 package + '/opt/homebrew/etc/openssl@1.1/cert.pem', // macOS silicon homebrew, openssl@1.1 package ); foreach($otherLocations as $location) { @@ -158,7 +158,7 @@ class CaBundle * * @return bool */ - public static function validateCaFile($filename, LoggerInterface $logger = null) + public static function validateCaFile($filename, ?LoggerInterface $logger = null) { static $warned = false; @@ -168,19 +168,7 @@ class CaBundle $contents = file_get_contents($filename); - // assume the CA is valid if php is vulnerable to - // https://www.sektioneins.de/advisories/advisory-012013-php-openssl_x509_parse-memory-corruption-vulnerability.html - if (!static::isOpensslParseSafe()) { - if (!$warned && $logger) { - $logger->warning(sprintf( - 'Your version of PHP, %s, is affected by CVE-2013-6420 and cannot safely perform certificate validation, we strongly suggest you upgrade.', - PHP_VERSION - )); - $warned = true; - } - - $isValid = !empty($contents); - } elseif (is_string($contents) && strlen($contents) > 0) { + if (is_string($contents) && strlen($contents) > 0) { $contents = preg_replace("/^(\\-+(?:BEGIN|END))\\s+TRUSTED\\s+(CERTIFICATE\\-+)\$/m", '$1 $2', $contents); if (null === $contents) { // regex extraction failed @@ -209,100 +197,7 @@ class CaBundle */ public static function isOpensslParseSafe() { - if (null !== self::$useOpensslParse) { - return self::$useOpensslParse; - } - - if (PHP_VERSION_ID >= 50600) { - return self::$useOpensslParse = true; - } - - // Vulnerable: - // PHP 5.3.0 - PHP 5.3.27 - // PHP 5.4.0 - PHP 5.4.22 - // PHP 5.5.0 - PHP 5.5.6 - if ( - (PHP_VERSION_ID < 50400 && PHP_VERSION_ID >= 50328) - || (PHP_VERSION_ID < 50500 && PHP_VERSION_ID >= 50423) - || PHP_VERSION_ID >= 50507 - ) { - // This version of PHP has the fix for CVE-2013-6420 applied. - return self::$useOpensslParse = true; - } - - if (defined('PHP_WINDOWS_VERSION_BUILD')) { - // Windows is probably insecure in this case. - return self::$useOpensslParse = false; - } - - $compareDistroVersionPrefix = function ($prefix, $fixedVersion) { - $regex = '{^'.preg_quote($prefix).'([0-9]+)$}'; - - if (preg_match($regex, PHP_VERSION, $m)) { - return ((int) $m[1]) >= $fixedVersion; - } - - return false; - }; - - // Hard coded list of PHP distributions with the fix backported. - if ( - $compareDistroVersionPrefix('5.3.3-7+squeeze', 18) // Debian 6 (Squeeze) - || $compareDistroVersionPrefix('5.4.4-14+deb7u', 7) // Debian 7 (Wheezy) - || $compareDistroVersionPrefix('5.3.10-1ubuntu3.', 9) // Ubuntu 12.04 (Precise) - ) { - return self::$useOpensslParse = true; - } - - // Symfony Process component is missing so we assume it is unsafe at this point - if (!class_exists('Symfony\Component\Process\PhpProcess')) { - return self::$useOpensslParse = false; - } - - // This is where things get crazy, because distros backport security - // fixes the chances are on NIX systems the fix has been applied but - // it's not possible to verify that from the PHP version. - // - // To verify exec a new PHP process and run the issue testcase with - // known safe input that replicates the bug. - - // Based on testcase in https://github.com/php/php-src/commit/c1224573c773b6845e83505f717fbf820fc18415 - // changes in https://github.com/php/php-src/commit/76a7fd893b7d6101300cc656058704a73254d593 - $cert = 'LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUVwRENDQTR5Z0F3SUJBZ0lKQUp6dThyNnU2ZUJjTUEwR0NTcUdTSWIzRFFFQkJRVUFNSUhETVFzd0NRWUQKVlFRR0V3SkVSVEVjTUJvR0ExVUVDQXdUVG05eVpISm9aV2x1TFZkbGMzUm1ZV3hsYmpFUU1BNEdBMVVFQnd3SApTOE9Ed3Jac2JqRVVNQklHQTFVRUNnd0xVMlZyZEdsdmJrVnBibk14SHpBZEJnTlZCQXNNRmsxaGJHbGphVzkxCmN5QkRaWEowSUZObFkzUnBiMjR4SVRBZkJnTlZCQU1NR0cxaGJHbGphVzkxY3k1elpXdDBhVzl1WldsdWN5NWsKWlRFcU1DZ0dDU3FHU0liM0RRRUpBUlliYzNSbFptRnVMbVZ6YzJWeVFITmxhM1JwYjI1bGFXNXpMbVJsTUhVWQpaREU1TnpBd01UQXhNREF3TURBd1dnQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBCkFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUEKQUFBQUFBQVhEVEUwTVRFeU9ERXhNemt6TlZvd2djTXhDekFKQmdOVkJBWVRBa1JGTVJ3d0dnWURWUVFJREJOTwpiM0prY21obGFXNHRWMlZ6ZEdaaGJHVnVNUkF3RGdZRFZRUUhEQWRMdzRQQ3RteHVNUlF3RWdZRFZRUUtEQXRUClpXdDBhVzl1UldsdWN6RWZNQjBHQTFVRUN3d1dUV0ZzYVdOcGIzVnpJRU5sY25RZ1UyVmpkR2x2YmpFaE1COEcKQTFVRUF3d1liV0ZzYVdOcGIzVnpMbk5sYTNScGIyNWxhVzV6TG1SbE1Tb3dLQVlKS29aSWh2Y05BUWtCRmh0egpkR1ZtWVc0dVpYTnpaWEpBYzJWcmRHbHZibVZwYm5NdVpHVXdnZ0VpTUEwR0NTcUdTSWIzRFFFQkFRVUFBNElCCkR3QXdnZ0VLQW9JQkFRRERBZjNobDdKWTBYY0ZuaXlFSnBTU0RxbjBPcUJyNlFQNjV1c0pQUnQvOFBhRG9xQnUKd0VZVC9OYSs2ZnNnUGpDMHVLOURaZ1dnMnRIV1dvYW5TYmxBTW96NVBINlorUzRTSFJaN2UyZERJalBqZGhqaAowbUxnMlVNTzV5cDBWNzk3R2dzOWxOdDZKUmZIODFNTjJvYlhXczROdHp0TE11RDZlZ3FwcjhkRGJyMzRhT3M4CnBrZHVpNVVhd1Raa3N5NXBMUEhxNWNNaEZHbTA2djY1Q0xvMFYyUGQ5K0tBb2tQclBjTjVLTEtlYno3bUxwazYKU01lRVhPS1A0aWRFcXh5UTdPN2ZCdUhNZWRzUWh1K3ByWTNzaTNCVXlLZlF0UDVDWm5YMmJwMHdLSHhYMTJEWAoxbmZGSXQ5RGJHdkhUY3lPdU4rblpMUEJtM3ZXeG50eUlJdlZBZ01CQUFHalFqQkFNQWtHQTFVZEV3UUNNQUF3CkVRWUpZSVpJQVliNFFnRUJCQVFEQWdlQU1Bc0dBMVVkRHdRRUF3SUZvREFUQmdOVkhTVUVEREFLQmdnckJnRUYKQlFjREFqQU5CZ2txaGtpRzl3MEJBUVVGQUFPQ0FRRUFHMGZaWVlDVGJkajFYWWMrMVNub2FQUit2SThDOENhRAo4KzBVWWhkbnlVNGdnYTBCQWNEclk5ZTk0ZUVBdTZacXljRjZGakxxWFhkQWJvcHBXb2NyNlQ2R0QxeDMzQ2tsClZBcnpHL0t4UW9oR0QySmVxa2hJTWxEb214SE83a2EzOStPYThpMnZXTFZ5alU4QVp2V01BcnVIYTRFRU55RzcKbFcyQWFnYUZLRkNyOVRuWFRmcmR4R1ZFYnY3S1ZRNmJkaGc1cDVTanBXSDErTXEwM3VSM1pYUEJZZHlWODMxOQpvMGxWajFLRkkyRENML2xpV2lzSlJvb2YrMWNSMzVDdGQwd1lCY3BCNlRac2xNY09QbDc2ZHdLd0pnZUpvMlFnClpzZm1jMnZDMS9xT2xOdU5xLzBUenprVkd2OEVUVDNDZ2FVK1VYZTRYT1Z2a2NjZWJKbjJkZz09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K'; - $script = <<<'EOT' - -error_reporting(-1); -$info = openssl_x509_parse(base64_decode('%s')); -var_dump(PHP_VERSION, $info['issuer']['emailAddress'], $info['validFrom_time_t']); - -EOT; - $script = '<'."?php\n".sprintf($script, $cert); - - try { - $process = new PhpProcess($script); - $process->mustRun(); - } catch (\Exception $e) { - // In the case of any exceptions just accept it is not possible to - // determine the safety of openssl_x509_parse and bail out. - return self::$useOpensslParse = false; - } - - $output = preg_split('{\r?\n}', trim($process->getOutput())); - $errorOutput = trim($process->getErrorOutput()); - - if ( - is_array($output) - && count($output) === 3 - && $output[0] === sprintf('string(%d) "%s"', strlen(PHP_VERSION), PHP_VERSION) - && $output[1] === 'string(27) "stefan.esser@sektioneins.de"' - && $output[2] === 'int(-1)' - && preg_match('{openssl_x509_parse\(\): illegal (?:ASN1 data type for|length in) timestamp in - on line \d+}', $errorOutput) - ) { - // This PHP has the fix backported probably by a distro security team. - return self::$useOpensslParse = true; - } - - return self::$useOpensslParse = false; + return true; } /** @@ -313,7 +208,6 @@ EOT; { self::$caFileValidity = array(); self::$caPath = null; - self::$useOpensslParse = null; } /** @@ -338,12 +232,12 @@ EOT; * @param LoggerInterface|null $logger * @return bool */ - private static function caFileUsable($certFile, LoggerInterface $logger = null) + private static function caFileUsable($certFile, ?LoggerInterface $logger = null) { return $certFile - && static::isFile($certFile, $logger) - && static::isReadable($certFile, $logger) - && static::validateCaFile($certFile, $logger); + && self::isFile($certFile, $logger) + && self::isReadable($certFile, $logger) + && self::validateCaFile($certFile, $logger); } /** @@ -351,12 +245,12 @@ EOT; * @param LoggerInterface|null $logger * @return bool */ - private static function caDirUsable($certDir, LoggerInterface $logger = null) + private static function caDirUsable($certDir, ?LoggerInterface $logger = null) { return $certDir - && static::isDir($certDir, $logger) - && static::isReadable($certDir, $logger) - && static::glob($certDir . '/*', $logger); + && self::isDir($certDir, $logger) + && self::isReadable($certDir, $logger) + && self::glob($certDir . '/*', $logger); } /** @@ -364,7 +258,7 @@ EOT; * @param LoggerInterface|null $logger * @return bool */ - private static function isFile($certFile, LoggerInterface $logger = null) + private static function isFile($certFile, ?LoggerInterface $logger = null) { $isFile = @is_file($certFile); if (!$isFile && $logger) { @@ -379,7 +273,7 @@ EOT; * @param LoggerInterface|null $logger * @return bool */ - private static function isDir($certDir, LoggerInterface $logger = null) + private static function isDir($certDir, ?LoggerInterface $logger = null) { $isDir = @is_dir($certDir); if (!$isDir && $logger) { @@ -394,7 +288,7 @@ EOT; * @param LoggerInterface|null $logger * @return bool */ - private static function isReadable($certFileOrDir, LoggerInterface $logger = null) + private static function isReadable($certFileOrDir, ?LoggerInterface $logger = null) { $isReadable = @is_readable($certFileOrDir); if (!$isReadable && $logger) { @@ -409,7 +303,7 @@ EOT; * @param LoggerInterface|null $logger * @return bool */ - private static function glob($pattern, LoggerInterface $logger = null) + private static function glob($pattern, ?LoggerInterface $logger = null) { $certs = glob($pattern); if ($certs === false) { diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json new file mode 100644 index 0000000..e7ef256 --- /dev/null +++ b/vendor/composer/installed.json @@ -0,0 +1,1655 @@ +{ + "packages": [ + { + "name": "claviska/simpleimage", + "version": "3.7.0", + "version_normalized": "3.7.0.0", + "source": { + "type": "git", + "url": "https://github.com/claviska/SimpleImage.git", + "reference": "abd15ced313c7b8041d7d73d8d2398b4f2510cf1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/claviska/SimpleImage/zipball/abd15ced313c7b8041d7d73d8d2398b4f2510cf1", + "reference": "abd15ced313c7b8041d7d73d8d2398b4f2510cf1", + "shasum": "" + }, + "require": { + "ext-gd": "*", + "league/color-extractor": "0.3.*", + "php": ">=5.6.0" + }, + "time": "2022-07-05T13:18:44+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-0": { + "claviska": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Cory LaViska", + "homepage": "http://www.abeautifulsite.net/", + "role": "Developer" + } + ], + "description": "A PHP class that makes working with images as simple as possible.", + "support": { + "issues": "https://github.com/claviska/SimpleImage/issues", + "source": "https://github.com/claviska/SimpleImage/tree/3.7.0" + }, + "funding": [ + { + "url": "https://github.com/claviska", + "type": "github" + } + ], + "install-path": "../claviska/simpleimage" + }, + { + "name": "composer/ca-bundle", + "version": "1.5.1", + "version_normalized": "1.5.1.0", + "source": { + "type": "git", + "url": "https://github.com/composer/ca-bundle.git", + "reference": "063d9aa8696582f5a41dffbbaf3c81024f0a604a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/ca-bundle/zipball/063d9aa8696582f5a41dffbbaf3c81024f0a604a", + "reference": "063d9aa8696582f5a41dffbbaf3c81024f0a604a", + "shasum": "" + }, + "require": { + "ext-openssl": "*", + "ext-pcre": "*", + "php": "^7.2 || ^8.0" + }, + "require-dev": { + "phpstan/phpstan": "^1.10", + "psr/log": "^1.0 || ^2.0 || ^3.0", + "symfony/phpunit-bridge": "^4.2 || ^5", + "symfony/process": "^4.0 || ^5.0 || ^6.0 || ^7.0" + }, + "time": "2024-07-08T15:28:20+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Composer\\CaBundle\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + } + ], + "description": "Lets you find a path to the system CA bundle, and includes a fallback to the Mozilla CA bundle.", + "keywords": [ + "cabundle", + "cacert", + "certificate", + "ssl", + "tls" + ], + "support": { + "irc": "irc://irc.freenode.org/composer", + "issues": "https://github.com/composer/ca-bundle/issues", + "source": "https://github.com/composer/ca-bundle/tree/1.5.1" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], + "install-path": "./ca-bundle" + }, + { + "name": "embed/embed", + "version": "v4.4.8", + "version_normalized": "4.4.8.0", + "source": { + "type": "git", + "url": "https://github.com/oscarotero/Embed.git", + "reference": "49134080764018bc6b8a2488dd1c8cc2c47d15fc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/oscarotero/Embed/zipball/49134080764018bc6b8a2488dd1c8cc2c47d15fc", + "reference": "49134080764018bc6b8a2488dd1c8cc2c47d15fc", + "shasum": "" + }, + "require": { + "composer/ca-bundle": "^1.0", + "ext-curl": "*", + "ext-dom": "*", + "ext-json": "*", + "ext-mbstring": "*", + "ml/json-ld": "^1.1", + "oscarotero/html-parser": "^0.1.4", + "php": "^7.4|^8", + "psr/http-client": "^1.0", + "psr/http-factory": "^1.0", + "psr/http-message": "^1.0|^2.0" + }, + "require-dev": { + "brick/varexporter": "^0.3.1", + "friendsofphp/php-cs-fixer": "^2.0", + "nyholm/psr7": "^1.2", + "oscarotero/php-cs-fixer-config": "^1.0", + "phpunit/phpunit": "^9.0", + "symfony/css-selector": "^5.0" + }, + "suggest": { + "symfony/css-selector": "If you want to get elements using css selectors" + }, + "time": "2023-05-22T18:48:30+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "Embed\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Oscar Otero", + "email": "oom@oscarotero.com", + "homepage": "http://oscarotero.com", + "role": "Developer" + } + ], + "description": "PHP library to retrieve page info using oembed, opengraph, etc", + "homepage": "https://github.com/oscarotero/Embed", + "keywords": [ + "embed", + "embedly", + "oembed", + "opengraph", + "twitter cards" + ], + "support": { + "email": "oom@oscarotero.com", + "issues": "https://github.com/oscarotero/Embed/issues", + "source": "https://github.com/oscarotero/Embed/tree/v4.4.8" + }, + "funding": [ + { + "url": "https://paypal.me/oscarotero", + "type": "custom" + }, + { + "url": "https://github.com/oscarotero", + "type": "github" + }, + { + "url": "https://www.patreon.com/misteroom", + "type": "patreon" + } + ], + "install-path": "../embed/embed" + }, + { + "name": "filp/whoops", + "version": "2.14.5", + "version_normalized": "2.14.5.0", + "source": { + "type": "git", + "url": "https://github.com/filp/whoops.git", + "reference": "a63e5e8f26ebbebf8ed3c5c691637325512eb0dc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/filp/whoops/zipball/a63e5e8f26ebbebf8ed3c5c691637325512eb0dc", + "reference": "a63e5e8f26ebbebf8ed3c5c691637325512eb0dc", + "shasum": "" + }, + "require": { + "php": "^5.5.9 || ^7.0 || ^8.0", + "psr/log": "^1.0.1 || ^2.0 || ^3.0" + }, + "require-dev": { + "mockery/mockery": "^0.9 || ^1.0", + "phpunit/phpunit": "^4.8.36 || ^5.7.27 || ^6.5.14 || ^7.5.20 || ^8.5.8 || ^9.3.3", + "symfony/var-dumper": "^2.6 || ^3.0 || ^4.0 || ^5.0" + }, + "suggest": { + "symfony/var-dumper": "Pretty print complex values better with var-dumper available", + "whoops/soap": "Formats errors as SOAP responses" + }, + "time": "2022-01-07T12:00:00+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.7-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Whoops\\": "src/Whoops/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Filipe Dobreira", + "homepage": "https://github.com/filp", + "role": "Developer" + } + ], + "description": "php error handling for cool kids", + "homepage": "https://filp.github.io/whoops/", + "keywords": [ + "error", + "exception", + "handling", + "library", + "throwable", + "whoops" + ], + "support": { + "issues": "https://github.com/filp/whoops/issues", + "source": "https://github.com/filp/whoops/tree/2.14.5" + }, + "funding": [ + { + "url": "https://github.com/denis-sokolov", + "type": "github" + } + ], + "install-path": "../filp/whoops" + }, + { + "name": "getkirby/cms", + "version": "3.7.5.5", + "version_normalized": "3.7.5.5", + "source": { + "type": "git", + "url": "https://github.com/getkirby/kirby.git", + "reference": "a645ec70bc0152cc3caa07df303dd57ac25b30db" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/getkirby/kirby/zipball/a645ec70bc0152cc3caa07df303dd57ac25b30db", + "reference": "a645ec70bc0152cc3caa07df303dd57ac25b30db", + "shasum": "" + }, + "require": { + "claviska/simpleimage": "3.7.0", + "ext-ctype": "*", + "ext-curl": "*", + "ext-dom": "*", + "ext-filter": "*", + "ext-hash": "*", + "ext-iconv": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-openssl": "*", + "ext-simplexml": "*", + "filp/whoops": "2.14.5", + "getkirby/composer-installer": "^1.2.1", + "laminas/laminas-escaper": "2.10.0", + "michelf/php-smartypants": "1.8.1", + "php": ">=7.4.0 <8.2.0", + "phpmailer/phpmailer": "6.6.4", + "symfony/polyfill-intl-idn": "1.26.0", + "symfony/polyfill-mbstring": "1.26.0" + }, + "replace": { + "symfony/polyfill-php72": "*" + }, + "suggest": { + "ext-PDO": "Support for using databases", + "ext-apcu": "Support for the Apcu cache driver", + "ext-exif": "Support for exif information from images", + "ext-fileinfo": "Improved mime type detection for files", + "ext-intl": "Improved i18n number formatting", + "ext-memcached": "Support for the Memcached cache driver", + "ext-zip": "Support for ZIP archive file functions", + "ext-zlib": "Sanitization and validation for svgz files" + }, + "time": "2024-08-24T20:23:32+00:00", + "type": "kirby-cms", + "extra": { + "unused": [ + "symfony/polyfill-intl-idn" + ] + }, + "installation-source": "dist", + "autoload": { + "files": [ + "config/setup.php", + "config/helpers.php" + ], + "psr-4": { + "Kirby\\": "src/" + }, + "classmap": [ + "dependencies/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "proprietary" + ], + "authors": [ + { + "name": "Kirby Team", + "email": "support@getkirby.com", + "homepage": "https://getkirby.com" + } + ], + "description": "The Kirby 3 core", + "homepage": "https://getkirby.com", + "keywords": [ + "cms", + "core", + "kirby" + ], + "support": { + "email": "support@getkirby.com", + "forum": "https://forum.getkirby.com", + "issues": "https://github.com/getkirby/kirby/issues", + "source": "https://github.com/getkirby/kirby" + }, + "funding": [ + { + "url": "https://getkirby.com/buy", + "type": "custom" + } + ], + "install-path": "../../kirby" + }, + { + "name": "getkirby/composer-installer", + "version": "1.2.1", + "version_normalized": "1.2.1.0", + "source": { + "type": "git", + "url": "https://github.com/getkirby/composer-installer.git", + "reference": "c98ece30bfba45be7ce457e1102d1b169d922f3d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/getkirby/composer-installer/zipball/c98ece30bfba45be7ce457e1102d1b169d922f3d", + "reference": "c98ece30bfba45be7ce457e1102d1b169d922f3d", + "shasum": "" + }, + "require": { + "composer-plugin-api": "^1.0 || ^2.0" + }, + "require-dev": { + "composer/composer": "^1.8 || ^2.0" + }, + "time": "2020-12-28T12:54:39+00:00", + "type": "composer-plugin", + "extra": { + "class": "Kirby\\ComposerInstaller\\Plugin" + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Kirby\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Kirby's custom Composer installer for the Kirby CMS and for Kirby plugins", + "homepage": "https://getkirby.com", + "support": { + "issues": "https://github.com/getkirby/composer-installer/issues", + "source": "https://github.com/getkirby/composer-installer/tree/1.2.1" + }, + "funding": [ + { + "url": "https://getkirby.com/buy", + "type": "custom" + } + ], + "install-path": "../getkirby/composer-installer" + }, + { + "name": "guzzlehttp/psr7", + "version": "2.7.0", + "version_normalized": "2.7.0.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/psr7.git", + "reference": "a70f5c95fb43bc83f07c9c948baa0dc1829bf201" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/a70f5c95fb43bc83f07c9c948baa0dc1829bf201", + "reference": "a70f5c95fb43bc83f07c9c948baa0dc1829bf201", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0", + "psr/http-factory": "^1.0", + "psr/http-message": "^1.1 || ^2.0", + "ralouphie/getallheaders": "^3.0" + }, + "provide": { + "psr/http-factory-implementation": "1.0", + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "http-interop/http-factory-tests": "0.9.0", + "phpunit/phpunit": "^8.5.39 || ^9.6.20" + }, + "suggest": { + "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" + }, + "time": "2024-07-18T11:15:46+00:00", + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "GuzzleHttp\\Psr7\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://sagikazarmark.hu" + } + ], + "description": "PSR-7 message implementation that also provides common utility methods", + "keywords": [ + "http", + "message", + "psr-7", + "request", + "response", + "stream", + "uri", + "url" + ], + "support": { + "issues": "https://github.com/guzzle/psr7/issues", + "source": "https://github.com/guzzle/psr7/tree/2.7.0" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/psr7", + "type": "tidelift" + } + ], + "install-path": "../guzzlehttp/psr7" + }, + { + "name": "jg/kirby-fields-block", + "version": "v1.2.1", + "version_normalized": "1.2.1.0", + "source": { + "type": "git", + "url": "https://github.com/jongacnik/kirby-fields-block.git", + "reference": "e56c4d109edd921a1b4436e3df0e64b1117f1b83" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/jongacnik/kirby-fields-block/zipball/e56c4d109edd921a1b4436e3df0e64b1117f1b83", + "reference": "e56c4d109edd921a1b4436e3df0e64b1117f1b83", + "shasum": "" + }, + "require": { + "getkirby/composer-installer": "^1.1" + }, + "time": "2023-01-22T19:02:00+00:00", + "type": "kirby-plugin", + "installation-source": "dist", + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jon Gacnik", + "email": "jon@folderstudio.com" + } + ], + "description": "Kirby Fields Block", + "support": { + "issues": "https://github.com/jongacnik/kirby-fields-block/issues", + "source": "https://github.com/jongacnik/kirby-fields-block/tree/v1.2.1" + }, + "install-path": "../../site/plugins/kirby-fields-block" + }, + { + "name": "laminas/laminas-escaper", + "version": "2.10.0", + "version_normalized": "2.10.0.0", + "source": { + "type": "git", + "url": "https://github.com/laminas/laminas-escaper.git", + "reference": "58af67282db37d24e584a837a94ee55b9c7552be" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laminas/laminas-escaper/zipball/58af67282db37d24e584a837a94ee55b9c7552be", + "reference": "58af67282db37d24e584a837a94ee55b9c7552be", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "ext-mbstring": "*", + "php": "^7.4 || ~8.0.0 || ~8.1.0" + }, + "conflict": { + "zendframework/zend-escaper": "*" + }, + "require-dev": { + "infection/infection": "^0.26.6", + "laminas/laminas-coding-standard": "~2.3.0", + "maglnet/composer-require-checker": "^3.8.0", + "phpunit/phpunit": "^9.5.18", + "psalm/plugin-phpunit": "^0.16.1", + "vimeo/psalm": "^4.22.0" + }, + "time": "2022-03-08T20:15:36+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Laminas\\Escaper\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "description": "Securely and safely escape HTML, HTML attributes, JavaScript, CSS, and URLs", + "homepage": "https://laminas.dev", + "keywords": [ + "escaper", + "laminas" + ], + "support": { + "chat": "https://laminas.dev/chat", + "docs": "https://docs.laminas.dev/laminas-escaper/", + "forum": "https://discourse.laminas.dev", + "issues": "https://github.com/laminas/laminas-escaper/issues", + "rss": "https://github.com/laminas/laminas-escaper/releases.atom", + "source": "https://github.com/laminas/laminas-escaper" + }, + "funding": [ + { + "url": "https://funding.communitybridge.org/projects/laminas-project", + "type": "community_bridge" + } + ], + "install-path": "../laminas/laminas-escaper" + }, + { + "name": "league/color-extractor", + "version": "0.3.2", + "version_normalized": "0.3.2.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/color-extractor.git", + "reference": "837086ec60f50c84c611c613963e4ad2e2aec806" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/color-extractor/zipball/837086ec60f50c84c611c613963e4ad2e2aec806", + "reference": "837086ec60f50c84c611c613963e4ad2e2aec806", + "shasum": "" + }, + "require": { + "ext-gd": "*", + "php": ">=5.4.0" + }, + "replace": { + "matthecat/colorextractor": "*" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "~2", + "phpunit/phpunit": "~5" + }, + "time": "2016-12-15T09:30:02+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mathieu Lechat", + "email": "math.lechat@gmail.com", + "homepage": "http://matthecat.com", + "role": "Developer" + } + ], + "description": "Extract colors from an image as a human would do.", + "homepage": "https://github.com/thephpleague/color-extractor", + "keywords": [ + "color", + "extract", + "human", + "image", + "palette" + ], + "support": { + "issues": "https://github.com/thephpleague/color-extractor/issues", + "source": "https://github.com/thephpleague/color-extractor/tree/master" + }, + "install-path": "../league/color-extractor" + }, + { + "name": "michelf/php-smartypants", + "version": "1.8.1", + "version_normalized": "1.8.1.0", + "source": { + "type": "git", + "url": "https://github.com/michelf/php-smartypants.git", + "reference": "47d17c90a4dfd0ccf1f87e25c65e6c8012415aad" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/michelf/php-smartypants/zipball/47d17c90a4dfd0ccf1f87e25c65e6c8012415aad", + "reference": "47d17c90a4dfd0ccf1f87e25c65e6c8012415aad", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "time": "2016-12-13T01:01:17+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-0": { + "Michelf": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Michel Fortin", + "email": "michel.fortin@michelf.ca", + "homepage": "https://michelf.ca/", + "role": "Developer" + }, + { + "name": "John Gruber", + "homepage": "https://daringfireball.net/" + } + ], + "description": "PHP SmartyPants", + "homepage": "https://michelf.ca/projects/php-smartypants/", + "keywords": [ + "dashes", + "quotes", + "spaces", + "typographer", + "typography" + ], + "support": { + "issues": "https://github.com/michelf/php-smartypants/issues", + "source": "https://github.com/michelf/php-smartypants/tree/1.8.1" + }, + "install-path": "../michelf/php-smartypants" + }, + { + "name": "ml/iri", + "version": "1.1.4", + "version_normalized": "1.1.4.0", + "target-dir": "ML/IRI", + "source": { + "type": "git", + "url": "https://github.com/lanthaler/IRI.git", + "reference": "cbd44fa913e00ea624241b38cefaa99da8d71341" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/lanthaler/IRI/zipball/cbd44fa913e00ea624241b38cefaa99da8d71341", + "reference": "cbd44fa913e00ea624241b38cefaa99da8d71341", + "shasum": "" + }, + "require": { + "lib-pcre": ">=4.0", + "php": ">=5.3.0" + }, + "time": "2014-01-21T13:43:39+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-0": { + "ML\\IRI": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Markus Lanthaler", + "email": "mail@markus-lanthaler.com", + "homepage": "http://www.markus-lanthaler.com", + "role": "Developer" + } + ], + "description": "IRI handling for PHP", + "homepage": "http://www.markus-lanthaler.com", + "keywords": [ + "URN", + "iri", + "uri", + "url" + ], + "support": { + "issues": "https://github.com/lanthaler/IRI/issues", + "source": "https://github.com/lanthaler/IRI/tree/master" + }, + "install-path": "../ml/iri/ML/IRI" + }, + { + "name": "ml/json-ld", + "version": "1.2.1", + "version_normalized": "1.2.1.0", + "source": { + "type": "git", + "url": "https://github.com/lanthaler/JsonLD.git", + "reference": "537e68e87a6bce23e57c575cd5dcac1f67ce25d8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/lanthaler/JsonLD/zipball/537e68e87a6bce23e57c575cd5dcac1f67ce25d8", + "reference": "537e68e87a6bce23e57c575cd5dcac1f67ce25d8", + "shasum": "" + }, + "require": { + "ext-json": "*", + "ml/iri": "^1.1.1", + "php": ">=5.3.0" + }, + "require-dev": { + "json-ld/tests": "1.0", + "phpunit/phpunit": "^4" + }, + "time": "2022-09-29T08:45:17+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "ML\\JsonLD\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Markus Lanthaler", + "email": "mail@markus-lanthaler.com", + "homepage": "http://www.markus-lanthaler.com", + "role": "Developer" + } + ], + "description": "JSON-LD Processor for PHP", + "homepage": "http://www.markus-lanthaler.com", + "keywords": [ + "JSON-LD", + "jsonld" + ], + "support": { + "issues": "https://github.com/lanthaler/JsonLD/issues", + "source": "https://github.com/lanthaler/JsonLD/tree/1.2.1" + }, + "install-path": "../ml/json-ld" + }, + { + "name": "oscarotero/html-parser", + "version": "v0.1.8", + "version_normalized": "0.1.8.0", + "source": { + "type": "git", + "url": "https://github.com/oscarotero/html-parser.git", + "reference": "10f3219267a365d9433f2f7d1694209c9d436c8d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/oscarotero/html-parser/zipball/10f3219267a365d9433f2f7d1694209c9d436c8d", + "reference": "10f3219267a365d9433f2f7d1694209c9d436c8d", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^2.11", + "phpunit/phpunit": "^8.0" + }, + "time": "2023-11-29T20:28:41+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "HtmlParser\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Oscar Otero", + "email": "oom@oscarotero.com", + "homepage": "http://oscarotero.com", + "role": "Developer" + } + ], + "description": "Parse html strings to DOMDocument", + "homepage": "https://github.com/oscarotero/html-parser", + "keywords": [ + "dom", + "html", + "parser" + ], + "support": { + "email": "oom@oscarotero.com", + "issues": "https://github.com/oscarotero/html-parser/issues", + "source": "https://github.com/oscarotero/html-parser/tree/v0.1.8" + }, + "install-path": "../oscarotero/html-parser" + }, + { + "name": "phpmailer/phpmailer", + "version": "v6.6.4", + "version_normalized": "6.6.4.0", + "source": { + "type": "git", + "url": "https://github.com/PHPMailer/PHPMailer.git", + "reference": "a94fdebaea6bd17f51be0c2373ab80d3d681269b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/a94fdebaea6bd17f51be0c2373ab80d3d681269b", + "reference": "a94fdebaea6bd17f51be0c2373ab80d3d681269b", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "ext-filter": "*", + "ext-hash": "*", + "php": ">=5.5.0" + }, + "require-dev": { + "dealerdirect/phpcodesniffer-composer-installer": "^0.7.0", + "doctrine/annotations": "^1.2", + "php-parallel-lint/php-console-highlighter": "^1.0.0", + "php-parallel-lint/php-parallel-lint": "^1.3.2", + "phpcompatibility/php-compatibility": "^9.3.5", + "roave/security-advisories": "dev-latest", + "squizlabs/php_codesniffer": "^3.6.2", + "yoast/phpunit-polyfills": "^1.0.0" + }, + "suggest": { + "ext-mbstring": "Needed to send email in multibyte encoding charset or decode encoded addresses", + "hayageek/oauth2-yahoo": "Needed for Yahoo XOAUTH2 authentication", + "league/oauth2-google": "Needed for Google XOAUTH2 authentication", + "psr/log": "For optional PSR-3 debug logging", + "stevenmaguire/oauth2-microsoft": "Needed for Microsoft XOAUTH2 authentication", + "symfony/polyfill-mbstring": "To support UTF-8 if the Mbstring PHP extension is not enabled (^1.2)" + }, + "time": "2022-08-22T09:22:00+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "PHPMailer\\PHPMailer\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-2.1-only" + ], + "authors": [ + { + "name": "Marcus Bointon", + "email": "phpmailer@synchromedia.co.uk" + }, + { + "name": "Jim Jagielski", + "email": "jimjag@gmail.com" + }, + { + "name": "Andy Prevost", + "email": "codeworxtech@users.sourceforge.net" + }, + { + "name": "Brent R. Matzelle" + } + ], + "description": "PHPMailer is a full-featured email creation and transfer class for PHP", + "support": { + "issues": "https://github.com/PHPMailer/PHPMailer/issues", + "source": "https://github.com/PHPMailer/PHPMailer/tree/v6.6.4" + }, + "funding": [ + { + "url": "https://github.com/Synchro", + "type": "github" + } + ], + "install-path": "../phpmailer/phpmailer" + }, + { + "name": "psr/http-client", + "version": "1.0.3", + "version_normalized": "1.0.3.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-client.git", + "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-client/zipball/bb5906edc1c324c9a05aa0873d40117941e5fa90", + "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90", + "shasum": "" + }, + "require": { + "php": "^7.0 || ^8.0", + "psr/http-message": "^1.0 || ^2.0" + }, + "time": "2023-09-23T14:17:50+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Psr\\Http\\Client\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP clients", + "homepage": "https://github.com/php-fig/http-client", + "keywords": [ + "http", + "http-client", + "psr", + "psr-18" + ], + "support": { + "source": "https://github.com/php-fig/http-client" + }, + "install-path": "../psr/http-client" + }, + { + "name": "psr/http-factory", + "version": "1.1.0", + "version_normalized": "1.1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-factory.git", + "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-factory/zipball/2b4765fddfe3b508ac62f829e852b1501d3f6e8a", + "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a", + "shasum": "" + }, + "require": { + "php": ">=7.1", + "psr/http-message": "^1.0 || ^2.0" + }, + "time": "2024-04-15T12:06:14+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "PSR-17: Common interfaces for PSR-7 HTTP message factories", + "keywords": [ + "factory", + "http", + "message", + "psr", + "psr-17", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-factory" + }, + "install-path": "../psr/http-factory" + }, + { + "name": "psr/http-message", + "version": "2.0", + "version_normalized": "2.0.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message.git", + "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/402d35bcb92c70c026d1a6a9883f06b2ead23d71", + "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "time": "2023-04-04T09:54:51+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP messages", + "homepage": "https://github.com/php-fig/http-message", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-message/tree/2.0" + }, + "install-path": "../psr/http-message" + }, + { + "name": "psr/log", + "version": "1.1.4", + "version_normalized": "1.1.4.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "d49695b909c3b7628b6289db5479a1c204601f11" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/d49695b909c3b7628b6289db5479a1c204601f11", + "reference": "d49695b909c3b7628b6289db5479a1c204601f11", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "time": "2021-05-03T11:20:27+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Psr\\Log\\": "Psr/Log/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "support": { + "source": "https://github.com/php-fig/log/tree/1.1.4" + }, + "install-path": "../psr/log" + }, + { + "name": "ralouphie/getallheaders", + "version": "3.0.3", + "version_normalized": "3.0.3.0", + "source": { + "type": "git", + "url": "https://github.com/ralouphie/getallheaders.git", + "reference": "120b605dfeb996808c31b6477290a714d356e822" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", + "reference": "120b605dfeb996808c31b6477290a714d356e822", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.1", + "phpunit/phpunit": "^5 || ^6.5" + }, + "time": "2019-03-08T08:55:37+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "files": [ + "src/getallheaders.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ralph Khattar", + "email": "ralph.khattar@gmail.com" + } + ], + "description": "A polyfill for getallheaders.", + "support": { + "issues": "https://github.com/ralouphie/getallheaders/issues", + "source": "https://github.com/ralouphie/getallheaders/tree/develop" + }, + "install-path": "../ralouphie/getallheaders" + }, + { + "name": "sylvainjule/color-palette", + "version": "1.0.4", + "version_normalized": "1.0.4.0", + "source": { + "type": "git", + "url": "https://github.com/sylvainjule/kirby-color-palette.git", + "reference": "290da479c5bddf55a61974119243987504085223" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sylvainjule/kirby-color-palette/zipball/290da479c5bddf55a61974119243987504085223", + "reference": "290da479c5bddf55a61974119243987504085223", + "shasum": "" + }, + "require": { + "getkirby/composer-installer": "^1.1" + }, + "time": "2020-04-11T10:05:01+00:00", + "type": "kirby-plugin", + "extra": { + "installer-name": "color-palette" + }, + "installation-source": "dist", + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Sylvain Julé", + "email": "contact@sylvain-jule.fr" + } + ], + "description": "A color palette to pick colors from for Kirby", + "support": { + "issues": "https://github.com/sylvainjule/kirby-color-palette/issues", + "source": "https://github.com/sylvainjule/kirby-color-palette/tree/master" + }, + "install-path": "../../site/plugins/color-palette" + }, + { + "name": "sylvainjule/embed", + "version": "1.1.2", + "version_normalized": "1.1.2.0", + "source": { + "type": "git", + "url": "https://github.com/sylvainjule/kirby-embed.git", + "reference": "19a586d64883790b7c5f2366bf5ea128e63d47b3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sylvainjule/kirby-embed/zipball/19a586d64883790b7c5f2366bf5ea128e63d47b3", + "reference": "19a586d64883790b7c5f2366bf5ea128e63d47b3", + "shasum": "" + }, + "require": { + "embed/embed": "4.4.8", + "getkirby/composer-installer": "^1.1", + "guzzlehttp/psr7": "^2.6" + }, + "time": "2024-03-08T14:51:01+00:00", + "type": "kirby-plugin", + "extra": { + "installer-name": "embed" + }, + "installation-source": "dist", + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Sylvain Julé", + "email": "contact@sylvain-jule.fr" + } + ], + "description": "Embed field for Kirby 3", + "support": { + "issues": "https://github.com/sylvainjule/kirby-embed/issues", + "source": "https://github.com/sylvainjule/kirby-embed/tree/1.1.2" + }, + "install-path": "../../site/plugins/embed" + }, + { + "name": "symfony/polyfill-intl-idn", + "version": "v1.26.0", + "version_normalized": "1.26.0.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-idn.git", + "reference": "59a8d271f00dd0e4c2e518104cc7963f655a1aa8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/59a8d271f00dd0e4c2e518104cc7963f655a1aa8", + "reference": "59a8d271f00dd0e4c2e518104cc7963f655a1aa8", + "shasum": "" + }, + "require": { + "php": ">=7.1", + "symfony/polyfill-intl-normalizer": "^1.10", + "symfony/polyfill-php72": "^1.10" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "time": "2022-05-24T11:49:31+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.26-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "installation-source": "dist", + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Idn\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Laurent Bassin", + "email": "laurent@bassin.info" + }, + { + "name": "Trevor Rowbotham", + "email": "trevor.rowbotham@pm.me" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's idn_to_ascii and idn_to_utf8 functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "idn", + "intl", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.26.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "install-path": "../symfony/polyfill-intl-idn" + }, + { + "name": "symfony/polyfill-intl-normalizer", + "version": "v1.30.0", + "version_normalized": "1.30.0.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-normalizer.git", + "reference": "a95281b0be0d9ab48050ebd988b967875cdb9fdb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/a95281b0be0d9ab48050ebd988b967875cdb9fdb", + "reference": "a95281b0be0d9ab48050ebd988b967875cdb9fdb", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "time": "2024-05-31T15:07:36+00:00", + "type": "library", + "extra": { + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "installation-source": "dist", + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Normalizer\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's Normalizer class and related functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "intl", + "normalizer", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.30.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "install-path": "../symfony/polyfill-intl-normalizer" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.26.0", + "version_normalized": "1.26.0.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "9344f9cb97f3b19424af1a21a3b0e75b0a7d8d7e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/9344f9cb97f3b19424af1a21a3b0e75b0a7d8d7e", + "reference": "9344f9cb97f3b19424af1a21a3b0e75b0a7d8d7e", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "provide": { + "ext-mbstring": "*" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "time": "2022-05-24T11:49:31+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.26-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "installation-source": "dist", + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the Mbstring extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.26.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "install-path": "../symfony/polyfill-mbstring" + } + ], + "dev": true, + "dev-package-names": [] +} diff --git a/vendor/composer/installed.php b/vendor/composer/installed.php new file mode 100644 index 0000000..98a502e --- /dev/null +++ b/vendor/composer/installed.php @@ -0,0 +1,272 @@ + array( + 'name' => 'getkirby/plainkit', + 'pretty_version' => 'dev-main', + 'version' => 'dev-main', + 'reference' => 'a4b2aece7b44b516ca8349830f01c2eccae22ff0', + 'type' => 'project', + 'install_path' => __DIR__ . '/../../', + 'aliases' => array(), + 'dev' => true, + ), + 'versions' => array( + 'claviska/simpleimage' => array( + 'pretty_version' => '3.7.0', + 'version' => '3.7.0.0', + 'reference' => 'abd15ced313c7b8041d7d73d8d2398b4f2510cf1', + 'type' => 'library', + 'install_path' => __DIR__ . '/../claviska/simpleimage', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'composer/ca-bundle' => array( + 'pretty_version' => '1.5.1', + 'version' => '1.5.1.0', + 'reference' => '063d9aa8696582f5a41dffbbaf3c81024f0a604a', + 'type' => 'library', + 'install_path' => __DIR__ . '/./ca-bundle', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'embed/embed' => array( + 'pretty_version' => 'v4.4.8', + 'version' => '4.4.8.0', + 'reference' => '49134080764018bc6b8a2488dd1c8cc2c47d15fc', + 'type' => 'library', + 'install_path' => __DIR__ . '/../embed/embed', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'filp/whoops' => array( + 'pretty_version' => '2.14.5', + 'version' => '2.14.5.0', + 'reference' => 'a63e5e8f26ebbebf8ed3c5c691637325512eb0dc', + 'type' => 'library', + 'install_path' => __DIR__ . '/../filp/whoops', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'getkirby/cms' => array( + 'pretty_version' => '3.7.5.5', + 'version' => '3.7.5.5', + 'reference' => 'a645ec70bc0152cc3caa07df303dd57ac25b30db', + 'type' => 'kirby-cms', + 'install_path' => __DIR__ . '/../../kirby', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'getkirby/composer-installer' => array( + 'pretty_version' => '1.2.1', + 'version' => '1.2.1.0', + 'reference' => 'c98ece30bfba45be7ce457e1102d1b169d922f3d', + 'type' => 'composer-plugin', + 'install_path' => __DIR__ . '/../getkirby/composer-installer', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'getkirby/plainkit' => array( + 'pretty_version' => 'dev-main', + 'version' => 'dev-main', + 'reference' => 'a4b2aece7b44b516ca8349830f01c2eccae22ff0', + 'type' => 'project', + 'install_path' => __DIR__ . '/../../', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'guzzlehttp/psr7' => array( + 'pretty_version' => '2.7.0', + 'version' => '2.7.0.0', + 'reference' => 'a70f5c95fb43bc83f07c9c948baa0dc1829bf201', + 'type' => 'library', + 'install_path' => __DIR__ . '/../guzzlehttp/psr7', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'jg/kirby-fields-block' => array( + 'pretty_version' => 'v1.2.1', + 'version' => '1.2.1.0', + 'reference' => 'e56c4d109edd921a1b4436e3df0e64b1117f1b83', + 'type' => 'kirby-plugin', + 'install_path' => __DIR__ . '/../../site/plugins/kirby-fields-block', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'laminas/laminas-escaper' => array( + 'pretty_version' => '2.10.0', + 'version' => '2.10.0.0', + 'reference' => '58af67282db37d24e584a837a94ee55b9c7552be', + 'type' => 'library', + 'install_path' => __DIR__ . '/../laminas/laminas-escaper', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'league/color-extractor' => array( + 'pretty_version' => '0.3.2', + 'version' => '0.3.2.0', + 'reference' => '837086ec60f50c84c611c613963e4ad2e2aec806', + 'type' => 'library', + 'install_path' => __DIR__ . '/../league/color-extractor', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'matthecat/colorextractor' => array( + 'dev_requirement' => false, + 'replaced' => array( + 0 => '*', + ), + ), + 'michelf/php-smartypants' => array( + 'pretty_version' => '1.8.1', + 'version' => '1.8.1.0', + 'reference' => '47d17c90a4dfd0ccf1f87e25c65e6c8012415aad', + 'type' => 'library', + 'install_path' => __DIR__ . '/../michelf/php-smartypants', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'ml/iri' => array( + 'pretty_version' => '1.1.4', + 'version' => '1.1.4.0', + 'reference' => 'cbd44fa913e00ea624241b38cefaa99da8d71341', + 'type' => 'library', + 'install_path' => __DIR__ . '/../ml/iri/ML/IRI', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'ml/json-ld' => array( + 'pretty_version' => '1.2.1', + 'version' => '1.2.1.0', + 'reference' => '537e68e87a6bce23e57c575cd5dcac1f67ce25d8', + 'type' => 'library', + 'install_path' => __DIR__ . '/../ml/json-ld', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'oscarotero/html-parser' => array( + 'pretty_version' => 'v0.1.8', + 'version' => '0.1.8.0', + 'reference' => '10f3219267a365d9433f2f7d1694209c9d436c8d', + 'type' => 'library', + 'install_path' => __DIR__ . '/../oscarotero/html-parser', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'phpmailer/phpmailer' => array( + 'pretty_version' => 'v6.6.4', + 'version' => '6.6.4.0', + 'reference' => 'a94fdebaea6bd17f51be0c2373ab80d3d681269b', + 'type' => 'library', + 'install_path' => __DIR__ . '/../phpmailer/phpmailer', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'psr/http-client' => array( + 'pretty_version' => '1.0.3', + 'version' => '1.0.3.0', + 'reference' => 'bb5906edc1c324c9a05aa0873d40117941e5fa90', + 'type' => 'library', + 'install_path' => __DIR__ . '/../psr/http-client', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'psr/http-factory' => array( + 'pretty_version' => '1.1.0', + 'version' => '1.1.0.0', + 'reference' => '2b4765fddfe3b508ac62f829e852b1501d3f6e8a', + 'type' => 'library', + 'install_path' => __DIR__ . '/../psr/http-factory', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'psr/http-factory-implementation' => array( + 'dev_requirement' => false, + 'provided' => array( + 0 => '1.0', + ), + ), + 'psr/http-message' => array( + 'pretty_version' => '2.0', + 'version' => '2.0.0.0', + 'reference' => '402d35bcb92c70c026d1a6a9883f06b2ead23d71', + 'type' => 'library', + 'install_path' => __DIR__ . '/../psr/http-message', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'psr/http-message-implementation' => array( + 'dev_requirement' => false, + 'provided' => array( + 0 => '1.0', + ), + ), + 'psr/log' => array( + 'pretty_version' => '1.1.4', + 'version' => '1.1.4.0', + 'reference' => 'd49695b909c3b7628b6289db5479a1c204601f11', + 'type' => 'library', + 'install_path' => __DIR__ . '/../psr/log', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'ralouphie/getallheaders' => array( + 'pretty_version' => '3.0.3', + 'version' => '3.0.3.0', + 'reference' => '120b605dfeb996808c31b6477290a714d356e822', + 'type' => 'library', + 'install_path' => __DIR__ . '/../ralouphie/getallheaders', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'sylvainjule/color-palette' => array( + 'pretty_version' => '1.0.4', + 'version' => '1.0.4.0', + 'reference' => '290da479c5bddf55a61974119243987504085223', + 'type' => 'kirby-plugin', + 'install_path' => __DIR__ . '/../../site/plugins/color-palette', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'sylvainjule/embed' => array( + 'pretty_version' => '1.1.2', + 'version' => '1.1.2.0', + 'reference' => '19a586d64883790b7c5f2366bf5ea128e63d47b3', + 'type' => 'kirby-plugin', + 'install_path' => __DIR__ . '/../../site/plugins/embed', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'symfony/polyfill-intl-idn' => array( + 'pretty_version' => 'v1.26.0', + 'version' => '1.26.0.0', + 'reference' => '59a8d271f00dd0e4c2e518104cc7963f655a1aa8', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/polyfill-intl-idn', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'symfony/polyfill-intl-normalizer' => array( + 'pretty_version' => 'v1.30.0', + 'version' => '1.30.0.0', + 'reference' => 'a95281b0be0d9ab48050ebd988b967875cdb9fdb', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/polyfill-intl-normalizer', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'symfony/polyfill-mbstring' => array( + 'pretty_version' => 'v1.26.0', + 'version' => '1.26.0.0', + 'reference' => '9344f9cb97f3b19424af1a21a3b0e75b0a7d8d7e', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/polyfill-mbstring', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'symfony/polyfill-php72' => array( + 'dev_requirement' => false, + 'replaced' => array( + 0 => '*', + ), + ), + ), +); diff --git a/site/plugins/embed/vendor/composer/platform_check.php b/vendor/composer/platform_check.php similarity index 100% rename from site/plugins/embed/vendor/composer/platform_check.php rename to vendor/composer/platform_check.php diff --git a/site/plugins/embed/vendor/embed/embed/CHANGELOG.md b/vendor/embed/embed/CHANGELOG.md similarity index 100% rename from site/plugins/embed/vendor/embed/embed/CHANGELOG.md rename to vendor/embed/embed/CHANGELOG.md diff --git a/site/plugins/embed/vendor/embed/embed/LICENSE b/vendor/embed/embed/LICENSE similarity index 100% rename from site/plugins/embed/vendor/embed/embed/LICENSE rename to vendor/embed/embed/LICENSE diff --git a/site/plugins/embed/vendor/embed/embed/README.md b/vendor/embed/embed/README.md similarity index 100% rename from site/plugins/embed/vendor/embed/embed/README.md rename to vendor/embed/embed/README.md diff --git a/site/plugins/embed/vendor/embed/embed/composer.json b/vendor/embed/embed/composer.json similarity index 100% rename from site/plugins/embed/vendor/embed/embed/composer.json rename to vendor/embed/embed/composer.json diff --git a/site/plugins/embed/vendor/embed/embed/src/Adapters/Archive/Api.php b/vendor/embed/embed/src/Adapters/Archive/Api.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/Adapters/Archive/Api.php rename to vendor/embed/embed/src/Adapters/Archive/Api.php diff --git a/site/plugins/embed/vendor/embed/embed/src/Adapters/Archive/Detectors/AuthorName.php b/vendor/embed/embed/src/Adapters/Archive/Detectors/AuthorName.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/Adapters/Archive/Detectors/AuthorName.php rename to vendor/embed/embed/src/Adapters/Archive/Detectors/AuthorName.php diff --git a/site/plugins/embed/vendor/embed/embed/src/Adapters/Archive/Detectors/Code.php b/vendor/embed/embed/src/Adapters/Archive/Detectors/Code.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/Adapters/Archive/Detectors/Code.php rename to vendor/embed/embed/src/Adapters/Archive/Detectors/Code.php diff --git a/site/plugins/embed/vendor/embed/embed/src/Adapters/Archive/Detectors/Description.php b/vendor/embed/embed/src/Adapters/Archive/Detectors/Description.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/Adapters/Archive/Detectors/Description.php rename to vendor/embed/embed/src/Adapters/Archive/Detectors/Description.php diff --git a/site/plugins/embed/vendor/embed/embed/src/Adapters/Archive/Detectors/ProviderName.php b/vendor/embed/embed/src/Adapters/Archive/Detectors/ProviderName.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/Adapters/Archive/Detectors/ProviderName.php rename to vendor/embed/embed/src/Adapters/Archive/Detectors/ProviderName.php diff --git a/site/plugins/embed/vendor/embed/embed/src/Adapters/Archive/Detectors/PublishedTime.php b/vendor/embed/embed/src/Adapters/Archive/Detectors/PublishedTime.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/Adapters/Archive/Detectors/PublishedTime.php rename to vendor/embed/embed/src/Adapters/Archive/Detectors/PublishedTime.php diff --git a/site/plugins/embed/vendor/embed/embed/src/Adapters/Archive/Detectors/Title.php b/vendor/embed/embed/src/Adapters/Archive/Detectors/Title.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/Adapters/Archive/Detectors/Title.php rename to vendor/embed/embed/src/Adapters/Archive/Detectors/Title.php diff --git a/site/plugins/embed/vendor/embed/embed/src/Adapters/Archive/Extractor.php b/vendor/embed/embed/src/Adapters/Archive/Extractor.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/Adapters/Archive/Extractor.php rename to vendor/embed/embed/src/Adapters/Archive/Extractor.php diff --git a/site/plugins/embed/vendor/embed/embed/src/Adapters/Bandcamp/Detectors/ProviderName.php b/vendor/embed/embed/src/Adapters/Bandcamp/Detectors/ProviderName.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/Adapters/Bandcamp/Detectors/ProviderName.php rename to vendor/embed/embed/src/Adapters/Bandcamp/Detectors/ProviderName.php diff --git a/site/plugins/embed/vendor/embed/embed/src/Adapters/Bandcamp/Extractor.php b/vendor/embed/embed/src/Adapters/Bandcamp/Extractor.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/Adapters/Bandcamp/Extractor.php rename to vendor/embed/embed/src/Adapters/Bandcamp/Extractor.php diff --git a/site/plugins/embed/vendor/embed/embed/src/Adapters/CadenaSer/Detectors/Code.php b/vendor/embed/embed/src/Adapters/CadenaSer/Detectors/Code.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/Adapters/CadenaSer/Detectors/Code.php rename to vendor/embed/embed/src/Adapters/CadenaSer/Detectors/Code.php diff --git a/site/plugins/embed/vendor/embed/embed/src/Adapters/CadenaSer/Extractor.php b/vendor/embed/embed/src/Adapters/CadenaSer/Extractor.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/Adapters/CadenaSer/Extractor.php rename to vendor/embed/embed/src/Adapters/CadenaSer/Extractor.php diff --git a/site/plugins/embed/vendor/embed/embed/src/Adapters/Facebook/Detectors/Title.php b/vendor/embed/embed/src/Adapters/Facebook/Detectors/Title.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/Adapters/Facebook/Detectors/Title.php rename to vendor/embed/embed/src/Adapters/Facebook/Detectors/Title.php diff --git a/site/plugins/embed/vendor/embed/embed/src/Adapters/Facebook/Extractor.php b/vendor/embed/embed/src/Adapters/Facebook/Extractor.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/Adapters/Facebook/Extractor.php rename to vendor/embed/embed/src/Adapters/Facebook/Extractor.php diff --git a/site/plugins/embed/vendor/embed/embed/src/Adapters/Facebook/OEmbed.php b/vendor/embed/embed/src/Adapters/Facebook/OEmbed.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/Adapters/Facebook/OEmbed.php rename to vendor/embed/embed/src/Adapters/Facebook/OEmbed.php diff --git a/site/plugins/embed/vendor/embed/embed/src/Adapters/Flickr/Detectors/Code.php b/vendor/embed/embed/src/Adapters/Flickr/Detectors/Code.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/Adapters/Flickr/Detectors/Code.php rename to vendor/embed/embed/src/Adapters/Flickr/Detectors/Code.php diff --git a/site/plugins/embed/vendor/embed/embed/src/Adapters/Flickr/Extractor.php b/vendor/embed/embed/src/Adapters/Flickr/Extractor.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/Adapters/Flickr/Extractor.php rename to vendor/embed/embed/src/Adapters/Flickr/Extractor.php diff --git a/site/plugins/embed/vendor/embed/embed/src/Adapters/Gist/Api.php b/vendor/embed/embed/src/Adapters/Gist/Api.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/Adapters/Gist/Api.php rename to vendor/embed/embed/src/Adapters/Gist/Api.php diff --git a/site/plugins/embed/vendor/embed/embed/src/Adapters/Gist/Detectors/AuthorName.php b/vendor/embed/embed/src/Adapters/Gist/Detectors/AuthorName.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/Adapters/Gist/Detectors/AuthorName.php rename to vendor/embed/embed/src/Adapters/Gist/Detectors/AuthorName.php diff --git a/site/plugins/embed/vendor/embed/embed/src/Adapters/Gist/Detectors/AuthorUrl.php b/vendor/embed/embed/src/Adapters/Gist/Detectors/AuthorUrl.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/Adapters/Gist/Detectors/AuthorUrl.php rename to vendor/embed/embed/src/Adapters/Gist/Detectors/AuthorUrl.php diff --git a/site/plugins/embed/vendor/embed/embed/src/Adapters/Gist/Detectors/Code.php b/vendor/embed/embed/src/Adapters/Gist/Detectors/Code.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/Adapters/Gist/Detectors/Code.php rename to vendor/embed/embed/src/Adapters/Gist/Detectors/Code.php diff --git a/site/plugins/embed/vendor/embed/embed/src/Adapters/Gist/Detectors/PublishedTime.php b/vendor/embed/embed/src/Adapters/Gist/Detectors/PublishedTime.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/Adapters/Gist/Detectors/PublishedTime.php rename to vendor/embed/embed/src/Adapters/Gist/Detectors/PublishedTime.php diff --git a/site/plugins/embed/vendor/embed/embed/src/Adapters/Gist/Extractor.php b/vendor/embed/embed/src/Adapters/Gist/Extractor.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/Adapters/Gist/Extractor.php rename to vendor/embed/embed/src/Adapters/Gist/Extractor.php diff --git a/site/plugins/embed/vendor/embed/embed/src/Adapters/Github/Detectors/Code.php b/vendor/embed/embed/src/Adapters/Github/Detectors/Code.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/Adapters/Github/Detectors/Code.php rename to vendor/embed/embed/src/Adapters/Github/Detectors/Code.php diff --git a/site/plugins/embed/vendor/embed/embed/src/Adapters/Github/Extractor.php b/vendor/embed/embed/src/Adapters/Github/Extractor.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/Adapters/Github/Extractor.php rename to vendor/embed/embed/src/Adapters/Github/Extractor.php diff --git a/site/plugins/embed/vendor/embed/embed/src/Adapters/Ideone/Detectors/Code.php b/vendor/embed/embed/src/Adapters/Ideone/Detectors/Code.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/Adapters/Ideone/Detectors/Code.php rename to vendor/embed/embed/src/Adapters/Ideone/Detectors/Code.php diff --git a/site/plugins/embed/vendor/embed/embed/src/Adapters/Ideone/Extractor.php b/vendor/embed/embed/src/Adapters/Ideone/Extractor.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/Adapters/Ideone/Extractor.php rename to vendor/embed/embed/src/Adapters/Ideone/Extractor.php diff --git a/site/plugins/embed/vendor/embed/embed/src/Adapters/ImageShack/Api.php b/vendor/embed/embed/src/Adapters/ImageShack/Api.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/Adapters/ImageShack/Api.php rename to vendor/embed/embed/src/Adapters/ImageShack/Api.php diff --git a/site/plugins/embed/vendor/embed/embed/src/Adapters/ImageShack/Detectors/AuthorName.php b/vendor/embed/embed/src/Adapters/ImageShack/Detectors/AuthorName.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/Adapters/ImageShack/Detectors/AuthorName.php rename to vendor/embed/embed/src/Adapters/ImageShack/Detectors/AuthorName.php diff --git a/site/plugins/embed/vendor/embed/embed/src/Adapters/ImageShack/Detectors/AuthorUrl.php b/vendor/embed/embed/src/Adapters/ImageShack/Detectors/AuthorUrl.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/Adapters/ImageShack/Detectors/AuthorUrl.php rename to vendor/embed/embed/src/Adapters/ImageShack/Detectors/AuthorUrl.php diff --git a/site/plugins/embed/vendor/embed/embed/src/Adapters/ImageShack/Detectors/Description.php b/vendor/embed/embed/src/Adapters/ImageShack/Detectors/Description.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/Adapters/ImageShack/Detectors/Description.php rename to vendor/embed/embed/src/Adapters/ImageShack/Detectors/Description.php diff --git a/site/plugins/embed/vendor/embed/embed/src/Adapters/ImageShack/Detectors/Image.php b/vendor/embed/embed/src/Adapters/ImageShack/Detectors/Image.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/Adapters/ImageShack/Detectors/Image.php rename to vendor/embed/embed/src/Adapters/ImageShack/Detectors/Image.php diff --git a/site/plugins/embed/vendor/embed/embed/src/Adapters/ImageShack/Detectors/ProviderName.php b/vendor/embed/embed/src/Adapters/ImageShack/Detectors/ProviderName.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/Adapters/ImageShack/Detectors/ProviderName.php rename to vendor/embed/embed/src/Adapters/ImageShack/Detectors/ProviderName.php diff --git a/site/plugins/embed/vendor/embed/embed/src/Adapters/ImageShack/Detectors/PublishedTime.php b/vendor/embed/embed/src/Adapters/ImageShack/Detectors/PublishedTime.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/Adapters/ImageShack/Detectors/PublishedTime.php rename to vendor/embed/embed/src/Adapters/ImageShack/Detectors/PublishedTime.php diff --git a/site/plugins/embed/vendor/embed/embed/src/Adapters/ImageShack/Detectors/Title.php b/vendor/embed/embed/src/Adapters/ImageShack/Detectors/Title.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/Adapters/ImageShack/Detectors/Title.php rename to vendor/embed/embed/src/Adapters/ImageShack/Detectors/Title.php diff --git a/site/plugins/embed/vendor/embed/embed/src/Adapters/ImageShack/Extractor.php b/vendor/embed/embed/src/Adapters/ImageShack/Extractor.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/Adapters/ImageShack/Extractor.php rename to vendor/embed/embed/src/Adapters/ImageShack/Extractor.php diff --git a/site/plugins/embed/vendor/embed/embed/src/Adapters/Instagram/Extractor.php b/vendor/embed/embed/src/Adapters/Instagram/Extractor.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/Adapters/Instagram/Extractor.php rename to vendor/embed/embed/src/Adapters/Instagram/Extractor.php diff --git a/site/plugins/embed/vendor/embed/embed/src/Adapters/Instagram/OEmbed.php b/vendor/embed/embed/src/Adapters/Instagram/OEmbed.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/Adapters/Instagram/OEmbed.php rename to vendor/embed/embed/src/Adapters/Instagram/OEmbed.php diff --git a/site/plugins/embed/vendor/embed/embed/src/Adapters/Pinterest/Detectors/Code.php b/vendor/embed/embed/src/Adapters/Pinterest/Detectors/Code.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/Adapters/Pinterest/Detectors/Code.php rename to vendor/embed/embed/src/Adapters/Pinterest/Detectors/Code.php diff --git a/site/plugins/embed/vendor/embed/embed/src/Adapters/Pinterest/Extractor.php b/vendor/embed/embed/src/Adapters/Pinterest/Extractor.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/Adapters/Pinterest/Extractor.php rename to vendor/embed/embed/src/Adapters/Pinterest/Extractor.php diff --git a/site/plugins/embed/vendor/embed/embed/src/Adapters/Sassmeister/Detectors/Code.php b/vendor/embed/embed/src/Adapters/Sassmeister/Detectors/Code.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/Adapters/Sassmeister/Detectors/Code.php rename to vendor/embed/embed/src/Adapters/Sassmeister/Detectors/Code.php diff --git a/site/plugins/embed/vendor/embed/embed/src/Adapters/Sassmeister/Extractor.php b/vendor/embed/embed/src/Adapters/Sassmeister/Extractor.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/Adapters/Sassmeister/Extractor.php rename to vendor/embed/embed/src/Adapters/Sassmeister/Extractor.php diff --git a/site/plugins/embed/vendor/embed/embed/src/Adapters/Slides/Detectors/Code.php b/vendor/embed/embed/src/Adapters/Slides/Detectors/Code.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/Adapters/Slides/Detectors/Code.php rename to vendor/embed/embed/src/Adapters/Slides/Detectors/Code.php diff --git a/site/plugins/embed/vendor/embed/embed/src/Adapters/Slides/Extractor.php b/vendor/embed/embed/src/Adapters/Slides/Extractor.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/Adapters/Slides/Extractor.php rename to vendor/embed/embed/src/Adapters/Slides/Extractor.php diff --git a/site/plugins/embed/vendor/embed/embed/src/Adapters/Snipplr/Detectors/Code.php b/vendor/embed/embed/src/Adapters/Snipplr/Detectors/Code.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/Adapters/Snipplr/Detectors/Code.php rename to vendor/embed/embed/src/Adapters/Snipplr/Detectors/Code.php diff --git a/site/plugins/embed/vendor/embed/embed/src/Adapters/Snipplr/Extractor.php b/vendor/embed/embed/src/Adapters/Snipplr/Extractor.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/Adapters/Snipplr/Extractor.php rename to vendor/embed/embed/src/Adapters/Snipplr/Extractor.php diff --git a/site/plugins/embed/vendor/embed/embed/src/Adapters/Twitch/Detectors/Code.php b/vendor/embed/embed/src/Adapters/Twitch/Detectors/Code.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/Adapters/Twitch/Detectors/Code.php rename to vendor/embed/embed/src/Adapters/Twitch/Detectors/Code.php diff --git a/site/plugins/embed/vendor/embed/embed/src/Adapters/Twitch/Extractor.php b/vendor/embed/embed/src/Adapters/Twitch/Extractor.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/Adapters/Twitch/Extractor.php rename to vendor/embed/embed/src/Adapters/Twitch/Extractor.php diff --git a/site/plugins/embed/vendor/embed/embed/src/Adapters/Twitter/Api.php b/vendor/embed/embed/src/Adapters/Twitter/Api.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/Adapters/Twitter/Api.php rename to vendor/embed/embed/src/Adapters/Twitter/Api.php diff --git a/site/plugins/embed/vendor/embed/embed/src/Adapters/Twitter/Detectors/AuthorName.php b/vendor/embed/embed/src/Adapters/Twitter/Detectors/AuthorName.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/Adapters/Twitter/Detectors/AuthorName.php rename to vendor/embed/embed/src/Adapters/Twitter/Detectors/AuthorName.php diff --git a/site/plugins/embed/vendor/embed/embed/src/Adapters/Twitter/Detectors/AuthorUrl.php b/vendor/embed/embed/src/Adapters/Twitter/Detectors/AuthorUrl.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/Adapters/Twitter/Detectors/AuthorUrl.php rename to vendor/embed/embed/src/Adapters/Twitter/Detectors/AuthorUrl.php diff --git a/site/plugins/embed/vendor/embed/embed/src/Adapters/Twitter/Detectors/Description.php b/vendor/embed/embed/src/Adapters/Twitter/Detectors/Description.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/Adapters/Twitter/Detectors/Description.php rename to vendor/embed/embed/src/Adapters/Twitter/Detectors/Description.php diff --git a/site/plugins/embed/vendor/embed/embed/src/Adapters/Twitter/Detectors/Image.php b/vendor/embed/embed/src/Adapters/Twitter/Detectors/Image.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/Adapters/Twitter/Detectors/Image.php rename to vendor/embed/embed/src/Adapters/Twitter/Detectors/Image.php diff --git a/site/plugins/embed/vendor/embed/embed/src/Adapters/Twitter/Detectors/ProviderName.php b/vendor/embed/embed/src/Adapters/Twitter/Detectors/ProviderName.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/Adapters/Twitter/Detectors/ProviderName.php rename to vendor/embed/embed/src/Adapters/Twitter/Detectors/ProviderName.php diff --git a/site/plugins/embed/vendor/embed/embed/src/Adapters/Twitter/Detectors/PublishedTime.php b/vendor/embed/embed/src/Adapters/Twitter/Detectors/PublishedTime.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/Adapters/Twitter/Detectors/PublishedTime.php rename to vendor/embed/embed/src/Adapters/Twitter/Detectors/PublishedTime.php diff --git a/site/plugins/embed/vendor/embed/embed/src/Adapters/Twitter/Detectors/Title.php b/vendor/embed/embed/src/Adapters/Twitter/Detectors/Title.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/Adapters/Twitter/Detectors/Title.php rename to vendor/embed/embed/src/Adapters/Twitter/Detectors/Title.php diff --git a/site/plugins/embed/vendor/embed/embed/src/Adapters/Twitter/Extractor.php b/vendor/embed/embed/src/Adapters/Twitter/Extractor.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/Adapters/Twitter/Extractor.php rename to vendor/embed/embed/src/Adapters/Twitter/Extractor.php diff --git a/site/plugins/embed/vendor/embed/embed/src/Adapters/Wikipedia/Api.php b/vendor/embed/embed/src/Adapters/Wikipedia/Api.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/Adapters/Wikipedia/Api.php rename to vendor/embed/embed/src/Adapters/Wikipedia/Api.php diff --git a/site/plugins/embed/vendor/embed/embed/src/Adapters/Wikipedia/Detectors/Description.php b/vendor/embed/embed/src/Adapters/Wikipedia/Detectors/Description.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/Adapters/Wikipedia/Detectors/Description.php rename to vendor/embed/embed/src/Adapters/Wikipedia/Detectors/Description.php diff --git a/site/plugins/embed/vendor/embed/embed/src/Adapters/Wikipedia/Detectors/Title.php b/vendor/embed/embed/src/Adapters/Wikipedia/Detectors/Title.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/Adapters/Wikipedia/Detectors/Title.php rename to vendor/embed/embed/src/Adapters/Wikipedia/Detectors/Title.php diff --git a/site/plugins/embed/vendor/embed/embed/src/Adapters/Wikipedia/Extractor.php b/vendor/embed/embed/src/Adapters/Wikipedia/Extractor.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/Adapters/Wikipedia/Extractor.php rename to vendor/embed/embed/src/Adapters/Wikipedia/Extractor.php diff --git a/site/plugins/embed/vendor/embed/embed/src/Adapters/Youtube/Detectors/Feeds.php b/vendor/embed/embed/src/Adapters/Youtube/Detectors/Feeds.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/Adapters/Youtube/Detectors/Feeds.php rename to vendor/embed/embed/src/Adapters/Youtube/Detectors/Feeds.php diff --git a/site/plugins/embed/vendor/embed/embed/src/Adapters/Youtube/Extractor.php b/vendor/embed/embed/src/Adapters/Youtube/Extractor.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/Adapters/Youtube/Extractor.php rename to vendor/embed/embed/src/Adapters/Youtube/Extractor.php diff --git a/site/plugins/embed/vendor/embed/embed/src/ApiTrait.php b/vendor/embed/embed/src/ApiTrait.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/ApiTrait.php rename to vendor/embed/embed/src/ApiTrait.php diff --git a/site/plugins/embed/vendor/embed/embed/src/Detectors/AuthorName.php b/vendor/embed/embed/src/Detectors/AuthorName.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/Detectors/AuthorName.php rename to vendor/embed/embed/src/Detectors/AuthorName.php diff --git a/site/plugins/embed/vendor/embed/embed/src/Detectors/AuthorUrl.php b/vendor/embed/embed/src/Detectors/AuthorUrl.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/Detectors/AuthorUrl.php rename to vendor/embed/embed/src/Detectors/AuthorUrl.php diff --git a/site/plugins/embed/vendor/embed/embed/src/Detectors/Cms.php b/vendor/embed/embed/src/Detectors/Cms.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/Detectors/Cms.php rename to vendor/embed/embed/src/Detectors/Cms.php diff --git a/site/plugins/embed/vendor/embed/embed/src/Detectors/Code.php b/vendor/embed/embed/src/Detectors/Code.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/Detectors/Code.php rename to vendor/embed/embed/src/Detectors/Code.php diff --git a/site/plugins/embed/vendor/embed/embed/src/Detectors/Description.php b/vendor/embed/embed/src/Detectors/Description.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/Detectors/Description.php rename to vendor/embed/embed/src/Detectors/Description.php diff --git a/site/plugins/embed/vendor/embed/embed/src/Detectors/Detector.php b/vendor/embed/embed/src/Detectors/Detector.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/Detectors/Detector.php rename to vendor/embed/embed/src/Detectors/Detector.php diff --git a/site/plugins/embed/vendor/embed/embed/src/Detectors/Favicon.php b/vendor/embed/embed/src/Detectors/Favicon.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/Detectors/Favicon.php rename to vendor/embed/embed/src/Detectors/Favicon.php diff --git a/site/plugins/embed/vendor/embed/embed/src/Detectors/Feeds.php b/vendor/embed/embed/src/Detectors/Feeds.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/Detectors/Feeds.php rename to vendor/embed/embed/src/Detectors/Feeds.php diff --git a/site/plugins/embed/vendor/embed/embed/src/Detectors/Icon.php b/vendor/embed/embed/src/Detectors/Icon.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/Detectors/Icon.php rename to vendor/embed/embed/src/Detectors/Icon.php diff --git a/site/plugins/embed/vendor/embed/embed/src/Detectors/Image.php b/vendor/embed/embed/src/Detectors/Image.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/Detectors/Image.php rename to vendor/embed/embed/src/Detectors/Image.php diff --git a/site/plugins/embed/vendor/embed/embed/src/Detectors/Keywords.php b/vendor/embed/embed/src/Detectors/Keywords.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/Detectors/Keywords.php rename to vendor/embed/embed/src/Detectors/Keywords.php diff --git a/site/plugins/embed/vendor/embed/embed/src/Detectors/Language.php b/vendor/embed/embed/src/Detectors/Language.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/Detectors/Language.php rename to vendor/embed/embed/src/Detectors/Language.php diff --git a/site/plugins/embed/vendor/embed/embed/src/Detectors/Languages.php b/vendor/embed/embed/src/Detectors/Languages.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/Detectors/Languages.php rename to vendor/embed/embed/src/Detectors/Languages.php diff --git a/site/plugins/embed/vendor/embed/embed/src/Detectors/License.php b/vendor/embed/embed/src/Detectors/License.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/Detectors/License.php rename to vendor/embed/embed/src/Detectors/License.php diff --git a/site/plugins/embed/vendor/embed/embed/src/Detectors/ProviderName.php b/vendor/embed/embed/src/Detectors/ProviderName.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/Detectors/ProviderName.php rename to vendor/embed/embed/src/Detectors/ProviderName.php diff --git a/site/plugins/embed/vendor/embed/embed/src/Detectors/ProviderUrl.php b/vendor/embed/embed/src/Detectors/ProviderUrl.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/Detectors/ProviderUrl.php rename to vendor/embed/embed/src/Detectors/ProviderUrl.php diff --git a/site/plugins/embed/vendor/embed/embed/src/Detectors/PublishedTime.php b/vendor/embed/embed/src/Detectors/PublishedTime.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/Detectors/PublishedTime.php rename to vendor/embed/embed/src/Detectors/PublishedTime.php diff --git a/site/plugins/embed/vendor/embed/embed/src/Detectors/Redirect.php b/vendor/embed/embed/src/Detectors/Redirect.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/Detectors/Redirect.php rename to vendor/embed/embed/src/Detectors/Redirect.php diff --git a/site/plugins/embed/vendor/embed/embed/src/Detectors/Title.php b/vendor/embed/embed/src/Detectors/Title.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/Detectors/Title.php rename to vendor/embed/embed/src/Detectors/Title.php diff --git a/site/plugins/embed/vendor/embed/embed/src/Detectors/Url.php b/vendor/embed/embed/src/Detectors/Url.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/Detectors/Url.php rename to vendor/embed/embed/src/Detectors/Url.php diff --git a/site/plugins/embed/vendor/embed/embed/src/Document.php b/vendor/embed/embed/src/Document.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/Document.php rename to vendor/embed/embed/src/Document.php diff --git a/site/plugins/embed/vendor/embed/embed/src/Embed.php b/vendor/embed/embed/src/Embed.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/Embed.php rename to vendor/embed/embed/src/Embed.php diff --git a/site/plugins/embed/vendor/embed/embed/src/EmbedCode.php b/vendor/embed/embed/src/EmbedCode.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/EmbedCode.php rename to vendor/embed/embed/src/EmbedCode.php diff --git a/site/plugins/embed/vendor/embed/embed/src/Extractor.php b/vendor/embed/embed/src/Extractor.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/Extractor.php rename to vendor/embed/embed/src/Extractor.php diff --git a/site/plugins/embed/vendor/embed/embed/src/ExtractorFactory.php b/vendor/embed/embed/src/ExtractorFactory.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/ExtractorFactory.php rename to vendor/embed/embed/src/ExtractorFactory.php diff --git a/site/plugins/embed/vendor/embed/embed/src/Http/Crawler.php b/vendor/embed/embed/src/Http/Crawler.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/Http/Crawler.php rename to vendor/embed/embed/src/Http/Crawler.php diff --git a/site/plugins/embed/vendor/embed/embed/src/Http/CurlClient.php b/vendor/embed/embed/src/Http/CurlClient.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/Http/CurlClient.php rename to vendor/embed/embed/src/Http/CurlClient.php diff --git a/site/plugins/embed/vendor/embed/embed/src/Http/CurlDispatcher.php b/vendor/embed/embed/src/Http/CurlDispatcher.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/Http/CurlDispatcher.php rename to vendor/embed/embed/src/Http/CurlDispatcher.php diff --git a/site/plugins/embed/vendor/embed/embed/src/Http/FactoryDiscovery.php b/vendor/embed/embed/src/Http/FactoryDiscovery.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/Http/FactoryDiscovery.php rename to vendor/embed/embed/src/Http/FactoryDiscovery.php diff --git a/site/plugins/embed/vendor/embed/embed/src/Http/NetworkException.php b/vendor/embed/embed/src/Http/NetworkException.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/Http/NetworkException.php rename to vendor/embed/embed/src/Http/NetworkException.php diff --git a/site/plugins/embed/vendor/embed/embed/src/Http/RequestException.php b/vendor/embed/embed/src/Http/RequestException.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/Http/RequestException.php rename to vendor/embed/embed/src/Http/RequestException.php diff --git a/site/plugins/embed/vendor/embed/embed/src/HttpApiTrait.php b/vendor/embed/embed/src/HttpApiTrait.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/HttpApiTrait.php rename to vendor/embed/embed/src/HttpApiTrait.php diff --git a/site/plugins/embed/vendor/embed/embed/src/LinkedData.php b/vendor/embed/embed/src/LinkedData.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/LinkedData.php rename to vendor/embed/embed/src/LinkedData.php diff --git a/site/plugins/embed/vendor/embed/embed/src/Metas.php b/vendor/embed/embed/src/Metas.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/Metas.php rename to vendor/embed/embed/src/Metas.php diff --git a/site/plugins/embed/vendor/embed/embed/src/OEmbed.php b/vendor/embed/embed/src/OEmbed.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/OEmbed.php rename to vendor/embed/embed/src/OEmbed.php diff --git a/site/plugins/embed/vendor/embed/embed/src/QueryResult.php b/vendor/embed/embed/src/QueryResult.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/QueryResult.php rename to vendor/embed/embed/src/QueryResult.php diff --git a/site/plugins/embed/vendor/embed/embed/src/functions.php b/vendor/embed/embed/src/functions.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/functions.php rename to vendor/embed/embed/src/functions.php diff --git a/site/plugins/embed/vendor/embed/embed/src/resources/oembed.php b/vendor/embed/embed/src/resources/oembed.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/resources/oembed.php rename to vendor/embed/embed/src/resources/oembed.php diff --git a/site/plugins/embed/vendor/embed/embed/src/resources/suffix.php b/vendor/embed/embed/src/resources/suffix.php similarity index 100% rename from site/plugins/embed/vendor/embed/embed/src/resources/suffix.php rename to vendor/embed/embed/src/resources/suffix.php diff --git a/vendor/filp/whoops/.github/FUNDING.yml b/vendor/filp/whoops/.github/FUNDING.yml new file mode 100644 index 0000000..74f6e85 --- /dev/null +++ b/vendor/filp/whoops/.github/FUNDING.yml @@ -0,0 +1 @@ +github: denis-sokolov diff --git a/vendor/filp/whoops/.github/workflows/tests.yml b/vendor/filp/whoops/.github/workflows/tests.yml new file mode 100644 index 0000000..8f07dd5 --- /dev/null +++ b/vendor/filp/whoops/.github/workflows/tests.yml @@ -0,0 +1,56 @@ +name: Tests + +on: + push: + pull_request: + +jobs: + tests: + name: PHP ${{ matrix.php }} + runs-on: ubuntu-20.04 + + strategy: + matrix: + php: ['5.5', '5.6', '7.0', '7.1', '7.2', '7.3', '7.4', '8.0', '8.1'] + + steps: + - name: Checkout Code + uses: actions/checkout@v2 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + tools: composer:v2 + coverage: none + env: + update: true + + - name: Setup Problem Matchers + run: echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json" + + - name: Fix PHPUnit Version PHP < 7.4 + uses: nick-invision/retry@v1 + with: + timeout_minutes: 5 + max_attempts: 5 + command: composer require "phpunit/phpunit:^4.8.36 || ^5.7.27 || ^6.5.14 || ^7.5.20 || ^8.5.8" --dev --no-update --no-interaction + if: "matrix.php < 7.4" + + - name: Fix PHPUnit Version PHP >= 7.4 + uses: nick-invision/retry@v1 + with: + timeout_minutes: 5 + max_attempts: 5 + command: composer require "phpunit/phpunit:^9.3.3" --dev --no-update --no-interaction + if: "matrix.php >= 7.4" + + - name: Install PHP Dependencies + uses: nick-invision/retry@v1 + with: + timeout_minutes: 5 + max_attempts: 5 + command: composer update --no-interaction --no-progress + + - name: Execute PHPUnit + run: vendor/bin/phpunit diff --git a/vendor/filp/whoops/.mailmap b/vendor/filp/whoops/.mailmap new file mode 100644 index 0000000..13ac5d7 --- /dev/null +++ b/vendor/filp/whoops/.mailmap @@ -0,0 +1,2 @@ +Denis Sokolov +Filipe Dobreira diff --git a/vendor/filp/whoops/CHANGELOG.md b/vendor/filp/whoops/CHANGELOG.md new file mode 100644 index 0000000..88458ab --- /dev/null +++ b/vendor/filp/whoops/CHANGELOG.md @@ -0,0 +1,126 @@ +# 2.14.5 + +* Allow ArrayAccess on super globals + +# 2.14.4 + +* Fix PHP 5.5 support. +* Allow to use psr/log 2 or 3. + +# 2.14.3 + +* Support PHP 8.1 + +# 2.14.1 + +* Fix syntax highlighting scrolling too far. +* Improve the way we detect xdebug linkformat. + +# 2.14.0 + +* Switched syntax highlighting to Prism.js + +Avoids licensing issues with prettify, and uses a maintaned, modern project. + +# 2.13.0 + +* Add Netbeans editor + +# 2.12.1 + +* Avoid redirecting away from an error. + +# 2.12.0 + +* Hide non-string values in super globals when requested. + +# 2.11.0 + +* Customize exit code + +# 2.10.0 + +* Better chaining on handler classes + +# 2.9.2 + +* Fix copy button styles + +# 2.9.1 + +* Fix xdebug function crash on PHP 8 + +# 2.9.0 + +* JsonResponseHandler includes the exception code + +# 2.8.0 + +* Support PHP 8 + +# 2.7.3 + +* PrettyPageHandler functionality to hide superglobal keys has a clearer name hideSuperglobalKey + +# 2.7.2 + +* PrettyPageHandler now accepts custom js files +* PrettyPageHandler templateHelper is now accessible through inheritance + +# 2.7.1 + +* Fix a PHP warning in some cases with anonymous classes. + +# 2.7.0 + +* removeFirstHandler and removeLastHandler. + +# 2.6.0 + +* Fix 2.4.0 pushHandler changing the order of handlers. + +# 2.5.1 + +* Fix error messaging in a rare case. + +# 2.5.0 + +* Automatically configure xdebug if available. + +# 2.4.1 + +* Try harder to close all output buffers + +# 2.4.0 + +* Allow to prepend and append handlers. + +# 2.3.2 + +* Various fixes from the community. + +# 2.3.1 + +* Prevent exception in Whoops when caught exception frame is not related to real file + +# 2.3.0 + +* Show previous exception messages. + +# 2.2.0 + +* Support PHP 7.2 + +# 2.1.0 + +* Add a `SystemFacade` to allow clients to override Whoops behavior. +* Show frame arguments in `PrettyPageHandler`. +* Highlight the line with the error. +* Add icons to search on Google and Stack Overflow. + +# 2.0.0 + +Backwards compatibility breaking changes: + +* `Run` class is now `final`. If you inherited from `Run`, please now instead use a custom `SystemFacade` injected into the `Run` constructor, or contribute your changes to our core. +* PHP < 5.5 support dropped. diff --git a/kirby/vendor/filp/whoops/LICENSE.md b/vendor/filp/whoops/LICENSE.md similarity index 100% rename from kirby/vendor/filp/whoops/LICENSE.md rename to vendor/filp/whoops/LICENSE.md diff --git a/vendor/filp/whoops/SECURITY.md b/vendor/filp/whoops/SECURITY.md new file mode 100644 index 0000000..edfd946 --- /dev/null +++ b/vendor/filp/whoops/SECURITY.md @@ -0,0 +1,12 @@ +# Security Policy + +## Supported Versions + +Only the latest released version of Whoops is supported. +To facilitate upgrades we almost never make backwards-incompatible changes. + +## Reporting a Vulnerability + +Please report vulnerabilities over email, by sending an email to `denis` at `sokolov` dot `cc`. + + diff --git a/kirby/vendor/filp/whoops/composer.json b/vendor/filp/whoops/composer.json similarity index 100% rename from kirby/vendor/filp/whoops/composer.json rename to vendor/filp/whoops/composer.json diff --git a/kirby/vendor/filp/whoops/src/Whoops/Exception/ErrorException.php b/vendor/filp/whoops/src/Whoops/Exception/ErrorException.php similarity index 100% rename from kirby/vendor/filp/whoops/src/Whoops/Exception/ErrorException.php rename to vendor/filp/whoops/src/Whoops/Exception/ErrorException.php diff --git a/kirby/vendor/filp/whoops/src/Whoops/Exception/Formatter.php b/vendor/filp/whoops/src/Whoops/Exception/Formatter.php similarity index 81% rename from kirby/vendor/filp/whoops/src/Whoops/Exception/Formatter.php rename to vendor/filp/whoops/src/Whoops/Exception/Formatter.php index a041530..573dda0 100644 --- a/kirby/vendor/filp/whoops/src/Whoops/Exception/Formatter.php +++ b/vendor/filp/whoops/src/Whoops/Exception/Formatter.php @@ -6,19 +6,16 @@ namespace Whoops\Exception; -use Whoops\Inspector\InspectorInterface; - class Formatter { /** * Returns all basic information about the exception in a simple array * for further convertion to other languages - * @param InspectorInterface $inspector - * @param bool $shouldAddTrace - * @param array $frameFilters + * @param Inspector $inspector + * @param bool $shouldAddTrace * @return array */ - public static function formatExceptionAsDataArray(InspectorInterface $inspector, $shouldAddTrace, array $frameFilters = []) + public static function formatExceptionAsDataArray(Inspector $inspector, $shouldAddTrace) { $exception = $inspector->getException(); $response = [ @@ -30,7 +27,7 @@ class Formatter ]; if ($shouldAddTrace) { - $frames = $inspector->getFrames($frameFilters); + $frames = $inspector->getFrames(); $frameData = []; foreach ($frames as $frame) { @@ -50,7 +47,7 @@ class Formatter return $response; } - public static function formatExceptionPlain(InspectorInterface $inspector) + public static function formatExceptionPlain(Inspector $inspector) { $message = $inspector->getException()->getMessage(); $frames = $inspector->getFrames(); diff --git a/kirby/vendor/filp/whoops/src/Whoops/Exception/Frame.php b/vendor/filp/whoops/src/Whoops/Exception/Frame.php similarity index 99% rename from kirby/vendor/filp/whoops/src/Whoops/Exception/Frame.php rename to vendor/filp/whoops/src/Whoops/Exception/Frame.php index 469070e..2d7297b 100644 --- a/kirby/vendor/filp/whoops/src/Whoops/Exception/Frame.php +++ b/vendor/filp/whoops/src/Whoops/Exception/Frame.php @@ -31,6 +31,9 @@ class Frame implements Serializable */ protected $application; + /** + * @param array[] + */ public function __construct(array $frame) { $this->frame = $frame; diff --git a/kirby/vendor/filp/whoops/src/Whoops/Exception/FrameCollection.php b/vendor/filp/whoops/src/Whoops/Exception/FrameCollection.php similarity index 99% rename from kirby/vendor/filp/whoops/src/Whoops/Exception/FrameCollection.php rename to vendor/filp/whoops/src/Whoops/Exception/FrameCollection.php index 922c035..723b475 100644 --- a/kirby/vendor/filp/whoops/src/Whoops/Exception/FrameCollection.php +++ b/vendor/filp/whoops/src/Whoops/Exception/FrameCollection.php @@ -25,6 +25,9 @@ class FrameCollection implements ArrayAccess, IteratorAggregate, Serializable, C */ private $frames; + /** + * @param array $frames + */ public function __construct(array $frames) { $this->frames = array_map(function ($frame) { diff --git a/kirby/vendor/filp/whoops/src/Whoops/Exception/Inspector.php b/vendor/filp/whoops/src/Whoops/Exception/Inspector.php similarity index 90% rename from kirby/vendor/filp/whoops/src/Whoops/Exception/Inspector.php rename to vendor/filp/whoops/src/Whoops/Exception/Inspector.php index a183563..8570959 100644 --- a/kirby/vendor/filp/whoops/src/Whoops/Exception/Inspector.php +++ b/vendor/filp/whoops/src/Whoops/Exception/Inspector.php @@ -6,11 +6,9 @@ namespace Whoops\Exception; -use Whoops\Inspector\InspectorFactory; -use Whoops\Inspector\InspectorInterface; use Whoops\Util\Misc; -class Inspector implements InspectorInterface +class Inspector { /** * @var \Throwable @@ -32,19 +30,12 @@ class Inspector implements InspectorInterface */ private $previousExceptions; - /** - * @var \Whoops\Inspector\InspectorFactoryInterface|null - */ - protected $inspectorFactory; - /** * @param \Throwable $exception The exception to inspect - * @param \Whoops\Inspector\InspectorFactoryInterface $factory */ - public function __construct($exception, $factory = null) + public function __construct($exception) { $this->exception = $exception; - $this->inspectorFactory = $factory ?: new InspectorFactory(); } /** @@ -146,7 +137,7 @@ class Inspector implements InspectorInterface $previousException = $this->exception->getPrevious(); if ($previousException) { - $this->previousExceptionInspector = $this->inspectorFactory->create($previousException); + $this->previousExceptionInspector = new Inspector($previousException); } } @@ -176,12 +167,9 @@ class Inspector implements InspectorInterface /** * Returns an iterator for the inspected exception's * frames. - * - * @param array $frameFilters - * * @return \Whoops\Exception\FrameCollection */ - public function getFrames(array $frameFilters = []) + public function getFrames() { if ($this->frames === null) { $frames = $this->getTrace($this->exception); @@ -237,13 +225,6 @@ class Inspector implements InspectorInterface $newFrames->prependFrames($outerFrames->topDiff($newFrames)); $this->frames = $newFrames; } - - // Apply frame filters callbacks on the frames stack - if (!empty($frameFilters)) { - foreach ($frameFilters as $filterCallback) { - $this->frames->filter($filterCallback); - } - } } return $this->frames; @@ -320,6 +301,7 @@ class Inspector implements InspectorInterface * Determine if the frame can be used to fill in previous frame's missing info * happens for call_user_func and call_user_func_array usages (PHP Bug #44428) * + * @param array $frame * @return bool */ protected function isValidNextFrame(array $frame) diff --git a/kirby/vendor/filp/whoops/src/Whoops/Handler/CallbackHandler.php b/vendor/filp/whoops/src/Whoops/Handler/CallbackHandler.php similarity index 100% rename from kirby/vendor/filp/whoops/src/Whoops/Handler/CallbackHandler.php rename to vendor/filp/whoops/src/Whoops/Handler/CallbackHandler.php diff --git a/kirby/vendor/filp/whoops/src/Whoops/Handler/Handler.php b/vendor/filp/whoops/src/Whoops/Handler/Handler.php similarity index 88% rename from kirby/vendor/filp/whoops/src/Whoops/Handler/Handler.php rename to vendor/filp/whoops/src/Whoops/Handler/Handler.php index 21435fc..cf1f708 100644 --- a/kirby/vendor/filp/whoops/src/Whoops/Handler/Handler.php +++ b/vendor/filp/whoops/src/Whoops/Handler/Handler.php @@ -6,7 +6,7 @@ namespace Whoops\Handler; -use Whoops\Inspector\InspectorInterface; +use Whoops\Exception\Inspector; use Whoops\RunInterface; /** @@ -36,7 +36,7 @@ abstract class Handler implements HandlerInterface private $run; /** - * @var InspectorInterface $inspector + * @var Inspector $inspector */ private $inspector; @@ -62,15 +62,15 @@ abstract class Handler implements HandlerInterface } /** - * @param InspectorInterface $inspector + * @param Inspector $inspector */ - public function setInspector(InspectorInterface $inspector) + public function setInspector(Inspector $inspector) { $this->inspector = $inspector; } /** - * @return InspectorInterface + * @return Inspector */ protected function getInspector() { diff --git a/kirby/vendor/filp/whoops/src/Whoops/Handler/HandlerInterface.php b/vendor/filp/whoops/src/Whoops/Handler/HandlerInterface.php similarity index 79% rename from kirby/vendor/filp/whoops/src/Whoops/Handler/HandlerInterface.php rename to vendor/filp/whoops/src/Whoops/Handler/HandlerInterface.php index 2deae98..0265a85 100644 --- a/kirby/vendor/filp/whoops/src/Whoops/Handler/HandlerInterface.php +++ b/vendor/filp/whoops/src/Whoops/Handler/HandlerInterface.php @@ -6,7 +6,7 @@ namespace Whoops\Handler; -use Whoops\Inspector\InspectorInterface; +use Whoops\Exception\Inspector; use Whoops\RunInterface; interface HandlerInterface @@ -29,8 +29,8 @@ interface HandlerInterface public function setException($exception); /** - * @param InspectorInterface $inspector + * @param Inspector $inspector * @return void */ - public function setInspector(InspectorInterface $inspector); + public function setInspector(Inspector $inspector); } diff --git a/kirby/vendor/filp/whoops/src/Whoops/Handler/JsonResponseHandler.php b/vendor/filp/whoops/src/Whoops/Handler/JsonResponseHandler.php similarity index 89% rename from kirby/vendor/filp/whoops/src/Whoops/Handler/JsonResponseHandler.php rename to vendor/filp/whoops/src/Whoops/Handler/JsonResponseHandler.php index 9051b36..2966d38 100644 --- a/kirby/vendor/filp/whoops/src/Whoops/Handler/JsonResponseHandler.php +++ b/vendor/filp/whoops/src/Whoops/Handler/JsonResponseHandler.php @@ -60,8 +60,7 @@ class JsonResponseHandler extends Handler 'errors' => [ Formatter::formatExceptionAsDataArray( $this->getInspector(), - $this->addTraceToOutput(), - $this->getRun()->getFrameFilters() + $this->addTraceToOutput() ), ] ]; @@ -69,8 +68,7 @@ class JsonResponseHandler extends Handler $response = [ 'error' => Formatter::formatExceptionAsDataArray( $this->getInspector(), - $this->addTraceToOutput(), - $this->getRun()->getFrameFilters() + $this->addTraceToOutput() ), ]; } diff --git a/kirby/vendor/filp/whoops/src/Whoops/Handler/PlainTextHandler.php b/vendor/filp/whoops/src/Whoops/Handler/PlainTextHandler.php similarity index 99% rename from kirby/vendor/filp/whoops/src/Whoops/Handler/PlainTextHandler.php rename to vendor/filp/whoops/src/Whoops/Handler/PlainTextHandler.php index ea38b76..6c148aa 100644 --- a/kirby/vendor/filp/whoops/src/Whoops/Handler/PlainTextHandler.php +++ b/vendor/filp/whoops/src/Whoops/Handler/PlainTextHandler.php @@ -282,7 +282,7 @@ class PlainTextHandler extends Handler return ''; } $inspector = $this->getInspector(); - $frames = $inspector->getFrames($this->getRun()->getFrameFilters()); + $frames = $inspector->getFrames(); $response = "\nStack trace:"; diff --git a/kirby/vendor/filp/whoops/src/Whoops/Handler/PrettyPageHandler.php b/vendor/filp/whoops/src/Whoops/Handler/PrettyPageHandler.php similarity index 98% rename from kirby/vendor/filp/whoops/src/Whoops/Handler/PrettyPageHandler.php rename to vendor/filp/whoops/src/Whoops/Handler/PrettyPageHandler.php index 167407e..e5a2560 100644 --- a/kirby/vendor/filp/whoops/src/Whoops/Handler/PrettyPageHandler.php +++ b/vendor/filp/whoops/src/Whoops/Handler/PrettyPageHandler.php @@ -287,7 +287,6 @@ class PrettyPageHandler extends Handler $vars["tables"] = array_merge($extraTables, $vars["tables"]); $plainTextHandler = new PlainTextHandler(); - $plainTextHandler->setRun($this->getRun()); $plainTextHandler->setException($this->getException()); $plainTextHandler->setInspector($this->getInspector()); $vars["preface"] = ""; @@ -305,7 +304,7 @@ class PrettyPageHandler extends Handler */ protected function getExceptionFrames() { - $frames = $this->getInspector()->getFrames($this->getRun()->getFrameFilters()); + $frames = $this->getInspector()->getFrames(); if ($this->getApplicationPaths()) { foreach ($frames as $frame) { @@ -354,6 +353,7 @@ class PrettyPageHandler extends Handler * will be flattened with `print_r`. * * @param string $label + * @param array $data * * @return static */ @@ -383,7 +383,7 @@ class PrettyPageHandler extends Handler throw new InvalidArgumentException('Expecting callback argument to be callable'); } - $this->extraTables[$label] = function (\Whoops\Inspector\InspectorInterface $inspector = null) use ($callback) { + $this->extraTables[$label] = function (\Whoops\Exception\Inspector $inspector = null) use ($callback) { try { $result = call_user_func($callback, $inspector); @@ -755,9 +755,11 @@ class PrettyPageHandler extends Handler /** * Set the application paths. * + * @param array $applicationPaths + * * @return void */ - public function setApplicationPaths(array $applicationPaths) + public function setApplicationPaths($applicationPaths) { $this->applicationPaths = $applicationPaths; } diff --git a/kirby/vendor/filp/whoops/src/Whoops/Handler/XmlResponseHandler.php b/vendor/filp/whoops/src/Whoops/Handler/XmlResponseHandler.php similarity index 96% rename from kirby/vendor/filp/whoops/src/Whoops/Handler/XmlResponseHandler.php rename to vendor/filp/whoops/src/Whoops/Handler/XmlResponseHandler.php index dcfd551..d695750 100644 --- a/kirby/vendor/filp/whoops/src/Whoops/Handler/XmlResponseHandler.php +++ b/vendor/filp/whoops/src/Whoops/Handler/XmlResponseHandler.php @@ -43,8 +43,7 @@ class XmlResponseHandler extends Handler $response = [ 'error' => Formatter::formatExceptionAsDataArray( $this->getInspector(), - $this->addTraceToOutput(), - $this->getRun()->getFrameFilters() + $this->addTraceToOutput() ), ]; diff --git a/vendor/filp/whoops/src/Whoops/Resources/css/prism.css b/vendor/filp/whoops/src/Whoops/Resources/css/prism.css new file mode 100644 index 0000000..5faf2b8 --- /dev/null +++ b/vendor/filp/whoops/src/Whoops/Resources/css/prism.css @@ -0,0 +1,237 @@ +/* PrismJS 1.24.1 +https://prismjs.com/download.html#themes=prism-tomorrow&languages=markup+markup-templating+php&plugins=line-highlight+line-numbers */ +/** + * prism.js tomorrow night eighties for JavaScript, CoffeeScript, CSS and HTML + * Based on https://github.com/chriskempson/tomorrow-theme + * @author Rose Pritchard + */ + +code[class*="language-"], +pre[class*="language-"] { + color: #ccc; + background: none; + font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; + font-size: 1em; + text-align: left; + white-space: pre; + word-spacing: normal; + word-break: normal; + word-wrap: normal; + line-height: 1.5; + + -moz-tab-size: 4; + -o-tab-size: 4; + tab-size: 4; + + -webkit-hyphens: none; + -moz-hyphens: none; + -ms-hyphens: none; + hyphens: none; + +} + +/* Code blocks */ +pre[class*="language-"] { + padding: 1em; + margin: .5em 0; + overflow: auto; +} + +:not(pre) > code[class*="language-"], +pre[class*="language-"] { + background: #2d2d2d; +} + +/* Inline code */ +:not(pre) > code[class*="language-"] { + padding: .1em; + border-radius: .3em; + white-space: normal; +} + +.token.comment, +.token.block-comment, +.token.prolog, +.token.doctype, +.token.cdata { + color: #999; +} + +.token.punctuation { + color: #ccc; +} + +.token.tag, +.token.attr-name, +.token.namespace, +.token.deleted { + color: #e2777a; +} + +.token.function-name { + color: #6196cc; +} + +.token.boolean, +.token.number, +.token.function { + color: #f08d49; +} + +.token.property, +.token.class-name, +.token.constant, +.token.symbol { + color: #f8c555; +} + +.token.selector, +.token.important, +.token.atrule, +.token.keyword, +.token.builtin { + color: #cc99cd; +} + +.token.string, +.token.char, +.token.attr-value, +.token.regex, +.token.variable { + color: #7ec699; +} + +.token.operator, +.token.entity, +.token.url { + color: #67cdcc; +} + +.token.important, +.token.bold { + font-weight: bold; +} +.token.italic { + font-style: italic; +} + +.token.entity { + cursor: help; +} + +.token.inserted { + color: green; +} + +pre[data-line] { + position: relative; + padding: 1em 0 1em 3em; +} + +.line-highlight { + position: absolute; + left: 0; + right: 0; + padding: inherit 0; + margin-top: 1em; /* Same as .prism’s padding-top */ + + background: hsla(24, 20%, 50%,.08); + background: linear-gradient(to right, hsla(24, 20%, 50%,.1) 70%, hsla(24, 20%, 50%,0)); + + pointer-events: none; + + line-height: inherit; + white-space: pre; +} + +@media print { + .line-highlight { + /* + * This will prevent browsers from replacing the background color with white. + * It's necessary because the element is layered on top of the displayed code. + */ + -webkit-print-color-adjust: exact; + color-adjust: exact; + } +} + + .line-highlight:before, + .line-highlight[data-end]:after { + content: attr(data-start); + position: absolute; + top: .4em; + left: .6em; + min-width: 1em; + padding: 0 .5em; + background-color: hsla(24, 20%, 50%,.4); + color: hsl(24, 20%, 95%); + font: bold 65%/1.5 sans-serif; + text-align: center; + vertical-align: .3em; + border-radius: 999px; + text-shadow: none; + box-shadow: 0 1px white; + } + + .line-highlight[data-end]:after { + content: attr(data-end); + top: auto; + bottom: .4em; + } + +.line-numbers .line-highlight:before, +.line-numbers .line-highlight:after { + content: none; +} + +pre[id].linkable-line-numbers span.line-numbers-rows { + pointer-events: all; +} +pre[id].linkable-line-numbers span.line-numbers-rows > span:before { + cursor: pointer; +} +pre[id].linkable-line-numbers span.line-numbers-rows > span:hover:before { + background-color: rgba(128, 128, 128, .2); +} + +pre[class*="language-"].line-numbers { + position: relative; + padding-left: 3.8em; + counter-reset: linenumber; +} + +pre[class*="language-"].line-numbers > code { + position: relative; + white-space: inherit; +} + +.line-numbers .line-numbers-rows { + position: absolute; + pointer-events: none; + top: 0; + font-size: 100%; + left: -3.8em; + width: 3em; /* works for line-numbers below 1000 lines */ + letter-spacing: -1px; + border-right: 1px solid #999; + + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + +} + + .line-numbers-rows > span { + display: block; + counter-increment: linenumber; + } + + .line-numbers-rows > span:before { + content: counter(linenumber); + color: #999; + display: block; + padding-right: 0.8em; + text-align: right; + } + diff --git a/kirby/vendor/filp/whoops/src/Whoops/Resources/css/whoops.base.css b/vendor/filp/whoops/src/Whoops/Resources/css/whoops.base.css similarity index 98% rename from kirby/vendor/filp/whoops/src/Whoops/Resources/css/whoops.base.css rename to vendor/filp/whoops/src/Whoops/Resources/css/whoops.base.css index edd5cd8..4400caa 100644 --- a/kirby/vendor/filp/whoops/src/Whoops/Resources/css/whoops.base.css +++ b/vendor/filp/whoops/src/Whoops/Resources/css/whoops.base.css @@ -290,12 +290,13 @@ header { border-radius: 6px; background-color: rgba(255, 255, 255, .05); } - - .frame-comment a { - font-weight: bold; - text-decoration: underline; - color: #c6c6c6; - } + .frame-comment a { + font-weight: bold; + text-decoration: none; + } + .frame-comment a:hover { + color: #4bb1b1; + } .frame-comment:not(:last-child) { border-bottom: 1px dotted rgba(0, 0, 0, .3); diff --git a/kirby/vendor/filp/whoops/src/Whoops/Resources/js/clipboard.min.js b/vendor/filp/whoops/src/Whoops/Resources/js/clipboard.min.js similarity index 100% rename from kirby/vendor/filp/whoops/src/Whoops/Resources/js/clipboard.min.js rename to vendor/filp/whoops/src/Whoops/Resources/js/clipboard.min.js diff --git a/vendor/filp/whoops/src/Whoops/Resources/js/prism.js b/vendor/filp/whoops/src/Whoops/Resources/js/prism.js new file mode 100644 index 0000000..068dd0b --- /dev/null +++ b/vendor/filp/whoops/src/Whoops/Resources/js/prism.js @@ -0,0 +1,8 @@ +/* PrismJS 1.24.1 +https://prismjs.com/download.html#themes=prism-tomorrow&languages=markup+markup-templating+php&plugins=line-highlight+line-numbers */ +var _self="undefined"!=typeof window?window:"undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?self:{},Prism=function(u){var c=/\blang(?:uage)?-([\w-]+)\b/i,n=0,e={},M={manual:u.Prism&&u.Prism.manual,disableWorkerMessageHandler:u.Prism&&u.Prism.disableWorkerMessageHandler,util:{encode:function e(n){return n instanceof W?new W(n.type,e(n.content),n.alias):Array.isArray(n)?n.map(e):n.replace(/&/g,"&").replace(/=l.reach);y+=m.value.length,m=m.next){var b=m.value;if(t.length>n.length)return;if(!(b instanceof W)){var k,x=1;if(h){if(!(k=z(v,y,n,f)))break;var w=k.index,A=k.index+k[0].length,P=y;for(P+=m.value.length;P<=w;)m=m.next,P+=m.value.length;if(P-=m.value.length,y=P,m.value instanceof W)continue;for(var E=m;E!==t.tail&&(Pl.reach&&(l.reach=N);var j=m.prev;O&&(j=I(t,j,O),y+=O.length),q(t,j,x);var C=new W(o,g?M.tokenize(S,g):S,d,S);if(m=I(t,j,C),L&&I(t,m,L),1l.reach&&(l.reach=_.reach)}}}}}}(e,a,n,a.head,0),function(e){var n=[],t=e.head.next;for(;t!==e.tail;)n.push(t.value),t=t.next;return n}(a)},hooks:{all:{},add:function(e,n){var t=M.hooks.all;t[e]=t[e]||[],t[e].push(n)},run:function(e,n){var t=M.hooks.all[e];if(t&&t.length)for(var r,a=0;r=t[a++];)r(n)}},Token:W};function W(e,n,t,r){this.type=e,this.content=n,this.alias=t,this.length=0|(r||"").length}function z(e,n,t,r){e.lastIndex=n;var a=e.exec(t);if(a&&r&&a[1]){var i=a[1].length;a.index+=i,a[0]=a[0].slice(i)}return a}function i(){var e={value:null,prev:null,next:null},n={value:null,prev:e,next:null};e.next=n,this.head=e,this.tail=n,this.length=0}function I(e,n,t){var r=n.next,a={value:t,prev:n,next:r};return n.next=a,r.prev=a,e.length++,a}function q(e,n,t){for(var r=n.next,a=0;a"+a.content+""},!u.document)return u.addEventListener&&(M.disableWorkerMessageHandler||u.addEventListener("message",function(e){var n=JSON.parse(e.data),t=n.language,r=n.code,a=n.immediateClose;u.postMessage(M.highlight(r,M.languages[t],t)),a&&u.close()},!1)),M;var t=M.util.currentScript();function r(){M.manual||M.highlightAll()}if(t&&(M.filename=t.src,t.hasAttribute("data-manual")&&(M.manual=!0)),!M.manual){var a=document.readyState;"loading"===a||"interactive"===a&&t&&t.defer?document.addEventListener("DOMContentLoaded",r):window.requestAnimationFrame?window.requestAnimationFrame(r):window.setTimeout(r,16)}return M}(_self);"undefined"!=typeof module&&module.exports&&(module.exports=Prism),"undefined"!=typeof global&&(global.Prism=Prism); +Prism.languages.markup={comment://,prolog:/<\?[\s\S]+?\?>/,doctype:{pattern:/"'[\]]|"[^"]*"|'[^']*')+(?:\[(?:[^<"'\]]|"[^"]*"|'[^']*'|<(?!!--)|)*\]\s*)?>/i,greedy:!0,inside:{"internal-subset":{pattern:/(^[^\[]*\[)[\s\S]+(?=\]>$)/,lookbehind:!0,greedy:!0,inside:null},string:{pattern:/"[^"]*"|'[^']*'/,greedy:!0},punctuation:/^$|[[\]]/,"doctype-tag":/^DOCTYPE/,name:/[^\s<>'"]+/}},cdata://i,tag:{pattern:/<\/?(?!\d)[^\s>\/=$<%]+(?:\s(?:\s*[^\s>\/=]+(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))|(?=[\s/>])))+)?\s*\/?>/,greedy:!0,inside:{tag:{pattern:/^<\/?[^\s>\/]+/,inside:{punctuation:/^<\/?/,namespace:/^[^\s>\/:]+:/}},"special-attr":[],"attr-value":{pattern:/=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+)/,inside:{punctuation:[{pattern:/^=/,alias:"attr-equals"},/"|'/]}},punctuation:/\/?>/,"attr-name":{pattern:/[^\s>\/]+/,inside:{namespace:/^[^\s>\/:]+:/}}}},entity:[{pattern:/&[\da-z]{1,8};/i,alias:"named-entity"},/&#x?[\da-f]{1,8};/i]},Prism.languages.markup.tag.inside["attr-value"].inside.entity=Prism.languages.markup.entity,Prism.languages.markup.doctype.inside["internal-subset"].inside=Prism.languages.markup,Prism.hooks.add("wrap",function(a){"entity"===a.type&&(a.attributes.title=a.content.replace(/&/,"&"))}),Object.defineProperty(Prism.languages.markup.tag,"addInlined",{value:function(a,e){var s={};s["language-"+e]={pattern:/(^$)/i,lookbehind:!0,inside:Prism.languages[e]},s.cdata=/^$/i;var t={"included-cdata":{pattern://i,inside:s}};t["language-"+e]={pattern:/[\s\S]+/,inside:Prism.languages[e]};var n={};n[a]={pattern:RegExp("(<__[^>]*>)(?:))*\\]\\]>|(?!)".replace(/__/g,function(){return a}),"i"),lookbehind:!0,greedy:!0,inside:t},Prism.languages.insertBefore("markup","cdata",n)}}),Object.defineProperty(Prism.languages.markup.tag,"addAttribute",{value:function(a,e){Prism.languages.markup.tag.inside["special-attr"].push({pattern:RegExp("(^|[\"'\\s])(?:"+a+")\\s*=\\s*(?:\"[^\"]*\"|'[^']*'|[^\\s'\">=]+(?=[\\s>]))","i"),lookbehind:!0,inside:{"attr-name":/^[^\s=]+/,"attr-value":{pattern:/=[\s\S]+/,inside:{value:{pattern:/(^=\s*(["']|(?!["'])))\S[\s\S]*(?=\2$)/,lookbehind:!0,alias:[e,"language-"+e],inside:Prism.languages[e]},punctuation:[{pattern:/^=/,alias:"attr-equals"},/"|'/]}}}})}}),Prism.languages.html=Prism.languages.markup,Prism.languages.mathml=Prism.languages.markup,Prism.languages.svg=Prism.languages.markup,Prism.languages.xml=Prism.languages.extend("markup",{}),Prism.languages.ssml=Prism.languages.xml,Prism.languages.atom=Prism.languages.xml,Prism.languages.rss=Prism.languages.xml; +!function(h){function v(e,n){return"___"+e.toUpperCase()+n+"___"}Object.defineProperties(h.languages["markup-templating"]={},{buildPlaceholders:{value:function(a,r,e,o){if(a.language===r){var c=a.tokenStack=[];a.code=a.code.replace(e,function(e){if("function"==typeof o&&!o(e))return e;for(var n,t=c.length;-1!==a.code.indexOf(n=v(r,t));)++t;return c[t]=e,n}),a.grammar=h.languages.markup}}},tokenizePlaceholders:{value:function(p,k){if(p.language===k&&p.tokenStack){p.grammar=h.languages[k];var m=0,d=Object.keys(p.tokenStack);!function e(n){for(var t=0;t=d.length);t++){var a=n[t];if("string"==typeof a||a.content&&"string"==typeof a.content){var r=d[m],o=p.tokenStack[r],c="string"==typeof a?a:a.content,i=v(k,r),u=c.indexOf(i);if(-1|\?\?=?|\.{3}|\??->|[!=]=?=?|::|\*\*=?|--|\+\+|&&|\|\||<<|>>|[?~]|[/^|%*&<>.+-]=?/,s=/[{}\[\](),:;]/;a.languages.php={delimiter:{pattern:/\?>$|^<\?(?:php(?=\s)|=)?/i,alias:"important"},comment:e,variable:/\$+(?:\w+\b|(?=\{))/i,package:{pattern:/(namespace\s+|use\s+(?:function\s+)?)(?:\\?\b[a-z_]\w*)+\b(?!\\)/i,lookbehind:!0,inside:{punctuation:/\\/}},"class-name-definition":{pattern:/(\b(?:class|enum|interface|trait)\s+)\b[a-z_]\w*(?!\\)\b/i,lookbehind:!0,alias:"class-name"},"function-definition":{pattern:/(\bfunction\s+)[a-z_]\w*(?=\s*\()/i,lookbehind:!0,alias:"function"},keyword:[{pattern:/(\(\s*)\b(?:bool|boolean|int|integer|float|string|object|array)\b(?=\s*\))/i,alias:"type-casting",greedy:!0,lookbehind:!0},{pattern:/([(,?]\s*)\b(?:bool|int|float|string|object|array(?!\s*\()|mixed|self|static|callable|iterable|(?:null|false)(?=\s*\|))\b(?=\s*\$)/i,alias:"type-hint",greedy:!0,lookbehind:!0},{pattern:/([(,?]\s*[\w|]\|\s*)(?:null|false)\b(?=\s*\$)/i,alias:"type-hint",greedy:!0,lookbehind:!0},{pattern:/(\)\s*:\s*(?:\?\s*)?)\b(?:bool|int|float|string|object|void|array(?!\s*\()|mixed|self|static|callable|iterable|(?:null|false)(?=\s*\|))\b/i,alias:"return-type",greedy:!0,lookbehind:!0},{pattern:/(\)\s*:\s*(?:\?\s*)?[\w|]\|\s*)(?:null|false)\b/i,alias:"return-type",greedy:!0,lookbehind:!0},{pattern:/\b(?:bool|int|float|string|object|void|array(?!\s*\()|mixed|iterable|(?:null|false)(?=\s*\|))\b/i,alias:"type-declaration",greedy:!0},{pattern:/(\|\s*)(?:null|false)\b/i,alias:"type-declaration",greedy:!0,lookbehind:!0},{pattern:/\b(?:parent|self|static)(?=\s*::)/i,alias:"static-context",greedy:!0},{pattern:/(\byield\s+)from\b/i,lookbehind:!0},/\bclass\b/i,{pattern:/((?:^|[^\s>:]|(?:^|[^-])>|(?:^|[^:]):)\s*)\b(?:__halt_compiler|abstract|and|array|as|break|callable|case|catch|clone|const|continue|declare|default|die|do|echo|else|elseif|empty|enddeclare|endfor|endforeach|endif|endswitch|endwhile|enum|eval|exit|extends|final|finally|fn|for|foreach|function|global|goto|if|implements|include|include_once|instanceof|insteadof|interface|isset|list|namespace|match|new|or|parent|print|private|protected|public|require|require_once|return|self|static|switch|throw|trait|try|unset|use|var|while|xor|yield)\b/i,lookbehind:!0}],"argument-name":{pattern:/([(,]\s+)\b[a-z_]\w*(?=\s*:(?!:))/i,lookbehind:!0},"class-name":[{pattern:/(\b(?:extends|implements|instanceof|new(?!\s+self|\s+static))\s+|\bcatch\s*\()\b[a-z_]\w*(?!\\)\b/i,greedy:!0,lookbehind:!0},{pattern:/(\|\s*)\b[a-z_]\w*(?!\\)\b/i,greedy:!0,lookbehind:!0},{pattern:/\b[a-z_]\w*(?!\\)\b(?=\s*\|)/i,greedy:!0},{pattern:/(\|\s*)(?:\\?\b[a-z_]\w*)+\b/i,alias:"class-name-fully-qualified",greedy:!0,lookbehind:!0,inside:{punctuation:/\\/}},{pattern:/(?:\\?\b[a-z_]\w*)+\b(?=\s*\|)/i,alias:"class-name-fully-qualified",greedy:!0,inside:{punctuation:/\\/}},{pattern:/(\b(?:extends|implements|instanceof|new(?!\s+self\b|\s+static\b))\s+|\bcatch\s*\()(?:\\?\b[a-z_]\w*)+\b(?!\\)/i,alias:"class-name-fully-qualified",greedy:!0,lookbehind:!0,inside:{punctuation:/\\/}},{pattern:/\b[a-z_]\w*(?=\s*\$)/i,alias:"type-declaration",greedy:!0},{pattern:/(?:\\?\b[a-z_]\w*)+(?=\s*\$)/i,alias:["class-name-fully-qualified","type-declaration"],greedy:!0,inside:{punctuation:/\\/}},{pattern:/\b[a-z_]\w*(?=\s*::)/i,alias:"static-context",greedy:!0},{pattern:/(?:\\?\b[a-z_]\w*)+(?=\s*::)/i,alias:["class-name-fully-qualified","static-context"],greedy:!0,inside:{punctuation:/\\/}},{pattern:/([(,?]\s*)[a-z_]\w*(?=\s*\$)/i,alias:"type-hint",greedy:!0,lookbehind:!0},{pattern:/([(,?]\s*)(?:\\?\b[a-z_]\w*)+(?=\s*\$)/i,alias:["class-name-fully-qualified","type-hint"],greedy:!0,lookbehind:!0,inside:{punctuation:/\\/}},{pattern:/(\)\s*:\s*(?:\?\s*)?)\b[a-z_]\w*(?!\\)\b/i,alias:"return-type",greedy:!0,lookbehind:!0},{pattern:/(\)\s*:\s*(?:\?\s*)?)(?:\\?\b[a-z_]\w*)+\b(?!\\)/i,alias:["class-name-fully-qualified","return-type"],greedy:!0,lookbehind:!0,inside:{punctuation:/\\/}}],constant:t,function:{pattern:/(^|[^\\\w])\\?[a-z_](?:[\w\\]*\w)?(?=\s*\()/i,lookbehind:!0,inside:{punctuation:/\\/}},property:{pattern:/(->\s*)\w+/,lookbehind:!0},number:i,operator:n,punctuation:s};var l={pattern:/\{\$(?:\{(?:\{[^{}]+\}|[^{}]+)\}|[^{}])+\}|(^|[^\\{])\$+(?:\w+(?:\[[^\r\n\[\]]+\]|->\w+)?)/,lookbehind:!0,inside:a.languages.php},r=[{pattern:/<<<'([^']+)'[\r\n](?:.*[\r\n])*?\1;/,alias:"nowdoc-string",greedy:!0,inside:{delimiter:{pattern:/^<<<'[^']+'|[a-z_]\w*;$/i,alias:"symbol",inside:{punctuation:/^<<<'?|[';]$/}}}},{pattern:/<<<(?:"([^"]+)"[\r\n](?:.*[\r\n])*?\1;|([a-z_]\w*)[\r\n](?:.*[\r\n])*?\2;)/i,alias:"heredoc-string",greedy:!0,inside:{delimiter:{pattern:/^<<<(?:"[^"]+"|[a-z_]\w*)|[a-z_]\w*;$/i,alias:"symbol",inside:{punctuation:/^<<<"?|[";]$/}},interpolation:l}},{pattern:/`(?:\\[\s\S]|[^\\`])*`/,alias:"backtick-quoted-string",greedy:!0},{pattern:/'(?:\\[\s\S]|[^\\'])*'/,alias:"single-quoted-string",greedy:!0},{pattern:/"(?:\\[\s\S]|[^\\"])*"/,alias:"double-quoted-string",greedy:!0,inside:{interpolation:l}}];a.languages.insertBefore("php","variable",{string:r,attribute:{pattern:/#\[(?:[^"'\/#]|\/(?![*/])|\/\/.*$|#(?!\[).*$|\/\*(?:[^*]|\*(?!\/))*\*\/|"(?:\\[\s\S]|[^\\"])*"|'(?:\\[\s\S]|[^\\'])*')+\](?=\s*[a-z$#])/im,greedy:!0,inside:{"attribute-content":{pattern:/^(#\[)[\s\S]+(?=\]$)/,lookbehind:!0,inside:{comment:e,string:r,"attribute-class-name":[{pattern:/([^:]|^)\b[a-z_]\w*(?!\\)\b/i,alias:"class-name",greedy:!0,lookbehind:!0},{pattern:/([^:]|^)(?:\\?\b[a-z_]\w*)+/i,alias:["class-name","class-name-fully-qualified"],greedy:!0,lookbehind:!0,inside:{punctuation:/\\/}}],constant:t,number:i,operator:n,punctuation:s}},delimiter:{pattern:/^#\[|\]$/,alias:"punctuation"}}}}),a.hooks.add("before-tokenize",function(e){if(/<\?/.test(e.code)){a.languages["markup-templating"].buildPlaceholders(e,"php",/<\?(?:[^"'/#]|\/(?![*/])|("|')(?:\\[\s\S]|(?!\1)[^\\])*\1|(?:\/\/|#(?!\[))(?:[^?\n\r]|\?(?!>))*(?=$|\?>|[\r\n])|#\[|\/\*(?:[^*]|\*(?!\/))*(?:\*\/|$))*?(?:\?>|$)/gi)}}),a.hooks.add("after-tokenize",function(e){a.languages["markup-templating"].tokenizePlaceholders(e,"php")})}(Prism); +!function(){if("undefined"!=typeof Prism&&"undefined"!=typeof document&&document.querySelector){var t,o="line-numbers",s="linkable-line-numbers",a=function(){if(void 0===t){var e=document.createElement("div");e.style.fontSize="13px",e.style.lineHeight="1.5",e.style.padding="0",e.style.border="0",e.innerHTML=" 
       ",document.body.appendChild(e),t=38===e.offsetHeight,document.body.removeChild(e)}return t},l=!0,u=0;Prism.hooks.add("before-sanity-check",function(e){var t=e.element.parentElement;if(c(t)){var n=0;v(".line-highlight",t).forEach(function(e){n+=e.textContent.length,e.parentNode.removeChild(e)}),n&&/^(?: \n)+$/.test(e.code.slice(-n))&&(e.code=e.code.slice(0,-n))}}),Prism.hooks.add("complete",function e(t){var n=t.element.parentElement;if(c(n)){clearTimeout(u);var i=Prism.plugins.lineNumbers,r=t.plugins&&t.plugins.lineNumbers;if(b(n,o)&&i&&!r)Prism.hooks.add("line-numbers",e);else d(n)(),u=setTimeout(f,1)}}),window.addEventListener("hashchange",f),window.addEventListener("resize",function(){v("pre").filter(c).map(function(e){return d(e)}).forEach(y)})}function v(e,t){return Array.prototype.slice.call((t||document).querySelectorAll(e))}function b(e,t){return e.classList.contains(t)}function y(e){e()}function c(e){return!(!e||!/pre/i.test(e.nodeName))&&(!!e.hasAttribute("data-line")||!(!e.id||!Prism.util.isActive(e,s)))}function d(u,e,c){var t=(e="string"==typeof e?e:u.getAttribute("data-line")||"").replace(/\s+/g,"").split(",").filter(Boolean),d=+u.getAttribute("data-line-offset")||0,f=(a()?parseInt:parseFloat)(getComputedStyle(u).lineHeight),p=Prism.util.isActive(u,o),n=u.querySelector("code"),h=p?u:n||u,m=[],g=n&&h!=n?function(e,t){var n=getComputedStyle(e),i=getComputedStyle(t);function r(e){return+e.substr(0,e.length-2)}return t.offsetTop+r(i.borderTopWidth)+r(i.paddingTop)-r(n.paddingTop)}(u,n):0;t.forEach(function(e){var t=e.split("-"),n=+t[0],i=+t[1]||n,r=u.querySelector('.line-highlight[data-range="'+e+'"]')||document.createElement("div");if(m.push(function(){r.setAttribute("aria-hidden","true"),r.setAttribute("data-range",e),r.className=(c||"")+" line-highlight"}),p&&Prism.plugins.lineNumbers){var o=Prism.plugins.lineNumbers.getLine(u,n),s=Prism.plugins.lineNumbers.getLine(u,i);if(o){var a=o.offsetTop+g+"px";m.push(function(){r.style.top=a})}if(s){var l=s.offsetTop-o.offsetTop+s.offsetHeight+"px";m.push(function(){r.style.height=l})}}else m.push(function(){r.setAttribute("data-start",String(n)),n span",u).forEach(function(e,t){var n=t+r;e.onclick=function(){var e=i+"."+n;l=!1,location.hash=e,setTimeout(function(){l=!0},1)}})}return function(){m.forEach(y)}}function f(){var e=location.hash.slice(1);v(".temporary.line-highlight").forEach(function(e){e.parentNode.removeChild(e)});var t=(e.match(/\.([\d,-]+)$/)||[,""])[1];if(t&&!document.getElementById(e)){var n=e.slice(0,e.lastIndexOf(".")),i=document.getElementById(n);if(i)i.hasAttribute("data-line")||i.setAttribute("data-line",""),d(i,t,"temporary ")(),l&&document.querySelector(".temporary.line-highlight").scrollIntoView()}}}(); +!function(){if("undefined"!=typeof Prism&&"undefined"!=typeof document){var o="line-numbers",a=/\n(?!$)/g,e=Prism.plugins.lineNumbers={getLine:function(e,n){if("PRE"===e.tagName&&e.classList.contains(o)){var t=e.querySelector(".line-numbers-rows");if(t){var i=parseInt(e.getAttribute("data-start"),10)||1,r=i+(t.children.length-1);n");(i=document.createElement("span")).setAttribute("aria-hidden","true"),i.className="line-numbers-rows",i.innerHTML=l,t.hasAttribute("data-start")&&(t.style.counterReset="linenumber "+(parseInt(t.getAttribute("data-start"),10)-1)),e.element.appendChild(i),u([t]),Prism.hooks.run("line-numbers",e)}}}),Prism.hooks.add("line-numbers",function(e){e.plugins=e.plugins||{},e.plugins.lineNumbers=!0})}function u(e){if(0!=(e=e.filter(function(e){var n=function(e){return e?window.getComputedStyle?getComputedStyle(e):e.currentStyle||null:null}(e)["white-space"];return"pre-wrap"===n||"pre-line"===n})).length){var n=e.map(function(e){var n=e.querySelector("code"),t=e.querySelector(".line-numbers-rows");if(n&&t){var i=e.querySelector(".line-numbers-sizer"),r=n.textContent.split(a);i||((i=document.createElement("span")).className="line-numbers-sizer",n.appendChild(i)),i.innerHTML="0",i.style.display="block";var s=i.getBoundingClientRect().height;return i.innerHTML="",{element:e,lines:r,lineHeights:[],oneLinerHeight:s,sizer:i}}}).filter(Boolean);n.forEach(function(e){var i=e.sizer,n=e.lines,r=e.lineHeights,s=e.oneLinerHeight;r[n.length-1]=void 0,n.forEach(function(e,n){if(e&&1
      escape($code) ?>
      diff --git a/kirby/vendor/filp/whoops/src/Whoops/Resources/views/frame_list.html.php b/vendor/filp/whoops/src/Whoops/Resources/views/frame_list.html.php similarity index 100% rename from kirby/vendor/filp/whoops/src/Whoops/Resources/views/frame_list.html.php rename to vendor/filp/whoops/src/Whoops/Resources/views/frame_list.html.php diff --git a/kirby/vendor/filp/whoops/src/Whoops/Resources/views/frames_container.html.php b/vendor/filp/whoops/src/Whoops/Resources/views/frames_container.html.php similarity index 100% rename from kirby/vendor/filp/whoops/src/Whoops/Resources/views/frames_container.html.php rename to vendor/filp/whoops/src/Whoops/Resources/views/frames_container.html.php diff --git a/kirby/vendor/filp/whoops/src/Whoops/Resources/views/frames_description.html.php b/vendor/filp/whoops/src/Whoops/Resources/views/frames_description.html.php similarity index 100% rename from kirby/vendor/filp/whoops/src/Whoops/Resources/views/frames_description.html.php rename to vendor/filp/whoops/src/Whoops/Resources/views/frames_description.html.php diff --git a/kirby/vendor/filp/whoops/src/Whoops/Resources/views/header.html.php b/vendor/filp/whoops/src/Whoops/Resources/views/header.html.php similarity index 100% rename from kirby/vendor/filp/whoops/src/Whoops/Resources/views/header.html.php rename to vendor/filp/whoops/src/Whoops/Resources/views/header.html.php diff --git a/kirby/vendor/filp/whoops/src/Whoops/Resources/views/header_outer.html.php b/vendor/filp/whoops/src/Whoops/Resources/views/header_outer.html.php similarity index 100% rename from kirby/vendor/filp/whoops/src/Whoops/Resources/views/header_outer.html.php rename to vendor/filp/whoops/src/Whoops/Resources/views/header_outer.html.php diff --git a/kirby/vendor/filp/whoops/src/Whoops/Resources/views/layout.html.php b/vendor/filp/whoops/src/Whoops/Resources/views/layout.html.php similarity index 100% rename from kirby/vendor/filp/whoops/src/Whoops/Resources/views/layout.html.php rename to vendor/filp/whoops/src/Whoops/Resources/views/layout.html.php diff --git a/kirby/vendor/filp/whoops/src/Whoops/Resources/views/panel_details.html.php b/vendor/filp/whoops/src/Whoops/Resources/views/panel_details.html.php similarity index 100% rename from kirby/vendor/filp/whoops/src/Whoops/Resources/views/panel_details.html.php rename to vendor/filp/whoops/src/Whoops/Resources/views/panel_details.html.php diff --git a/kirby/vendor/filp/whoops/src/Whoops/Resources/views/panel_details_outer.html.php b/vendor/filp/whoops/src/Whoops/Resources/views/panel_details_outer.html.php similarity index 100% rename from kirby/vendor/filp/whoops/src/Whoops/Resources/views/panel_details_outer.html.php rename to vendor/filp/whoops/src/Whoops/Resources/views/panel_details_outer.html.php diff --git a/kirby/vendor/filp/whoops/src/Whoops/Resources/views/panel_left.html.php b/vendor/filp/whoops/src/Whoops/Resources/views/panel_left.html.php similarity index 100% rename from kirby/vendor/filp/whoops/src/Whoops/Resources/views/panel_left.html.php rename to vendor/filp/whoops/src/Whoops/Resources/views/panel_left.html.php diff --git a/kirby/vendor/filp/whoops/src/Whoops/Resources/views/panel_left_outer.html.php b/vendor/filp/whoops/src/Whoops/Resources/views/panel_left_outer.html.php similarity index 100% rename from kirby/vendor/filp/whoops/src/Whoops/Resources/views/panel_left_outer.html.php rename to vendor/filp/whoops/src/Whoops/Resources/views/panel_left_outer.html.php diff --git a/kirby/vendor/filp/whoops/src/Whoops/Run.php b/vendor/filp/whoops/src/Whoops/Run.php similarity index 91% rename from kirby/vendor/filp/whoops/src/Whoops/Run.php rename to vendor/filp/whoops/src/Whoops/Run.php index 0862768..52486d0 100644 --- a/kirby/vendor/filp/whoops/src/Whoops/Run.php +++ b/vendor/filp/whoops/src/Whoops/Run.php @@ -9,13 +9,10 @@ namespace Whoops; use InvalidArgumentException; use Throwable; use Whoops\Exception\ErrorException; +use Whoops\Exception\Inspector; use Whoops\Handler\CallbackHandler; use Whoops\Handler\Handler; use Whoops\Handler\HandlerInterface; -use Whoops\Inspector\CallableInspectorFactory; -use Whoops\Inspector\InspectorFactory; -use Whoops\Inspector\InspectorFactoryInterface; -use Whoops\Inspector\InspectorInterface; use Whoops\Util\Misc; use Whoops\Util\SystemFacade; @@ -69,22 +66,9 @@ final class Run implements RunInterface */ private $canThrowExceptions = true; - /** - * The inspector factory to create inspectors. - * - * @var InspectorFactoryInterface - */ - private $inspectorFactory; - - /** - * @var array - */ - private $frameFilters = []; - public function __construct(SystemFacade $system = null) { $this->system = $system ?: new SystemFacade; - $this->inspectorFactory = new InspectorFactory(); } /** @@ -181,17 +165,6 @@ final class Run implements RunInterface return $this; } - public function getFrameFilters() - { - return $this->frameFilters; - } - - public function clearFrameFilters() - { - $this->frameFilters = []; - return $this; - } - /** * Registers this instance as an error handler. * @@ -206,7 +179,6 @@ final class Run implements RunInterface class_exists("\\Whoops\\Exception\\FrameCollection"); class_exists("\\Whoops\\Exception\\Frame"); class_exists("\\Whoops\\Exception\\Inspector"); - class_exists("\\Whoops\\Inspector\\InspectorFactory"); $this->system->setErrorHandler([$this, self::ERROR_HANDLER]); $this->system->setExceptionHandler([$this, self::EXCEPTION_HANDLER]); @@ -516,38 +488,14 @@ final class Run implements RunInterface } } - - /** - * @param InspectorFactoryInterface $factory - * - * @return void - */ - public function setInspectorFactory(InspectorFactoryInterface $factory) - { - $this->inspectorFactory = $factory; - } - - public function addFrameFilter($filterCallback) - { - if (!is_callable($filterCallback)) { - throw new \InvalidArgumentException(sprintf( - "A frame filter must be of type callable, %s type given.", - gettype($filterCallback) - )); - } - - $this->frameFilters[] = $filterCallback; - return $this; - } - /** * @param Throwable $exception * - * @return InspectorInterface + * @return Inspector */ private function getInspector($exception) { - return $this->inspectorFactory->create($exception); + return new Inspector($exception); } /** diff --git a/kirby/vendor/filp/whoops/src/Whoops/RunInterface.php b/vendor/filp/whoops/src/Whoops/RunInterface.php similarity index 90% rename from kirby/vendor/filp/whoops/src/Whoops/RunInterface.php rename to vendor/filp/whoops/src/Whoops/RunInterface.php index 0ef3e3f..8162fe4 100644 --- a/kirby/vendor/filp/whoops/src/Whoops/RunInterface.php +++ b/vendor/filp/whoops/src/Whoops/RunInterface.php @@ -49,16 +49,6 @@ interface RunInterface */ public function clearHandlers(); - /** - * @return array - */ - public function getFrameFilters(); - - /** - * @return Run - */ - public function clearFrameFilters(); - /** * Registers this instance as an error handler. * @@ -147,12 +137,4 @@ interface RunInterface * Special case to deal with Fatal errors and the like. */ public function handleShutdown(); - - /** - * Registers a filter callback in the frame filters stack. - * - * @param callable $filterCallback - * @return \Whoops\Run - */ - public function addFrameFilter($filterCallback); } diff --git a/kirby/vendor/filp/whoops/src/Whoops/Util/HtmlDumperOutput.php b/vendor/filp/whoops/src/Whoops/Util/HtmlDumperOutput.php similarity index 100% rename from kirby/vendor/filp/whoops/src/Whoops/Util/HtmlDumperOutput.php rename to vendor/filp/whoops/src/Whoops/Util/HtmlDumperOutput.php diff --git a/kirby/vendor/filp/whoops/src/Whoops/Util/Misc.php b/vendor/filp/whoops/src/Whoops/Util/Misc.php similarity index 100% rename from kirby/vendor/filp/whoops/src/Whoops/Util/Misc.php rename to vendor/filp/whoops/src/Whoops/Util/Misc.php diff --git a/kirby/vendor/filp/whoops/src/Whoops/Util/SystemFacade.php b/vendor/filp/whoops/src/Whoops/Util/SystemFacade.php similarity index 100% rename from kirby/vendor/filp/whoops/src/Whoops/Util/SystemFacade.php rename to vendor/filp/whoops/src/Whoops/Util/SystemFacade.php diff --git a/kirby/vendor/filp/whoops/src/Whoops/Util/TemplateHelper.php b/vendor/filp/whoops/src/Whoops/Util/TemplateHelper.php similarity index 99% rename from kirby/vendor/filp/whoops/src/Whoops/Util/TemplateHelper.php rename to vendor/filp/whoops/src/Whoops/Util/TemplateHelper.php index 8e4df32..9c7cec2 100644 --- a/kirby/vendor/filp/whoops/src/Whoops/Util/TemplateHelper.php +++ b/vendor/filp/whoops/src/Whoops/Util/TemplateHelper.php @@ -232,6 +232,7 @@ class TemplateHelper * passed to the template. * * @param string $template + * @param array $additionalVariables */ public function render($template, array $additionalVariables = null) { @@ -253,6 +254,8 @@ class TemplateHelper /** * Sets the variables to be passed to all templates rendered * by this template helper. + * + * @param array $variables */ public function setVariables(array $variables) { diff --git a/site/plugins/embed/vendor/getkirby/composer-installer/composer.json b/vendor/getkirby/composer-installer/composer.json similarity index 100% rename from site/plugins/embed/vendor/getkirby/composer-installer/composer.json rename to vendor/getkirby/composer-installer/composer.json diff --git a/vendor/getkirby/composer-installer/composer.lock b/vendor/getkirby/composer-installer/composer.lock new file mode 100644 index 0000000..8461817 --- /dev/null +++ b/vendor/getkirby/composer-installer/composer.lock @@ -0,0 +1,1680 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "981db668fb0d4f37f7b64daf03b5f131", + "packages": [], + "packages-dev": [ + { + "name": "composer/ca-bundle", + "version": "1.2.8", + "source": { + "type": "git", + "url": "https://github.com/composer/ca-bundle.git", + "reference": "8a7ecad675253e4654ea05505233285377405215" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/ca-bundle/zipball/8a7ecad675253e4654ea05505233285377405215", + "reference": "8a7ecad675253e4654ea05505233285377405215", + "shasum": "" + }, + "require": { + "ext-openssl": "*", + "ext-pcre": "*", + "php": "^5.3.2 || ^7.0 || ^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35 || ^5.7 || 6.5 - 8", + "psr/log": "^1.0", + "symfony/process": "^2.5 || ^3.0 || ^4.0 || ^5.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Composer\\CaBundle\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + } + ], + "description": "Lets you find a path to the system CA bundle, and includes a fallback to the Mozilla CA bundle.", + "keywords": [ + "cabundle", + "cacert", + "certificate", + "ssl", + "tls" + ], + "support": { + "irc": "irc://irc.freenode.org/composer", + "issues": "https://github.com/composer/ca-bundle/issues", + "source": "https://github.com/composer/ca-bundle/tree/1.2.8" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], + "time": "2020-08-23T12:54:47+00:00" + }, + { + "name": "composer/composer", + "version": "2.0.8", + "source": { + "type": "git", + "url": "https://github.com/composer/composer.git", + "reference": "62139b2806178adb979d76bd3437534a1a9fd490" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/composer/zipball/62139b2806178adb979d76bd3437534a1a9fd490", + "reference": "62139b2806178adb979d76bd3437534a1a9fd490", + "shasum": "" + }, + "require": { + "composer/ca-bundle": "^1.0", + "composer/semver": "^3.0", + "composer/spdx-licenses": "^1.2", + "composer/xdebug-handler": "^1.1", + "justinrainbow/json-schema": "^5.2.10", + "php": "^5.3.2 || ^7.0 || ^8.0", + "psr/log": "^1.0", + "react/promise": "^1.2 || ^2.7", + "seld/jsonlint": "^1.4", + "seld/phar-utils": "^1.0", + "symfony/console": "^2.8.52 || ^3.4.35 || ^4.4 || ^5.0", + "symfony/filesystem": "^2.8.52 || ^3.4.35 || ^4.4 || ^5.0", + "symfony/finder": "^2.8.52 || ^3.4.35 || ^4.4 || ^5.0", + "symfony/process": "^2.8.52 || ^3.4.35 || ^4.4 || ^5.0" + }, + "require-dev": { + "phpspec/prophecy": "^1.10", + "symfony/phpunit-bridge": "^4.2 || ^5.0" + }, + "suggest": { + "ext-openssl": "Enabling the openssl extension allows you to access https URLs for repositories and packages", + "ext-zip": "Enabling the zip extension allows you to unzip archives", + "ext-zlib": "Allow gzip compression of HTTP requests" + }, + "bin": [ + "bin/composer" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "psr-4": { + "Composer\\": "src/Composer" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nils Adermann", + "email": "naderman@naderman.de", + "homepage": "https://www.naderman.de" + }, + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "https://seld.be" + } + ], + "description": "Composer helps you declare, manage and install dependencies of PHP projects. It ensures you have the right stack everywhere.", + "homepage": "https://getcomposer.org/", + "keywords": [ + "autoload", + "dependency", + "package" + ], + "support": { + "irc": "irc://irc.freenode.org/composer", + "issues": "https://github.com/composer/composer/issues", + "source": "https://github.com/composer/composer/tree/2.0.8" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], + "time": "2020-12-03T16:20:39+00:00" + }, + { + "name": "composer/semver", + "version": "3.2.4", + "source": { + "type": "git", + "url": "https://github.com/composer/semver.git", + "reference": "a02fdf930a3c1c3ed3a49b5f63859c0c20e10464" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/semver/zipball/a02fdf930a3c1c3ed3a49b5f63859c0c20e10464", + "reference": "a02fdf930a3c1c3ed3a49b5f63859c0c20e10464", + "shasum": "" + }, + "require": { + "php": "^5.3.2 || ^7.0 || ^8.0" + }, + "require-dev": { + "phpstan/phpstan": "^0.12.54", + "symfony/phpunit-bridge": "^4.2 || ^5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Composer\\Semver\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nils Adermann", + "email": "naderman@naderman.de", + "homepage": "http://www.naderman.de" + }, + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + }, + { + "name": "Rob Bast", + "email": "rob.bast@gmail.com", + "homepage": "http://robbast.nl" + } + ], + "description": "Semver library that offers utilities, version constraint parsing and validation.", + "keywords": [ + "semantic", + "semver", + "validation", + "versioning" + ], + "support": { + "irc": "irc://irc.freenode.org/composer", + "issues": "https://github.com/composer/semver/issues", + "source": "https://github.com/composer/semver/tree/3.2.4" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], + "time": "2020-11-13T08:59:24+00:00" + }, + { + "name": "composer/spdx-licenses", + "version": "1.5.5", + "source": { + "type": "git", + "url": "https://github.com/composer/spdx-licenses.git", + "reference": "de30328a7af8680efdc03e396aad24befd513200" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/spdx-licenses/zipball/de30328a7af8680efdc03e396aad24befd513200", + "reference": "de30328a7af8680efdc03e396aad24befd513200", + "shasum": "" + }, + "require": { + "php": "^5.3.2 || ^7.0 || ^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35 || ^5.7 || 6.5 - 7" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Composer\\Spdx\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nils Adermann", + "email": "naderman@naderman.de", + "homepage": "http://www.naderman.de" + }, + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + }, + { + "name": "Rob Bast", + "email": "rob.bast@gmail.com", + "homepage": "http://robbast.nl" + } + ], + "description": "SPDX licenses list and validation library.", + "keywords": [ + "license", + "spdx", + "validator" + ], + "support": { + "irc": "irc://irc.freenode.org/composer", + "issues": "https://github.com/composer/spdx-licenses/issues", + "source": "https://github.com/composer/spdx-licenses/tree/1.5.5" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], + "time": "2020-12-03T16:04:16+00:00" + }, + { + "name": "composer/xdebug-handler", + "version": "1.4.5", + "source": { + "type": "git", + "url": "https://github.com/composer/xdebug-handler.git", + "reference": "f28d44c286812c714741478d968104c5e604a1d4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/f28d44c286812c714741478d968104c5e604a1d4", + "reference": "f28d44c286812c714741478d968104c5e604a1d4", + "shasum": "" + }, + "require": { + "php": "^5.3.2 || ^7.0 || ^8.0", + "psr/log": "^1.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35 || ^5.7 || 6.5 - 8" + }, + "type": "library", + "autoload": { + "psr-4": { + "Composer\\XdebugHandler\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "John Stevenson", + "email": "john-stevenson@blueyonder.co.uk" + } + ], + "description": "Restarts a process without Xdebug.", + "keywords": [ + "Xdebug", + "performance" + ], + "support": { + "irc": "irc://irc.freenode.org/composer", + "issues": "https://github.com/composer/xdebug-handler/issues", + "source": "https://github.com/composer/xdebug-handler/tree/1.4.5" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], + "time": "2020-11-13T08:04:11+00:00" + }, + { + "name": "justinrainbow/json-schema", + "version": "5.2.10", + "source": { + "type": "git", + "url": "https://github.com/justinrainbow/json-schema.git", + "reference": "2ba9c8c862ecd5510ed16c6340aa9f6eadb4f31b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/justinrainbow/json-schema/zipball/2ba9c8c862ecd5510ed16c6340aa9f6eadb4f31b", + "reference": "2ba9c8c862ecd5510ed16c6340aa9f6eadb4f31b", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "~2.2.20||~2.15.1", + "json-schema/json-schema-test-suite": "1.2.0", + "phpunit/phpunit": "^4.8.35" + }, + "bin": [ + "bin/validate-json" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "JsonSchema\\": "src/JsonSchema/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bruno Prieto Reis", + "email": "bruno.p.reis@gmail.com" + }, + { + "name": "Justin Rainbow", + "email": "justin.rainbow@gmail.com" + }, + { + "name": "Igor Wiedler", + "email": "igor@wiedler.ch" + }, + { + "name": "Robert Schönthal", + "email": "seroscho@googlemail.com" + } + ], + "description": "A library to validate a json schema.", + "homepage": "https://github.com/justinrainbow/json-schema", + "keywords": [ + "json", + "schema" + ], + "support": { + "issues": "https://github.com/justinrainbow/json-schema/issues", + "source": "https://github.com/justinrainbow/json-schema/tree/5.2.10" + }, + "time": "2020-05-27T16:41:55+00:00" + }, + { + "name": "psr/container", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/container.git", + "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/container/zipball/b7ce3b176482dbbc1245ebf52b181af44c2cf55f", + "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Container\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common Container Interface (PHP FIG PSR-11)", + "homepage": "https://github.com/php-fig/container", + "keywords": [ + "PSR-11", + "container", + "container-interface", + "container-interop", + "psr" + ], + "support": { + "issues": "https://github.com/php-fig/container/issues", + "source": "https://github.com/php-fig/container/tree/master" + }, + "time": "2017-02-14T16:28:37+00:00" + }, + { + "name": "psr/log", + "version": "1.1.3", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "0f73288fd15629204f9d42b7055f72dacbe811fc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/0f73288fd15629204f9d42b7055f72dacbe811fc", + "reference": "0f73288fd15629204f9d42b7055f72dacbe811fc", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Log\\": "Psr/Log/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "support": { + "source": "https://github.com/php-fig/log/tree/1.1.3" + }, + "time": "2020-03-23T09:12:05+00:00" + }, + { + "name": "react/promise", + "version": "v2.8.0", + "source": { + "type": "git", + "url": "https://github.com/reactphp/promise.git", + "reference": "f3cff96a19736714524ca0dd1d4130de73dbbbc4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/promise/zipball/f3cff96a19736714524ca0dd1d4130de73dbbbc4", + "reference": "f3cff96a19736714524ca0dd1d4130de73dbbbc4", + "shasum": "" + }, + "require": { + "php": ">=5.4.0" + }, + "require-dev": { + "phpunit/phpunit": "^7.0 || ^6.5 || ^5.7 || ^4.8.36" + }, + "type": "library", + "autoload": { + "psr-4": { + "React\\Promise\\": "src/" + }, + "files": [ + "src/functions_include.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jan Sorgalla", + "email": "jsorgalla@gmail.com" + } + ], + "description": "A lightweight implementation of CommonJS Promises/A for PHP", + "keywords": [ + "promise", + "promises" + ], + "support": { + "issues": "https://github.com/reactphp/promise/issues", + "source": "https://github.com/reactphp/promise/tree/v2.8.0" + }, + "time": "2020-05-12T15:16:56+00:00" + }, + { + "name": "seld/jsonlint", + "version": "1.8.3", + "source": { + "type": "git", + "url": "https://github.com/Seldaek/jsonlint.git", + "reference": "9ad6ce79c342fbd44df10ea95511a1b24dee5b57" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Seldaek/jsonlint/zipball/9ad6ce79c342fbd44df10ea95511a1b24dee5b57", + "reference": "9ad6ce79c342fbd44df10ea95511a1b24dee5b57", + "shasum": "" + }, + "require": { + "php": "^5.3 || ^7.0 || ^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0" + }, + "bin": [ + "bin/jsonlint" + ], + "type": "library", + "autoload": { + "psr-4": { + "Seld\\JsonLint\\": "src/Seld/JsonLint/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + } + ], + "description": "JSON Linter", + "keywords": [ + "json", + "linter", + "parser", + "validator" + ], + "support": { + "issues": "https://github.com/Seldaek/jsonlint/issues", + "source": "https://github.com/Seldaek/jsonlint/tree/1.8.3" + }, + "funding": [ + { + "url": "https://github.com/Seldaek", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/seld/jsonlint", + "type": "tidelift" + } + ], + "time": "2020-11-11T09:19:24+00:00" + }, + { + "name": "seld/phar-utils", + "version": "1.1.1", + "source": { + "type": "git", + "url": "https://github.com/Seldaek/phar-utils.git", + "reference": "8674b1d84ffb47cc59a101f5d5a3b61e87d23796" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Seldaek/phar-utils/zipball/8674b1d84ffb47cc59a101f5d5a3b61e87d23796", + "reference": "8674b1d84ffb47cc59a101f5d5a3b61e87d23796", + "shasum": "" + }, + "require": { + "php": ">=5.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Seld\\PharUtils\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be" + } + ], + "description": "PHAR file format utilities, for when PHP phars you up", + "keywords": [ + "phar" + ], + "support": { + "issues": "https://github.com/Seldaek/phar-utils/issues", + "source": "https://github.com/Seldaek/phar-utils/tree/master" + }, + "time": "2020-07-07T18:42:57+00:00" + }, + { + "name": "symfony/console", + "version": "v5.2.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/console.git", + "reference": "47c02526c532fb381374dab26df05e7313978976" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/console/zipball/47c02526c532fb381374dab26df05e7313978976", + "reference": "47c02526c532fb381374dab26df05e7313978976", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php73": "^1.8", + "symfony/polyfill-php80": "^1.15", + "symfony/service-contracts": "^1.1|^2", + "symfony/string": "^5.1" + }, + "conflict": { + "symfony/dependency-injection": "<4.4", + "symfony/dotenv": "<5.1", + "symfony/event-dispatcher": "<4.4", + "symfony/lock": "<4.4", + "symfony/process": "<4.4" + }, + "provide": { + "psr/log-implementation": "1.0" + }, + "require-dev": { + "psr/log": "~1.0", + "symfony/config": "^4.4|^5.0", + "symfony/dependency-injection": "^4.4|^5.0", + "symfony/event-dispatcher": "^4.4|^5.0", + "symfony/lock": "^4.4|^5.0", + "symfony/process": "^4.4|^5.0", + "symfony/var-dumper": "^4.4|^5.0" + }, + "suggest": { + "psr/log": "For using the console logger", + "symfony/event-dispatcher": "", + "symfony/lock": "", + "symfony/process": "" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Console\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Console Component", + "homepage": "https://symfony.com", + "keywords": [ + "cli", + "command line", + "console", + "terminal" + ], + "support": { + "source": "https://github.com/symfony/console/tree/v5.2.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-12-18T08:03:05+00:00" + }, + { + "name": "symfony/filesystem", + "version": "v5.2.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/filesystem.git", + "reference": "fa8f8cab6b65e2d99a118e082935344c5ba8c60d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/fa8f8cab6b65e2d99a118e082935344c5ba8c60d", + "reference": "fa8f8cab6b65e2d99a118e082935344c5ba8c60d", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/polyfill-ctype": "~1.8" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Filesystem\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Filesystem Component", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/filesystem/tree/v5.2.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-11-30T17:05:38+00:00" + }, + { + "name": "symfony/finder", + "version": "v5.2.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/finder.git", + "reference": "0b9231a5922fd7287ba5b411893c0ecd2733e5ba" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/finder/zipball/0b9231a5922fd7287ba5b411893c0ecd2733e5ba", + "reference": "0b9231a5922fd7287ba5b411893c0ecd2733e5ba", + "shasum": "" + }, + "require": { + "php": ">=7.2.5" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Finder\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Finder Component", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/finder/tree/v5.2.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-12-08T17:02:38+00:00" + }, + { + "name": "symfony/polyfill-ctype", + "version": "v1.20.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "f4ba089a5b6366e453971d3aad5fe8e897b37f41" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/f4ba089a5b6366e453971d3aad5fe8e897b37f41", + "reference": "f4ba089a5b6366e453971d3aad5fe8e897b37f41", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "suggest": { + "ext-ctype": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.20-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for ctype functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "ctype", + "polyfill", + "portable" + ], + "support": { + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.20.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-10-23T14:02:19+00:00" + }, + { + "name": "symfony/polyfill-intl-grapheme", + "version": "v1.20.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-grapheme.git", + "reference": "c7cf3f858ec7d70b89559d6e6eb1f7c2517d479c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/c7cf3f858ec7d70b89559d6e6eb1f7c2517d479c", + "reference": "c7cf3f858ec7d70b89559d6e6eb1f7c2517d479c", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.20-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Intl\\Grapheme\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's grapheme_* functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "grapheme", + "intl", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.20.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-10-23T14:02:19+00:00" + }, + { + "name": "symfony/polyfill-intl-normalizer", + "version": "v1.20.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-normalizer.git", + "reference": "727d1096295d807c309fb01a851577302394c897" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/727d1096295d807c309fb01a851577302394c897", + "reference": "727d1096295d807c309fb01a851577302394c897", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.20-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Intl\\Normalizer\\": "" + }, + "files": [ + "bootstrap.php" + ], + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's Normalizer class and related functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "intl", + "normalizer", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.20.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-10-23T14:02:19+00:00" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.20.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "39d483bdf39be819deabf04ec872eb0b2410b531" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/39d483bdf39be819deabf04ec872eb0b2410b531", + "reference": "39d483bdf39be819deabf04ec872eb0b2410b531", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.20-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the Mbstring extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.20.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-10-23T14:02:19+00:00" + }, + { + "name": "symfony/polyfill-php73", + "version": "v1.20.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php73.git", + "reference": "8ff431c517be11c78c48a39a66d37431e26a6bed" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/8ff431c517be11c78c48a39a66d37431e26a6bed", + "reference": "8ff431c517be11c78c48a39a66d37431e26a6bed", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.20-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Php73\\": "" + }, + "files": [ + "bootstrap.php" + ], + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php73/tree/v1.20.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-10-23T14:02:19+00:00" + }, + { + "name": "symfony/polyfill-php80", + "version": "v1.20.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php80.git", + "reference": "e70aa8b064c5b72d3df2abd5ab1e90464ad009de" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/e70aa8b064c5b72d3df2abd5ab1e90464ad009de", + "reference": "e70aa8b064c5b72d3df2abd5ab1e90464ad009de", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.20-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Php80\\": "" + }, + "files": [ + "bootstrap.php" + ], + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ion Bazan", + "email": "ion.bazan@gmail.com" + }, + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php80/tree/v1.20.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-10-23T14:02:19+00:00" + }, + { + "name": "symfony/process", + "version": "v5.2.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/process.git", + "reference": "bd8815b8b6705298beaa384f04fabd459c10bedd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/process/zipball/bd8815b8b6705298beaa384f04fabd459c10bedd", + "reference": "bd8815b8b6705298beaa384f04fabd459c10bedd", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/polyfill-php80": "^1.15" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Process\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Process Component", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/process/tree/v5.2.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-12-08T17:03:37+00:00" + }, + { + "name": "symfony/service-contracts", + "version": "v2.2.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/service-contracts.git", + "reference": "d15da7ba4957ffb8f1747218be9e1a121fd298a1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/d15da7ba4957ffb8f1747218be9e1a121fd298a1", + "reference": "d15da7ba4957ffb8f1747218be9e1a121fd298a1", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "psr/container": "^1.0" + }, + "suggest": { + "symfony/service-implementation": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.2-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Service\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to writing services", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/service-contracts/tree/master" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-09-07T11:33:47+00:00" + }, + { + "name": "symfony/string", + "version": "v5.2.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/string.git", + "reference": "5bd67751d2e3f7d6f770c9154b8fbcb2aa05f7ed" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/string/zipball/5bd67751d2e3f7d6f770c9154b8fbcb2aa05f7ed", + "reference": "5bd67751d2e3f7d6f770c9154b8fbcb2aa05f7ed", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-intl-grapheme": "~1.0", + "symfony/polyfill-intl-normalizer": "~1.0", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php80": "~1.15" + }, + "require-dev": { + "symfony/error-handler": "^4.4|^5.0", + "symfony/http-client": "^4.4|^5.0", + "symfony/translation-contracts": "^1.1|^2", + "symfony/var-exporter": "^4.4|^5.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\String\\": "" + }, + "files": [ + "Resources/functions.php" + ], + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony String component", + "homepage": "https://symfony.com", + "keywords": [ + "grapheme", + "i18n", + "string", + "unicode", + "utf-8", + "utf8" + ], + "support": { + "source": "https://github.com/symfony/string/tree/v5.2.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-12-05T07:33:16+00:00" + } + ], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": { + "composer-plugin-api": "^1.0 || ^2.0" + }, + "platform-dev": [], + "plugin-api-version": "2.0.0" +} diff --git a/site/plugins/embed/vendor/getkirby/composer-installer/readme.md b/vendor/getkirby/composer-installer/readme.md similarity index 100% rename from site/plugins/embed/vendor/getkirby/composer-installer/readme.md rename to vendor/getkirby/composer-installer/readme.md diff --git a/site/plugins/embed/vendor/getkirby/composer-installer/src/ComposerInstaller/CmsInstaller.php b/vendor/getkirby/composer-installer/src/ComposerInstaller/CmsInstaller.php similarity index 100% rename from site/plugins/embed/vendor/getkirby/composer-installer/src/ComposerInstaller/CmsInstaller.php rename to vendor/getkirby/composer-installer/src/ComposerInstaller/CmsInstaller.php diff --git a/site/plugins/embed/vendor/getkirby/composer-installer/src/ComposerInstaller/Installer.php b/vendor/getkirby/composer-installer/src/ComposerInstaller/Installer.php similarity index 100% rename from site/plugins/embed/vendor/getkirby/composer-installer/src/ComposerInstaller/Installer.php rename to vendor/getkirby/composer-installer/src/ComposerInstaller/Installer.php diff --git a/site/plugins/embed/vendor/getkirby/composer-installer/src/ComposerInstaller/Plugin.php b/vendor/getkirby/composer-installer/src/ComposerInstaller/Plugin.php similarity index 100% rename from site/plugins/embed/vendor/getkirby/composer-installer/src/ComposerInstaller/Plugin.php rename to vendor/getkirby/composer-installer/src/ComposerInstaller/Plugin.php diff --git a/site/plugins/embed/vendor/getkirby/composer-installer/src/ComposerInstaller/PluginInstaller.php b/vendor/getkirby/composer-installer/src/ComposerInstaller/PluginInstaller.php similarity index 100% rename from site/plugins/embed/vendor/getkirby/composer-installer/src/ComposerInstaller/PluginInstaller.php rename to vendor/getkirby/composer-installer/src/ComposerInstaller/PluginInstaller.php diff --git a/site/plugins/embed/vendor/guzzlehttp/psr7/CHANGELOG.md b/vendor/guzzlehttp/psr7/CHANGELOG.md similarity index 95% rename from site/plugins/embed/vendor/guzzlehttp/psr7/CHANGELOG.md rename to vendor/guzzlehttp/psr7/CHANGELOG.md index d897fee..75aabfb 100644 --- a/site/plugins/embed/vendor/guzzlehttp/psr7/CHANGELOG.md +++ b/vendor/guzzlehttp/psr7/CHANGELOG.md @@ -5,6 +5,34 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## 2.7.0 - 2024-07-18 + +### Added + +- Add `Utils::redactUserInfo()` method +- Add ability to encode bools as ints in `Query::build` + +## 2.6.3 - 2024-07-18 + +### Fixed + +- Make `StreamWrapper::stream_stat()` return `false` if inner stream's size is `null` + +### Changed + +- PHP 8.4 support + +## 2.6.2 - 2023-12-03 + +### Fixed + +- Fixed another issue with the fact that PHP transforms numeric strings in array keys to ints + +### Changed + +- Updated links in docs to their canonical versions +- Replaced `call_user_func*` with native calls + ## 2.6.1 - 2023-08-27 ### Fixed diff --git a/site/plugins/embed/vendor/guzzlehttp/psr7/LICENSE b/vendor/guzzlehttp/psr7/LICENSE similarity index 100% rename from site/plugins/embed/vendor/guzzlehttp/psr7/LICENSE rename to vendor/guzzlehttp/psr7/LICENSE diff --git a/site/plugins/embed/vendor/guzzlehttp/psr7/README.md b/vendor/guzzlehttp/psr7/README.md similarity index 96% rename from site/plugins/embed/vendor/guzzlehttp/psr7/README.md rename to vendor/guzzlehttp/psr7/README.md index a64ec90..2e9bb0b 100644 --- a/site/plugins/embed/vendor/guzzlehttp/psr7/README.md +++ b/vendor/guzzlehttp/psr7/README.md @@ -24,8 +24,8 @@ composer require guzzlehttp/psr7 | Version | Status | PHP Version | |---------|---------------------|--------------| -| 1.x | Security fixes only | >=5.4,<8.1 | -| 2.x | Latest | >=7.2.5,<8.4 | +| 1.x | EOL (2024-06-30) | >=5.4,<8.2 | +| 2.x | Latest | >=7.2.5,<8.5 | ## AppendStream @@ -273,7 +273,7 @@ class EofCallbackStream implements StreamInterface // Invoke the callback when EOF is hit. if ($this->eof()) { - call_user_func($this->callback); + ($this->callback)(); } return $result; @@ -436,7 +436,7 @@ will be parsed into `['foo[a]' => '1', 'foo[b]' => '2'])`. ## `GuzzleHttp\Psr7\Query::build` -`public static function build(array $params, int|false $encoding = PHP_QUERY_RFC3986): string` +`public static function build(array $params, int|false $encoding = PHP_QUERY_RFC3986, bool $treatBoolsAsInts = true): string` Build a query string from an array of key value pairs. @@ -498,11 +498,18 @@ a message. ## `GuzzleHttp\Psr7\Utils::readLine` -`public static function readLine(StreamInterface $stream, int $maxLength = null): string` +`public static function readLine(StreamInterface $stream, ?int $maxLength = null): string` Read a line from the stream up to the maximum allowed buffer length. +## `GuzzleHttp\Psr7\Utils::redactUserInfo` + +`public static function redactUserInfo(UriInterface $uri): UriInterface` + +Redact the password in the user info part of a URI. + + ## `GuzzleHttp\Psr7\Utils::streamFor` `public static function streamFor(resource|string|null|int|float|bool|StreamInterface|callable|\Iterator $resource = '', array $options = []): StreamInterface` @@ -637,7 +644,7 @@ this library also provides additional functionality when working with URIs as st An instance of `Psr\Http\Message\UriInterface` can either be an absolute URI or a relative reference. An absolute URI has a scheme. A relative reference is used to express a URI relative to another URI, the base URI. Relative references can be divided into several forms according to -[RFC 3986 Section 4.2](https://tools.ietf.org/html/rfc3986#section-4.2): +[RFC 3986 Section 4.2](https://datatracker.ietf.org/doc/html/rfc3986#section-4.2): - network-path references, e.g. `//example.com/path` - absolute-path references, e.g. `/path` @@ -674,7 +681,7 @@ termed a relative-path reference. ### `GuzzleHttp\Psr7\Uri::isSameDocumentReference` -`public static function isSameDocumentReference(UriInterface $uri, UriInterface $base = null): bool` +`public static function isSameDocumentReference(UriInterface $uri, ?UriInterface $base = null): bool` Whether the URI is a same-document reference. A same-document reference refers to a URI that is, aside from its fragment component, identical to the base URI. When no base URI is given, only an empty URI reference @@ -696,8 +703,8 @@ or the standard port. This method can be used independently of the implementatio `public static function composeComponents($scheme, $authority, $path, $query, $fragment): string` Composes a URI reference string from its various components according to -[RFC 3986 Section 5.3](https://tools.ietf.org/html/rfc3986#section-5.3). Usually this method does not need to be called -manually but instead is used indirectly via `Psr\Http\Message\UriInterface::__toString`. +[RFC 3986 Section 5.3](https://datatracker.ietf.org/doc/html/rfc3986#section-5.3). Usually this method does not need +to be called manually but instead is used indirectly via `Psr\Http\Message\UriInterface::__toString`. ### `GuzzleHttp\Psr7\Uri::fromParts` @@ -741,8 +748,8 @@ Determines if a modified URL should be considered cross-origin with respect to a ## Reference Resolution `GuzzleHttp\Psr7\UriResolver` provides methods to resolve a URI reference in the context of a base URI according -to [RFC 3986 Section 5](https://tools.ietf.org/html/rfc3986#section-5). This is for example also what web browsers -do when resolving a link in a website based on the current request URI. +to [RFC 3986 Section 5](https://datatracker.ietf.org/doc/html/rfc3986#section-5). This is for example also what web +browsers do when resolving a link in a website based on the current request URI. ### `GuzzleHttp\Psr7\UriResolver::resolve` @@ -755,7 +762,7 @@ Converts the relative URI into a new URI that is resolved against the base URI. `public static function removeDotSegments(string $path): string` Removes dot segments from a path and returns the new path according to -[RFC 3986 Section 5.2.4](https://tools.ietf.org/html/rfc3986#section-5.2.4). +[RFC 3986 Section 5.2.4](https://datatracker.ietf.org/doc/html/rfc3986#section-5.2.4). ### `GuzzleHttp\Psr7\UriResolver::relativize` @@ -781,7 +788,7 @@ echo UriResolver::relativize($base, new Uri('http://example.org/a/b/')); // pr ## Normalization and Comparison `GuzzleHttp\Psr7\UriNormalizer` provides methods to normalize and compare URIs according to -[RFC 3986 Section 6](https://tools.ietf.org/html/rfc3986#section-6). +[RFC 3986 Section 6](https://datatracker.ietf.org/doc/html/rfc3986#section-6). ### `GuzzleHttp\Psr7\UriNormalizer::normalize` diff --git a/site/plugins/embed/vendor/guzzlehttp/psr7/composer.json b/vendor/guzzlehttp/psr7/composer.json similarity index 94% rename from site/plugins/embed/vendor/guzzlehttp/psr7/composer.json rename to vendor/guzzlehttp/psr7/composer.json index d51dd62..28d15f5 100644 --- a/site/plugins/embed/vendor/guzzlehttp/psr7/composer.json +++ b/vendor/guzzlehttp/psr7/composer.json @@ -60,9 +60,9 @@ "psr/http-message-implementation": "1.0" }, "require-dev": { - "bamarni/composer-bin-plugin": "^1.8.1", - "http-interop/http-factory-tests": "^0.9", - "phpunit/phpunit": "^8.5.29 || ^9.5.23" + "bamarni/composer-bin-plugin": "^1.8.2", + "http-interop/http-factory-tests": "0.9.0", + "phpunit/phpunit": "^8.5.39 || ^9.6.20" }, "suggest": { "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" diff --git a/site/plugins/embed/vendor/guzzlehttp/psr7/src/AppendStream.php b/vendor/guzzlehttp/psr7/src/AppendStream.php similarity index 100% rename from site/plugins/embed/vendor/guzzlehttp/psr7/src/AppendStream.php rename to vendor/guzzlehttp/psr7/src/AppendStream.php diff --git a/site/plugins/embed/vendor/guzzlehttp/psr7/src/BufferStream.php b/vendor/guzzlehttp/psr7/src/BufferStream.php similarity index 100% rename from site/plugins/embed/vendor/guzzlehttp/psr7/src/BufferStream.php rename to vendor/guzzlehttp/psr7/src/BufferStream.php diff --git a/site/plugins/embed/vendor/guzzlehttp/psr7/src/CachingStream.php b/vendor/guzzlehttp/psr7/src/CachingStream.php similarity index 99% rename from site/plugins/embed/vendor/guzzlehttp/psr7/src/CachingStream.php rename to vendor/guzzlehttp/psr7/src/CachingStream.php index f34722c..7e4554d 100644 --- a/site/plugins/embed/vendor/guzzlehttp/psr7/src/CachingStream.php +++ b/vendor/guzzlehttp/psr7/src/CachingStream.php @@ -33,7 +33,7 @@ final class CachingStream implements StreamInterface */ public function __construct( StreamInterface $stream, - StreamInterface $target = null + ?StreamInterface $target = null ) { $this->remoteStream = $stream; $this->stream = $target ?: new Stream(Utils::tryFopen('php://temp', 'r+')); diff --git a/site/plugins/embed/vendor/guzzlehttp/psr7/src/DroppingStream.php b/vendor/guzzlehttp/psr7/src/DroppingStream.php similarity index 100% rename from site/plugins/embed/vendor/guzzlehttp/psr7/src/DroppingStream.php rename to vendor/guzzlehttp/psr7/src/DroppingStream.php diff --git a/site/plugins/embed/vendor/guzzlehttp/psr7/src/Exception/MalformedUriException.php b/vendor/guzzlehttp/psr7/src/Exception/MalformedUriException.php similarity index 100% rename from site/plugins/embed/vendor/guzzlehttp/psr7/src/Exception/MalformedUriException.php rename to vendor/guzzlehttp/psr7/src/Exception/MalformedUriException.php diff --git a/site/plugins/embed/vendor/guzzlehttp/psr7/src/FnStream.php b/vendor/guzzlehttp/psr7/src/FnStream.php similarity index 81% rename from site/plugins/embed/vendor/guzzlehttp/psr7/src/FnStream.php rename to vendor/guzzlehttp/psr7/src/FnStream.php index 9fdddb9..9e6a7f3 100644 --- a/site/plugins/embed/vendor/guzzlehttp/psr7/src/FnStream.php +++ b/vendor/guzzlehttp/psr7/src/FnStream.php @@ -54,7 +54,7 @@ final class FnStream implements StreamInterface public function __destruct() { if (isset($this->_fn_close)) { - call_user_func($this->_fn_close); + ($this->_fn_close)(); } } @@ -93,7 +93,8 @@ final class FnStream implements StreamInterface public function __toString(): string { try { - return call_user_func($this->_fn___toString); + /** @var string */ + return ($this->_fn___toString)(); } catch (\Throwable $e) { if (\PHP_VERSION_ID >= 70400) { throw $e; @@ -106,67 +107,67 @@ final class FnStream implements StreamInterface public function close(): void { - call_user_func($this->_fn_close); + ($this->_fn_close)(); } public function detach() { - return call_user_func($this->_fn_detach); + return ($this->_fn_detach)(); } public function getSize(): ?int { - return call_user_func($this->_fn_getSize); + return ($this->_fn_getSize)(); } public function tell(): int { - return call_user_func($this->_fn_tell); + return ($this->_fn_tell)(); } public function eof(): bool { - return call_user_func($this->_fn_eof); + return ($this->_fn_eof)(); } public function isSeekable(): bool { - return call_user_func($this->_fn_isSeekable); + return ($this->_fn_isSeekable)(); } public function rewind(): void { - call_user_func($this->_fn_rewind); + ($this->_fn_rewind)(); } public function seek($offset, $whence = SEEK_SET): void { - call_user_func($this->_fn_seek, $offset, $whence); + ($this->_fn_seek)($offset, $whence); } public function isWritable(): bool { - return call_user_func($this->_fn_isWritable); + return ($this->_fn_isWritable)(); } public function write($string): int { - return call_user_func($this->_fn_write, $string); + return ($this->_fn_write)($string); } public function isReadable(): bool { - return call_user_func($this->_fn_isReadable); + return ($this->_fn_isReadable)(); } public function read($length): string { - return call_user_func($this->_fn_read, $length); + return ($this->_fn_read)($length); } public function getContents(): string { - return call_user_func($this->_fn_getContents); + return ($this->_fn_getContents)(); } /** @@ -174,6 +175,6 @@ final class FnStream implements StreamInterface */ public function getMetadata($key = null) { - return call_user_func($this->_fn_getMetadata, $key); + return ($this->_fn_getMetadata)($key); } } diff --git a/site/plugins/embed/vendor/guzzlehttp/psr7/src/Header.php b/vendor/guzzlehttp/psr7/src/Header.php similarity index 99% rename from site/plugins/embed/vendor/guzzlehttp/psr7/src/Header.php rename to vendor/guzzlehttp/psr7/src/Header.php index 6e38e00..bbce8b0 100644 --- a/site/plugins/embed/vendor/guzzlehttp/psr7/src/Header.php +++ b/vendor/guzzlehttp/psr7/src/Header.php @@ -22,7 +22,7 @@ final class Header foreach ((array) $header as $value) { foreach (self::splitList($value) as $val) { $part = []; - foreach (preg_split('/;(?=([^"]*"[^"]*")*[^"]*$)/', $val) as $kvp) { + foreach (preg_split('/;(?=([^"]*"[^"]*")*[^"]*$)/', $val) ?: [] as $kvp) { if (preg_match_all('/<[^>]+>|[^=]+/', $kvp, $matches)) { $m = $matches[0]; if (isset($m[1])) { diff --git a/site/plugins/embed/vendor/guzzlehttp/psr7/src/HttpFactory.php b/vendor/guzzlehttp/psr7/src/HttpFactory.php similarity index 96% rename from site/plugins/embed/vendor/guzzlehttp/psr7/src/HttpFactory.php rename to vendor/guzzlehttp/psr7/src/HttpFactory.php index 73d17e3..3ef1510 100644 --- a/site/plugins/embed/vendor/guzzlehttp/psr7/src/HttpFactory.php +++ b/vendor/guzzlehttp/psr7/src/HttpFactory.php @@ -27,10 +27,10 @@ final class HttpFactory implements RequestFactoryInterface, ResponseFactoryInter { public function createUploadedFile( StreamInterface $stream, - int $size = null, + ?int $size = null, int $error = \UPLOAD_ERR_OK, - string $clientFilename = null, - string $clientMediaType = null + ?string $clientFilename = null, + ?string $clientMediaType = null ): UploadedFileInterface { if ($size === null) { $size = $stream->getSize(); diff --git a/site/plugins/embed/vendor/guzzlehttp/psr7/src/InflateStream.php b/vendor/guzzlehttp/psr7/src/InflateStream.php similarity index 82% rename from site/plugins/embed/vendor/guzzlehttp/psr7/src/InflateStream.php rename to vendor/guzzlehttp/psr7/src/InflateStream.php index 599b55d..e674c9a 100644 --- a/site/plugins/embed/vendor/guzzlehttp/psr7/src/InflateStream.php +++ b/vendor/guzzlehttp/psr7/src/InflateStream.php @@ -13,9 +13,9 @@ use Psr\Http\Message\StreamInterface; * then appends the zlib.inflate filter. The stream is then converted back * to a Guzzle stream resource to be used as a Guzzle stream. * - * @see http://tools.ietf.org/html/rfc1950 - * @see http://tools.ietf.org/html/rfc1952 - * @see http://php.net/manual/en/filters.compression.php + * @see https://datatracker.ietf.org/doc/html/rfc1950 + * @see https://datatracker.ietf.org/doc/html/rfc1952 + * @see https://www.php.net/manual/en/filters.compression.php */ final class InflateStream implements StreamInterface { @@ -28,7 +28,7 @@ final class InflateStream implements StreamInterface { $resource = StreamWrapper::getResource($stream); // Specify window=15+32, so zlib will use header detection to both gzip (with header) and zlib data - // See http://www.zlib.net/manual.html#Advanced definition of inflateInit2 + // See https://www.zlib.net/manual.html#Advanced definition of inflateInit2 // "Add 32 to windowBits to enable zlib and gzip decoding with automatic header detection" // Default window size is 15. stream_filter_append($resource, 'zlib.inflate', STREAM_FILTER_READ, ['window' => 15 + 32]); diff --git a/site/plugins/embed/vendor/guzzlehttp/psr7/src/LazyOpenStream.php b/vendor/guzzlehttp/psr7/src/LazyOpenStream.php similarity index 100% rename from site/plugins/embed/vendor/guzzlehttp/psr7/src/LazyOpenStream.php rename to vendor/guzzlehttp/psr7/src/LazyOpenStream.php diff --git a/site/plugins/embed/vendor/guzzlehttp/psr7/src/LimitStream.php b/vendor/guzzlehttp/psr7/src/LimitStream.php similarity index 100% rename from site/plugins/embed/vendor/guzzlehttp/psr7/src/LimitStream.php rename to vendor/guzzlehttp/psr7/src/LimitStream.php diff --git a/site/plugins/embed/vendor/guzzlehttp/psr7/src/Message.php b/vendor/guzzlehttp/psr7/src/Message.php similarity index 96% rename from site/plugins/embed/vendor/guzzlehttp/psr7/src/Message.php rename to vendor/guzzlehttp/psr7/src/Message.php index 6e6c3e5..5561a51 100644 --- a/site/plugins/embed/vendor/guzzlehttp/psr7/src/Message.php +++ b/vendor/guzzlehttp/psr7/src/Message.php @@ -146,7 +146,7 @@ final class Message // If these aren't the same, then one line didn't match and there's an invalid header. if ($count !== substr_count($rawHeaders, "\n")) { - // Folding is deprecated, see https://tools.ietf.org/html/rfc7230#section-3.2.4 + // Folding is deprecated, see https://datatracker.ietf.org/doc/html/rfc7230#section-3.2.4 if (preg_match(Rfc7230::HEADER_FOLD_REGEX, $rawHeaders)) { throw new \InvalidArgumentException('Invalid header syntax: Obsolete line folding'); } @@ -227,9 +227,9 @@ final class Message public static function parseResponse(string $message): ResponseInterface { $data = self::parseMessage($message); - // According to https://tools.ietf.org/html/rfc7230#section-3.1.2 the space - // between status-code and reason-phrase is required. But browsers accept - // responses without space and reason as well. + // According to https://datatracker.ietf.org/doc/html/rfc7230#section-3.1.2 + // the space between status-code and reason-phrase is required. But + // browsers accept responses without space and reason as well. if (!preg_match('/^HTTP\/.* [0-9]{3}( .*|$)/', $data['start-line'])) { throw new \InvalidArgumentException('Invalid response string: '.$data['start-line']); } diff --git a/site/plugins/embed/vendor/guzzlehttp/psr7/src/MessageTrait.php b/vendor/guzzlehttp/psr7/src/MessageTrait.php similarity index 96% rename from site/plugins/embed/vendor/guzzlehttp/psr7/src/MessageTrait.php rename to vendor/guzzlehttp/psr7/src/MessageTrait.php index e05ebea..65dbc4b 100644 --- a/site/plugins/embed/vendor/guzzlehttp/psr7/src/MessageTrait.php +++ b/vendor/guzzlehttp/psr7/src/MessageTrait.php @@ -141,7 +141,7 @@ trait MessageTrait } /** - * @param array $headers + * @param (string|string[])[] $headers */ private function setHeaders(array $headers): void { @@ -193,7 +193,7 @@ trait MessageTrait * * @return string[] Trimmed header values * - * @see https://tools.ietf.org/html/rfc7230#section-3.2.4 + * @see https://datatracker.ietf.org/doc/html/rfc7230#section-3.2.4 */ private function trimAndValidateHeaderValues(array $values): array { @@ -213,7 +213,7 @@ trait MessageTrait } /** - * @see https://tools.ietf.org/html/rfc7230#section-3.2 + * @see https://datatracker.ietf.org/doc/html/rfc7230#section-3.2 * * @param mixed $header */ @@ -234,7 +234,7 @@ trait MessageTrait } /** - * @see https://tools.ietf.org/html/rfc7230#section-3.2 + * @see https://datatracker.ietf.org/doc/html/rfc7230#section-3.2 * * field-value = *( field-content / obs-fold ) * field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ] diff --git a/site/plugins/embed/vendor/guzzlehttp/psr7/src/MimeType.php b/vendor/guzzlehttp/psr7/src/MimeType.php similarity index 100% rename from site/plugins/embed/vendor/guzzlehttp/psr7/src/MimeType.php rename to vendor/guzzlehttp/psr7/src/MimeType.php diff --git a/site/plugins/embed/vendor/guzzlehttp/psr7/src/MultipartStream.php b/vendor/guzzlehttp/psr7/src/MultipartStream.php similarity index 88% rename from site/plugins/embed/vendor/guzzlehttp/psr7/src/MultipartStream.php rename to vendor/guzzlehttp/psr7/src/MultipartStream.php index 41c48ee..43d718f 100644 --- a/site/plugins/embed/vendor/guzzlehttp/psr7/src/MultipartStream.php +++ b/vendor/guzzlehttp/psr7/src/MultipartStream.php @@ -32,7 +32,7 @@ final class MultipartStream implements StreamInterface * * @throws \InvalidArgumentException */ - public function __construct(array $elements = [], string $boundary = null) + public function __construct(array $elements = [], ?string $boundary = null) { $this->boundary = $boundary ?: bin2hex(random_bytes(20)); $this->stream = $this->createStream($elements); @@ -51,7 +51,7 @@ final class MultipartStream implements StreamInterface /** * Get the headers needed before transferring the content of a POST file * - * @param array $headers + * @param string[] $headers */ private function getHeaders(array $headers): string { @@ -112,10 +112,15 @@ final class MultipartStream implements StreamInterface $stream->addStream(Utils::streamFor("\r\n")); } + /** + * @param string[] $headers + * + * @return array{0: StreamInterface, 1: string[]} + */ private function createElement(string $name, StreamInterface $stream, ?string $filename, array $headers): array { // Set a default content-disposition header if one was no provided - $disposition = $this->getHeader($headers, 'content-disposition'); + $disposition = self::getHeader($headers, 'content-disposition'); if (!$disposition) { $headers['Content-Disposition'] = ($filename === '0' || $filename) ? sprintf( @@ -127,7 +132,7 @@ final class MultipartStream implements StreamInterface } // Set a default content-length header if one was no provided - $length = $this->getHeader($headers, 'content-length'); + $length = self::getHeader($headers, 'content-length'); if (!$length) { if ($length = $stream->getSize()) { $headers['Content-Length'] = (string) $length; @@ -135,7 +140,7 @@ final class MultipartStream implements StreamInterface } // Set a default Content-Type if one was not supplied - $type = $this->getHeader($headers, 'content-type'); + $type = self::getHeader($headers, 'content-type'); if (!$type && ($filename === '0' || $filename)) { $headers['Content-Type'] = MimeType::fromFilename($filename) ?? 'application/octet-stream'; } @@ -143,11 +148,14 @@ final class MultipartStream implements StreamInterface return [$stream, $headers]; } - private function getHeader(array $headers, string $key) + /** + * @param string[] $headers + */ + private static function getHeader(array $headers, string $key): ?string { $lowercaseHeader = strtolower($key); foreach ($headers as $k => $v) { - if (strtolower($k) === $lowercaseHeader) { + if (strtolower((string) $k) === $lowercaseHeader) { return $v; } } diff --git a/site/plugins/embed/vendor/guzzlehttp/psr7/src/NoSeekStream.php b/vendor/guzzlehttp/psr7/src/NoSeekStream.php similarity index 100% rename from site/plugins/embed/vendor/guzzlehttp/psr7/src/NoSeekStream.php rename to vendor/guzzlehttp/psr7/src/NoSeekStream.php diff --git a/site/plugins/embed/vendor/guzzlehttp/psr7/src/PumpStream.php b/vendor/guzzlehttp/psr7/src/PumpStream.php similarity index 96% rename from site/plugins/embed/vendor/guzzlehttp/psr7/src/PumpStream.php rename to vendor/guzzlehttp/psr7/src/PumpStream.php index 5585190..e204070 100644 --- a/site/plugins/embed/vendor/guzzlehttp/psr7/src/PumpStream.php +++ b/vendor/guzzlehttp/psr7/src/PumpStream.php @@ -18,7 +18,7 @@ use Psr\Http\Message\StreamInterface; */ final class PumpStream implements StreamInterface { - /** @var callable|null */ + /** @var callable(int): (string|false|null)|null */ private $source; /** @var int|null */ @@ -163,9 +163,9 @@ final class PumpStream implements StreamInterface private function pump(int $length): void { - if ($this->source) { + if ($this->source !== null) { do { - $data = call_user_func($this->source, $length); + $data = ($this->source)($length); if ($data === false || $data === null) { $this->source = null; diff --git a/site/plugins/embed/vendor/guzzlehttp/psr7/src/Query.php b/vendor/guzzlehttp/psr7/src/Query.php similarity index 80% rename from site/plugins/embed/vendor/guzzlehttp/psr7/src/Query.php rename to vendor/guzzlehttp/psr7/src/Query.php index 8b94927..ccf867a 100644 --- a/site/plugins/embed/vendor/guzzlehttp/psr7/src/Query.php +++ b/vendor/guzzlehttp/psr7/src/Query.php @@ -63,12 +63,15 @@ final class Query * string. This function does not modify the provided keys when an array is * encountered (like `http_build_query()` would). * - * @param array $params Query string parameters. - * @param int|false $encoding Set to false to not encode, PHP_QUERY_RFC3986 - * to encode using RFC3986, or PHP_QUERY_RFC1738 - * to encode using RFC1738. + * @param array $params Query string parameters. + * @param int|false $encoding Set to false to not encode, + * PHP_QUERY_RFC3986 to encode using + * RFC3986, or PHP_QUERY_RFC1738 to + * encode using RFC1738. + * @param bool $treatBoolsAsInts Set to true to encode as 0/1, and + * false as false/true. */ - public static function build(array $params, $encoding = PHP_QUERY_RFC3986): string + public static function build(array $params, $encoding = PHP_QUERY_RFC3986, bool $treatBoolsAsInts = true): string { if (!$params) { return ''; @@ -86,12 +89,14 @@ final class Query throw new \InvalidArgumentException('Invalid type'); } + $castBool = $treatBoolsAsInts ? static function ($v) { return (int) $v; } : static function ($v) { return $v ? 'true' : 'false'; }; + $qs = ''; foreach ($params as $k => $v) { $k = $encoder((string) $k); if (!is_array($v)) { $qs .= $k; - $v = is_bool($v) ? (int) $v : $v; + $v = is_bool($v) ? $castBool($v) : $v; if ($v !== null) { $qs .= '='.$encoder((string) $v); } @@ -99,7 +104,7 @@ final class Query } else { foreach ($v as $vv) { $qs .= $k; - $vv = is_bool($vv) ? (int) $vv : $vv; + $vv = is_bool($vv) ? $castBool($vv) : $vv; if ($vv !== null) { $qs .= '='.$encoder((string) $vv); } diff --git a/site/plugins/embed/vendor/guzzlehttp/psr7/src/Request.php b/vendor/guzzlehttp/psr7/src/Request.php similarity index 96% rename from site/plugins/embed/vendor/guzzlehttp/psr7/src/Request.php rename to vendor/guzzlehttp/psr7/src/Request.php index db29d95..faafe1a 100644 --- a/site/plugins/embed/vendor/guzzlehttp/psr7/src/Request.php +++ b/vendor/guzzlehttp/psr7/src/Request.php @@ -28,7 +28,7 @@ class Request implements RequestInterface /** * @param string $method HTTP method * @param string|UriInterface $uri URI - * @param array $headers Request headers + * @param (string|string[])[] $headers Request headers * @param string|resource|StreamInterface|null $body Request body * @param string $version Protocol version */ @@ -143,7 +143,7 @@ class Request implements RequestInterface $this->headerNames['host'] = 'Host'; } // Ensure Host is the first header. - // See: http://tools.ietf.org/html/rfc7230#section-5.4 + // See: https://datatracker.ietf.org/doc/html/rfc7230#section-5.4 $this->headers = [$header => [$host]] + $this->headers; } diff --git a/site/plugins/embed/vendor/guzzlehttp/psr7/src/Response.php b/vendor/guzzlehttp/psr7/src/Response.php similarity index 98% rename from site/plugins/embed/vendor/guzzlehttp/psr7/src/Response.php rename to vendor/guzzlehttp/psr7/src/Response.php index 8fc1147..34e612f 100644 --- a/site/plugins/embed/vendor/guzzlehttp/psr7/src/Response.php +++ b/vendor/guzzlehttp/psr7/src/Response.php @@ -86,7 +86,7 @@ class Response implements ResponseInterface /** * @param int $status Status code - * @param array $headers Response headers + * @param (string|string[])[] $headers Response headers * @param string|resource|StreamInterface|null $body Response body * @param string $version Protocol version * @param string|null $reason Reason phrase (when empty a default will be used based on the status code) @@ -96,7 +96,7 @@ class Response implements ResponseInterface array $headers = [], $body = null, string $version = '1.1', - string $reason = null + ?string $reason = null ) { $this->assertStatusCodeRange($status); diff --git a/site/plugins/embed/vendor/guzzlehttp/psr7/src/Rfc7230.php b/vendor/guzzlehttp/psr7/src/Rfc7230.php similarity index 100% rename from site/plugins/embed/vendor/guzzlehttp/psr7/src/Rfc7230.php rename to vendor/guzzlehttp/psr7/src/Rfc7230.php diff --git a/site/plugins/embed/vendor/guzzlehttp/psr7/src/ServerRequest.php b/vendor/guzzlehttp/psr7/src/ServerRequest.php similarity index 99% rename from site/plugins/embed/vendor/guzzlehttp/psr7/src/ServerRequest.php rename to vendor/guzzlehttp/psr7/src/ServerRequest.php index c852d96..3cc9534 100644 --- a/site/plugins/embed/vendor/guzzlehttp/psr7/src/ServerRequest.php +++ b/vendor/guzzlehttp/psr7/src/ServerRequest.php @@ -59,7 +59,7 @@ class ServerRequest extends Request implements ServerRequestInterface /** * @param string $method HTTP method * @param string|UriInterface $uri URI - * @param array $headers Request headers + * @param (string|string[])[] $headers Request headers * @param string|resource|StreamInterface|null $body Request body * @param string $version Protocol version * @param array $serverParams Typically the $_SERVER superglobal diff --git a/site/plugins/embed/vendor/guzzlehttp/psr7/src/Stream.php b/vendor/guzzlehttp/psr7/src/Stream.php similarity index 98% rename from site/plugins/embed/vendor/guzzlehttp/psr7/src/Stream.php rename to vendor/guzzlehttp/psr7/src/Stream.php index f730dda..0aff9b2 100644 --- a/site/plugins/embed/vendor/guzzlehttp/psr7/src/Stream.php +++ b/vendor/guzzlehttp/psr7/src/Stream.php @@ -12,8 +12,8 @@ use Psr\Http\Message\StreamInterface; class Stream implements StreamInterface { /** - * @see http://php.net/manual/function.fopen.php - * @see http://php.net/manual/en/function.gzopen.php + * @see https://www.php.net/manual/en/function.fopen.php + * @see https://www.php.net/manual/en/function.gzopen.php */ private const READABLE_MODES = '/r|a\+|ab\+|w\+|wb\+|x\+|xb\+|c\+|cb\+/'; private const WRITABLE_MODES = '/a|w|r\+|rb\+|rw|x|c/'; diff --git a/site/plugins/embed/vendor/guzzlehttp/psr7/src/StreamDecoratorTrait.php b/vendor/guzzlehttp/psr7/src/StreamDecoratorTrait.php similarity index 98% rename from site/plugins/embed/vendor/guzzlehttp/psr7/src/StreamDecoratorTrait.php rename to vendor/guzzlehttp/psr7/src/StreamDecoratorTrait.php index 96196a3..601c13a 100644 --- a/site/plugins/embed/vendor/guzzlehttp/psr7/src/StreamDecoratorTrait.php +++ b/vendor/guzzlehttp/psr7/src/StreamDecoratorTrait.php @@ -70,7 +70,7 @@ trait StreamDecoratorTrait { /** @var callable $callable */ $callable = [$this->stream, $method]; - $result = call_user_func_array($callable, $args); + $result = ($callable)(...$args); // Always return the wrapped object if the result is a return $this return $result === $this->stream ? $this : $result; diff --git a/site/plugins/embed/vendor/guzzlehttp/psr7/src/StreamWrapper.php b/vendor/guzzlehttp/psr7/src/StreamWrapper.php similarity index 83% rename from site/plugins/embed/vendor/guzzlehttp/psr7/src/StreamWrapper.php rename to vendor/guzzlehttp/psr7/src/StreamWrapper.php index b3655cb..77b04d7 100644 --- a/site/plugins/embed/vendor/guzzlehttp/psr7/src/StreamWrapper.php +++ b/vendor/guzzlehttp/psr7/src/StreamWrapper.php @@ -69,7 +69,7 @@ final class StreamWrapper } } - public function stream_open(string $path, string $mode, int $options, string &$opened_path = null): bool + public function stream_open(string $path, string $mode, int $options, ?string &$opened_path = null): bool { $options = stream_context_get_options($this->context); @@ -122,10 +122,28 @@ final class StreamWrapper } /** - * @return array + * @return array{ + * dev: int, + * ino: int, + * mode: int, + * nlink: int, + * uid: int, + * gid: int, + * rdev: int, + * size: int, + * atime: int, + * mtime: int, + * ctime: int, + * blksize: int, + * blocks: int + * }|false */ - public function stream_stat(): array + public function stream_stat() { + if ($this->stream->getSize() === null) { + return false; + } + static $modeMap = [ 'r' => 33060, 'rb' => 33060, @@ -152,7 +170,21 @@ final class StreamWrapper } /** - * @return array + * @return array{ + * dev: int, + * ino: int, + * mode: int, + * nlink: int, + * uid: int, + * gid: int, + * rdev: int, + * size: int, + * atime: int, + * mtime: int, + * ctime: int, + * blksize: int, + * blocks: int + * } */ public function url_stat(string $path, int $flags): array { diff --git a/site/plugins/embed/vendor/guzzlehttp/psr7/src/UploadedFile.php b/vendor/guzzlehttp/psr7/src/UploadedFile.php similarity index 95% rename from site/plugins/embed/vendor/guzzlehttp/psr7/src/UploadedFile.php rename to vendor/guzzlehttp/psr7/src/UploadedFile.php index b1521bc..9c9ea49 100644 --- a/site/plugins/embed/vendor/guzzlehttp/psr7/src/UploadedFile.php +++ b/vendor/guzzlehttp/psr7/src/UploadedFile.php @@ -64,8 +64,8 @@ class UploadedFile implements UploadedFileInterface $streamOrFile, ?int $size, int $errorStatus, - string $clientFilename = null, - string $clientMediaType = null + ?string $clientFilename = null, + ?string $clientMediaType = null ) { $this->setError($errorStatus); $this->size = $size; @@ -113,7 +113,7 @@ class UploadedFile implements UploadedFileInterface $this->error = $error; } - private function isStringNotEmpty($param): bool + private static function isStringNotEmpty($param): bool { return is_string($param) && false === empty($param); } @@ -163,7 +163,7 @@ class UploadedFile implements UploadedFileInterface { $this->validateActive(); - if (false === $this->isStringNotEmpty($targetPath)) { + if (false === self::isStringNotEmpty($targetPath)) { throw new InvalidArgumentException( 'Invalid path provided for move operation; must be a non-empty string' ); diff --git a/site/plugins/embed/vendor/guzzlehttp/psr7/src/Uri.php b/vendor/guzzlehttp/psr7/src/Uri.php similarity index 95% rename from site/plugins/embed/vendor/guzzlehttp/psr7/src/Uri.php rename to vendor/guzzlehttp/psr7/src/Uri.php index fbba7f1..481dfca 100644 --- a/site/plugins/embed/vendor/guzzlehttp/psr7/src/Uri.php +++ b/vendor/guzzlehttp/psr7/src/Uri.php @@ -41,14 +41,14 @@ class Uri implements UriInterface, \JsonSerializable /** * Unreserved characters for use in a regex. * - * @see https://tools.ietf.org/html/rfc3986#section-2.3 + * @see https://datatracker.ietf.org/doc/html/rfc3986#section-2.3 */ private const CHAR_UNRESERVED = 'a-zA-Z0-9_\-\.~'; /** * Sub-delims for use in a regex. * - * @see https://tools.ietf.org/html/rfc3986#section-2.2 + * @see https://datatracker.ietf.org/doc/html/rfc3986#section-2.2 */ private const CHAR_SUB_DELIMS = '!\$&\'\(\)\*\+,;='; private const QUERY_SEPARATORS_REPLACEMENT = ['=' => '%3D', '&' => '%26']; @@ -162,7 +162,7 @@ class Uri implements UriInterface, \JsonSerializable * `file:///` is the more common syntax for the file scheme anyway (Chrome for example redirects to * that format). * - * @see https://tools.ietf.org/html/rfc3986#section-5.3 + * @see https://datatracker.ietf.org/doc/html/rfc3986#section-5.3 */ public static function composeComponents(?string $scheme, ?string $authority, string $path, ?string $query, ?string $fragment): string { @@ -219,7 +219,7 @@ class Uri implements UriInterface, \JsonSerializable * @see Uri::isNetworkPathReference * @see Uri::isAbsolutePathReference * @see Uri::isRelativePathReference - * @see https://tools.ietf.org/html/rfc3986#section-4 + * @see https://datatracker.ietf.org/doc/html/rfc3986#section-4 */ public static function isAbsolute(UriInterface $uri): bool { @@ -231,7 +231,7 @@ class Uri implements UriInterface, \JsonSerializable * * A relative reference that begins with two slash characters is termed an network-path reference. * - * @see https://tools.ietf.org/html/rfc3986#section-4.2 + * @see https://datatracker.ietf.org/doc/html/rfc3986#section-4.2 */ public static function isNetworkPathReference(UriInterface $uri): bool { @@ -243,7 +243,7 @@ class Uri implements UriInterface, \JsonSerializable * * A relative reference that begins with a single slash character is termed an absolute-path reference. * - * @see https://tools.ietf.org/html/rfc3986#section-4.2 + * @see https://datatracker.ietf.org/doc/html/rfc3986#section-4.2 */ public static function isAbsolutePathReference(UriInterface $uri): bool { @@ -258,7 +258,7 @@ class Uri implements UriInterface, \JsonSerializable * * A relative reference that does not begin with a slash character is termed a relative-path reference. * - * @see https://tools.ietf.org/html/rfc3986#section-4.2 + * @see https://datatracker.ietf.org/doc/html/rfc3986#section-4.2 */ public static function isRelativePathReference(UriInterface $uri): bool { @@ -277,9 +277,9 @@ class Uri implements UriInterface, \JsonSerializable * @param UriInterface $uri The URI to check * @param UriInterface|null $base An optional base URI to compare against * - * @see https://tools.ietf.org/html/rfc3986#section-4.4 + * @see https://datatracker.ietf.org/doc/html/rfc3986#section-4.4 */ - public static function isSameDocumentReference(UriInterface $uri, UriInterface $base = null): bool + public static function isSameDocumentReference(UriInterface $uri, ?UriInterface $base = null): bool { if ($base !== null) { $uri = UriResolver::resolve($base, $uri); @@ -336,8 +336,8 @@ class Uri implements UriInterface, \JsonSerializable * * It has the same behavior as withQueryValue() but for an associative array of key => value. * - * @param UriInterface $uri URI to use as a base. - * @param array $keyValueArray Associative array of key and values + * @param UriInterface $uri URI to use as a base. + * @param (string|null)[] $keyValueArray Associative array of key and values */ public static function withQueryValues(UriInterface $uri, array $keyValueArray): UriInterface { @@ -353,7 +353,7 @@ class Uri implements UriInterface, \JsonSerializable /** * Creates a URI from a hash of `parse_url` components. * - * @see http://php.net/manual/en/function.parse-url.php + * @see https://www.php.net/manual/en/function.parse-url.php * * @throws MalformedUriException If the components do not form a valid URI. */ @@ -638,7 +638,7 @@ class Uri implements UriInterface, \JsonSerializable } /** - * @param string[] $keys + * @param (string|int)[] $keys * * @return string[] */ @@ -650,7 +650,9 @@ class Uri implements UriInterface, \JsonSerializable return []; } - $decodedKeys = array_map('rawurldecode', $keys); + $decodedKeys = array_map(function ($k): string { + return rawurldecode((string) $k); + }, $keys); return array_filter(explode('&', $current), function ($part) use ($decodedKeys) { return !in_array(rawurldecode(explode('=', $part)[0]), $decodedKeys, true); diff --git a/site/plugins/embed/vendor/guzzlehttp/psr7/src/UriComparator.php b/vendor/guzzlehttp/psr7/src/UriComparator.php similarity index 100% rename from site/plugins/embed/vendor/guzzlehttp/psr7/src/UriComparator.php rename to vendor/guzzlehttp/psr7/src/UriComparator.php diff --git a/site/plugins/embed/vendor/guzzlehttp/psr7/src/UriNormalizer.php b/vendor/guzzlehttp/psr7/src/UriNormalizer.php similarity index 96% rename from site/plugins/embed/vendor/guzzlehttp/psr7/src/UriNormalizer.php rename to vendor/guzzlehttp/psr7/src/UriNormalizer.php index cd4c383..e174557 100644 --- a/site/plugins/embed/vendor/guzzlehttp/psr7/src/UriNormalizer.php +++ b/vendor/guzzlehttp/psr7/src/UriNormalizer.php @@ -11,7 +11,7 @@ use Psr\Http\Message\UriInterface; * * @author Tobias Schultze * - * @see https://tools.ietf.org/html/rfc3986#section-6 + * @see https://datatracker.ietf.org/doc/html/rfc3986#section-6 */ final class UriNormalizer { @@ -119,7 +119,7 @@ final class UriNormalizer * @param UriInterface $uri The URI to normalize * @param int $flags A bitmask of normalizations to apply, see constants * - * @see https://tools.ietf.org/html/rfc3986#section-6.2 + * @see https://datatracker.ietf.org/doc/html/rfc3986#section-6.2 */ public static function normalize(UriInterface $uri, int $flags = self::PRESERVING_NORMALIZATIONS): UriInterface { @@ -174,7 +174,7 @@ final class UriNormalizer * @param UriInterface $uri2 An URI to compare * @param int $normalizations A bitmask of normalizations to apply, see constants * - * @see https://tools.ietf.org/html/rfc3986#section-6.1 + * @see https://datatracker.ietf.org/doc/html/rfc3986#section-6.1 */ public static function isEquivalent(UriInterface $uri1, UriInterface $uri2, int $normalizations = self::PRESERVING_NORMALIZATIONS): bool { @@ -185,7 +185,7 @@ final class UriNormalizer { $regex = '/(?:%[A-Fa-f0-9]{2})++/'; - $callback = function (array $match) { + $callback = function (array $match): string { return strtoupper($match[0]); }; @@ -201,7 +201,7 @@ final class UriNormalizer { $regex = '/%(?:2D|2E|5F|7E|3[0-9]|[46][1-9A-F]|[57][0-9A])/i'; - $callback = function (array $match) { + $callback = function (array $match): string { return rawurldecode($match[0]); }; diff --git a/site/plugins/embed/vendor/guzzlehttp/psr7/src/UriResolver.php b/vendor/guzzlehttp/psr7/src/UriResolver.php similarity index 97% rename from site/plugins/embed/vendor/guzzlehttp/psr7/src/UriResolver.php rename to vendor/guzzlehttp/psr7/src/UriResolver.php index 38d5793..3737be1 100644 --- a/site/plugins/embed/vendor/guzzlehttp/psr7/src/UriResolver.php +++ b/vendor/guzzlehttp/psr7/src/UriResolver.php @@ -11,14 +11,14 @@ use Psr\Http\Message\UriInterface; * * @author Tobias Schultze * - * @see https://tools.ietf.org/html/rfc3986#section-5 + * @see https://datatracker.ietf.org/doc/html/rfc3986#section-5 */ final class UriResolver { /** * Removes dot segments from a path and returns the new path. * - * @see http://tools.ietf.org/html/rfc3986#section-5.2.4 + * @see https://datatracker.ietf.org/doc/html/rfc3986#section-5.2.4 */ public static function removeDotSegments(string $path): string { @@ -53,7 +53,7 @@ final class UriResolver /** * Converts the relative URI into a new URI that is resolved against the base URI. * - * @see http://tools.ietf.org/html/rfc3986#section-5.2 + * @see https://datatracker.ietf.org/doc/html/rfc3986#section-5.2 */ public static function resolve(UriInterface $base, UriInterface $rel): UriInterface { diff --git a/site/plugins/embed/vendor/guzzlehttp/psr7/src/Utils.php b/vendor/guzzlehttp/psr7/src/Utils.php similarity index 96% rename from site/plugins/embed/vendor/guzzlehttp/psr7/src/Utils.php rename to vendor/guzzlehttp/psr7/src/Utils.php index 917c05e..7682d2c 100644 --- a/site/plugins/embed/vendor/guzzlehttp/psr7/src/Utils.php +++ b/vendor/guzzlehttp/psr7/src/Utils.php @@ -14,18 +14,18 @@ final class Utils /** * Remove the items given by the keys, case insensitively from the data. * - * @param string[] $keys + * @param (string|int)[] $keys */ public static function caselessRemove(array $keys, array $data): array { $result = []; foreach ($keys as &$key) { - $key = strtolower($key); + $key = strtolower((string) $key); } foreach ($data as $k => $v) { - if (!is_string($k) || !in_array(strtolower($k), $keys)) { + if (!in_array(strtolower((string) $k), $keys)) { $result[$k] = $v; } } @@ -231,7 +231,7 @@ final class Utils * @param StreamInterface $stream Stream to read from * @param int|null $maxLength Maximum buffer length */ - public static function readLine(StreamInterface $stream, int $maxLength = null): string + public static function readLine(StreamInterface $stream, ?int $maxLength = null): string { $buffer = ''; $size = 0; @@ -250,6 +250,20 @@ final class Utils return $buffer; } + /** + * Redact the password in the user info part of a URI. + */ + public static function redactUserInfo(UriInterface $uri): UriInterface + { + $userInfo = $uri->getUserInfo(); + + if (false !== ($pos = \strpos($userInfo, ':'))) { + return $uri->withUserInfo(\substr($userInfo, 0, $pos), '***'); + } + + return $uri; + } + /** * Create a new stream based on the input type. * diff --git a/kirby/vendor/laminas/laminas-escaper/COPYRIGHT.md b/vendor/laminas/laminas-escaper/COPYRIGHT.md similarity index 100% rename from kirby/vendor/laminas/laminas-escaper/COPYRIGHT.md rename to vendor/laminas/laminas-escaper/COPYRIGHT.md diff --git a/kirby/vendor/laminas/laminas-escaper/LICENSE.md b/vendor/laminas/laminas-escaper/LICENSE.md similarity index 100% rename from kirby/vendor/laminas/laminas-escaper/LICENSE.md rename to vendor/laminas/laminas-escaper/LICENSE.md diff --git a/vendor/laminas/laminas-escaper/README.md b/vendor/laminas/laminas-escaper/README.md new file mode 100644 index 0000000..2383208 --- /dev/null +++ b/vendor/laminas/laminas-escaper/README.md @@ -0,0 +1,43 @@ +# laminas-escaper + +[![Build Status](https://github.com/laminas/laminas-escaper/actions/workflows/continuous-integration.yml/badge.svg)](https://github.com/laminas/laminas-escaper/actions/workflows/continuous-integration.yml) + +> ## 🇷🇺 Русским гражданам +> +> Мы, участники Laminas, родились и живем в разных странах. У многих из нас есть друзья, родственники и коллеги как в России, так и в Украине. Некоторые из нас родились в России. Некоторые из нас живут в России. У некоторых бабушки и дедушки сражались с фашистами во Второй мировой войне. Здесь никто не поддерживает фашизм. +> +> У одного из нас есть украинская родственница, которая спаслась из дома вместе с сыном. Поезд задержался из-за бомбежки на дороге впереди. У нас есть друзья, которые прячутся в бомбоубежищах. Мы с тревогой ждем весточки от них после воздушных налетов, которые беспорядочно наносят удары и попадают по больницам, школам, детским садам и домам. Мы не берем это из каких-либо СМИ. Мы наблюдаем это напрямую. +> +> Вы доверяете нам достаточно, чтоб использовать наши программы, и мы просим вас довериться нам вновь. Мы нуждаемся в помощи. Выходите и протестуйте против этой бесполезной войны. Остановите кровопролитие. Скажите "Нет войне!" +> +> ## 🇺🇸 To Citizens of Russia +> +> We at Laminas come from all over the world. Many of us have friends, family and colleagues in both Russia and Ukraine. Some of us were born in Russia. Some of us currently live in Russia. Some have grandparents who fought Nazis in World War II. Nobody here supports fascism. +> +> One team member has a Ukrainian relative who fled her home with her son. The train was delayed due to bombing on the road ahead. We have friends who are hiding in bomb shelters. We anxiously follow up on them after the air raids, which indiscriminately fire at hospitals, schools, kindergartens and houses. We're not taking this from any media. These are our actual experiences. +> +> You trust us enough to use our software. We ask that you trust us to say the truth on this. We need your help. Go out and protest this unnecessary war. Stop the bloodshed. Say "stop the war!" + +The OWASP Top 10 web security risks study lists Cross-Site Scripting (XSS) in +second place. PHP’s sole functionality against XSS is limited to two functions +of which one is commonly misapplied. Thus, the laminas-escaper component was written. +It offers developers a way to escape output and defend from XSS and related +vulnerabilities by introducing contextual escaping based on peer-reviewed rules. + +## Installation + +Run the following to install this library: + +```bash +$ composer require laminas/laminas-escaper +``` + +## Documentation + +Browse the documentation online at https://docs.laminas.dev/laminas-escaper/ + +## Support + +* [Issues](https://github.com/laminas/laminas-escaper/issues/) +* [Chat](https://laminas.dev/chat/) +* [Forum](https://discourse.laminas.dev/) diff --git a/kirby/vendor/laminas/laminas-escaper/composer.json b/vendor/laminas/laminas-escaper/composer.json similarity index 86% rename from kirby/vendor/laminas/laminas-escaper/composer.json rename to vendor/laminas/laminas-escaper/composer.json index 16cf063..64513b6 100644 --- a/kirby/vendor/laminas/laminas-escaper/composer.json +++ b/vendor/laminas/laminas-escaper/composer.json @@ -18,7 +18,7 @@ "config": { "sort-packages": true, "platform": { - "php": "8.1.99" + "php": "7.4.99" }, "allow-plugins": { "dealerdirect/phpcodesniffer-composer-installer": true, @@ -29,17 +29,17 @@ "extra": { }, "require": { - "php": "~8.1.0 || ~8.2.0 || ~8.3.0", + "php": "^7.4 || ~8.0.0 || ~8.1.0", "ext-ctype": "*", "ext-mbstring": "*" }, "require-dev": { - "infection/infection": "^0.27.0", - "laminas/laminas-coding-standard": "~2.5.0", + "infection/infection": "^0.26.6", + "laminas/laminas-coding-standard": "~2.3.0", "maglnet/composer-require-checker": "^3.8.0", - "phpunit/phpunit": "^9.6.7", - "psalm/plugin-phpunit": "^0.18.4", - "vimeo/psalm": "^5.9" + "phpunit/phpunit": "^9.5.18", + "psalm/plugin-phpunit": "^0.16.1", + "vimeo/psalm": "^4.22.0" }, "autoload": { "psr-4": { diff --git a/vendor/laminas/laminas-escaper/composer.lock b/vendor/laminas/laminas-escaper/composer.lock new file mode 100644 index 0000000..174a4ce --- /dev/null +++ b/vendor/laminas/laminas-escaper/composer.lock @@ -0,0 +1,5327 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "36c2688d8dcb1e1c07970fea2d09b88d", + "packages": [], + "packages-dev": [ + { + "name": "amphp/amp", + "version": "v2.6.2", + "source": { + "type": "git", + "url": "https://github.com/amphp/amp.git", + "reference": "9d5100cebffa729aaffecd3ad25dc5aeea4f13bb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/amp/zipball/9d5100cebffa729aaffecd3ad25dc5aeea4f13bb", + "reference": "9d5100cebffa729aaffecd3ad25dc5aeea4f13bb", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "require-dev": { + "amphp/php-cs-fixer-config": "dev-master", + "amphp/phpunit-util": "^1", + "ext-json": "*", + "jetbrains/phpstorm-stubs": "^2019.3", + "phpunit/phpunit": "^7 | ^8 | ^9", + "psalm/phar": "^3.11@dev", + "react/promise": "^2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.x-dev" + } + }, + "autoload": { + "files": [ + "lib/functions.php", + "lib/Internal/functions.php" + ], + "psr-4": { + "Amp\\": "lib" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Daniel Lowrey", + "email": "rdlowrey@php.net" + }, + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + }, + { + "name": "Bob Weinand", + "email": "bobwei9@hotmail.com" + }, + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + } + ], + "description": "A non-blocking concurrency framework for PHP applications.", + "homepage": "https://amphp.org/amp", + "keywords": [ + "async", + "asynchronous", + "awaitable", + "concurrency", + "event", + "event-loop", + "future", + "non-blocking", + "promise" + ], + "support": { + "irc": "irc://irc.freenode.org/amphp", + "issues": "https://github.com/amphp/amp/issues", + "source": "https://github.com/amphp/amp/tree/v2.6.2" + }, + "funding": [ + { + "url": "https://github.com/amphp", + "type": "github" + } + ], + "time": "2022-02-20T17:52:18+00:00" + }, + { + "name": "amphp/byte-stream", + "version": "v1.8.1", + "source": { + "type": "git", + "url": "https://github.com/amphp/byte-stream.git", + "reference": "acbd8002b3536485c997c4e019206b3f10ca15bd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/byte-stream/zipball/acbd8002b3536485c997c4e019206b3f10ca15bd", + "reference": "acbd8002b3536485c997c4e019206b3f10ca15bd", + "shasum": "" + }, + "require": { + "amphp/amp": "^2", + "php": ">=7.1" + }, + "require-dev": { + "amphp/php-cs-fixer-config": "dev-master", + "amphp/phpunit-util": "^1.4", + "friendsofphp/php-cs-fixer": "^2.3", + "jetbrains/phpstorm-stubs": "^2019.3", + "phpunit/phpunit": "^6 || ^7 || ^8", + "psalm/phar": "^3.11.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "files": [ + "lib/functions.php" + ], + "psr-4": { + "Amp\\ByteStream\\": "lib" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + }, + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + } + ], + "description": "A stream abstraction to make working with non-blocking I/O simple.", + "homepage": "http://amphp.org/byte-stream", + "keywords": [ + "amp", + "amphp", + "async", + "io", + "non-blocking", + "stream" + ], + "support": { + "irc": "irc://irc.freenode.org/amphp", + "issues": "https://github.com/amphp/byte-stream/issues", + "source": "https://github.com/amphp/byte-stream/tree/v1.8.1" + }, + "funding": [ + { + "url": "https://github.com/amphp", + "type": "github" + } + ], + "time": "2021-03-30T17:13:30+00:00" + }, + { + "name": "composer/package-versions-deprecated", + "version": "1.11.99.5", + "source": { + "type": "git", + "url": "https://github.com/composer/package-versions-deprecated.git", + "reference": "b4f54f74ef3453349c24a845d22392cd31e65f1d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/package-versions-deprecated/zipball/b4f54f74ef3453349c24a845d22392cd31e65f1d", + "reference": "b4f54f74ef3453349c24a845d22392cd31e65f1d", + "shasum": "" + }, + "require": { + "composer-plugin-api": "^1.1.0 || ^2.0", + "php": "^7 || ^8" + }, + "replace": { + "ocramius/package-versions": "1.11.99" + }, + "require-dev": { + "composer/composer": "^1.9.3 || ^2.0@dev", + "ext-zip": "^1.13", + "phpunit/phpunit": "^6.5 || ^7" + }, + "type": "composer-plugin", + "extra": { + "class": "PackageVersions\\Installer", + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "PackageVersions\\": "src/PackageVersions" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com" + }, + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be" + } + ], + "description": "Composer plugin that provides efficient querying for installed package versions (no runtime IO)", + "support": { + "issues": "https://github.com/composer/package-versions-deprecated/issues", + "source": "https://github.com/composer/package-versions-deprecated/tree/1.11.99.5" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], + "time": "2022-01-17T14:14:24+00:00" + }, + { + "name": "composer/pcre", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/composer/pcre.git", + "reference": "e300eb6c535192decd27a85bc72a9290f0d6b3bd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/pcre/zipball/e300eb6c535192decd27a85bc72a9290f0d6b3bd", + "reference": "e300eb6c535192decd27a85bc72a9290f0d6b3bd", + "shasum": "" + }, + "require": { + "php": "^7.4 || ^8.0" + }, + "require-dev": { + "phpstan/phpstan": "^1.3", + "phpstan/phpstan-strict-rules": "^1.1", + "symfony/phpunit-bridge": "^5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Composer\\Pcre\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + } + ], + "description": "PCRE wrapping library that offers type-safe preg_* replacements.", + "keywords": [ + "PCRE", + "preg", + "regex", + "regular expression" + ], + "support": { + "issues": "https://github.com/composer/pcre/issues", + "source": "https://github.com/composer/pcre/tree/3.0.0" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], + "time": "2022-02-25T20:21:48+00:00" + }, + { + "name": "composer/semver", + "version": "3.2.9", + "source": { + "type": "git", + "url": "https://github.com/composer/semver.git", + "reference": "a951f614bd64dcd26137bc9b7b2637ddcfc57649" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/semver/zipball/a951f614bd64dcd26137bc9b7b2637ddcfc57649", + "reference": "a951f614bd64dcd26137bc9b7b2637ddcfc57649", + "shasum": "" + }, + "require": { + "php": "^5.3.2 || ^7.0 || ^8.0" + }, + "require-dev": { + "phpstan/phpstan": "^1.4", + "symfony/phpunit-bridge": "^4.2 || ^5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Composer\\Semver\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nils Adermann", + "email": "naderman@naderman.de", + "homepage": "http://www.naderman.de" + }, + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + }, + { + "name": "Rob Bast", + "email": "rob.bast@gmail.com", + "homepage": "http://robbast.nl" + } + ], + "description": "Semver library that offers utilities, version constraint parsing and validation.", + "keywords": [ + "semantic", + "semver", + "validation", + "versioning" + ], + "support": { + "irc": "irc://irc.freenode.org/composer", + "issues": "https://github.com/composer/semver/issues", + "source": "https://github.com/composer/semver/tree/3.2.9" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], + "time": "2022-02-04T13:58:43+00:00" + }, + { + "name": "composer/xdebug-handler", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/composer/xdebug-handler.git", + "reference": "ced299686f41dce890debac69273b47ffe98a40c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/ced299686f41dce890debac69273b47ffe98a40c", + "reference": "ced299686f41dce890debac69273b47ffe98a40c", + "shasum": "" + }, + "require": { + "composer/pcre": "^1 || ^2 || ^3", + "php": "^7.2.5 || ^8.0", + "psr/log": "^1 || ^2 || ^3" + }, + "require-dev": { + "phpstan/phpstan": "^1.0", + "phpstan/phpstan-strict-rules": "^1.1", + "symfony/phpunit-bridge": "^6.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Composer\\XdebugHandler\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "John Stevenson", + "email": "john-stevenson@blueyonder.co.uk" + } + ], + "description": "Restarts a process without Xdebug.", + "keywords": [ + "Xdebug", + "performance" + ], + "support": { + "irc": "irc://irc.freenode.org/composer", + "issues": "https://github.com/composer/xdebug-handler/issues", + "source": "https://github.com/composer/xdebug-handler/tree/3.0.3" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], + "time": "2022-02-25T21:32:43+00:00" + }, + { + "name": "dealerdirect/phpcodesniffer-composer-installer", + "version": "v0.7.2", + "source": { + "type": "git", + "url": "https://github.com/Dealerdirect/phpcodesniffer-composer-installer.git", + "reference": "1c968e542d8843d7cd71de3c5c9c3ff3ad71a1db" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Dealerdirect/phpcodesniffer-composer-installer/zipball/1c968e542d8843d7cd71de3c5c9c3ff3ad71a1db", + "reference": "1c968e542d8843d7cd71de3c5c9c3ff3ad71a1db", + "shasum": "" + }, + "require": { + "composer-plugin-api": "^1.0 || ^2.0", + "php": ">=5.3", + "squizlabs/php_codesniffer": "^2.0 || ^3.1.0 || ^4.0" + }, + "require-dev": { + "composer/composer": "*", + "php-parallel-lint/php-parallel-lint": "^1.3.1", + "phpcompatibility/php-compatibility": "^9.0" + }, + "type": "composer-plugin", + "extra": { + "class": "Dealerdirect\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\Plugin" + }, + "autoload": { + "psr-4": { + "Dealerdirect\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Franck Nijhof", + "email": "franck.nijhof@dealerdirect.com", + "homepage": "http://www.frenck.nl", + "role": "Developer / IT Manager" + }, + { + "name": "Contributors", + "homepage": "https://github.com/Dealerdirect/phpcodesniffer-composer-installer/graphs/contributors" + } + ], + "description": "PHP_CodeSniffer Standards Composer Installer Plugin", + "homepage": "http://www.dealerdirect.com", + "keywords": [ + "PHPCodeSniffer", + "PHP_CodeSniffer", + "code quality", + "codesniffer", + "composer", + "installer", + "phpcbf", + "phpcs", + "plugin", + "qa", + "quality", + "standard", + "standards", + "style guide", + "stylecheck", + "tests" + ], + "support": { + "issues": "https://github.com/dealerdirect/phpcodesniffer-composer-installer/issues", + "source": "https://github.com/dealerdirect/phpcodesniffer-composer-installer" + }, + "time": "2022-02-04T12:51:07+00:00" + }, + { + "name": "dnoegel/php-xdg-base-dir", + "version": "v0.1.1", + "source": { + "type": "git", + "url": "https://github.com/dnoegel/php-xdg-base-dir.git", + "reference": "8f8a6e48c5ecb0f991c2fdcf5f154a47d85f9ffd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/dnoegel/php-xdg-base-dir/zipball/8f8a6e48c5ecb0f991c2fdcf5f154a47d85f9ffd", + "reference": "8f8a6e48c5ecb0f991c2fdcf5f154a47d85f9ffd", + "shasum": "" + }, + "require": { + "php": ">=5.3.2" + }, + "require-dev": { + "phpunit/phpunit": "~7.0|~6.0|~5.0|~4.8.35" + }, + "type": "library", + "autoload": { + "psr-4": { + "XdgBaseDir\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "implementation of xdg base directory specification for php", + "support": { + "issues": "https://github.com/dnoegel/php-xdg-base-dir/issues", + "source": "https://github.com/dnoegel/php-xdg-base-dir/tree/v0.1.1" + }, + "time": "2019-12-04T15:06:13+00:00" + }, + { + "name": "doctrine/instantiator", + "version": "1.4.1", + "source": { + "type": "git", + "url": "https://github.com/doctrine/instantiator.git", + "reference": "10dcfce151b967d20fde1b34ae6640712c3891bc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/10dcfce151b967d20fde1b34ae6640712c3891bc", + "reference": "10dcfce151b967d20fde1b34ae6640712c3891bc", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "doctrine/coding-standard": "^9", + "ext-pdo": "*", + "ext-phar": "*", + "phpbench/phpbench": "^0.16 || ^1", + "phpstan/phpstan": "^1.4", + "phpstan/phpstan-phpunit": "^1", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", + "vimeo/psalm": "^4.22" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com", + "homepage": "https://ocramius.github.io/" + } + ], + "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", + "homepage": "https://www.doctrine-project.org/projects/instantiator.html", + "keywords": [ + "constructor", + "instantiate" + ], + "support": { + "issues": "https://github.com/doctrine/instantiator/issues", + "source": "https://github.com/doctrine/instantiator/tree/1.4.1" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finstantiator", + "type": "tidelift" + } + ], + "time": "2022-03-03T08:28:38+00:00" + }, + { + "name": "felixfbecker/advanced-json-rpc", + "version": "v3.2.1", + "source": { + "type": "git", + "url": "https://github.com/felixfbecker/php-advanced-json-rpc.git", + "reference": "b5f37dbff9a8ad360ca341f3240dc1c168b45447" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/felixfbecker/php-advanced-json-rpc/zipball/b5f37dbff9a8ad360ca341f3240dc1c168b45447", + "reference": "b5f37dbff9a8ad360ca341f3240dc1c168b45447", + "shasum": "" + }, + "require": { + "netresearch/jsonmapper": "^1.0 || ^2.0 || ^3.0 || ^4.0", + "php": "^7.1 || ^8.0", + "phpdocumentor/reflection-docblock": "^4.3.4 || ^5.0.0" + }, + "require-dev": { + "phpunit/phpunit": "^7.0 || ^8.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "AdvancedJsonRpc\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "ISC" + ], + "authors": [ + { + "name": "Felix Becker", + "email": "felix.b@outlook.com" + } + ], + "description": "A more advanced JSONRPC implementation", + "support": { + "issues": "https://github.com/felixfbecker/php-advanced-json-rpc/issues", + "source": "https://github.com/felixfbecker/php-advanced-json-rpc/tree/v3.2.1" + }, + "time": "2021-06-11T22:34:44+00:00" + }, + { + "name": "felixfbecker/language-server-protocol", + "version": "1.5.1", + "source": { + "type": "git", + "url": "https://github.com/felixfbecker/php-language-server-protocol.git", + "reference": "9d846d1f5cf101deee7a61c8ba7caa0a975cd730" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/felixfbecker/php-language-server-protocol/zipball/9d846d1f5cf101deee7a61c8ba7caa0a975cd730", + "reference": "9d846d1f5cf101deee7a61c8ba7caa0a975cd730", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "require-dev": { + "phpstan/phpstan": "*", + "squizlabs/php_codesniffer": "^3.1", + "vimeo/psalm": "^4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "LanguageServerProtocol\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "ISC" + ], + "authors": [ + { + "name": "Felix Becker", + "email": "felix.b@outlook.com" + } + ], + "description": "PHP classes for the Language Server Protocol", + "keywords": [ + "language", + "microsoft", + "php", + "server" + ], + "support": { + "issues": "https://github.com/felixfbecker/php-language-server-protocol/issues", + "source": "https://github.com/felixfbecker/php-language-server-protocol/tree/1.5.1" + }, + "time": "2021-02-22T14:02:09+00:00" + }, + { + "name": "infection/abstract-testframework-adapter", + "version": "0.5.0", + "source": { + "type": "git", + "url": "https://github.com/infection/abstract-testframework-adapter.git", + "reference": "18925e20d15d1a5995bb85c9dc09e8751e1e069b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/infection/abstract-testframework-adapter/zipball/18925e20d15d1a5995bb85c9dc09e8751e1e069b", + "reference": "18925e20d15d1a5995bb85c9dc09e8751e1e069b", + "shasum": "" + }, + "require": { + "php": "^7.4 || ^8.0" + }, + "require-dev": { + "ergebnis/composer-normalize": "^2.8", + "friendsofphp/php-cs-fixer": "^2.17", + "phpunit/phpunit": "^9.5" + }, + "type": "library", + "autoload": { + "psr-4": { + "Infection\\AbstractTestFramework\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Maks Rafalko", + "email": "maks.rafalko@gmail.com" + } + ], + "description": "Abstract Test Framework Adapter for Infection", + "support": { + "issues": "https://github.com/infection/abstract-testframework-adapter/issues", + "source": "https://github.com/infection/abstract-testframework-adapter/tree/0.5.0" + }, + "funding": [ + { + "url": "https://github.com/infection", + "type": "github" + }, + { + "url": "https://opencollective.com/infection", + "type": "open_collective" + } + ], + "time": "2021-08-17T18:49:12+00:00" + }, + { + "name": "infection/extension-installer", + "version": "0.1.2", + "source": { + "type": "git", + "url": "https://github.com/infection/extension-installer.git", + "reference": "9b351d2910b9a23ab4815542e93d541e0ca0cdcf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/infection/extension-installer/zipball/9b351d2910b9a23ab4815542e93d541e0ca0cdcf", + "reference": "9b351d2910b9a23ab4815542e93d541e0ca0cdcf", + "shasum": "" + }, + "require": { + "composer-plugin-api": "^1.1 || ^2.0" + }, + "require-dev": { + "composer/composer": "^1.9 || ^2.0", + "friendsofphp/php-cs-fixer": "^2.18, <2.19", + "infection/infection": "^0.15.2", + "php-coveralls/php-coveralls": "^2.4", + "phpstan/extension-installer": "^1.0", + "phpstan/phpstan": "^0.12.10", + "phpstan/phpstan-phpunit": "^0.12.6", + "phpstan/phpstan-strict-rules": "^0.12.2", + "phpstan/phpstan-webmozart-assert": "^0.12.2", + "phpunit/phpunit": "^9.5", + "vimeo/psalm": "^4.8" + }, + "type": "composer-plugin", + "extra": { + "class": "Infection\\ExtensionInstaller\\Plugin" + }, + "autoload": { + "psr-4": { + "Infection\\ExtensionInstaller\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Maks Rafalko", + "email": "maks.rafalko@gmail.com" + } + ], + "description": "Infection Extension Installer", + "support": { + "issues": "https://github.com/infection/extension-installer/issues", + "source": "https://github.com/infection/extension-installer/tree/0.1.2" + }, + "funding": [ + { + "url": "https://github.com/infection", + "type": "github" + }, + { + "url": "https://opencollective.com/infection", + "type": "open_collective" + } + ], + "time": "2021-10-20T22:08:34+00:00" + }, + { + "name": "infection/include-interceptor", + "version": "0.2.5", + "source": { + "type": "git", + "url": "https://github.com/infection/include-interceptor.git", + "reference": "0cc76d95a79d9832d74e74492b0a30139904bdf7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/infection/include-interceptor/zipball/0cc76d95a79d9832d74e74492b0a30139904bdf7", + "reference": "0cc76d95a79d9832d74e74492b0a30139904bdf7", + "shasum": "" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^2.16", + "infection/infection": "^0.15.0", + "phan/phan": "^2.4 || ^3", + "php-coveralls/php-coveralls": "^2.2", + "phpstan/phpstan": "^0.12.8", + "phpunit/phpunit": "^8.5", + "vimeo/psalm": "^3.8" + }, + "type": "library", + "autoload": { + "psr-4": { + "Infection\\StreamWrapper\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Maks Rafalko", + "email": "maks.rafalko@gmail.com" + } + ], + "description": "Stream Wrapper: Include Interceptor. Allows to replace included (autoloaded) file with another one.", + "support": { + "issues": "https://github.com/infection/include-interceptor/issues", + "source": "https://github.com/infection/include-interceptor/tree/0.2.5" + }, + "funding": [ + { + "url": "https://github.com/infection", + "type": "github" + }, + { + "url": "https://opencollective.com/infection", + "type": "open_collective" + } + ], + "time": "2021-08-09T10:03:57+00:00" + }, + { + "name": "infection/infection", + "version": "0.26.6", + "source": { + "type": "git", + "url": "https://github.com/infection/infection.git", + "reference": "de9b6b92f00ff1cb39decddf95797a4ebec3a1ee" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/infection/infection/zipball/de9b6b92f00ff1cb39decddf95797a4ebec3a1ee", + "reference": "de9b6b92f00ff1cb39decddf95797a4ebec3a1ee", + "shasum": "" + }, + "require": { + "composer-runtime-api": "^2.0", + "composer/xdebug-handler": "^2.0 || ^3.0", + "ext-dom": "*", + "ext-json": "*", + "ext-libxml": "*", + "infection/abstract-testframework-adapter": "^0.5.0", + "infection/extension-installer": "^0.1.0", + "infection/include-interceptor": "^0.2.5", + "justinrainbow/json-schema": "^5.2.10", + "nikic/php-parser": "^4.13.2", + "ondram/ci-detector": "^4.1.0", + "php": "^7.4.7 || ^8.0", + "sanmai/later": "^0.1.1", + "sanmai/pipeline": "^5.1 || ^6", + "sebastian/diff": "^3.0.2 || ^4.0", + "seld/jsonlint": "^1.7", + "symfony/console": "^3.4.29 || ^4.1.19 || ^5.0 || ^6.0", + "symfony/filesystem": "^3.4.29 || ^4.1.19 || ^5.0 || ^6.0", + "symfony/finder": "^3.4.29 || ^4.1.19 || ^5.0 || ^6.0", + "symfony/process": "^3.4.29 || ^4.1.19 || ^5.0 || ^6.0", + "thecodingmachine/safe": "^1.1.3", + "webmozart/assert": "^1.3", + "webmozart/path-util": "^2.3" + }, + "conflict": { + "dg/bypass-finals": "*", + "phpunit/php-code-coverage": ">9 <9.1.4" + }, + "require-dev": { + "brianium/paratest": "^6.3", + "ext-simplexml": "*", + "helmich/phpunit-json-assert": "^3.0", + "phpspec/prophecy-phpunit": "^2.0", + "phpstan/extension-installer": "^1.1.0", + "phpstan/phpstan": "^1.2.0", + "phpstan/phpstan-phpunit": "^1.0.0", + "phpstan/phpstan-strict-rules": "^1.1.0", + "phpstan/phpstan-webmozart-assert": "^1.0.2", + "phpunit/phpunit": "^9.3.11", + "symfony/phpunit-bridge": "^4.4.18 || ^5.1.10", + "symfony/yaml": "^5.0", + "thecodingmachine/phpstan-safe-rule": "^1.1.0" + }, + "bin": [ + "bin/infection" + ], + "type": "library", + "autoload": { + "psr-4": { + "Infection\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Maks Rafalko", + "email": "maks.rafalko@gmail.com", + "homepage": "https://twitter.com/maks_rafalko" + }, + { + "name": "Oleg Zhulnev", + "homepage": "https://github.com/sidz" + }, + { + "name": "Gert de Pagter", + "homepage": "https://github.com/BackEndTea" + }, + { + "name": "Théo FIDRY", + "email": "theo.fidry@gmail.com", + "homepage": "https://twitter.com/tfidry" + }, + { + "name": "Alexey Kopytko", + "email": "alexey@kopytko.com", + "homepage": "https://www.alexeykopytko.com" + }, + { + "name": "Andreas Möller", + "email": "am@localheinz.com", + "homepage": "https://localheinz.com" + } + ], + "description": "Infection is a Mutation Testing framework for PHP. The mutation adequacy score can be used to measure the effectiveness of a test set in terms of its ability to detect faults.", + "keywords": [ + "coverage", + "mutant", + "mutation framework", + "mutation testing", + "testing", + "unit testing" + ], + "support": { + "issues": "https://github.com/infection/infection/issues", + "source": "https://github.com/infection/infection/tree/0.26.6" + }, + "funding": [ + { + "url": "https://github.com/infection", + "type": "github" + }, + { + "url": "https://opencollective.com/infection", + "type": "open_collective" + } + ], + "time": "2022-03-07T11:40:30+00:00" + }, + { + "name": "justinrainbow/json-schema", + "version": "5.2.11", + "source": { + "type": "git", + "url": "https://github.com/justinrainbow/json-schema.git", + "reference": "2ab6744b7296ded80f8cc4f9509abbff393399aa" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/justinrainbow/json-schema/zipball/2ab6744b7296ded80f8cc4f9509abbff393399aa", + "reference": "2ab6744b7296ded80f8cc4f9509abbff393399aa", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "~2.2.20||~2.15.1", + "json-schema/json-schema-test-suite": "1.2.0", + "phpunit/phpunit": "^4.8.35" + }, + "bin": [ + "bin/validate-json" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "JsonSchema\\": "src/JsonSchema/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bruno Prieto Reis", + "email": "bruno.p.reis@gmail.com" + }, + { + "name": "Justin Rainbow", + "email": "justin.rainbow@gmail.com" + }, + { + "name": "Igor Wiedler", + "email": "igor@wiedler.ch" + }, + { + "name": "Robert Schönthal", + "email": "seroscho@googlemail.com" + } + ], + "description": "A library to validate a json schema.", + "homepage": "https://github.com/justinrainbow/json-schema", + "keywords": [ + "json", + "schema" + ], + "support": { + "issues": "https://github.com/justinrainbow/json-schema/issues", + "source": "https://github.com/justinrainbow/json-schema/tree/5.2.11" + }, + "time": "2021-07-22T09:24:00+00:00" + }, + { + "name": "laminas/laminas-coding-standard", + "version": "2.3.0", + "source": { + "type": "git", + "url": "https://github.com/laminas/laminas-coding-standard.git", + "reference": "bcf6e07fe4690240be7beb6d884d0b0fafa6a251" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laminas/laminas-coding-standard/zipball/bcf6e07fe4690240be7beb6d884d0b0fafa6a251", + "reference": "bcf6e07fe4690240be7beb6d884d0b0fafa6a251", + "shasum": "" + }, + "require": { + "dealerdirect/phpcodesniffer-composer-installer": "^0.7", + "php": "^7.3 || ^8.0", + "slevomat/coding-standard": "^7.0", + "squizlabs/php_codesniffer": "^3.6", + "webimpress/coding-standard": "^1.2" + }, + "type": "phpcodesniffer-standard", + "autoload": { + "psr-4": { + "LaminasCodingStandard\\": "src/LaminasCodingStandard/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "description": "Laminas Coding Standard", + "homepage": "https://laminas.dev", + "keywords": [ + "Coding Standard", + "laminas" + ], + "support": { + "chat": "https://laminas.dev/chat", + "docs": "https://docs.laminas.dev/laminas-coding-standard/", + "forum": "https://discourse.laminas.dev", + "issues": "https://github.com/laminas/laminas-coding-standard/issues", + "rss": "https://github.com/laminas/laminas-coding-standard/releases.atom", + "source": "https://github.com/laminas/laminas-coding-standard" + }, + "funding": [ + { + "url": "https://funding.communitybridge.org/projects/laminas-project", + "type": "community_bridge" + } + ], + "time": "2021-05-29T15:53:59+00:00" + }, + { + "name": "maglnet/composer-require-checker", + "version": "3.8.0", + "source": { + "type": "git", + "url": "https://github.com/maglnet/ComposerRequireChecker.git", + "reference": "537138b833ab0f9ad72b667a72bece2a765e88ab" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/maglnet/ComposerRequireChecker/zipball/537138b833ab0f9ad72b667a72bece2a765e88ab", + "reference": "537138b833ab0f9ad72b667a72bece2a765e88ab", + "shasum": "" + }, + "require": { + "composer-runtime-api": "^2.0.0", + "ext-json": "*", + "ext-phar": "*", + "nikic/php-parser": "^4.13.0", + "php": "^7.4 || ^8.0", + "symfony/console": "^5.4.0", + "webmozart/assert": "^1.9.1", + "webmozart/glob": "^4.4.0" + }, + "require-dev": { + "doctrine/coding-standard": "^9.0.0", + "ext-zend-opcache": "*", + "mikey179/vfsstream": "^1.6.10", + "phing/phing": "^2.17.0", + "phpstan/phpstan": "^1.2.0", + "phpunit/phpunit": "^9.5.10", + "vimeo/psalm": "^4.14.0" + }, + "bin": [ + "bin/composer-require-checker" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.1-dev" + } + }, + "autoload": { + "psr-4": { + "ComposerRequireChecker\\": "src/ComposerRequireChecker" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com", + "homepage": "http://ocramius.github.io/" + }, + { + "name": "Matthias Glaub", + "email": "magl@magl.net", + "homepage": "http://magl.net" + } + ], + "description": "CLI tool to analyze composer dependencies and verify that no unknown symbols are used in the sources of a package", + "homepage": "https://github.com/maglnet/ComposerRequireChecker", + "keywords": [ + "analysis", + "cli", + "composer", + "dependency", + "imports", + "require", + "requirements" + ], + "support": { + "issues": "https://github.com/maglnet/ComposerRequireChecker/issues", + "source": "https://github.com/maglnet/ComposerRequireChecker/tree/3.8.0" + }, + "time": "2021-12-07T14:25:47+00:00" + }, + { + "name": "myclabs/deep-copy", + "version": "1.11.0", + "source": { + "type": "git", + "url": "https://github.com/myclabs/DeepCopy.git", + "reference": "14daed4296fae74d9e3201d2c4925d1acb7aa614" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/14daed4296fae74d9e3201d2c4925d1acb7aa614", + "reference": "14daed4296fae74d9e3201d2c4925d1acb7aa614", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "conflict": { + "doctrine/collections": "<1.6.8", + "doctrine/common": "<2.13.3 || >=3,<3.2.2" + }, + "require-dev": { + "doctrine/collections": "^1.6.8", + "doctrine/common": "^2.13.3 || ^3.2.2", + "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13" + }, + "type": "library", + "autoload": { + "files": [ + "src/DeepCopy/deep_copy.php" + ], + "psr-4": { + "DeepCopy\\": "src/DeepCopy/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Create deep copies (clones) of your objects", + "keywords": [ + "clone", + "copy", + "duplicate", + "object", + "object graph" + ], + "support": { + "issues": "https://github.com/myclabs/DeepCopy/issues", + "source": "https://github.com/myclabs/DeepCopy/tree/1.11.0" + }, + "funding": [ + { + "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy", + "type": "tidelift" + } + ], + "time": "2022-03-03T13:19:32+00:00" + }, + { + "name": "netresearch/jsonmapper", + "version": "v4.0.0", + "source": { + "type": "git", + "url": "https://github.com/cweiske/jsonmapper.git", + "reference": "8bbc021a8edb2e4a7ea2f8ad4fa9ec9dce2fcb8d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/cweiske/jsonmapper/zipball/8bbc021a8edb2e4a7ea2f8ad4fa9ec9dce2fcb8d", + "reference": "8bbc021a8edb2e4a7ea2f8ad4fa9ec9dce2fcb8d", + "shasum": "" + }, + "require": { + "ext-json": "*", + "ext-pcre": "*", + "ext-reflection": "*", + "ext-spl": "*", + "php": ">=7.1" + }, + "require-dev": { + "phpunit/phpunit": "~7.5 || ~8.0 || ~9.0", + "squizlabs/php_codesniffer": "~3.5" + }, + "type": "library", + "autoload": { + "psr-0": { + "JsonMapper": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "OSL-3.0" + ], + "authors": [ + { + "name": "Christian Weiske", + "email": "cweiske@cweiske.de", + "homepage": "http://github.com/cweiske/jsonmapper/", + "role": "Developer" + } + ], + "description": "Map nested JSON structures onto PHP classes", + "support": { + "email": "cweiske@cweiske.de", + "issues": "https://github.com/cweiske/jsonmapper/issues", + "source": "https://github.com/cweiske/jsonmapper/tree/v4.0.0" + }, + "time": "2020-12-01T19:48:11+00:00" + }, + { + "name": "nikic/php-parser", + "version": "v4.13.2", + "source": { + "type": "git", + "url": "https://github.com/nikic/PHP-Parser.git", + "reference": "210577fe3cf7badcc5814d99455df46564f3c077" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/210577fe3cf7badcc5814d99455df46564f3c077", + "reference": "210577fe3cf7badcc5814d99455df46564f3c077", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": ">=7.0" + }, + "require-dev": { + "ircmaxell/php-yacc": "^0.0.7", + "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0" + }, + "bin": [ + "bin/php-parse" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.9-dev" + } + }, + "autoload": { + "psr-4": { + "PhpParser\\": "lib/PhpParser" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Nikita Popov" + } + ], + "description": "A PHP parser written in PHP", + "keywords": [ + "parser", + "php" + ], + "support": { + "issues": "https://github.com/nikic/PHP-Parser/issues", + "source": "https://github.com/nikic/PHP-Parser/tree/v4.13.2" + }, + "time": "2021-11-30T19:35:32+00:00" + }, + { + "name": "ondram/ci-detector", + "version": "4.1.0", + "source": { + "type": "git", + "url": "https://github.com/OndraM/ci-detector.git", + "reference": "8a4b664e916df82ff26a44709942dfd593fa6f30" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/OndraM/ci-detector/zipball/8a4b664e916df82ff26a44709942dfd593fa6f30", + "reference": "8a4b664e916df82ff26a44709942dfd593fa6f30", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "ergebnis/composer-normalize": "^2.2", + "lmc/coding-standard": "^1.3 || ^2.1", + "php-parallel-lint/php-parallel-lint": "^1.2", + "phpstan/extension-installer": "^1.0.5", + "phpstan/phpstan": "^0.12.58", + "phpstan/phpstan-phpunit": "^0.12.16", + "phpunit/phpunit": "^7.1 || ^8.0 || ^9.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "OndraM\\CiDetector\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ondřej Machulda", + "email": "ondrej.machulda@gmail.com" + } + ], + "description": "Detect continuous integration environment and provide unified access to properties of current build", + "keywords": [ + "CircleCI", + "Codeship", + "Wercker", + "adapter", + "appveyor", + "aws", + "aws codebuild", + "azure", + "azure devops", + "azure pipelines", + "bamboo", + "bitbucket", + "buddy", + "ci-info", + "codebuild", + "continuous integration", + "continuousphp", + "devops", + "drone", + "github", + "gitlab", + "interface", + "jenkins", + "pipelines", + "sourcehut", + "teamcity", + "travis" + ], + "support": { + "issues": "https://github.com/OndraM/ci-detector/issues", + "source": "https://github.com/OndraM/ci-detector/tree/4.1.0" + }, + "time": "2021-04-14T09:16:52+00:00" + }, + { + "name": "openlss/lib-array2xml", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/nullivex/lib-array2xml.git", + "reference": "a91f18a8dfc69ffabe5f9b068bc39bb202c81d90" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nullivex/lib-array2xml/zipball/a91f18a8dfc69ffabe5f9b068bc39bb202c81d90", + "reference": "a91f18a8dfc69ffabe5f9b068bc39bb202c81d90", + "shasum": "" + }, + "require": { + "php": ">=5.3.2" + }, + "type": "library", + "autoload": { + "psr-0": { + "LSS": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Bryan Tong", + "email": "bryan@nullivex.com", + "homepage": "https://www.nullivex.com" + }, + { + "name": "Tony Butler", + "email": "spudz76@gmail.com", + "homepage": "https://www.nullivex.com" + } + ], + "description": "Array2XML conversion library credit to lalit.org", + "homepage": "https://www.nullivex.com", + "keywords": [ + "array", + "array conversion", + "xml", + "xml conversion" + ], + "support": { + "issues": "https://github.com/nullivex/lib-array2xml/issues", + "source": "https://github.com/nullivex/lib-array2xml/tree/master" + }, + "time": "2019-03-29T20:06:56+00:00" + }, + { + "name": "phar-io/manifest", + "version": "2.0.3", + "source": { + "type": "git", + "url": "https://github.com/phar-io/manifest.git", + "reference": "97803eca37d319dfa7826cc2437fc020857acb53" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/97803eca37d319dfa7826cc2437fc020857acb53", + "reference": "97803eca37d319dfa7826cc2437fc020857acb53", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-phar": "*", + "ext-xmlwriter": "*", + "phar-io/version": "^3.0.1", + "php": "^7.2 || ^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", + "support": { + "issues": "https://github.com/phar-io/manifest/issues", + "source": "https://github.com/phar-io/manifest/tree/2.0.3" + }, + "time": "2021-07-20T11:28:43+00:00" + }, + { + "name": "phar-io/version", + "version": "3.2.1", + "source": { + "type": "git", + "url": "https://github.com/phar-io/version.git", + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/version/zipball/4f7fd7836c6f332bb2933569e566a0d6c4cbed74", + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Library for handling version information and constraints", + "support": { + "issues": "https://github.com/phar-io/version/issues", + "source": "https://github.com/phar-io/version/tree/3.2.1" + }, + "time": "2022-02-21T01:04:05+00:00" + }, + { + "name": "phpdocumentor/reflection-common", + "version": "2.2.0", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionCommon.git", + "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/1d01c49d4ed62f25aa84a747ad35d5a16924662b", + "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-2.x": "2.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jaap van Otterdijk", + "email": "opensource@ijaap.nl" + } + ], + "description": "Common reflection classes used by phpdocumentor to reflect the code structure", + "homepage": "http://www.phpdoc.org", + "keywords": [ + "FQSEN", + "phpDocumentor", + "phpdoc", + "reflection", + "static analysis" + ], + "support": { + "issues": "https://github.com/phpDocumentor/ReflectionCommon/issues", + "source": "https://github.com/phpDocumentor/ReflectionCommon/tree/2.x" + }, + "time": "2020-06-27T09:03:43+00:00" + }, + { + "name": "phpdocumentor/reflection-docblock", + "version": "5.3.0", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", + "reference": "622548b623e81ca6d78b721c5e029f4ce664f170" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/622548b623e81ca6d78b721c5e029f4ce664f170", + "reference": "622548b623e81ca6d78b721c5e029f4ce664f170", + "shasum": "" + }, + "require": { + "ext-filter": "*", + "php": "^7.2 || ^8.0", + "phpdocumentor/reflection-common": "^2.2", + "phpdocumentor/type-resolver": "^1.3", + "webmozart/assert": "^1.9.1" + }, + "require-dev": { + "mockery/mockery": "~1.3.2", + "psalm/phar": "^4.8" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "me@mikevanriel.com" + }, + { + "name": "Jaap van Otterdijk", + "email": "account@ijaap.nl" + } + ], + "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", + "support": { + "issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues", + "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.3.0" + }, + "time": "2021-10-19T17:43:47+00:00" + }, + { + "name": "phpdocumentor/type-resolver", + "version": "1.6.0", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/TypeResolver.git", + "reference": "93ebd0014cab80c4ea9f5e297ea48672f1b87706" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/93ebd0014cab80c4ea9f5e297ea48672f1b87706", + "reference": "93ebd0014cab80c4ea9f5e297ea48672f1b87706", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0", + "phpdocumentor/reflection-common": "^2.0" + }, + "require-dev": { + "ext-tokenizer": "*", + "psalm/phar": "^4.8" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-1.x": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "me@mikevanriel.com" + } + ], + "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", + "support": { + "issues": "https://github.com/phpDocumentor/TypeResolver/issues", + "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.6.0" + }, + "time": "2022-01-04T19:58:01+00:00" + }, + { + "name": "phpspec/prophecy", + "version": "v1.15.0", + "source": { + "type": "git", + "url": "https://github.com/phpspec/prophecy.git", + "reference": "bbcd7380b0ebf3961ee21409db7b38bc31d69a13" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/bbcd7380b0ebf3961ee21409db7b38bc31d69a13", + "reference": "bbcd7380b0ebf3961ee21409db7b38bc31d69a13", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.2", + "php": "^7.2 || ~8.0, <8.2", + "phpdocumentor/reflection-docblock": "^5.2", + "sebastian/comparator": "^3.0 || ^4.0", + "sebastian/recursion-context": "^3.0 || ^4.0" + }, + "require-dev": { + "phpspec/phpspec": "^6.0 || ^7.0", + "phpunit/phpunit": "^8.0 || ^9.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Prophecy\\": "src/Prophecy" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Konstantin Kudryashov", + "email": "ever.zet@gmail.com", + "homepage": "http://everzet.com" + }, + { + "name": "Marcello Duarte", + "email": "marcello.duarte@gmail.com" + } + ], + "description": "Highly opinionated mocking framework for PHP 5.3+", + "homepage": "https://github.com/phpspec/prophecy", + "keywords": [ + "Double", + "Dummy", + "fake", + "mock", + "spy", + "stub" + ], + "support": { + "issues": "https://github.com/phpspec/prophecy/issues", + "source": "https://github.com/phpspec/prophecy/tree/v1.15.0" + }, + "time": "2021-12-08T12:19:24+00:00" + }, + { + "name": "phpstan/phpdoc-parser", + "version": "1.2.0", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpdoc-parser.git", + "reference": "dbc093d7af60eff5cd575d2ed761b15ed40bd08e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/dbc093d7af60eff5cd575d2ed761b15ed40bd08e", + "reference": "dbc093d7af60eff5cd575d2ed761b15ed40bd08e", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "php-parallel-lint/php-parallel-lint": "^1.2", + "phpstan/extension-installer": "^1.0", + "phpstan/phpstan": "^1.0", + "phpstan/phpstan-strict-rules": "^1.0", + "phpunit/phpunit": "^9.5", + "symfony/process": "^5.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "psr-4": { + "PHPStan\\PhpDocParser\\": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPDoc parser with support for nullable, intersection and generic types", + "support": { + "issues": "https://github.com/phpstan/phpdoc-parser/issues", + "source": "https://github.com/phpstan/phpdoc-parser/tree/1.2.0" + }, + "time": "2021-09-16T20:46:02+00:00" + }, + { + "name": "phpunit/php-code-coverage", + "version": "9.2.15", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "2e9da11878c4202f97915c1cb4bb1ca318a63f5f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/2e9da11878c4202f97915c1cb4bb1ca318a63f5f", + "reference": "2e9da11878c4202f97915c1cb4bb1ca318a63f5f", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-libxml": "*", + "ext-xmlwriter": "*", + "nikic/php-parser": "^4.13.0", + "php": ">=7.3", + "phpunit/php-file-iterator": "^3.0.3", + "phpunit/php-text-template": "^2.0.2", + "sebastian/code-unit-reverse-lookup": "^2.0.2", + "sebastian/complexity": "^2.0", + "sebastian/environment": "^5.1.2", + "sebastian/lines-of-code": "^1.0.3", + "sebastian/version": "^3.0.1", + "theseer/tokenizer": "^1.2.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "suggest": { + "ext-pcov": "*", + "ext-xdebug": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "9.2-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", + "homepage": "https://github.com/sebastianbergmann/php-code-coverage", + "keywords": [ + "coverage", + "testing", + "xunit" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.15" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2022-03-07T09:28:20+00:00" + }, + { + "name": "phpunit/php-file-iterator", + "version": "3.0.6", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf", + "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "FilterIterator implementation that filters files based on a list of suffixes.", + "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", + "keywords": [ + "filesystem", + "iterator" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", + "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/3.0.6" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2021-12-02T12:48:52+00:00" + }, + { + "name": "phpunit/php-invoker", + "version": "3.1.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-invoker.git", + "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/5a10147d0aaf65b58940a0b72f71c9ac0423cc67", + "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "ext-pcntl": "*", + "phpunit/phpunit": "^9.3" + }, + "suggest": { + "ext-pcntl": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Invoke callables with a timeout", + "homepage": "https://github.com/sebastianbergmann/php-invoker/", + "keywords": [ + "process" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-invoker/issues", + "source": "https://github.com/sebastianbergmann/php-invoker/tree/3.1.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T05:58:55+00:00" + }, + { + "name": "phpunit/php-text-template", + "version": "2.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28", + "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "keywords": [ + "template" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-text-template/issues", + "source": "https://github.com/sebastianbergmann/php-text-template/tree/2.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T05:33:50+00:00" + }, + { + "name": "phpunit/php-timer", + "version": "5.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", + "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Utility class for timing", + "homepage": "https://github.com/sebastianbergmann/php-timer/", + "keywords": [ + "timer" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-timer/issues", + "source": "https://github.com/sebastianbergmann/php-timer/tree/5.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:16:10+00:00" + }, + { + "name": "phpunit/phpunit", + "version": "9.5.18", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "1b5856028273bfd855e60a887278857d872ec67a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/1b5856028273bfd855e60a887278857d872ec67a", + "reference": "1b5856028273bfd855e60a887278857d872ec67a", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.3.1", + "ext-dom": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-xml": "*", + "ext-xmlwriter": "*", + "myclabs/deep-copy": "^1.10.1", + "phar-io/manifest": "^2.0.3", + "phar-io/version": "^3.0.2", + "php": ">=7.3", + "phpspec/prophecy": "^1.12.1", + "phpunit/php-code-coverage": "^9.2.13", + "phpunit/php-file-iterator": "^3.0.5", + "phpunit/php-invoker": "^3.1.1", + "phpunit/php-text-template": "^2.0.3", + "phpunit/php-timer": "^5.0.2", + "sebastian/cli-parser": "^1.0.1", + "sebastian/code-unit": "^1.0.6", + "sebastian/comparator": "^4.0.5", + "sebastian/diff": "^4.0.3", + "sebastian/environment": "^5.1.3", + "sebastian/exporter": "^4.0.3", + "sebastian/global-state": "^5.0.1", + "sebastian/object-enumerator": "^4.0.3", + "sebastian/resource-operations": "^3.0.3", + "sebastian/type": "^2.3.4", + "sebastian/version": "^3.0.2" + }, + "require-dev": { + "ext-pdo": "*", + "phpspec/prophecy-phpunit": "^2.0.1" + }, + "suggest": { + "ext-soap": "*", + "ext-xdebug": "*" + }, + "bin": [ + "phpunit" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "9.5-dev" + } + }, + "autoload": { + "files": [ + "src/Framework/Assert/Functions.php" + ], + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "The PHP Unit Testing framework.", + "homepage": "https://phpunit.de/", + "keywords": [ + "phpunit", + "testing", + "xunit" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/phpunit/issues", + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.18" + }, + "funding": [ + { + "url": "https://phpunit.de/sponsors.html", + "type": "custom" + }, + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2022-03-08T06:52:28+00:00" + }, + { + "name": "psalm/plugin-phpunit", + "version": "0.16.1", + "source": { + "type": "git", + "url": "https://github.com/psalm/psalm-plugin-phpunit.git", + "reference": "5dd3be04f37a857d52880ef6af2524a441dfef24" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/psalm/psalm-plugin-phpunit/zipball/5dd3be04f37a857d52880ef6af2524a441dfef24", + "reference": "5dd3be04f37a857d52880ef6af2524a441dfef24", + "shasum": "" + }, + "require": { + "composer/package-versions-deprecated": "^1.10", + "composer/semver": "^1.4 || ^2.0 || ^3.0", + "ext-simplexml": "*", + "php": "^7.1 || ^8.0", + "vimeo/psalm": "dev-master || dev-4.x || ^4.5" + }, + "conflict": { + "phpunit/phpunit": "<7.5" + }, + "require-dev": { + "codeception/codeception": "^4.0.3", + "php": "^7.3 || ^8.0", + "phpunit/phpunit": "^7.5 || ^8.0 || ^9.0", + "squizlabs/php_codesniffer": "^3.3.1", + "weirdan/codeception-psalm-module": "^0.11.0", + "weirdan/prophecy-shim": "^1.0 || ^2.0" + }, + "type": "psalm-plugin", + "extra": { + "psalm": { + "pluginClass": "Psalm\\PhpUnitPlugin\\Plugin" + } + }, + "autoload": { + "psr-4": { + "Psalm\\PhpUnitPlugin\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Matt Brown", + "email": "github@muglug.com" + } + ], + "description": "Psalm plugin for PHPUnit", + "support": { + "issues": "https://github.com/psalm/psalm-plugin-phpunit/issues", + "source": "https://github.com/psalm/psalm-plugin-phpunit/tree/0.16.1" + }, + "time": "2021-06-18T23:56:46+00:00" + }, + { + "name": "psr/container", + "version": "1.1.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/container.git", + "reference": "513e0666f7216c7459170d56df27dfcefe1689ea" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/container/zipball/513e0666f7216c7459170d56df27dfcefe1689ea", + "reference": "513e0666f7216c7459170d56df27dfcefe1689ea", + "shasum": "" + }, + "require": { + "php": ">=7.4.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Psr\\Container\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common Container Interface (PHP FIG PSR-11)", + "homepage": "https://github.com/php-fig/container", + "keywords": [ + "PSR-11", + "container", + "container-interface", + "container-interop", + "psr" + ], + "support": { + "issues": "https://github.com/php-fig/container/issues", + "source": "https://github.com/php-fig/container/tree/1.1.2" + }, + "time": "2021-11-05T16:50:12+00:00" + }, + { + "name": "psr/log", + "version": "1.1.4", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "d49695b909c3b7628b6289db5479a1c204601f11" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/d49695b909c3b7628b6289db5479a1c204601f11", + "reference": "d49695b909c3b7628b6289db5479a1c204601f11", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Log\\": "Psr/Log/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "support": { + "source": "https://github.com/php-fig/log/tree/1.1.4" + }, + "time": "2021-05-03T11:20:27+00:00" + }, + { + "name": "sanmai/later", + "version": "0.1.2", + "source": { + "type": "git", + "url": "https://github.com/sanmai/later.git", + "reference": "9b659fecef2030193fd02402955bc39629d5606f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sanmai/later/zipball/9b659fecef2030193fd02402955bc39629d5606f", + "reference": "9b659fecef2030193fd02402955bc39629d5606f", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^2.13", + "infection/infection": ">=0.10.5", + "phan/phan": ">=2", + "php-coveralls/php-coveralls": "^2.0", + "phpstan/phpstan": ">=0.10", + "phpunit/phpunit": ">=7.4", + "vimeo/psalm": ">=2" + }, + "type": "library", + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "Later\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Alexey Kopytko", + "email": "alexey@kopytko.com" + } + ], + "description": "Later: deferred wrapper object", + "support": { + "issues": "https://github.com/sanmai/later/issues", + "source": "https://github.com/sanmai/later/tree/0.1.2" + }, + "funding": [ + { + "url": "https://github.com/sanmai", + "type": "github" + } + ], + "time": "2021-01-02T10:26:44+00:00" + }, + { + "name": "sanmai/pipeline", + "version": "v6.1", + "source": { + "type": "git", + "url": "https://github.com/sanmai/pipeline.git", + "reference": "3a88f2617237e18d5cd2aa38ca3d4b22770306c2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sanmai/pipeline/zipball/3a88f2617237e18d5cd2aa38ca3d4b22770306c2", + "reference": "3a88f2617237e18d5cd2aa38ca3d4b22770306c2", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "ergebnis/composer-normalize": "^2.8", + "friendsofphp/php-cs-fixer": "^3", + "infection/infection": ">=0.10.5", + "league/pipeline": "^1.0 || ^0.3", + "phan/phan": ">=1.1", + "php-coveralls/php-coveralls": "^2.4.1", + "phpstan/phpstan": ">=0.10", + "phpunit/phpunit": "^7.4 || ^8.1 || ^9.4", + "vimeo/psalm": ">=2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "v6.x-dev" + } + }, + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "Pipeline\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Alexey Kopytko", + "email": "alexey@kopytko.com" + } + ], + "description": "General-purpose collections pipeline", + "support": { + "issues": "https://github.com/sanmai/pipeline/issues", + "source": "https://github.com/sanmai/pipeline/tree/v6.1" + }, + "funding": [ + { + "url": "https://github.com/sanmai", + "type": "github" + } + ], + "time": "2022-01-30T08:15:59+00:00" + }, + { + "name": "sebastian/cli-parser", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/cli-parser.git", + "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/442e7c7e687e42adc03470c7b668bc4b2402c0b2", + "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for parsing CLI options", + "homepage": "https://github.com/sebastianbergmann/cli-parser", + "support": { + "issues": "https://github.com/sebastianbergmann/cli-parser/issues", + "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T06:08:49+00:00" + }, + { + "name": "sebastian/code-unit", + "version": "1.0.8", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit.git", + "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/1fc9f64c0927627ef78ba436c9b17d967e68e120", + "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Collection of value objects that represent the PHP code units", + "homepage": "https://github.com/sebastianbergmann/code-unit", + "support": { + "issues": "https://github.com/sebastianbergmann/code-unit/issues", + "source": "https://github.com/sebastianbergmann/code-unit/tree/1.0.8" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:08:54+00:00" + }, + { + "name": "sebastian/code-unit-reverse-lookup", + "version": "2.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", + "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", + "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Looks up which function or method a line of code belongs to", + "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", + "support": { + "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues", + "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/2.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T05:30:19+00:00" + }, + { + "name": "sebastian/comparator", + "version": "4.0.6", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "55f4261989e546dc112258c7a75935a81a7ce382" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/55f4261989e546dc112258c7a75935a81a7ce382", + "reference": "55f4261989e546dc112258c7a75935a81a7ce382", + "shasum": "" + }, + "require": { + "php": ">=7.3", + "sebastian/diff": "^4.0", + "sebastian/exporter": "^4.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + } + ], + "description": "Provides the functionality to compare PHP values for equality", + "homepage": "https://github.com/sebastianbergmann/comparator", + "keywords": [ + "comparator", + "compare", + "equality" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/comparator/issues", + "source": "https://github.com/sebastianbergmann/comparator/tree/4.0.6" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T15:49:45+00:00" + }, + { + "name": "sebastian/complexity", + "version": "2.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/complexity.git", + "reference": "739b35e53379900cc9ac327b2147867b8b6efd88" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/739b35e53379900cc9ac327b2147867b8b6efd88", + "reference": "739b35e53379900cc9ac327b2147867b8b6efd88", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^4.7", + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for calculating the complexity of PHP code units", + "homepage": "https://github.com/sebastianbergmann/complexity", + "support": { + "issues": "https://github.com/sebastianbergmann/complexity/issues", + "source": "https://github.com/sebastianbergmann/complexity/tree/2.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T15:52:27+00:00" + }, + { + "name": "sebastian/diff", + "version": "4.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/3461e3fccc7cfdfc2720be910d3bd73c69be590d", + "reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3", + "symfony/process": "^4.2 || ^5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" + } + ], + "description": "Diff implementation", + "homepage": "https://github.com/sebastianbergmann/diff", + "keywords": [ + "diff", + "udiff", + "unidiff", + "unified diff" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/diff/issues", + "source": "https://github.com/sebastianbergmann/diff/tree/4.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:10:38+00:00" + }, + { + "name": "sebastian/environment", + "version": "5.1.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/environment.git", + "reference": "388b6ced16caa751030f6a69e588299fa09200ac" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/388b6ced16caa751030f6a69e588299fa09200ac", + "reference": "388b6ced16caa751030f6a69e588299fa09200ac", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "suggest": { + "ext-posix": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides functionality to handle HHVM/PHP environments", + "homepage": "http://www.github.com/sebastianbergmann/environment", + "keywords": [ + "Xdebug", + "environment", + "hhvm" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/environment/issues", + "source": "https://github.com/sebastianbergmann/environment/tree/5.1.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T05:52:38+00:00" + }, + { + "name": "sebastian/exporter", + "version": "4.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/exporter.git", + "reference": "65e8b7db476c5dd267e65eea9cab77584d3cfff9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/65e8b7db476c5dd267e65eea9cab77584d3cfff9", + "reference": "65e8b7db476c5dd267e65eea9cab77584d3cfff9", + "shasum": "" + }, + "require": { + "php": ">=7.3", + "sebastian/recursion-context": "^4.0" + }, + "require-dev": { + "ext-mbstring": "*", + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Provides the functionality to export PHP variables for visualization", + "homepage": "https://www.github.com/sebastianbergmann/exporter", + "keywords": [ + "export", + "exporter" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/exporter/issues", + "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2021-11-11T14:18:36+00:00" + }, + { + "name": "sebastian/global-state", + "version": "5.0.5", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/global-state.git", + "reference": "0ca8db5a5fc9c8646244e629625ac486fa286bf2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/0ca8db5a5fc9c8646244e629625ac486fa286bf2", + "reference": "0ca8db5a5fc9c8646244e629625ac486fa286bf2", + "shasum": "" + }, + "require": { + "php": ">=7.3", + "sebastian/object-reflector": "^2.0", + "sebastian/recursion-context": "^4.0" + }, + "require-dev": { + "ext-dom": "*", + "phpunit/phpunit": "^9.3" + }, + "suggest": { + "ext-uopz": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Snapshotting of global state", + "homepage": "http://www.github.com/sebastianbergmann/global-state", + "keywords": [ + "global state" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/global-state/issues", + "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.5" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2022-02-14T08:28:10+00:00" + }, + { + "name": "sebastian/lines-of-code", + "version": "1.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/lines-of-code.git", + "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/c1c2e997aa3146983ed888ad08b15470a2e22ecc", + "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^4.6", + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for counting the lines of code in PHP source code", + "homepage": "https://github.com/sebastianbergmann/lines-of-code", + "support": { + "issues": "https://github.com/sebastianbergmann/lines-of-code/issues", + "source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-11-28T06:42:11+00:00" + }, + { + "name": "sebastian/object-enumerator", + "version": "4.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-enumerator.git", + "reference": "5c9eeac41b290a3712d88851518825ad78f45c71" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/5c9eeac41b290a3712d88851518825ad78f45c71", + "reference": "5c9eeac41b290a3712d88851518825ad78f45c71", + "shasum": "" + }, + "require": { + "php": ">=7.3", + "sebastian/object-reflector": "^2.0", + "sebastian/recursion-context": "^4.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Traverses array structures and object graphs to enumerate all referenced objects", + "homepage": "https://github.com/sebastianbergmann/object-enumerator/", + "support": { + "issues": "https://github.com/sebastianbergmann/object-enumerator/issues", + "source": "https://github.com/sebastianbergmann/object-enumerator/tree/4.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:12:34+00:00" + }, + { + "name": "sebastian/object-reflector", + "version": "2.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-reflector.git", + "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", + "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Allows reflection of object attributes, including inherited and non-public ones", + "homepage": "https://github.com/sebastianbergmann/object-reflector/", + "support": { + "issues": "https://github.com/sebastianbergmann/object-reflector/issues", + "source": "https://github.com/sebastianbergmann/object-reflector/tree/2.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:14:26+00:00" + }, + { + "name": "sebastian/recursion-context", + "version": "4.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "cd9d8cf3c5804de4341c283ed787f099f5506172" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/cd9d8cf3c5804de4341c283ed787f099f5506172", + "reference": "cd9d8cf3c5804de4341c283ed787f099f5506172", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides functionality to recursively process PHP variables", + "homepage": "http://www.github.com/sebastianbergmann/recursion-context", + "support": { + "issues": "https://github.com/sebastianbergmann/recursion-context/issues", + "source": "https://github.com/sebastianbergmann/recursion-context/tree/4.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:17:30+00:00" + }, + { + "name": "sebastian/resource-operations", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/resource-operations.git", + "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", + "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides a list of PHP built-in functions that operate on resources", + "homepage": "https://www.github.com/sebastianbergmann/resource-operations", + "support": { + "issues": "https://github.com/sebastianbergmann/resource-operations/issues", + "source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T06:45:17+00:00" + }, + { + "name": "sebastian/type", + "version": "2.3.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/type.git", + "reference": "b8cd8a1c753c90bc1a0f5372170e3e489136f914" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/b8cd8a1c753c90bc1a0f5372170e3e489136f914", + "reference": "b8cd8a1c753c90bc1a0f5372170e3e489136f914", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.3-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Collection of value objects that represent the types of the PHP type system", + "homepage": "https://github.com/sebastianbergmann/type", + "support": { + "issues": "https://github.com/sebastianbergmann/type/issues", + "source": "https://github.com/sebastianbergmann/type/tree/2.3.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2021-06-15T12:49:02+00:00" + }, + { + "name": "sebastian/version", + "version": "3.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "c6c1022351a901512170118436c764e473f6de8c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c6c1022351a901512170118436c764e473f6de8c", + "reference": "c6c1022351a901512170118436c764e473f6de8c", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that helps with managing the version number of Git-hosted PHP projects", + "homepage": "https://github.com/sebastianbergmann/version", + "support": { + "issues": "https://github.com/sebastianbergmann/version/issues", + "source": "https://github.com/sebastianbergmann/version/tree/3.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T06:39:44+00:00" + }, + { + "name": "seld/jsonlint", + "version": "1.8.3", + "source": { + "type": "git", + "url": "https://github.com/Seldaek/jsonlint.git", + "reference": "9ad6ce79c342fbd44df10ea95511a1b24dee5b57" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Seldaek/jsonlint/zipball/9ad6ce79c342fbd44df10ea95511a1b24dee5b57", + "reference": "9ad6ce79c342fbd44df10ea95511a1b24dee5b57", + "shasum": "" + }, + "require": { + "php": "^5.3 || ^7.0 || ^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0" + }, + "bin": [ + "bin/jsonlint" + ], + "type": "library", + "autoload": { + "psr-4": { + "Seld\\JsonLint\\": "src/Seld/JsonLint/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + } + ], + "description": "JSON Linter", + "keywords": [ + "json", + "linter", + "parser", + "validator" + ], + "support": { + "issues": "https://github.com/Seldaek/jsonlint/issues", + "source": "https://github.com/Seldaek/jsonlint/tree/1.8.3" + }, + "funding": [ + { + "url": "https://github.com/Seldaek", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/seld/jsonlint", + "type": "tidelift" + } + ], + "time": "2020-11-11T09:19:24+00:00" + }, + { + "name": "slevomat/coding-standard", + "version": "7.0.19", + "source": { + "type": "git", + "url": "https://github.com/slevomat/coding-standard.git", + "reference": "bef66a43815bbf9b5f49775e9ded3f7c6ba0cc37" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/slevomat/coding-standard/zipball/bef66a43815bbf9b5f49775e9ded3f7c6ba0cc37", + "reference": "bef66a43815bbf9b5f49775e9ded3f7c6ba0cc37", + "shasum": "" + }, + "require": { + "dealerdirect/phpcodesniffer-composer-installer": "^0.6.2 || ^0.7", + "php": "^7.1 || ^8.0", + "phpstan/phpdoc-parser": "^1.0.0", + "squizlabs/php_codesniffer": "^3.6.2" + }, + "require-dev": { + "phing/phing": "2.17.2", + "php-parallel-lint/php-parallel-lint": "1.3.2", + "phpstan/phpstan": "1.4.6", + "phpstan/phpstan-deprecation-rules": "1.0.0", + "phpstan/phpstan-phpunit": "1.0.0", + "phpstan/phpstan-strict-rules": "1.1.0", + "phpunit/phpunit": "7.5.20|8.5.21|9.5.16" + }, + "type": "phpcodesniffer-standard", + "extra": { + "branch-alias": { + "dev-master": "7.x-dev" + } + }, + "autoload": { + "psr-4": { + "SlevomatCodingStandard\\": "SlevomatCodingStandard" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Slevomat Coding Standard for PHP_CodeSniffer complements Consistence Coding Standard by providing sniffs with additional checks.", + "support": { + "issues": "https://github.com/slevomat/coding-standard/issues", + "source": "https://github.com/slevomat/coding-standard/tree/7.0.19" + }, + "funding": [ + { + "url": "https://github.com/kukulich", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/slevomat/coding-standard", + "type": "tidelift" + } + ], + "time": "2022-03-01T18:01:41+00:00" + }, + { + "name": "squizlabs/php_codesniffer", + "version": "3.6.2", + "source": { + "type": "git", + "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", + "reference": "5e4e71592f69da17871dba6e80dd51bce74a351a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/5e4e71592f69da17871dba6e80dd51bce74a351a", + "reference": "5e4e71592f69da17871dba6e80dd51bce74a351a", + "shasum": "" + }, + "require": { + "ext-simplexml": "*", + "ext-tokenizer": "*", + "ext-xmlwriter": "*", + "php": ">=5.4.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0" + }, + "bin": [ + "bin/phpcs", + "bin/phpcbf" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Greg Sherwood", + "role": "lead" + } + ], + "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", + "homepage": "https://github.com/squizlabs/PHP_CodeSniffer", + "keywords": [ + "phpcs", + "standards" + ], + "support": { + "issues": "https://github.com/squizlabs/PHP_CodeSniffer/issues", + "source": "https://github.com/squizlabs/PHP_CodeSniffer", + "wiki": "https://github.com/squizlabs/PHP_CodeSniffer/wiki" + }, + "time": "2021-12-12T21:44:58+00:00" + }, + { + "name": "symfony/console", + "version": "v5.4.5", + "source": { + "type": "git", + "url": "https://github.com/symfony/console.git", + "reference": "d8111acc99876953f52fe16d4c50eb60940d49ad" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/console/zipball/d8111acc99876953f52fe16d4c50eb60940d49ad", + "reference": "d8111acc99876953f52fe16d4c50eb60940d49ad", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php73": "^1.9", + "symfony/polyfill-php80": "^1.16", + "symfony/service-contracts": "^1.1|^2|^3", + "symfony/string": "^5.1|^6.0" + }, + "conflict": { + "psr/log": ">=3", + "symfony/dependency-injection": "<4.4", + "symfony/dotenv": "<5.1", + "symfony/event-dispatcher": "<4.4", + "symfony/lock": "<4.4", + "symfony/process": "<4.4" + }, + "provide": { + "psr/log-implementation": "1.0|2.0" + }, + "require-dev": { + "psr/log": "^1|^2", + "symfony/config": "^4.4|^5.0|^6.0", + "symfony/dependency-injection": "^4.4|^5.0|^6.0", + "symfony/event-dispatcher": "^4.4|^5.0|^6.0", + "symfony/lock": "^4.4|^5.0|^6.0", + "symfony/process": "^4.4|^5.0|^6.0", + "symfony/var-dumper": "^4.4|^5.0|^6.0" + }, + "suggest": { + "psr/log": "For using the console logger", + "symfony/event-dispatcher": "", + "symfony/lock": "", + "symfony/process": "" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Console\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Eases the creation of beautiful and testable command line interfaces", + "homepage": "https://symfony.com", + "keywords": [ + "cli", + "command line", + "console", + "terminal" + ], + "support": { + "source": "https://github.com/symfony/console/tree/v5.4.5" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-02-24T12:45:35+00:00" + }, + { + "name": "symfony/deprecation-contracts", + "version": "v2.5.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/deprecation-contracts.git", + "reference": "6f981ee24cf69ee7ce9736146d1c57c2780598a8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/6f981ee24cf69ee7ce9736146d1c57c2780598a8", + "reference": "6f981ee24cf69ee7ce9736146d1c57c2780598a8", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "files": [ + "function.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "A generic function and convention to trigger deprecation notices", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/deprecation-contracts/tree/v2.5.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2021-07-12T14:48:14+00:00" + }, + { + "name": "symfony/filesystem", + "version": "v5.4.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/filesystem.git", + "reference": "d53a45039974952af7f7ebc461ccdd4295e29440" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/d53a45039974952af7f7ebc461ccdd4295e29440", + "reference": "d53a45039974952af7f7ebc461ccdd4295e29440", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-mbstring": "~1.8", + "symfony/polyfill-php80": "^1.16" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Filesystem\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides basic utilities for the filesystem", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/filesystem/tree/v5.4.6" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-03-02T12:42:23+00:00" + }, + { + "name": "symfony/finder", + "version": "v5.4.3", + "source": { + "type": "git", + "url": "https://github.com/symfony/finder.git", + "reference": "231313534dded84c7ecaa79d14bc5da4ccb69b7d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/finder/zipball/231313534dded84c7ecaa79d14bc5da4ccb69b7d", + "reference": "231313534dded84c7ecaa79d14bc5da4ccb69b7d", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/polyfill-php80": "^1.16" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Finder\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Finds files and directories via an intuitive fluent interface", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/finder/tree/v5.4.3" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-01-26T16:34:36+00:00" + }, + { + "name": "symfony/polyfill-ctype", + "version": "v1.25.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "30885182c981ab175d4d034db0f6f469898070ab" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/30885182c981ab175d4d034db0f6f469898070ab", + "reference": "30885182c981ab175d4d034db0f6f469898070ab", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "provide": { + "ext-ctype": "*" + }, + "suggest": { + "ext-ctype": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.23-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for ctype functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "ctype", + "polyfill", + "portable" + ], + "support": { + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.25.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2021-10-20T20:35:02+00:00" + }, + { + "name": "symfony/polyfill-intl-grapheme", + "version": "v1.25.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-grapheme.git", + "reference": "81b86b50cf841a64252b439e738e97f4a34e2783" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/81b86b50cf841a64252b439e738e97f4a34e2783", + "reference": "81b86b50cf841a64252b439e738e97f4a34e2783", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.23-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Grapheme\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's grapheme_* functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "grapheme", + "intl", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.25.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2021-11-23T21:10:46+00:00" + }, + { + "name": "symfony/polyfill-intl-normalizer", + "version": "v1.25.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-normalizer.git", + "reference": "8590a5f561694770bdcd3f9b5c69dde6945028e8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/8590a5f561694770bdcd3f9b5c69dde6945028e8", + "reference": "8590a5f561694770bdcd3f9b5c69dde6945028e8", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.23-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Normalizer\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's Normalizer class and related functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "intl", + "normalizer", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.25.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2021-02-19T12:13:01+00:00" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.25.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "0abb51d2f102e00a4eefcf46ba7fec406d245825" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/0abb51d2f102e00a4eefcf46ba7fec406d245825", + "reference": "0abb51d2f102e00a4eefcf46ba7fec406d245825", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "provide": { + "ext-mbstring": "*" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.23-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the Mbstring extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.25.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2021-11-30T18:21:41+00:00" + }, + { + "name": "symfony/polyfill-php73", + "version": "v1.25.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php73.git", + "reference": "cc5db0e22b3cb4111010e48785a97f670b350ca5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/cc5db0e22b3cb4111010e48785a97f670b350ca5", + "reference": "cc5db0e22b3cb4111010e48785a97f670b350ca5", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.23-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php73\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php73/tree/v1.25.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2021-06-05T21:20:04+00:00" + }, + { + "name": "symfony/polyfill-php80", + "version": "v1.25.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php80.git", + "reference": "4407588e0d3f1f52efb65fbe92babe41f37fe50c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/4407588e0d3f1f52efb65fbe92babe41f37fe50c", + "reference": "4407588e0d3f1f52efb65fbe92babe41f37fe50c", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.23-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php80\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ion Bazan", + "email": "ion.bazan@gmail.com" + }, + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php80/tree/v1.25.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-03-04T08:16:47+00:00" + }, + { + "name": "symfony/process", + "version": "v5.4.5", + "source": { + "type": "git", + "url": "https://github.com/symfony/process.git", + "reference": "95440409896f90a5f85db07a32b517ecec17fa4c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/process/zipball/95440409896f90a5f85db07a32b517ecec17fa4c", + "reference": "95440409896f90a5f85db07a32b517ecec17fa4c", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/polyfill-php80": "^1.16" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Process\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Executes commands in sub-processes", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/process/tree/v5.4.5" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-01-30T18:16:22+00:00" + }, + { + "name": "symfony/service-contracts", + "version": "v2.5.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/service-contracts.git", + "reference": "1ab11b933cd6bc5464b08e81e2c5b07dec58b0fc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/1ab11b933cd6bc5464b08e81e2c5b07dec58b0fc", + "reference": "1ab11b933cd6bc5464b08e81e2c5b07dec58b0fc", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "psr/container": "^1.1", + "symfony/deprecation-contracts": "^2.1" + }, + "conflict": { + "ext-psr": "<1.1|>=2" + }, + "suggest": { + "symfony/service-implementation": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Service\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to writing services", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/service-contracts/tree/v2.5.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2021-11-04T16:48:04+00:00" + }, + { + "name": "symfony/string", + "version": "v5.4.3", + "source": { + "type": "git", + "url": "https://github.com/symfony/string.git", + "reference": "92043b7d8383e48104e411bc9434b260dbeb5a10" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/string/zipball/92043b7d8383e48104e411bc9434b260dbeb5a10", + "reference": "92043b7d8383e48104e411bc9434b260dbeb5a10", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-intl-grapheme": "~1.0", + "symfony/polyfill-intl-normalizer": "~1.0", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php80": "~1.15" + }, + "conflict": { + "symfony/translation-contracts": ">=3.0" + }, + "require-dev": { + "symfony/error-handler": "^4.4|^5.0|^6.0", + "symfony/http-client": "^4.4|^5.0|^6.0", + "symfony/translation-contracts": "^1.1|^2", + "symfony/var-exporter": "^4.4|^5.0|^6.0" + }, + "type": "library", + "autoload": { + "files": [ + "Resources/functions.php" + ], + "psr-4": { + "Symfony\\Component\\String\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides an object-oriented API to strings and deals with bytes, UTF-8 code points and grapheme clusters in a unified way", + "homepage": "https://symfony.com", + "keywords": [ + "grapheme", + "i18n", + "string", + "unicode", + "utf-8", + "utf8" + ], + "support": { + "source": "https://github.com/symfony/string/tree/v5.4.3" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-01-02T09:53:40+00:00" + }, + { + "name": "thecodingmachine/safe", + "version": "v1.3.3", + "source": { + "type": "git", + "url": "https://github.com/thecodingmachine/safe.git", + "reference": "a8ab0876305a4cdaef31b2350fcb9811b5608dbc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thecodingmachine/safe/zipball/a8ab0876305a4cdaef31b2350fcb9811b5608dbc", + "reference": "a8ab0876305a4cdaef31b2350fcb9811b5608dbc", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "require-dev": { + "phpstan/phpstan": "^0.12", + "squizlabs/php_codesniffer": "^3.2", + "thecodingmachine/phpstan-strict-rules": "^0.12" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "0.1-dev" + } + }, + "autoload": { + "files": [ + "deprecated/apc.php", + "deprecated/libevent.php", + "deprecated/mssql.php", + "deprecated/stats.php", + "lib/special_cases.php", + "generated/apache.php", + "generated/apcu.php", + "generated/array.php", + "generated/bzip2.php", + "generated/calendar.php", + "generated/classobj.php", + "generated/com.php", + "generated/cubrid.php", + "generated/curl.php", + "generated/datetime.php", + "generated/dir.php", + "generated/eio.php", + "generated/errorfunc.php", + "generated/exec.php", + "generated/fileinfo.php", + "generated/filesystem.php", + "generated/filter.php", + "generated/fpm.php", + "generated/ftp.php", + "generated/funchand.php", + "generated/gmp.php", + "generated/gnupg.php", + "generated/hash.php", + "generated/ibase.php", + "generated/ibmDb2.php", + "generated/iconv.php", + "generated/image.php", + "generated/imap.php", + "generated/info.php", + "generated/ingres-ii.php", + "generated/inotify.php", + "generated/json.php", + "generated/ldap.php", + "generated/libxml.php", + "generated/lzf.php", + "generated/mailparse.php", + "generated/mbstring.php", + "generated/misc.php", + "generated/msql.php", + "generated/mysql.php", + "generated/mysqli.php", + "generated/mysqlndMs.php", + "generated/mysqlndQc.php", + "generated/network.php", + "generated/oci8.php", + "generated/opcache.php", + "generated/openssl.php", + "generated/outcontrol.php", + "generated/password.php", + "generated/pcntl.php", + "generated/pcre.php", + "generated/pdf.php", + "generated/pgsql.php", + "generated/posix.php", + "generated/ps.php", + "generated/pspell.php", + "generated/readline.php", + "generated/rpminfo.php", + "generated/rrd.php", + "generated/sem.php", + "generated/session.php", + "generated/shmop.php", + "generated/simplexml.php", + "generated/sockets.php", + "generated/sodium.php", + "generated/solr.php", + "generated/spl.php", + "generated/sqlsrv.php", + "generated/ssdeep.php", + "generated/ssh2.php", + "generated/stream.php", + "generated/strings.php", + "generated/swoole.php", + "generated/uodbc.php", + "generated/uopz.php", + "generated/url.php", + "generated/var.php", + "generated/xdiff.php", + "generated/xml.php", + "generated/xmlrpc.php", + "generated/yaml.php", + "generated/yaz.php", + "generated/zip.php", + "generated/zlib.php" + ], + "psr-4": { + "Safe\\": [ + "lib/", + "deprecated/", + "generated/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHP core functions that throw exceptions instead of returning FALSE on error", + "support": { + "issues": "https://github.com/thecodingmachine/safe/issues", + "source": "https://github.com/thecodingmachine/safe/tree/v1.3.3" + }, + "time": "2020-10-28T17:51:34+00:00" + }, + { + "name": "theseer/tokenizer", + "version": "1.2.1", + "source": { + "type": "git", + "url": "https://github.com/theseer/tokenizer.git", + "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/34a41e998c2183e22995f158c581e7b5e755ab9e", + "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-tokenizer": "*", + "ext-xmlwriter": "*", + "php": "^7.2 || ^8.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + } + ], + "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", + "support": { + "issues": "https://github.com/theseer/tokenizer/issues", + "source": "https://github.com/theseer/tokenizer/tree/1.2.1" + }, + "funding": [ + { + "url": "https://github.com/theseer", + "type": "github" + } + ], + "time": "2021-07-28T10:34:58+00:00" + }, + { + "name": "vimeo/psalm", + "version": "4.22.0", + "source": { + "type": "git", + "url": "https://github.com/vimeo/psalm.git", + "reference": "fc2c6ab4d5fa5d644d8617089f012f3bb84b8703" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/vimeo/psalm/zipball/fc2c6ab4d5fa5d644d8617089f012f3bb84b8703", + "reference": "fc2c6ab4d5fa5d644d8617089f012f3bb84b8703", + "shasum": "" + }, + "require": { + "amphp/amp": "^2.4.2", + "amphp/byte-stream": "^1.5", + "composer/package-versions-deprecated": "^1.8.0", + "composer/semver": "^1.4 || ^2.0 || ^3.0", + "composer/xdebug-handler": "^1.1 || ^2.0 || ^3.0", + "dnoegel/php-xdg-base-dir": "^0.1.1", + "ext-ctype": "*", + "ext-dom": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-simplexml": "*", + "ext-tokenizer": "*", + "felixfbecker/advanced-json-rpc": "^3.0.3", + "felixfbecker/language-server-protocol": "^1.5", + "netresearch/jsonmapper": "^1.0 || ^2.0 || ^3.0 || ^4.0", + "nikic/php-parser": "^4.13", + "openlss/lib-array2xml": "^1.0", + "php": "^7.1|^8", + "sebastian/diff": "^3.0 || ^4.0", + "symfony/console": "^3.4.17 || ^4.1.6 || ^5.0 || ^6.0", + "webmozart/path-util": "^2.3" + }, + "provide": { + "psalm/psalm": "self.version" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.2", + "brianium/paratest": "^4.0||^6.0", + "ext-curl": "*", + "php-parallel-lint/php-parallel-lint": "^1.2", + "phpdocumentor/reflection-docblock": "^5", + "phpmyadmin/sql-parser": "5.1.0||dev-master", + "phpspec/prophecy": ">=1.9.0", + "phpunit/phpunit": "^9.0", + "psalm/plugin-phpunit": "^0.16", + "slevomat/coding-standard": "^7.0", + "squizlabs/php_codesniffer": "^3.5", + "symfony/process": "^4.3 || ^5.0 || ^6.0", + "weirdan/prophecy-shim": "^1.0 || ^2.0" + }, + "suggest": { + "ext-curl": "In order to send data to shepherd", + "ext-igbinary": "^2.0.5 is required, used to serialize caching data" + }, + "bin": [ + "psalm", + "psalm-language-server", + "psalm-plugin", + "psalm-refactor", + "psalter" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.x-dev", + "dev-3.x": "3.x-dev", + "dev-2.x": "2.x-dev", + "dev-1.x": "1.x-dev" + } + }, + "autoload": { + "files": [ + "src/functions.php", + "src/spl_object_id.php" + ], + "psr-4": { + "Psalm\\": "src/Psalm/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Matthew Brown" + } + ], + "description": "A static analysis tool for finding errors in PHP applications", + "keywords": [ + "code", + "inspection", + "php" + ], + "support": { + "issues": "https://github.com/vimeo/psalm/issues", + "source": "https://github.com/vimeo/psalm/tree/4.22.0" + }, + "time": "2022-02-24T20:34:05+00:00" + }, + { + "name": "webimpress/coding-standard", + "version": "1.2.4", + "source": { + "type": "git", + "url": "https://github.com/webimpress/coding-standard.git", + "reference": "cd0c4b0b97440c337c1f7da17b524674ca2f9ca9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/webimpress/coding-standard/zipball/cd0c4b0b97440c337c1f7da17b524674ca2f9ca9", + "reference": "cd0c4b0b97440c337c1f7da17b524674ca2f9ca9", + "shasum": "" + }, + "require": { + "php": "^7.3 || ^8.0", + "squizlabs/php_codesniffer": "^3.6.2" + }, + "require-dev": { + "phpunit/phpunit": "^9.5.13" + }, + "type": "phpcodesniffer-standard", + "extra": { + "dev-master": "1.2.x-dev", + "dev-develop": "1.3.x-dev" + }, + "autoload": { + "psr-4": { + "WebimpressCodingStandard\\": "src/WebimpressCodingStandard/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-2-Clause" + ], + "description": "Webimpress Coding Standard", + "keywords": [ + "Coding Standard", + "PSR-2", + "phpcs", + "psr-12", + "webimpress" + ], + "support": { + "issues": "https://github.com/webimpress/coding-standard/issues", + "source": "https://github.com/webimpress/coding-standard/tree/1.2.4" + }, + "funding": [ + { + "url": "https://github.com/michalbundyra", + "type": "github" + } + ], + "time": "2022-02-15T19:52:12+00:00" + }, + { + "name": "webmozart/assert", + "version": "1.10.0", + "source": { + "type": "git", + "url": "https://github.com/webmozarts/assert.git", + "reference": "6964c76c7804814a842473e0c8fd15bab0f18e25" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/webmozarts/assert/zipball/6964c76c7804814a842473e0c8fd15bab0f18e25", + "reference": "6964c76c7804814a842473e0c8fd15bab0f18e25", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0", + "symfony/polyfill-ctype": "^1.8" + }, + "conflict": { + "phpstan/phpstan": "<0.12.20", + "vimeo/psalm": "<4.6.1 || 4.6.2" + }, + "require-dev": { + "phpunit/phpunit": "^8.5.13" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.10-dev" + } + }, + "autoload": { + "psr-4": { + "Webmozart\\Assert\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Assertions to validate method input/output with nice error messages.", + "keywords": [ + "assert", + "check", + "validate" + ], + "support": { + "issues": "https://github.com/webmozarts/assert/issues", + "source": "https://github.com/webmozarts/assert/tree/1.10.0" + }, + "time": "2021-03-09T10:59:23+00:00" + }, + { + "name": "webmozart/glob", + "version": "4.4.0", + "source": { + "type": "git", + "url": "https://github.com/webmozarts/glob.git", + "reference": "539b5dbc10021d3f9242e7a9e9b6b37843179e83" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/webmozarts/glob/zipball/539b5dbc10021d3f9242e7a9e9b6b37843179e83", + "reference": "539b5dbc10021d3f9242e7a9e9b6b37843179e83", + "shasum": "" + }, + "require": { + "php": "^7.3 || ^8.0.0", + "webmozart/path-util": "^2.2" + }, + "require-dev": { + "phpunit/phpunit": "^9.5", + "symfony/filesystem": "^5.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.1-dev" + } + }, + "autoload": { + "psr-4": { + "Webmozart\\Glob\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "A PHP implementation of Ant's glob.", + "support": { + "issues": "https://github.com/webmozarts/glob/issues", + "source": "https://github.com/webmozarts/glob/tree/4.4.0" + }, + "time": "2021-10-07T16:13:08+00:00" + }, + { + "name": "webmozart/path-util", + "version": "2.3.0", + "source": { + "type": "git", + "url": "https://github.com/webmozart/path-util.git", + "reference": "d939f7edc24c9a1bb9c0dee5cb05d8e859490725" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/webmozart/path-util/zipball/d939f7edc24c9a1bb9c0dee5cb05d8e859490725", + "reference": "d939f7edc24c9a1bb9c0dee5cb05d8e859490725", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "webmozart/assert": "~1.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.6", + "sebastian/version": "^1.0.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.3-dev" + } + }, + "autoload": { + "psr-4": { + "Webmozart\\PathUtil\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "A robust cross-platform utility for normalizing, comparing and modifying file paths.", + "support": { + "issues": "https://github.com/webmozart/path-util/issues", + "source": "https://github.com/webmozart/path-util/tree/2.3.0" + }, + "abandoned": "symfony/filesystem", + "time": "2015-12-17T08:42:14+00:00" + } + ], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": { + "php": "^7.4 || ~8.0.0 || ~8.1.0", + "ext-ctype": "*", + "ext-mbstring": "*" + }, + "platform-dev": [], + "platform-overrides": { + "php": "7.4.99" + }, + "plugin-api-version": "2.2.0" +} diff --git a/kirby/vendor/laminas/laminas-escaper/src/Escaper.php b/vendor/laminas/laminas-escaper/src/Escaper.php similarity index 94% rename from kirby/vendor/laminas/laminas-escaper/src/Escaper.php rename to vendor/laminas/laminas-escaper/src/Escaper.php index c4964cb..d6a02e1 100644 --- a/kirby/vendor/laminas/laminas-escaper/src/Escaper.php +++ b/vendor/laminas/laminas-escaper/src/Escaper.php @@ -157,21 +157,9 @@ class Escaper $this->htmlSpecialCharsFlags = ENT_QUOTES | ENT_SUBSTITUTE; // set matcher callbacks - $this->htmlAttrMatcher = - /** @param array $matches */ - function (array $matches): string { - return $this->htmlAttrMatcher($matches); - }; - $this->jsMatcher = - /** @param array $matches */ - function (array $matches): string { - return $this->jsMatcher($matches); - }; - $this->cssMatcher = - /** @param array $matches */ - function (array $matches): string { - return $this->cssMatcher($matches); - }; + $this->htmlAttrMatcher = [$this, 'htmlAttrMatcher']; + $this->jsMatcher = [$this, 'jsMatcher']; + $this->cssMatcher = [$this, 'cssMatcher']; } /** diff --git a/kirby/vendor/laminas/laminas-escaper/src/Exception/ExceptionInterface.php b/vendor/laminas/laminas-escaper/src/Exception/ExceptionInterface.php similarity index 54% rename from kirby/vendor/laminas/laminas-escaper/src/Exception/ExceptionInterface.php rename to vendor/laminas/laminas-escaper/src/Exception/ExceptionInterface.php index 8f5fd89..87edfd2 100644 --- a/kirby/vendor/laminas/laminas-escaper/src/Exception/ExceptionInterface.php +++ b/vendor/laminas/laminas-escaper/src/Exception/ExceptionInterface.php @@ -4,8 +4,6 @@ declare(strict_types=1); namespace Laminas\Escaper\Exception; -use Throwable; - -interface ExceptionInterface extends Throwable +interface ExceptionInterface { } diff --git a/kirby/vendor/laminas/laminas-escaper/src/Exception/InvalidArgumentException.php b/vendor/laminas/laminas-escaper/src/Exception/InvalidArgumentException.php similarity index 100% rename from kirby/vendor/laminas/laminas-escaper/src/Exception/InvalidArgumentException.php rename to vendor/laminas/laminas-escaper/src/Exception/InvalidArgumentException.php diff --git a/kirby/vendor/laminas/laminas-escaper/src/Exception/RuntimeException.php b/vendor/laminas/laminas-escaper/src/Exception/RuntimeException.php similarity index 100% rename from kirby/vendor/laminas/laminas-escaper/src/Exception/RuntimeException.php rename to vendor/laminas/laminas-escaper/src/Exception/RuntimeException.php diff --git a/vendor/league/color-extractor/.gitignore b/vendor/league/color-extractor/.gitignore new file mode 100644 index 0000000..74ef5f8 --- /dev/null +++ b/vendor/league/color-extractor/.gitignore @@ -0,0 +1,5 @@ +vendor +composer.lock +.DS_Store +.idea +.php_cs.cache \ No newline at end of file diff --git a/vendor/league/color-extractor/.php_cs b/vendor/league/color-extractor/.php_cs new file mode 100644 index 0000000..c181874 --- /dev/null +++ b/vendor/league/color-extractor/.php_cs @@ -0,0 +1,13 @@ +files() + ->name('*.php') + ->in(array('src', 'tests')); + +return PhpCsFixer\Config::create() + ->setFinder($finder) + ->setRules([ + '@Symfony' => true, + 'array_syntax' => ['syntax' => 'short'], + ]); \ No newline at end of file diff --git a/vendor/league/color-extractor/.travis.yml b/vendor/league/color-extractor/.travis.yml new file mode 100644 index 0000000..073521e --- /dev/null +++ b/vendor/league/color-extractor/.travis.yml @@ -0,0 +1,16 @@ +language: php + +php: + - 5.4 + - 5.5 + - 5.6 + - 7.0 + - hhvm + +before_script: + - travis_retry composer self-update + - travis_retry composer install --no-interaction --prefer-source --dev + +script: + - phpunit --coverage-text + - ./vendor/bin/phpcs src --standard=psr2 diff --git a/vendor/league/color-extractor/CONTRIBUTING.md b/vendor/league/color-extractor/CONTRIBUTING.md new file mode 100644 index 0000000..102987b --- /dev/null +++ b/vendor/league/color-extractor/CONTRIBUTING.md @@ -0,0 +1,32 @@ +# Contributing + +Contributions are **welcome** and will be fully **credited**. + +We accept contributions via Pull Requests on [Github](https://github.com/php-loep/statsd). + + +## Pull Requests + +- **[PSR-2 Coding Standard](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md)** - The easiest way to apply the conventions is to install [PHP Code Sniffer](http://pear.php.net/package/PHP_CodeSniffer). + +- **Add tests!** - Your patch won't be accepted if it doesn't have tests. + +- **Document any change in behaviour** - Make sure the README and any other relevant documentation are kept up-to-date. + +- **Consider our release cycle** - We try to follow semver. Randomly breaking public APIs is not an option. + +- **Create topic branches** - Don't ask us to pull from your master branch. + +- **One pull request per feature** - If you want to do more than one thing, send multiple pull requests. + +- **Send coherent history** - Make sure each individual commit in your pull request is meaningful. If you had to make multiple intermediate commits while developing, please squash them before submitting. + + +## Running Tests + +``` bash +$ phpunit +``` + + +**Happy coding**! \ No newline at end of file diff --git a/kirby/vendor/league/color-extractor/LICENSE b/vendor/league/color-extractor/LICENSE similarity index 100% rename from kirby/vendor/league/color-extractor/LICENSE rename to vendor/league/color-extractor/LICENSE diff --git a/vendor/league/color-extractor/README.md b/vendor/league/color-extractor/README.md new file mode 100644 index 0000000..6d9a40c --- /dev/null +++ b/vendor/league/color-extractor/README.md @@ -0,0 +1,79 @@ +ColorExtractor +============== + +[![Build Status](https://travis-ci.org/thephpleague/color-extractor.png?branch=master)](https://travis-ci.org/thephpleague/color-extractor) +[![Total Downloads](https://poser.pugx.org/league/color-extractor/downloads.png)](https://packagist.org/packages/league/color-extractor) +[![Latest Stable Version](https://poser.pugx.org/league/color-extractor/v/stable.png)](https://packagist.org/packages/league/color-extractor) + +Extract colors from an image like a human would do. + +## Install + +Via Composer + +``` bash +$ composer require league/color-extractor:0.3.* +``` + +## Usage + +```php +require 'vendor/autoload.php'; + +use League\ColorExtractor\Color; +use League\ColorExtractor\ColorExtractor; +use League\ColorExtractor\Palette; + +$palette = Palette::fromFilename('./some/image.png'); + +// $palette is an iterator on colors sorted by pixel count +foreach($palette as $color => $count) { + // colors are represented by integers + echo Color::fromIntToHex($color), ': ', $count, "\n"; +} + +// it offers some helpers too +$topFive = $palette->getMostUsedColors(5); + +$colorCount = count($palette); + +$blackCount = $palette->getColorCount(Color::fromHexToInt('#000000')); + + +// an extractor is built from a palette +$extractor = new ColorExtractor($palette); + +// it defines an extract method which return the most “representative” colors +$colors = $extractor->extract(5); + +``` + +## Handling transparency + +By default **any pixel with alpha value greater than zero will be discarded**. This is because transparent colors are not perceived +as is. For exemple fully transparent black would be seen white on a white background. So if you want to take transparency into account +when building a palette you have to specify this background color. You can do this with the second argument of `Palette` constructors. +Its default value is `null`, meaning a color won't be added to the palette if its alpha component exists and is greater than zero. + +You can set it as an integer representing the color, then transparent colors will be blended before addition to the palette. + +```php +// we set a white background so fully transparent colors will be added as white in the palette +// pure red #FF0000 at 50% opacity will be stored as #FF8080 as it would be perceived +$palette = Palette::fromFilename('./some/image.png', Color::fromHexToInt('#FFFFFF')); +``` + +## Contributing + +Please see [CONTRIBUTING](https://github.com/thephpleague/color-extractor/blob/master/CONTRIBUTING.md) for details. + + +## Credits + +- [Mathieu Lechat](https://github.com/MatTheCat) +- [All Contributors](https://github.com/thephpleague/color-extractor/contributors) + + +## License + +The MIT License (MIT). Please see [License File](https://github.com/thephpleague/color-extractor/blob/master/LICENSE) for more information. diff --git a/kirby/vendor/league/color-extractor/composer.json b/vendor/league/color-extractor/composer.json similarity index 67% rename from kirby/vendor/league/color-extractor/composer.json rename to vendor/league/color-extractor/composer.json index d1132cf..a5fb009 100644 --- a/kirby/vendor/league/color-extractor/composer.json +++ b/vendor/league/color-extractor/composer.json @@ -17,24 +17,16 @@ } ], "require": { - "php": "^7.3 || ^8.0", + "php": ">=5.4.0", "ext-gd": "*" }, "require-dev": { "friendsofphp/php-cs-fixer": "~2", - "phpunit/phpunit": "^9.5" - }, - "suggest": { - "ext-curl": "To download images from remote URLs if allow_url_fopen is disabled for security reasons" + "phpunit/phpunit": "~5" }, "autoload": { "psr-4": { - "League\\ColorExtractor\\": "src" - } - }, - "autoload-dev": { - "psr-4": { - "League\\ColorExtractor\\Tests\\": "tests" + "": "src" } } } diff --git a/vendor/league/color-extractor/phpunit.xml.dist b/vendor/league/color-extractor/phpunit.xml.dist new file mode 100644 index 0000000..7a8e715 --- /dev/null +++ b/vendor/league/color-extractor/phpunit.xml.dist @@ -0,0 +1,13 @@ + + + + + tests/League/ColorExtractor + + + + + src/League/ColorExtractor + + + diff --git a/kirby/vendor/league/color-extractor/src/Color.php b/vendor/league/color-extractor/src/League/ColorExtractor/Color.php similarity index 100% rename from kirby/vendor/league/color-extractor/src/Color.php rename to vendor/league/color-extractor/src/League/ColorExtractor/Color.php diff --git a/kirby/vendor/league/color-extractor/src/ColorExtractor.php b/vendor/league/color-extractor/src/League/ColorExtractor/ColorExtractor.php similarity index 98% rename from kirby/vendor/league/color-extractor/src/ColorExtractor.php rename to vendor/league/color-extractor/src/League/ColorExtractor/ColorExtractor.php index 364a3bd..09e43c1 100644 --- a/kirby/vendor/league/color-extractor/src/ColorExtractor.php +++ b/vendor/league/color-extractor/src/League/ColorExtractor/ColorExtractor.php @@ -25,10 +25,6 @@ class ColorExtractor */ public function extract($colorCount = 1) { - if ($colorCount === 0) { - return []; - } - if (!$this->isInitialized()) { $this->initialize(); } @@ -79,9 +75,6 @@ class ColorExtractor protected static function mergeColors(\SplFixedArray $colors, $limit, $maxDelta) { $limit = min(count($colors), $limit); - if ($limit === 0) { - return []; - } if ($limit === 1) { return [$colors[0]]; } diff --git a/kirby/vendor/league/color-extractor/src/Palette.php b/vendor/league/color-extractor/src/League/ColorExtractor/Palette.php similarity index 62% rename from kirby/vendor/league/color-extractor/src/Palette.php rename to vendor/league/color-extractor/src/League/ColorExtractor/Palette.php index 5c5266f..d8fb4f9 100644 --- a/kirby/vendor/league/color-extractor/src/Palette.php +++ b/vendor/league/color-extractor/src/League/ColorExtractor/Palette.php @@ -2,41 +2,34 @@ namespace League\ColorExtractor; - - class Palette implements \Countable, \IteratorAggregate { - /** - * @var array - */ - protected $colors = []; - - /** + /** @var array */ + protected $colors; + + /** * @return int */ - #[\ReturnTypeWillChange] - public function count(): int + public function count() { return count($this->colors); } - /** - * @return \Traversable + /** + * @return \ArrayIterator */ - public function getIterator(): \Traversable + public function getIterator() { return new \ArrayIterator($this->colors); } - - /** + + /** + * @param int $color + * * @return int */ public function getColorCount($color) { - if (!array_key_exists($color, $this->colors)) { - return 0; - } - return $this->colors[$color]; } @@ -55,57 +48,10 @@ class Palette implements \Countable, \IteratorAggregate * @param int|null $backgroundColor * * @return Palette - * - * @throws \InvalidArgumentException */ public static function fromFilename($filename, $backgroundColor = null) { - if (!is_readable($filename)) { - throw new \InvalidArgumentException('Filename must be a valid path and should be readable'); - } - - return self::fromContents(file_get_contents($filename), $backgroundColor); - } - - /** - * @param string $url - * @param int|null $backgroundColor - * - * @return Palette - * - * @throws \RuntimeException - */ - public static function fromUrl($url, $backgroundColor = null) - { - if (!function_exists('curl_init')){ - return self::fromContents(file_get_contents($url)); - } - - $ch = curl_init(); - try { - curl_setopt($ch, CURLOPT_URL, $url); - curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); - $contents = curl_exec($ch); - if ($contents === false) { - throw new \RuntimeException('Failed to fetch image from URL'); - } - } finally { - curl_close($ch); - } - - return self::fromContents($contents, $backgroundColor); - } - - /** - * Create instance with file contents - * - * @param string $contents - * @param int|null $backgroundColor - * - * @return Palette - */ - public static function fromContents($contents, $backgroundColor = null) { - $image = imagecreatefromstring($contents); + $image = imagecreatefromstring(file_get_contents($filename)); $palette = self::fromGD($image, $backgroundColor); imagedestroy($image); @@ -113,16 +59,16 @@ class Palette implements \Countable, \IteratorAggregate } /** - * @param \GDImage|resource $image + * @param resource $image * @param int|null $backgroundColor * * @return Palette * * @throws \InvalidArgumentException */ - public static function fromGD($image, ?int $backgroundColor = null) + public static function fromGD($image, $backgroundColor = null) { - if (!$image instanceof \GDImage && (!is_resource($image) || get_resource_type($image) !== 'gd')) { + if (!is_resource($image) || get_resource_type($image) != 'gd') { throw new \InvalidArgumentException('Image must be a gd resource'); } if ($backgroundColor !== null && (!is_numeric($backgroundColor) || $backgroundColor < 0 || $backgroundColor > 16777215)) { diff --git a/vendor/league/color-extractor/tests/League/ColorExtractor/Test/PaletteTest.php b/vendor/league/color-extractor/tests/League/ColorExtractor/Test/PaletteTest.php new file mode 100644 index 0000000..c9a8eeb --- /dev/null +++ b/vendor/league/color-extractor/tests/League/ColorExtractor/Test/PaletteTest.php @@ -0,0 +1,67 @@ +jpegPath)); + $colors = $extractor->extract(1); + + $this->assertInternalType('array', $colors); + $this->assertCount(1, $colors); + $this->assertEquals(15985688, $colors[0]); + } + + public function testGifExtractSingleColor() + { + $extractor = new ColorExtractor(Palette::fromFilename($this->gifPath)); + $colors = $extractor->extract(1); + + $this->assertInternalType('array', $colors); + $this->assertCount(1, $colors); + $this->assertEquals(12022491, $colors[0]); + } + + public function testPngExtractSingleColor() + { + $extractor = new ColorExtractor(Palette::fromFilename($this->pngPath)); + $colors = $extractor->extract(1); + + $this->assertInternalType('array', $colors); + $this->assertCount(1, $colors); + $this->assertEquals(14024704, $colors[0]); + } + + public function testJpegExtractMultipleColors() + { + $extractor = new ColorExtractor(Palette::fromFilename($this->pngPath)); + $numColors = 3; + $colors = $extractor->extract($numColors); + + $this->assertInternalType('array', $colors); + $this->assertCount($numColors, $colors); + $this->assertEquals($colors, [14024704, 3407872, 7111569]); + } + + public function testTransparencyHandling() + { + $this->assertCount(0, Palette::fromFilename($this->transparentPngPath)); + + $whiteBackgroundPalette = Palette::fromFilename($this->transparentPngPath, Color::fromHexToInt('#FFFFFF')); + $this->assertEquals(iterator_to_array($whiteBackgroundPalette), [Color::fromHexToInt('#FF8080') => 1]); + + $blackBackgroundPalette = Palette::fromFilename($this->transparentPngPath, Color::fromHexToInt('#000000')); + $this->assertEquals(iterator_to_array($blackBackgroundPalette), [Color::fromHexToInt('#7E0000') => 1]); + } +} diff --git a/vendor/league/color-extractor/tests/assets/google.png b/vendor/league/color-extractor/tests/assets/google.png new file mode 100644 index 0000000000000000000000000000000000000000..c9a210d93137eb34c6370cecdf0ca9be227df54e GIT binary patch literal 21801 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 literal 0 HcmV?d00001 diff --git a/vendor/league/color-extractor/tests/assets/test.jpeg b/vendor/league/color-extractor/tests/assets/test.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..4f68aead63f822eeff64fe32d1fc5a332fb5fd8c GIT binary patch literal 16432 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 literal 0 HcmV?d00001 diff --git a/vendor/league/color-extractor/tests/assets/test.png b/vendor/league/color-extractor/tests/assets/test.png new file mode 100644 index 0000000000000000000000000000000000000000..25c88fd7e048d47189ef5681b2b45041c21b81ab GIT binary patch literal 296329 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Ν?9nF92ZgAf8D2;DbCT2e_OX3l=*OK)cZ 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