From 40455e18f591ddd1e24fbabdae8827ed77def910 Mon Sep 17 00:00:00 2001 From: Mike Alhayek Date: Sun, 5 May 2024 15:55:36 -0700 Subject: [PATCH 01/14] Adding a backport workflow (#15971) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Zoltán Lehóczky --- .github/workflows/backport.yml | 26 +++++++++++++++++++ .../contributing/reviewing-pull-requests.md | 6 +++++ 2 files changed, 32 insertions(+) create mode 100644 .github/workflows/backport.yml diff --git a/.github/workflows/backport.yml b/.github/workflows/backport.yml new file mode 100644 index 00000000000..998c9d96b7b --- /dev/null +++ b/.github/workflows/backport.yml @@ -0,0 +1,26 @@ +name: Backport PR to branch + +on: + issue_comment: + types: [created] + schedule: + # Once a day at 14:00 UTC to clean up old runs. + - cron: '0 14 * * *' + +permissions: + contents: write + issues: write + pull-requests: write + actions: write + +jobs: + backport: + if: ${{ contains(github.event.comment.body, '/backport to') || github.event_name == 'schedule' }} + uses: dotnet/arcade/.github/workflows/backport-base.yml@main + with: + repository_owners: 'OrchardCMS' + + pr_description_template: | + Backport of #%source_pr_number% to %target_branch% + + /cc %cc_users% diff --git a/src/docs/guides/contributing/reviewing-pull-requests.md b/src/docs/guides/contributing/reviewing-pull-requests.md index 1b59f6438ae..44bc52da582 100644 --- a/src/docs/guides/contributing/reviewing-pull-requests.md +++ b/src/docs/guides/contributing/reviewing-pull-requests.md @@ -24,3 +24,9 @@ If the PR is coming from a fork, working with its code locally won't be as trivi - Be sure to merge PRs that don't need a second opinion. This is especially important for external contributors who can't merge their PRs. Keeping PRs open will make them collect merge conflicts and make the contributor demotivated. - Be especially patient and encouraging with first-time contributors. This is indicated by such a flag on the PR. - You can add the [Feedback section](contributing-code.md) to your review comment (i.e. the one that you send your per-line comments with) to remind the author about the practices. + +## Backporting Pull Requests to Another Branch + +Occasionally, you may find it necessary to cherry-pick a pull request into a release branch after it has been merged into `main`. To facilitate this process, we've established a dedicated workflow called `backport`. + +To initiate the backporting process, simply leave a comment on the pull request you wish to backport. The comment should contain the following command: `/backport to release/1.8`. This command serves as a trigger for the backporting workflow, seamlessly bringing the desired pull request into the specified branch. From f53d16c5854817b6c540f84c90c590a9eef85783 Mon Sep 17 00:00:00 2001 From: Antoine Griffard Date: Mon, 6 May 2024 16:05:36 +0200 Subject: [PATCH 02/14] OpennIddict.Core 5.5.0 (#15991) --- src/OrchardCore.Build/Dependencies.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/OrchardCore.Build/Dependencies.props b/src/OrchardCore.Build/Dependencies.props index d8c31ef3fe5..61aa839902e 100644 --- a/src/OrchardCore.Build/Dependencies.props +++ b/src/OrchardCore.Build/Dependencies.props @@ -52,7 +52,7 @@ - + From c5c7e0386026ffdcb526491052974b1d2455fff5 Mon Sep 17 00:00:00 2001 From: tonywoo Date: Tue, 7 May 2024 00:59:23 +0800 Subject: [PATCH 03/14] Fixed an issue where feature profile expressions could not be serialized. (#15976) --- .../OrchardCore.Abstractions/Shell/Models/FeatureProfile.cs | 2 +- .../Documents/VolatileDocumentManager.cs | 2 +- .../OrchardCore.XmlRpc.Abstractions/XmlRpcContext.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/OrchardCore/OrchardCore.Abstractions/Shell/Models/FeatureProfile.cs b/src/OrchardCore/OrchardCore.Abstractions/Shell/Models/FeatureProfile.cs index 95cb72a6f80..a7c7a8e0261 100644 --- a/src/OrchardCore/OrchardCore.Abstractions/Shell/Models/FeatureProfile.cs +++ b/src/OrchardCore/OrchardCore.Abstractions/Shell/Models/FeatureProfile.cs @@ -9,7 +9,7 @@ public class FeatureProfile public string Name { get; set; } - public List FeatureRules = []; + public List FeatureRules { get; set; } = []; } public class FeatureRule diff --git a/src/OrchardCore/OrchardCore.Infrastructure/Documents/VolatileDocumentManager.cs b/src/OrchardCore/OrchardCore.Infrastructure/Documents/VolatileDocumentManager.cs index edb20522515..ea25f1b156d 100644 --- a/src/OrchardCore/OrchardCore.Infrastructure/Documents/VolatileDocumentManager.cs +++ b/src/OrchardCore/OrchardCore.Infrastructure/Documents/VolatileDocumentManager.cs @@ -116,7 +116,7 @@ private sealed class UpdateDelegates { public UpdateDelegate UpdateDelegateAsync; public AfterUpdateDelegate AfterUpdateDelegateAsync; - public HashSet Targets = []; + public HashSet Targets { get; set; } = []; } } } diff --git a/src/OrchardCore/OrchardCore.XmlRpc.Abstractions/XmlRpcContext.cs b/src/OrchardCore/OrchardCore.XmlRpc.Abstractions/XmlRpcContext.cs index 53efa216426..cb8ee8d6001 100644 --- a/src/OrchardCore/OrchardCore.XmlRpc.Abstractions/XmlRpcContext.cs +++ b/src/OrchardCore/OrchardCore.XmlRpc.Abstractions/XmlRpcContext.cs @@ -12,6 +12,6 @@ public class XmlRpcContext public IUrlHelper Url { get; set; } public XRpcMethodCall RpcMethodCall { get; set; } public XRpcMethodResponse RpcMethodResponse { get; set; } - public ICollection Drivers = []; + public ICollection Drivers { get; set; } = []; } } From d213f3d2b6df1f079f06166435291b24f78f7e03 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Tue, 7 May 2024 00:16:21 +0200 Subject: [PATCH 04/14] Add TonyWoo as a contributor for code (#15993) * update src/docs/community/contributors/README.md [skip ci] * update .all-contributorsrc [skip ci] --------- Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com> --- .all-contributorsrc | 9 +++++++++ src/docs/community/contributors/README.md | 3 ++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/.all-contributorsrc b/.all-contributorsrc index 3e73ec7df5e..d9a55b4f45d 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -3140,6 +3140,15 @@ "contributions": [ "code" ] + }, + { + "login": "TonyWoo", + "name": "tonywoo", + "avatar_url": "https://avatars.githubusercontent.com/u/689710?v=4", + "profile": "https://github.com/TonyWoo", + "contributions": [ + "code" + ] } ], "skipCi": true, diff --git a/src/docs/community/contributors/README.md b/src/docs/community/contributors/README.md index 78507bd2b2d..bc708142556 100644 --- a/src/docs/community/contributors/README.md +++ b/src/docs/community/contributors/README.md @@ -1,7 +1,7 @@ # Contributors ✨ -[![All Contributors](https://img.shields.io/badge/all_contributors-339-orange.svg?style=flat-square)](#contributors-) +[![All Contributors](https://img.shields.io/badge/all_contributors-340-orange.svg?style=flat-square)](#contributors-) Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key))! @@ -471,6 +471,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d Kartheek Penagamuri
Kartheek Penagamuri

💻 sobotama
sobotama

💻 rpedu
rpedu

💻 + tonywoo
tonywoo

💻 From 5a45ac58fc5aa24dfca1a1cf0e14b45690be158e Mon Sep 17 00:00:00 2001 From: MarGraz Date: Tue, 7 May 2024 00:30:24 +0200 Subject: [PATCH 05/14] Adding Content Item ApiController.cs endpoints documentation (#15512) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Zoltán Lehóczky Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Co-authored-by: Hisham Bin Ateya --- src/docs/reference/modules/Contents/README.md | 92 +++++++++++++++++++ 1 file changed, 92 insertions(+) diff --git a/src/docs/reference/modules/Contents/README.md b/src/docs/reference/modules/Contents/README.md index c3d3ccca13c..72d7b382e16 100644 --- a/src/docs/reference/modules/Contents/README.md +++ b/src/docs/reference/modules/Contents/README.md @@ -129,6 +129,98 @@ Well known properties include To log shapes call `@Orchard.ConsoleLog(Model.Content as object)` after calling `@await DisplayAsync(Model.Content)` This will allow the shape to execute, and populate the alternates for any child shapes. +## Contents Module RESTful Web API + +The `OrchardCore.Contents` module provides RESTful API endpoints via [`minimal API`](https://github.com/OrchardCMS/OrchardCore/tree/main/src/OrchardCore.Modules/OrchardCore.Contents/Endpoints/Api) featuring endpoints to manage _content items_. These endpoints allow for operations such as retrieving, creating, updating, and deleting single content item instances. Access to these endpoints requires authentication and appropriate user role permissions. + +### Useful modules and libraries + +- We would suggest you read the docs about the [GraphQL module](../Apis.GraphQL/README.md), to be used for querying content items. +- There's a [Swagger module](https://github.com/OrchardCoreContrib/OrchardCoreContrib.Modules/blob/main/src/OrchardCoreContrib.Apis.Swagger/README.md) made by the community, that allows you to create APIs documentation using Swagger. +- Lombiq provide a [client library](https://github.com/Lombiq/Orchard-Core-API-Client) for communicating with the Orchard Core web APIs. + +### Activating the "OpenId Authorization Server" and "OpenId Token Validation" Features, and setting User Roles + +To utilize the Orchard Core Contents API endpoints, user accounts must authenticate using the OAuth 2 standard by activating and configuring the "OpenId Authorization Server" and "OpenId Token Validation" features. Detailed configuration steps can be found in the [OpenId Authorization Server documentation](https://docs.orchardcore.net/en/main/docs/reference/modules/OpenId/#authorization-server) and the [OpenId Token Validation documentation](https://docs.orchardcore.net/en/main/docs/reference/modules/OpenId/#token-validation). + +It is usually better to **create a dedicated user for performing API calls**, maintain control over user rights, and easily activate/deactivate the API user. The `OrchardCore.OpenId` feature allows setting these user role permissions from "Roles → Edit (User)". Those are the available permissions: + +- View and edit the OpenID Connect client settings +- View and edit the OpenID Connect server settings +- View and edit the OpenID Connect validation settings +- View, add, edit, and remove the OpenID Connect applications +- View, add, edit, and remove the OpenID Connect scopes + +### Contents API Controller Endpoints + +#### GET /api/content/{contentItemId} + +##### Parameters + +| Name | Located in | Description | Required | Schema | +| ---- | ---------- | ----------- | -------- | ---- | +| contentItemId | path | The ID of the Content Item to be retrieved. | Yes | string | + +##### Responses + +| Code | Description | +| ---- | ----------- | +| 200 | Success | + +*** + +#### POST /api/content + +##### Parameters + +| Name | Located in | Description | Required | Schema | +| ---- | ---------- | ----------- | -------- | ---- | +| | payload | The content item model to be updated | Yes | Json | + +##### Body payload example + +```json +{ + "contentItem": "string", + "id": 0, + "contentItemId": "string", + "contentItemVersionId": "string", + "contentType": "string", + "published": true, + "latest": true, + "modifiedUtc": "2024-03-14T11:40:20.331Z", + "publishedUtc": "2024-03-14T11:40:20.331Z", + "createdUtc": "2024-03-14T11:40:20.331Z", + "owner": "string", + "author": "string", + "displayText": "string" +} +``` + +> This payload example model was obtained using the GraphiQL panel available in the Admin: _Configuration_ → _GraphiQL_. In this [video](https://www.youtube.com/watch?v=8SbW3TLNhF0) you can find an overview of how to use GraphiQL. + +##### Responses + +| Code | Description | +| ---- | ----------- | +| 200 | Success | + +*** + +#### DELETE /api/content/{contentItemId} + +##### Parameters + +| Name | Located in | Description | Required | Schema | +| ---- | ---------- | ----------- | -------- | ---- | +| contentItemId | path | The ID of the Content Item to be deleted. | Yes | string | + +##### Responses + +| Code | Description | +| ---- | ----------- | +| 200 | Success | + ## GraphQL The contents module provides a feature to provide GraphQL queries for content items. From 51a2374132a3a94d4d1de43483958586d84fd24c Mon Sep 17 00:00:00 2001 From: Mike Alhayek Date: Tue, 7 May 2024 13:56:21 -0700 Subject: [PATCH 06/14] Fix the search admin menu item (#16007) --- .../ContentTypesAdminNodeNavigationBuilder.cs | 2 +- .../OrchardCore.Queries/AdminMenu.cs | 6 +++-- .../OrchardCore.Search.AzureAI/AdminMenu.cs | 6 +++-- .../AdminMenu.cs | 7 ++++- .../OrchardCore.Search.Lucene/AdminMenu.cs | 7 ++++- .../OrchardCore.Search/AdminMenu.cs | 2 ++ .../Views/NavigationItem-admin.cshtml | 27 ++++++++++--------- .../Views/NavigationItemLink-admin.cshtml | 25 +++++++++++------ .../NavigationConstants.cs | 10 +++++++ 9 files changed, 65 insertions(+), 27 deletions(-) diff --git a/src/OrchardCore.Modules/OrchardCore.Contents/AdminNodes/ContentTypesAdminNodeNavigationBuilder.cs b/src/OrchardCore.Modules/OrchardCore.Contents/AdminNodes/ContentTypesAdminNodeNavigationBuilder.cs index 0394ecc5ff6..04055f04e13 100644 --- a/src/OrchardCore.Modules/OrchardCore.Contents/AdminNodes/ContentTypesAdminNodeNavigationBuilder.cs +++ b/src/OrchardCore.Modules/OrchardCore.Contents/AdminNodes/ContentTypesAdminNodeNavigationBuilder.cs @@ -129,7 +129,7 @@ private static List AddPrefixToClasses(string unprefixed) { return unprefixed?.Split(' ') .ToList() - .Select(c => "icon-class-" + c) + .Select(c => NavigationConstants.CssClassPrefix + c) .ToList() ?? []; } diff --git a/src/OrchardCore.Modules/OrchardCore.Queries/AdminMenu.cs b/src/OrchardCore.Modules/OrchardCore.Queries/AdminMenu.cs index 894630c941f..1d2ee295149 100644 --- a/src/OrchardCore.Modules/OrchardCore.Queries/AdminMenu.cs +++ b/src/OrchardCore.Modules/OrchardCore.Queries/AdminMenu.cs @@ -24,9 +24,11 @@ public Task BuildNavigationAsync(string name, NavigationBuilder builder) .Add(S["Search"], NavigationConstants.AdminMenuSearchPosition, search => search .AddClass("search") .Id("search") - .Add(S["Queries"], S["Queries"].PrefixPosition(), contentItems => contentItems - .Add(S["All queries"], "1", queries => queries + .Add(S["Queries"], S["Queries"].PrefixPosition(), queries => queries + .Add(S["All queries"], "1", allQueries => allQueries .Action("Index", "Admin", "OrchardCore.Queries") + .AddClass("searchallqueries") + .Id("searchallqueries") .Permission(Permissions.ManageQueries) .LocalNav() ) diff --git a/src/OrchardCore.Modules/OrchardCore.Search.AzureAI/AdminMenu.cs b/src/OrchardCore.Modules/OrchardCore.Search.AzureAI/AdminMenu.cs index 6dc478b9795..0a1c4dab1f7 100644 --- a/src/OrchardCore.Modules/OrchardCore.Search.AzureAI/AdminMenu.cs +++ b/src/OrchardCore.Modules/OrchardCore.Search.AzureAI/AdminMenu.cs @@ -24,11 +24,13 @@ public Task BuildNavigationAsync(string name, NavigationBuilder builder) builder .Add(S["Search"], NavigationConstants.AdminMenuSearchPosition, search => search - .AddClass("azure-ai-service") - .Id("azureaiservice") + .AddClass("search") + .Id("search") .Add(S["Indexing"], S["Indexing"].PrefixPosition(), indexing => indexing .Add(S["Azure AI Indices"], S["Azure AI Indices"].PrefixPosition(), indexes => indexes .Action("Index", "Admin", "OrchardCore.Search.AzureAI") + .AddClass("azureaiindices") + .Id("azureaiindices") .Permission(AzureAISearchIndexPermissionHelper.ManageAzureAISearchIndexes) .LocalNav() ) diff --git a/src/OrchardCore.Modules/OrchardCore.Search.Elasticsearch/AdminMenu.cs b/src/OrchardCore.Modules/OrchardCore.Search.Elasticsearch/AdminMenu.cs index c626b4f60f5..91f64af45b4 100644 --- a/src/OrchardCore.Modules/OrchardCore.Search.Elasticsearch/AdminMenu.cs +++ b/src/OrchardCore.Modules/OrchardCore.Search.Elasticsearch/AdminMenu.cs @@ -17,10 +17,13 @@ public Task BuildNavigationAsync(string name, NavigationBuilder builder) builder .Add(S["Search"], NavigationConstants.AdminMenuSearchPosition, search => search - .AddClass("elasticsearch").Id("Elasticsearch") + .AddClass("search") + .Id("search") .Add(S["Indexing"], S["Indexing"].PrefixPosition(), import => import .Add(S["Elasticsearch Indices"], S["Elasticsearch Indices"].PrefixPosition(), indexes => indexes .Action("Index", "Admin", "OrchardCore.Search.Elasticsearch") + .AddClass("elasticsearchindices") + .Id("elasticsearchindices") .Permission(Permissions.ManageElasticIndexes) .LocalNav() ) @@ -28,6 +31,8 @@ public Task BuildNavigationAsync(string name, NavigationBuilder builder) .Add(S["Queries"], S["Queries"].PrefixPosition(), import => import .Add(S["Run Elasticsearch Query"], S["Run Elasticsearch Query"].PrefixPosition(), queries => queries .Action("Query", "Admin", "OrchardCore.Search.Elasticsearch") + .AddClass("elasticsearchquery") + .Id("elasticsearchquery") .Permission(Permissions.ManageElasticIndexes) .LocalNav() ) diff --git a/src/OrchardCore.Modules/OrchardCore.Search.Lucene/AdminMenu.cs b/src/OrchardCore.Modules/OrchardCore.Search.Lucene/AdminMenu.cs index b76a984dcfc..5f74155324a 100644 --- a/src/OrchardCore.Modules/OrchardCore.Search.Lucene/AdminMenu.cs +++ b/src/OrchardCore.Modules/OrchardCore.Search.Lucene/AdminMenu.cs @@ -17,10 +17,13 @@ public Task BuildNavigationAsync(string name, NavigationBuilder builder) builder .Add(S["Search"], NavigationConstants.AdminMenuSearchPosition, search => search - .AddClass("search").Id("search") + .AddClass("search") + .Id("search") .Add(S["Indexing"], S["Indexing"].PrefixPosition(), import => import .Add(S["Lucene Indices"], S["Lucene Indices"].PrefixPosition(), indexes => indexes .Action("Index", "Admin", "OrchardCore.Search.Lucene") + .AddClass("luceneindices") + .Id("luceneindices") .Permission(Permissions.ManageLuceneIndexes) .LocalNav() ) @@ -28,6 +31,8 @@ public Task BuildNavigationAsync(string name, NavigationBuilder builder) .Add(S["Queries"], S["Queries"].PrefixPosition(), import => import .Add(S["Run Lucene Query"], S["Run Lucene Query"].PrefixPosition(), queries => queries .Action("Query", "Admin", "OrchardCore.Search.Lucene") + .AddClass("lucenequery") + .Id("lucenequery") .Permission(Permissions.ManageLuceneIndexes) .LocalNav() ) diff --git a/src/OrchardCore.Modules/OrchardCore.Search/AdminMenu.cs b/src/OrchardCore.Modules/OrchardCore.Search/AdminMenu.cs index a6228821f19..f2d2a6285f2 100644 --- a/src/OrchardCore.Modules/OrchardCore.Search/AdminMenu.cs +++ b/src/OrchardCore.Modules/OrchardCore.Search/AdminMenu.cs @@ -33,6 +33,8 @@ public Task BuildNavigationAsync(string name, NavigationBuilder builder) .Id("search") .Add(S["Settings"], S["Settings"].PrefixPosition(), settings => settings .Action("Index", "Admin", _routeValues) + .AddClass("searchsettings") + .Id("searchsettings") .Permission(Permissions.ManageSearchSettings) .LocalNav() ) diff --git a/src/OrchardCore.Themes/TheAdmin/Views/NavigationItem-admin.cshtml b/src/OrchardCore.Themes/TheAdmin/Views/NavigationItem-admin.cshtml index 26355fd95ed..4493c68e71e 100644 --- a/src/OrchardCore.Themes/TheAdmin/Views/NavigationItem-admin.cshtml +++ b/src/OrchardCore.Themes/TheAdmin/Views/NavigationItem-admin.cshtml @@ -1,26 +1,29 @@ +@using OrchardCore.Navigation @{ TagBuilder li = Tag(Model, "li"); - // Morphing the shape to keep Model untouched + // Morphing the shape to keep Model untouched. Model.Metadata.Alternates.Clear(); Model.Metadata.Type = "NavigationItemLink"; - Model.Metadata.Alternates.Add("NavigationItemLink_Id__" + Model.Id); - var prefix = "icon-class-"; + if (Model.Id != null) + { + Model.Metadata.Alternates.Add("NavigationItemLink_Id__" + Model.Id); + } - // Extract classes that are not icons from Model.Classes + // Extract classes that are not icons from 'Model.Classes'. var notIconClasses = ((IEnumerable)Model.Classes) - .ToList() - .Where(c => !c.StartsWith(prefix, StringComparison.OrdinalIgnoreCase)); + .Where(c => !c.StartsWith(NavigationConstants.CssClassPrefix, StringComparison.OrdinalIgnoreCase)) + .ToArray(); - if (notIconClasses.Count() > 0) + if (notIconClasses.Length > 0) { - li.Attributes["class"] = string.Join(" ", notIconClasses); + li.Attributes["class"] = string.Join(' ', notIconClasses); } else { - // This removes the class attribute on the li element else - // an empty class attribute gets rendered + // This removes the class attribute on the li element when + // an empty class attribute gets rendered. li.Attributes.Remove("class"); } @@ -29,7 +32,7 @@ li.AddCssClass("active"); } - // Render sub-items (MenuItem) + // Render sub-items (MenuItem). if (Model.HasItems) { li.AddCssClass("has-items"); @@ -38,7 +41,7 @@ if (li.Attributes.Where(a => a.Key == "id").Count() > 0) { - figure.Attributes["aria-labelledby"] = li.Attributes["id"] ; + figure.Attributes["aria-labelledby"] = li.Attributes["id"]; figCaption.Attributes["id"] = li.Attributes["id"]; li.Attributes["id"] = null; } diff --git a/src/OrchardCore.Themes/TheAdmin/Views/NavigationItemLink-admin.cshtml b/src/OrchardCore.Themes/TheAdmin/Views/NavigationItemLink-admin.cshtml index c93a83c959c..090ef8c99d9 100644 --- a/src/OrchardCore.Themes/TheAdmin/Views/NavigationItemLink-admin.cshtml +++ b/src/OrchardCore.Themes/TheAdmin/Views/NavigationItemLink-admin.cshtml @@ -1,9 +1,14 @@ @using OrchardCore.Localization +@using OrchardCore.Navigation @{ - // Morphing the shape to keep Model untouched + // Morphing the shape to keep Model untouched. Model.Metadata.Alternates.Clear(); Model.Metadata.Type = "NavigationItemText"; - Model.Metadata.Alternates.Add("NavigationItemText_Id__" + Model.Id); + + if (Model.Id != null) + { + Model.Metadata.Alternates.Add("NavigationItemText_Id__" + Model.Id); + } TagBuilder tag = Tag(Model, "a"); tag.Attributes["id"] = null; @@ -11,23 +16,27 @@ if (Model.Href == null || Model.Href.ToString() == "#") { tag.Attributes["href"] = "#m" + Model.GetHashCode().ToString(); - } - else + } + else { tag.Attributes["href"] = Model.Href; } - var prefix = "icon-class-"; - - // Extract classes that are not icons from Model.Classes. + // Extract classes that are not icons from 'Model.Classes'. var notIconClasses = ((IEnumerable)Model.Classes) - .Where(c => !c.StartsWith(prefix, StringComparison.OrdinalIgnoreCase)) + .Where(c => !c.StartsWith(NavigationConstants.CssClassPrefix, StringComparison.OrdinalIgnoreCase)) .ToArray(); if (notIconClasses.Length > 0) { tag.Attributes["class"] = string.Join(' ', notIconClasses); } + else + { + // This removes the class attribute on the li element when + // an empty class attribute gets rendered. + tag.Attributes.Remove("class"); + } tag.AddCssClass("item-label d-flex"); diff --git a/src/OrchardCore/OrchardCore.Navigation.Core/NavigationConstants.cs b/src/OrchardCore/OrchardCore.Navigation.Core/NavigationConstants.cs index 7e5c586dafd..70e19561e20 100644 --- a/src/OrchardCore/OrchardCore.Navigation.Core/NavigationConstants.cs +++ b/src/OrchardCore/OrchardCore.Navigation.Core/NavigationConstants.cs @@ -2,13 +2,23 @@ namespace OrchardCore.Navigation; public static class NavigationConstants { + public const string CssClassPrefix = "icon-class-"; + public const string AdminMenuContentPosition = "1"; + public const string AdminMenuDesignPosition = "2"; + public const string AdminMenuSearchPosition = "6"; + public const string AdminMenuSecurityPosition = "7"; + public const string AdminMenuAuditTrailPosition = "7.5"; + public const string AdminMenuWorkflowsPosition = "8"; + public const string AdminMenuConfigurationPosition = "100"; + public const string AdminId = "admin"; + public const string AdminMenuId = "adminMenu"; } From 8c9d21b60ba4c316123bcc9b49058108e40f463f Mon Sep 17 00:00:00 2001 From: Hisham Bin Ateya Date: Wed, 8 May 2024 00:50:13 +0300 Subject: [PATCH 07/14] Update Microsoft.Identity.Web 2.18.1 (#16003) --- src/OrchardCore.Build/Dependencies.props | 2 +- src/docs/resources/libraries/README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/OrchardCore.Build/Dependencies.props b/src/OrchardCore.Build/Dependencies.props index 61aa839902e..ed97ef3573c 100644 --- a/src/OrchardCore.Build/Dependencies.props +++ b/src/OrchardCore.Build/Dependencies.props @@ -41,7 +41,7 @@ - + diff --git a/src/docs/resources/libraries/README.md b/src/docs/resources/libraries/README.md index d203ddfc030..bcbbb0f0eb6 100644 --- a/src/docs/resources/libraries/README.md +++ b/src/docs/resources/libraries/README.md @@ -28,7 +28,7 @@ The below table lists the different .NET libraries used in Orchard Core: | [Markdig](https://github.com/lunet-io/markdig) | .NET Markdown engine. | 0.36.2 | [BSD-2-Clause](https://github.com/lunet-io/markdig/blob/master/license.txt) | | [MessagePack](https://github.com/neuecc/MessagePack-CSharp) | Extremely Fast MessagePack Serializer for C# | 2.2.60 | [MIT](https://github.com/neuecc/MessagePack-CSharp/blob/master/LICENSE) | | [Microsoft.Extensions.Http.Resilience](https://github.com/dotnet/extensions/tree/main/src/Libraries/Microsoft.Extensions.Http.Resilience) | Resilience mechanisms for HttpClient built on the Polly framework. | 8.4.0 | [MIT](https://github.com/dotnet/extensions/blob/main/LICENSE) | -| [Microsoft.Identity.Web](https://github.com/AzureAD/microsoft-identity-web) | Helps creating protected web apps and web APIs with Microsoft identity platform and Azure AD B2C. | 2.18.0 | [MIT](https://github.com/AzureAD/microsoft-identity-web/blob/master/LICENSE) | +| [Microsoft.Identity.Web](https://github.com/AzureAD/microsoft-identity-web) | Helps creating protected web apps and web APIs with Microsoft identity platform and Azure AD B2C. | 2.18.1 | [MIT](https://github.com/AzureAD/microsoft-identity-web/blob/master/LICENSE) | | [Microsoft.SourceLink.GitHub](https://github.com/dotnet/sourcelink) | Source Link enables a great source debugging experience. | 8.0.0 | [MIT](https://github.com/dotnet/sourcelink/blob/main/License.txt) | | [MimeKit](https://github.com/jstedfast/MailKit) | A cross-platform .NET library for IMAP, POP3, and SMTP. | 4.5.0 | [MIT](https://github.com/jstedfast/MailKit/blob/master/LICENSE) | | [MiniProfiler](https://github.com/MiniProfiler/dotnet) | A simple but effective mini-profiler for ASP.NET (and Core) websites | 4.3.8 | [MIT](https://github.com/MiniProfiler/dotnet/blob/main/LICENSE.txt) | From b3ba1e903c7b1118ee8bc88895e9445b6082c2f7 Mon Sep 17 00:00:00 2001 From: Hisham Bin Ateya Date: Wed, 8 May 2024 00:57:53 +0300 Subject: [PATCH 08/14] Update NLog.Web.AspNetCore 5.3.11 (#16011) --- src/OrchardCore.Build/Dependencies.props | 2 +- src/docs/resources/libraries/README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/OrchardCore.Build/Dependencies.props b/src/OrchardCore.Build/Dependencies.props index ed97ef3573c..c6b2af30359 100644 --- a/src/OrchardCore.Build/Dependencies.props +++ b/src/OrchardCore.Build/Dependencies.props @@ -50,7 +50,7 @@ - + diff --git a/src/docs/resources/libraries/README.md b/src/docs/resources/libraries/README.md index bcbbb0f0eb6..6ddc3e36168 100644 --- a/src/docs/resources/libraries/README.md +++ b/src/docs/resources/libraries/README.md @@ -38,7 +38,7 @@ The below table lists the different .NET libraries used in Orchard Core: | [Microsoft.Extensions.Azure](https://github.com/Azure/azure-sdk-for-net/blob/Microsoft.Extensions.Azure_1.7.3/sdk/extensions/Microsoft.Extensions.Azure/README.md) | Azure client library integration for ASP.NET Core | 1.7.3 | [MIT](https://github.com/AzureAD/microsoft-identity-web/blob/master/LICENSE) | | [Newtonsoft.Json](https://github.com/JamesNK/Newtonsoft.Json) | Json.NET is a popular high-performance JSON framework for .NET | 13.0.3 | [MIT](https://github.com/JamesNK/Newtonsoft.Json/blob/master/LICENSE.md) | | [NJsonSchema](https://github.com/RicoSuter/NJsonSchema) | JSON Schema reader, generator and validator for .NET | 11.0.0 | [MIT](https://github.com/RicoSuter/NJsonSchema/blob/master/LICENSE.md) | -| [NLog.Web.AspNetCore](https://github.com/NLog/NLog.Web/tree/master/src/NLog.Web.AspNetCore) | NLog integration for ASP.NET. | 5.3.10 | [BSD-3-Clause](https://github.com/NLog/NLog.Web/blob/master/LICENSE) | +| [NLog.Web.AspNetCore](https://github.com/NLog/NLog.Web/tree/master/src/NLog.Web.AspNetCore) | NLog integration for ASP.NET. | 5.3.11 | [BSD-3-Clause](https://github.com/NLog/NLog.Web/blob/master/LICENSE) | | [Noda Time](https://github.com/nodatime/nodatime) | A better date and time API for .NET. | 3.1.11 | [Apache-2.0](https://github.com/nodatime/nodatime/blob/master/LICENSE.txt) | | [OpenIddict](https://github.com/openiddict/openiddict-core) | Flexible and versatile OAuth 2.0/OpenID Connect stack for .NET. | 5.5.0 | [Apache-2.0](https://github.com/openiddict/openiddict-core/blob/dev/LICENSE.md) | | [PdfPig](https://github.com/UglyToad/PdfPig/) | Library to read and extract text and other content from PDF files. | 0.1.8 | [Apache-2.0](https://github.com/UglyToad/PdfPig/blob/master/LICENSE) | From 7f481118515604c36bdbabbadd36f9995dcbceb1 Mon Sep 17 00:00:00 2001 From: Hisham Bin Ateya Date: Wed, 8 May 2024 01:05:09 +0300 Subject: [PATCH 09/14] Update Azure.Identity 1.11.3 (#16009) --- src/OrchardCore.Build/Dependencies.props | 2 +- src/docs/resources/libraries/README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/OrchardCore.Build/Dependencies.props b/src/OrchardCore.Build/Dependencies.props index c6b2af30359..bee562ffc7d 100644 --- a/src/OrchardCore.Build/Dependencies.props +++ b/src/OrchardCore.Build/Dependencies.props @@ -15,7 +15,7 @@ - + diff --git a/src/docs/resources/libraries/README.md b/src/docs/resources/libraries/README.md index 6ddc3e36168..9b8024ac6e9 100644 --- a/src/docs/resources/libraries/README.md +++ b/src/docs/resources/libraries/README.md @@ -8,7 +8,7 @@ The below table lists the different .NET libraries used in Orchard Core: | [AWSSDK S3](https://github.com/aws/aws-sdk-net) | AWS SDK for .NET. | 3.7.104.11 |[Apache-2.0 license](https://github.com/aws/aws-sdk-net/blob/master/License.txt) | | [AWSSDK SecurityToken](https://github.com/aws/aws-sdk-net) | AWS SDK for .NET. | 3.7.101.60 |[Apache-2.0 license](https://github.com/aws/aws-sdk-net/blob/master/License.txt) | | [AWSSDK Extensions Setup](https://github.com/aws/aws-sdk-net) | AWS SDK for .NET. | 3.7.7 |[Apache-2.0 license](https://github.com/aws/aws-sdk-net/blob/master/License.txt) | -| [Azure Identity](https://github.com/Azure/azure-sdk-for-net/blob/master/sdk/identity/Azure.Identity/README.md) | Azure Active Directory token authentication support. | 1.11.2 |[MIT](https://github.com/Azure/azure-sdk-for-net/blob/master/LICENSE.txt) | +| [Azure Identity](https://github.com/Azure/azure-sdk-for-net/blob/master/sdk/identity/Azure.Identity/README.md) | Azure Active Directory token authentication support. | 1.11.3 |[MIT](https://github.com/Azure/azure-sdk-for-net/blob/master/LICENSE.txt) | | [Azure Communication Services](https://github.com/Azure/Communication) | Azure Communication Services are cloud-based services with REST APIs and client library SDKs to help you integrate communication into your applications | 1.0.1 |[MIT](https://github.com/Azure/azure-sdk-for-net/blob/master/LICENSE.txt) | | [Azure Configuration Secrets](https://github.com/Azure/azure-sdk-for-net/blob/Azure.Extensions.AspNetCore.Configuration.Secrets_1.3.1/sdk/extensions/Azure.Extensions.AspNetCore.Configuration.Secrets/README.md) | Azure Key Vault configuration provider implementation for Microsoft.Extensions.Configuration. | 1.3.1 |[MIT](https://github.com/Azure/azure-sdk-for-net/blob/master/LICENSE.txt) | | [Azure Storage Blobs](https://github.com/Azure/azure-sdk-for-net/blob/master/sdk/storage/Azure.Storage.Blobs/README.md) | Azure Storage Blobs client library for .NET. | 12.19.1 |[MIT](https://github.com/Azure/azure-sdk-for-net/blob/master/LICENSE.txt) | From 35c450b333b578fe02a740dd8ac607750b624157 Mon Sep 17 00:00:00 2001 From: Hisham Bin Ateya Date: Wed, 8 May 2024 02:12:56 +0300 Subject: [PATCH 10/14] Replace Irony.Core deprecated package (#16012) --- src/OrchardCore.Build/Dependencies.props | 2 +- .../OrchardCore.Queries/OrchardCore.Queries.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/OrchardCore.Build/Dependencies.props b/src/OrchardCore.Build/Dependencies.props index bee562ffc7d..9f85fa75d60 100644 --- a/src/OrchardCore.Build/Dependencies.props +++ b/src/OrchardCore.Build/Dependencies.props @@ -29,7 +29,7 @@ - + diff --git a/src/OrchardCore.Modules/OrchardCore.Queries/OrchardCore.Queries.csproj b/src/OrchardCore.Modules/OrchardCore.Queries/OrchardCore.Queries.csproj index 9a57b3388ca..56031665529 100644 --- a/src/OrchardCore.Modules/OrchardCore.Queries/OrchardCore.Queries.csproj +++ b/src/OrchardCore.Modules/OrchardCore.Queries/OrchardCore.Queries.csproj @@ -32,7 +32,7 @@ - + From 23ee4f18f6dfda40fa366f58ce2559e270d23b55 Mon Sep 17 00:00:00 2001 From: Antoine Griffard Date: Wed, 8 May 2024 17:18:44 +0200 Subject: [PATCH 11/14] mkdocs-git-authors-plugin 0.9.0 --- src/docs/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/docs/requirements.txt b/src/docs/requirements.txt index 959db9ed70b..934ebf90720 100644 --- a/src/docs/requirements.txt +++ b/src/docs/requirements.txt @@ -1,6 +1,6 @@ mkdocs>=1.6.0 mkdocs-material>=9.5.21 -mkdocs-git-authors-plugin>=0.8.0 +mkdocs-git-authors-plugin>=0.9.0 mkdocs-git-revision-date-localized-plugin>=1.2.5 pymdown-extensions>=10.8.1 mkdocs-exclude>=1.0.2 From c20c63e1210bf9024f5d42094df102553d85b6e0 Mon Sep 17 00:00:00 2001 From: Mike Alhayek Date: Thu, 9 May 2024 07:44:08 -0700 Subject: [PATCH 12/14] Add null check in AutorouteEntries (#16020) --- .../OrchardCore.Autoroute.Core/Services/AutorouteEntries.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/OrchardCore/OrchardCore.Autoroute.Core/Services/AutorouteEntries.cs b/src/OrchardCore/OrchardCore.Autoroute.Core/Services/AutorouteEntries.cs index 1f984e15e05..34224cec280 100644 --- a/src/OrchardCore/OrchardCore.Autoroute.Core/Services/AutorouteEntries.cs +++ b/src/OrchardCore/OrchardCore.Autoroute.Core/Services/AutorouteEntries.cs @@ -34,6 +34,8 @@ public AutorouteEntries(IVolatileDocumentManager autorou public async Task<(bool, AutorouteEntry)> TryGetEntryByPathAsync(string path) { + ArgumentException.ThrowIfNullOrEmpty(path); + await EnsureInitializedAsync(); if (_contentItemIds.TryGetValue(path.TrimEnd('/'), out var entry)) @@ -46,6 +48,8 @@ public AutorouteEntries(IVolatileDocumentManager autorou public async Task<(bool, AutorouteEntry)> TryGetEntryByContentItemIdAsync(string contentItemId) { + ArgumentException.ThrowIfNullOrEmpty(contentItemId); + await EnsureInitializedAsync(); if (_paths.TryGetValue(contentItemId, out var entry)) From 548eaa19747ffebe1d568778d971a62a665bdc19 Mon Sep 17 00:00:00 2001 From: Tony Han Date: Thu, 9 May 2024 22:45:49 +0800 Subject: [PATCH 13/14] Add type checking when importing types from recipes #15979 (#15980) --- .../RecipeSteps/ContentDefinitionStep.cs | 5 ++++ .../OrchardCore.Tests.csproj | 2 ++ .../Recipes/RecipeExecutorTests.cs | 22 +++++++++++++++ .../Recipes/RecipeFiles/recipe6.json | 27 +++++++++++++++++++ 4 files changed, 56 insertions(+) create mode 100644 test/OrchardCore.Tests/Recipes/RecipeFiles/recipe6.json diff --git a/src/OrchardCore.Modules/OrchardCore.ContentTypes/RecipeSteps/ContentDefinitionStep.cs b/src/OrchardCore.Modules/OrchardCore.ContentTypes/RecipeSteps/ContentDefinitionStep.cs index 1eb43b95749..d95309fa421 100644 --- a/src/OrchardCore.Modules/OrchardCore.ContentTypes/RecipeSteps/ContentDefinitionStep.cs +++ b/src/OrchardCore.Modules/OrchardCore.ContentTypes/RecipeSteps/ContentDefinitionStep.cs @@ -58,6 +58,11 @@ private Task UpdateContentTypeAsync(ContentTypeDefinition type, ContentTypeDefin foreach (var part in record.ContentTypePartDefinitionRecords) { + if (string.IsNullOrEmpty(part.PartName)) + { + throw new InvalidOperationException($"Unable to add content-part to the '{type.Name}' content-type. The part name cannot be null or empty."); + } + builder.WithPart(part.Name, part.PartName, partBuilder => partBuilder.MergeSettings(part.Settings)); } }); diff --git a/test/OrchardCore.Tests/OrchardCore.Tests.csproj b/test/OrchardCore.Tests/OrchardCore.Tests.csproj index 97879b76cfe..28995c4eb9f 100644 --- a/test/OrchardCore.Tests/OrchardCore.Tests.csproj +++ b/test/OrchardCore.Tests/OrchardCore.Tests.csproj @@ -29,6 +29,7 @@ + @@ -44,6 +45,7 @@ + diff --git a/test/OrchardCore.Tests/Recipes/RecipeExecutorTests.cs b/test/OrchardCore.Tests/Recipes/RecipeExecutorTests.cs index 3bcdd2d742d..979b6f350a3 100644 --- a/test/OrchardCore.Tests/Recipes/RecipeExecutorTests.cs +++ b/test/OrchardCore.Tests/Recipes/RecipeExecutorTests.cs @@ -8,6 +8,7 @@ using OrchardCore.Recipes.Models; using OrchardCore.Recipes.Services; using OrchardCore.Scripting; +using OrchardCore.Tests.Apis.Context; namespace OrchardCore.Recipes { @@ -50,6 +51,27 @@ public async Task ShouldTrimValidScriptExpression(string recipeName, string expe }); } + [Fact] + public async Task ContentDefinitionStep_WhenPartNameIsMissing_ThrowInvalidOperationException() + { + var context = new BlogContext(); + await context.InitializeAsync(); + await context.UsingTenantScopeAsync(async scope => + { + var recipeExecutor = scope.ServiceProvider.GetRequiredService(); + // Act + var executionId = Guid.NewGuid().ToString("n"); + var recipeDescriptor = new RecipeDescriptor { RecipeFileInfo = GetRecipeFileInfo("recipe6") }; + + var exception = await Assert.ThrowsAsync(async () => + { + await recipeExecutor.ExecuteAsync(executionId, recipeDescriptor, new Dictionary(), CancellationToken.None); + }); + + Assert.Equal("Unable to add content-part to the 'Message' content-type. The part name cannot be null or empty.", exception.Message); + }); + } + private static Task GetScopeAsync() => ShellScope.Context.CreateScopeAsync(); private static ShellContext CreateShellContext() => new() diff --git a/test/OrchardCore.Tests/Recipes/RecipeFiles/recipe6.json b/test/OrchardCore.Tests/Recipes/RecipeFiles/recipe6.json new file mode 100644 index 00000000000..c113645d8f0 --- /dev/null +++ b/test/OrchardCore.Tests/Recipes/RecipeFiles/recipe6.json @@ -0,0 +1,27 @@ +{ + "name": "Recipe6", + "displayName": "Recipe 6", + "description": "This recipe is designed to uncover potential bugs during the content-definition import process. It serves as a validation for the import functionality.", + "author": "Tony Han", + "website": "", + "version": "1.0.0", + "issetuprecipe": false, + "categories": [ "test" ], + "steps": [ + { + "name": "ContentDefinition", + "ContentTypes": [ + { + "Name": "Message", + "DisplayName": "Message", + "ContentTypePartDefinitionRecords": [ + { + // "PartName": "TitlePart", // Test PartName validation. + "Name": "TitlePart" + } + ] + } + ] + } + ] +} From 1ba8423fb3244f72664674fa7ad0bc17ec6dedd5 Mon Sep 17 00:00:00 2001 From: Mike Alhayek Date: Thu, 9 May 2024 08:27:22 -0700 Subject: [PATCH 14/14] Update the sort logic in the assets grouping (#15815) --- gulpfile.js | 35 +- package-lock.json | 126 - package.json | 6 +- .../wwwroot/Scripts/media.js | 6524 ++++++++--------- .../wwwroot/Scripts/media.min.js | 2 +- 5 files changed, 3288 insertions(+), 3405 deletions(-) diff --git a/gulpfile.js b/gulpfile.js index 58cc3b085c3..8275549bc79 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -4,8 +4,6 @@ var fs = require("graceful-fs"), merge = require("merge-stream"), gulp = require("gulp"), gulpif = require("gulp-if"), - print = require("gulp-print"), - debug = require("gulp-debug"), newer = require("gulp-newer"), plumber = require("gulp-plumber"), sourcemaps = require("gulp-sourcemaps"), @@ -53,7 +51,6 @@ gulp.task("rebuild-assets", function () { // Continuous watch (each asset group is built whenever one of its inputs changes). gulp.task("watch", function () { - var pathWin32 = require("path"); getAssetGroups().forEach(function (assetGroup) { var watchPaths = assetGroup.inputPaths.concat(assetGroup.watchPaths); var inputWatcher; @@ -66,7 +63,7 @@ gulp.task("watch", function () { else console.log("Asset file '" + watchedPath + "' was changed, rebuilding asset group."); var doRebuild = true; - var task = createAssetGroupTask(assetGroup, doRebuild); + createAssetGroupTask(assetGroup, doRebuild); }); } @@ -114,14 +111,29 @@ function getAssetGroups() { function resolveAssetGroupPaths(assetGroup, assetManifestPath) { assetGroup.manifestPath = assetManifestPath.replace(/\\/g, '/'); assetGroup.basePath = path.dirname(assetGroup.manifestPath); - var inputPaths = assetGroup.inputs.map(function (inputPath) { - return path.resolve(path.join(assetGroup.basePath, inputPath)).replace(/\\/g, '/'); - }); - // For wildcard input paths also sortthem to ensure file concatenation is consistent. - if (inputPaths.some(path => path.includes('*'))) { - inputPaths = glob.sync(inputPaths, {}).sort(); - } + var inputPaths = []; + + // The inputPaths can contain either a physical path to a file or a path with a wildcard. + // It's crucial to maintain the order of each file based on its position in the assets.json file. + // When a path contains a wildcard, we need to convert the wildcard to physical paths + // and sort them independently of the previous paths to ensure consistent concatenation. + assetGroup.inputs.forEach(inputPath => { + + var resolvedPath = path.resolve(path.join(assetGroup.basePath, inputPath)).replace(/\\/g, '/'); + + if (resolvedPath.includes('*')) { + var sortedPaths = glob.sync(resolvedPath, {}); + + sortedPaths.sort(); + + sortedPaths.forEach(sortedPath => { + inputPaths.push(sortedPath.replace(/\\/g, '/')); + }); + } else { + inputPaths.push(resolvedPath); + } + }); assetGroup.inputPaths = inputPaths; @@ -263,7 +275,6 @@ function buildJsPipeline(assetGroup, doConcat, doRebuild) { target: "es5", }; - console.log(assetGroup.inputPaths); return gulp.src(assetGroup.inputPaths) .pipe(gulpif(!doRebuild, gulpif(doConcat, diff --git a/package-lock.json b/package-lock.json index 2835b668f0a..b10491bc30e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,7 +20,6 @@ "gulp-cli": "^2.3.0", "gulp-concat": "2.6.1", "gulp-dart-sass": "1.1.0", - "gulp-debug": "4.0.0", "gulp-eol": "0.2.0", "gulp-header": "2.0.9", "gulp-if": "3.0.0", @@ -29,7 +28,6 @@ "gulp-newer": "1.4.0", "gulp-plumber": "1.2.1", "gulp-postcss": "^9.0.1", - "gulp-print": "5.0.2", "gulp-rename": "2.0.0", "gulp-sourcemaps": "^3.0.0", "gulp-terser": "2.1.0", @@ -4151,12 +4149,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/get-own-enumerable-property-symbols": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz", - "integrity": "sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==", - "dev": true - }, "node_modules/get-symbol-description": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", @@ -4627,26 +4619,6 @@ "node": ">=14" } }, - "node_modules/gulp-debug": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/gulp-debug/-/gulp-debug-4.0.0.tgz", - "integrity": "sha512-cn/GhMD2nVZCVxAl5vWao4/dcoZ8wUJ8w3oqTvQaGDmC1vT7swNOEbhQTWJp+/otKePT64aENcqAQXDcdj5H1g==", - "dev": true, - "dependencies": { - "chalk": "^2.3.0", - "fancy-log": "^1.3.2", - "plur": "^3.0.0", - "stringify-object": "^3.0.0", - "through2": "^2.0.0", - "tildify": "^1.1.2" - }, - "engines": { - "node": ">=6" - }, - "peerDependencies": { - "gulp": ">=4" - } - }, "node_modules/gulp-eol": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/gulp-eol/-/gulp-eol-0.2.0.tgz", @@ -5128,30 +5100,6 @@ "postcss": "^8.0.0" } }, - "node_modules/gulp-print": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/gulp-print/-/gulp-print-5.0.2.tgz", - "integrity": "sha512-iIpHMzC/b3gFvVXOfP9Jk94SWGIsDLVNUrxULRleQev+08ug07mh84b1AOlW6QDQdmInQiqDFqJN1UvhU2nXdg==", - "dev": true, - "dependencies": { - "ansi-colors": "^3.2.4", - "fancy-log": "^1.3.3", - "map-stream": "0.0.7", - "vinyl": "^2.2.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/gulp-print/node_modules/ansi-colors": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.4.tgz", - "integrity": "sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/gulp-rename": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/gulp-rename/-/gulp-rename-2.0.0.tgz", @@ -5783,15 +5731,6 @@ "node": ">=0.10.0" } }, - "node_modules/irregular-plurals": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/irregular-plurals/-/irregular-plurals-2.0.0.tgz", - "integrity": "sha512-Y75zBYLkh0lJ9qxeHlMjQ7bSbyiSqNW/UOPWDmzC7cXskL1hekSITh1Oc6JV0XCWWZ9DE8VYSB71xocLk3gmGw==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/is-absolute": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz", @@ -6074,15 +6013,6 @@ "node": ">=0.10.0" } }, - "node_modules/is-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", - "integrity": "sha512-l4RyHgRqGN4Y3+9JHVrNqO+tN0rV5My76uW5/nuO4K1b6vw5G8d/cmFjP9tRfEsdhZNt0IFdZuK/c2Vr4Nb+Qg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/is-plain-object": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", @@ -6114,15 +6044,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-regexp": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", - "integrity": "sha512-7zjFAPO4/gwyQAAgRRmqeEeyIICSdmCqa3tsVHMdBzaXXRiqopZL4Cyghg/XulGWrtABTpbnYYzzIRffLkP4oA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/is-relative": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz", @@ -7615,15 +7536,6 @@ "readable-stream": "^2.0.1" } }, - "node_modules/os-homedir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/os-locale": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", @@ -7994,18 +7906,6 @@ "node": ">=0.10.0" } }, - "node_modules/plur": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/plur/-/plur-3.1.1.tgz", - "integrity": "sha512-t1Ax8KUvV3FFII8ltczPn2tJdjqbd1sIzu6t4JL7nQ3EyeL/lTrj5PWKb06ic5/6XYDr65rQ4uzQEGN70/6X5w==", - "dev": true, - "dependencies": { - "irregular-plurals": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/posix-character-classes": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", @@ -9567,20 +9467,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/stringify-object": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz", - "integrity": "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==", - "dev": true, - "dependencies": { - "get-own-enumerable-property-symbols": "^3.0.0", - "is-obj": "^1.0.1", - "is-regexp": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/strip-ansi": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", @@ -9759,18 +9645,6 @@ "xtend": "~4.0.0" } }, - "node_modules/tildify": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/tildify/-/tildify-1.2.0.tgz", - "integrity": "sha512-Y9q1GaV/BO65Z9Yf4NOGMuwt3SGdptkZBnaaKfTQakrDyCLiuO1Kc5wxW4xLdsjzunRtqtOdhekiUFmZbklwYQ==", - "dev": true, - "dependencies": { - "os-homedir": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/time-stamp": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/time-stamp/-/time-stamp-1.1.0.tgz", diff --git a/package.json b/package.json index c650a0ea5cc..587795a457f 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,6 @@ "gulp-cli": "^2.3.0", "gulp-concat": "2.6.1", "gulp-dart-sass": "1.1.0", - "gulp-debug": "4.0.0", "gulp-eol": "0.2.0", "gulp-header": "2.0.9", "gulp-if": "3.0.0", @@ -34,7 +33,6 @@ "gulp-newer": "1.4.0", "gulp-plumber": "1.2.1", "gulp-postcss": "^9.0.1", - "gulp-print": "5.0.2", "gulp-rename": "2.0.0", "gulp-sourcemaps": "^3.0.0", "gulp-terser": "2.1.0", @@ -46,7 +44,7 @@ "postcss": "8.4.28", "postcss-rtl": "^2.0.0", "rtlcss": "4.1.0", - "typescript": "^5.2.2", - "source-map": "^0.7.4" + "source-map": "^0.7.4", + "typescript": "^5.2.2" } } diff --git a/src/OrchardCore.Modules/OrchardCore.Media/wwwroot/Scripts/media.js b/src/OrchardCore.Modules/OrchardCore.Media/wwwroot/Scripts/media.js index e18e4388362..379103923bf 100644 --- a/src/OrchardCore.Modules/OrchardCore.Media/wwwroot/Scripts/media.js +++ b/src/OrchardCore.Modules/OrchardCore.Media/wwwroot/Scripts/media.js @@ -4,3428 +4,3428 @@ */ function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); } -function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } -function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } -function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } -function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return _typeof(key) === "symbol" ? key : String(key); } -function _toPrimitive(input, hint) { if (_typeof(input) !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (_typeof(res) !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); } -var initialized; -var mediaApp; -var bus = new Vue(); -function initializeMediaApplication(displayMediaApplication, mediaApplicationUrl, pathBase) { - if (initialized) { - return; +/* + * jQuery File Upload Plugin + * https://github.com/blueimp/jQuery-File-Upload + * + * Copyright 2010, Sebastian Tschan + * https://blueimp.net + * + * Licensed under the MIT license: + * https://opensource.org/licenses/MIT + */ + +/* global define, require */ +/* eslint-disable new-cap */ + +(function (factory) { + 'use strict'; + + if (typeof define === 'function' && define.amd) { + // Register as an anonymous AMD module: + define(['jquery', 'jquery-ui/ui/widget'], factory); + } else if ((typeof exports === "undefined" ? "undefined" : _typeof(exports)) === 'object') { + // Node/CommonJS: + factory(require('jquery'), require('./vendor/jquery.ui.widget')); + } else { + // Browser globals: + factory(window.jQuery); } - initialized = true; - if (!mediaApplicationUrl) { - console.error('mediaApplicationUrl variable is not defined'); +})(function ($) { + 'use strict'; + + // Detect file input support, based on + // https://viljamis.com/2012/file-upload-support-on-mobile/ + $.support.fileInput = !(new RegExp( + // Handle devices which give false positives for the feature detection: + '(Android (1\\.[0156]|2\\.[01]))' + '|(Windows Phone (OS 7|8\\.0))|(XBLWP)|(ZuneWP)|(WPDesktop)' + '|(w(eb)?OSBrowser)|(webOS)' + '|(Kindle/(1\\.0|2\\.[05]|3\\.0))').test(window.navigator.userAgent) || + // Feature detection for all other devices: + $('').prop('disabled')); + + // The FileReader API is not actually used, but works as feature detection, + // as some Safari versions (5?) support XHR file uploads via the FormData API, + // but not non-multipart XHR file uploads. + // window.XMLHttpRequestUpload is not available on IE10, so we check for + // window.ProgressEvent instead to detect XHR2 file upload capability: + $.support.xhrFileUpload = !!(window.ProgressEvent && window.FileReader); + $.support.xhrFormDataFileUpload = !!window.FormData; + + // Detect support for Blob slicing (required for chunked uploads): + $.support.blobSlice = window.Blob && (Blob.prototype.slice || Blob.prototype.webkitSlice || Blob.prototype.mozSlice); + + /** + * Helper function to create drag handlers for dragover/dragenter/dragleave + * + * @param {string} type Event type + * @returns {Function} Drag handler + */ + function getDragHandler(type) { + var isDragOver = type === 'dragover'; + return function (e) { + e.dataTransfer = e.originalEvent && e.originalEvent.dataTransfer; + var dataTransfer = e.dataTransfer; + if (dataTransfer && $.inArray('Files', dataTransfer.types) !== -1 && this._trigger(type, $.Event(type, { + delegatedEvent: e + })) !== false) { + e.preventDefault(); + if (isDragOver) { + dataTransfer.dropEffect = 'copy'; + } + } + }; } - $.ajax({ - url: mediaApplicationUrl, - method: 'GET', - success: function success(content) { - $('.ta-content').append(content); - $(document).trigger('mediaapplication:ready'); - var _root = { - name: $('#t-mediaLibrary').text(), - path: '', - folder: '', - isDirectory: true, - canCreateFolder: $('#allowNewRootFolders').val() === 'true' - }; - mediaApp = new Vue({ - el: '#mediaApp', - data: { - selectedFolder: {}, - mediaItems: [], - selectedMedias: [], - errors: [], - dragDropThumbnail: new Image(), - smallThumbs: false, - gridView: false, - mediaFilter: '', - sortBy: '', - sortAsc: true, - itemsInPage: [] - }, - created: function created() { - var self = this; - self.dragDropThumbnail.src = (pathBase || '') + '/OrchardCore.Media/Images/drag-thumbnail.png'; - bus.$on('folderSelected', function (folder) { - self.selectedFolder = folder; - }); - bus.$on('folderDeleted', function () { - self.selectRoot(); - }); - bus.$on('folderAdded', function (folder) { - self.selectedFolder = folder; - folder.selected = true; - }); - bus.$on('mediaListMoved', function (errorInfo) { - self.loadFolder(self.selectedFolder); - if (errorInfo) { - self.errors.push(errorInfo); - } - }); - bus.$on('mediaRenamed', function (newName, newPath, oldPath, newUrl) { - var media = self.mediaItems.filter(function (item) { - return item.mediaPath === oldPath; - })[0]; - media.mediaPath = newPath; - media.name = newName; - media.url = newUrl; - }); - bus.$on('createFolderRequested', function (media) { - self.createFolder(); - }); - bus.$on('deleteFolderRequested', function (media) { - self.deleteFolder(); - }); - // common handlers for actions in both grid and table view. - bus.$on('sortChangeRequested', function (newSort) { - self.changeSort(newSort); + // The fileupload widget listens for change events on file input fields defined + // via fileInput setting and paste or drop events of the given dropZone. + // In addition to the default jQuery Widget methods, the fileupload widget + // exposes the "add" and "send" methods, to add or directly send files using + // the fileupload API. + // By default, files added via file input selection, paste, drag & drop or + // "add" method are uploaded immediately, but it is possible to override + // the "add" callback option to queue file uploads. + $.widget('blueimp.fileupload', { + options: { + // The drop target element(s), by the default the complete document. + // Set to null to disable drag & drop support: + dropZone: $(document), + // The paste target element(s), by the default undefined. + // Set to a DOM node or jQuery object to enable file pasting: + pasteZone: undefined, + // The file input field(s), that are listened to for change events. + // If undefined, it is set to the file input fields inside + // of the widget element on plugin initialization. + // Set to null to disable the change listener. + fileInput: undefined, + // By default, the file input field is replaced with a clone after + // each input field change event. This is required for iframe transport + // queues and allows change events to be fired for the same file + // selection, but can be disabled by setting the following option to false: + replaceFileInput: true, + // The parameter name for the file form data (the request argument name). + // If undefined or empty, the name property of the file input field is + // used, or "files[]" if the file input name property is also empty, + // can be a string or an array of strings: + paramName: undefined, + // By default, each file of a selection is uploaded using an individual + // request for XHR type uploads. Set to false to upload file + // selections in one request each: + singleFileUploads: true, + // To limit the number of files uploaded with one XHR request, + // set the following option to an integer greater than 0: + limitMultiFileUploads: undefined, + // The following option limits the number of files uploaded with one + // XHR request to keep the request size under or equal to the defined + // limit in bytes: + limitMultiFileUploadSize: undefined, + // Multipart file uploads add a number of bytes to each uploaded file, + // therefore the following option adds an overhead for each file used + // in the limitMultiFileUploadSize configuration: + limitMultiFileUploadSizeOverhead: 512, + // Set the following option to true to issue all file upload requests + // in a sequential order: + sequentialUploads: false, + // To limit the number of concurrent uploads, + // set the following option to an integer greater than 0: + limitConcurrentUploads: undefined, + // Set the following option to true to force iframe transport uploads: + forceIframeTransport: false, + // Set the following option to the location of a redirect url on the + // origin server, for cross-domain iframe transport uploads: + redirect: undefined, + // The parameter name for the redirect url, sent as part of the form + // data and set to 'redirect' if this option is empty: + redirectParamName: undefined, + // Set the following option to the location of a postMessage window, + // to enable postMessage transport uploads: + postMessage: undefined, + // By default, XHR file uploads are sent as multipart/form-data. + // The iframe transport is always using multipart/form-data. + // Set to false to enable non-multipart XHR uploads: + multipart: true, + // To upload large files in smaller chunks, set the following option + // to a preferred maximum chunk size. If set to 0, null or undefined, + // or the browser does not support the required Blob API, files will + // be uploaded as a whole. + maxChunkSize: undefined, + // When a non-multipart upload or a chunked multipart upload has been + // aborted, this option can be used to resume the upload by setting + // it to the size of the already uploaded bytes. This option is most + // useful when modifying the options object inside of the "add" or + // "send" callbacks, as the options are cloned for each file upload. + uploadedBytes: undefined, + // By default, failed (abort or error) file uploads are removed from the + // global progress calculation. Set the following option to false to + // prevent recalculating the global progress data: + recalculateProgress: true, + // Interval in milliseconds to calculate and trigger progress events: + progressInterval: 100, + // Interval in milliseconds to calculate progress bitrate: + bitrateInterval: 500, + // By default, uploads are started automatically when adding files: + autoUpload: true, + // By default, duplicate file names are expected to be handled on + // the server-side. If this is not possible (e.g. when uploading + // files directly to Amazon S3), the following option can be set to + // an empty object or an object mapping existing filenames, e.g.: + // { "image.jpg": true, "image (1).jpg": true } + // If it is set, all files will be uploaded with unique filenames, + // adding increasing number suffixes if necessary, e.g.: + // "image (2).jpg" + uniqueFilenames: undefined, + // Error and info messages: + messages: { + uploadedBytes: 'Uploaded bytes exceed file size' + }, + // Translation function, gets the message key to be translated + // and an object with context specific data as arguments: + i18n: function i18n(message, context) { + // eslint-disable-next-line no-param-reassign + message = this.messages[message] || message.toString(); + if (context) { + $.each(context, function (key, value) { + // eslint-disable-next-line no-param-reassign + message = message.replace('{' + key + '}', value); }); - bus.$on('mediaToggleRequested', function (media) { - self.toggleSelectionOfMedia(media); - }); - bus.$on('renameMediaRequested', function (media) { - self.renameMedia(media); - }); - bus.$on('deleteMediaRequested', function (media) { - self.deleteMediaItem(media); - }); - bus.$on('mediaDragStartRequested', function (media, e) { - self.handleDragStart(media, e); + } + return message; + }, + // Additional form data to be sent along with the file uploads can be set + // using this option, which accepts an array of objects with name and + // value properties, a function returning such an array, a FormData + // object (for XHR file uploads), or a simple object. + // The form of the first fileInput is given as parameter to the function: + formData: function formData(form) { + return form.serializeArray(); + }, + // The add callback is invoked as soon as files are added to the fileupload + // widget (via file input selection, drag & drop, paste or add API call). + // If the singleFileUploads option is enabled, this callback will be + // called once for each file in the selection for XHR file uploads, else + // once for each file selection. + // + // The upload starts when the submit method is invoked on the data parameter. + // The data object contains a files property holding the added files + // and allows you to override plugin options as well as define ajax settings. + // + // Listeners for this callback can also be bound the following way: + // .on('fileuploadadd', func); + // + // data.submit() returns a Promise object and allows to attach additional + // handlers using jQuery's Deferred callbacks: + // data.submit().done(func).fail(func).always(func); + add: function add(e, data) { + if (e.isDefaultPrevented()) { + return false; + } + if (data.autoUpload || data.autoUpload !== false && $(this).fileupload('option', 'autoUpload')) { + data.process().done(function () { + data.submit(); }); + } + }, + // Other callbacks: - // handler for pager events - bus.$on('pagerEvent', function (itemsInPage) { - self.itemsInPage = itemsInPage; - self.selectedMedias = []; + // Callback for the submit event of each file upload: + // submit: function (e, data) {}, // .on('fileuploadsubmit', func); + + // Callback for the start of each file upload request: + // send: function (e, data) {}, // .on('fileuploadsend', func); + + // Callback for successful uploads: + // done: function (e, data) {}, // .on('fileuploaddone', func); + + // Callback for failed (abort or error) uploads: + // fail: function (e, data) {}, // .on('fileuploadfail', func); + + // Callback for completed (success, abort or error) requests: + // always: function (e, data) {}, // .on('fileuploadalways', func); + + // Callback for upload progress events: + // progress: function (e, data) {}, // .on('fileuploadprogress', func); + + // Callback for global upload progress events: + // progressall: function (e, data) {}, // .on('fileuploadprogressall', func); + + // Callback for uploads start, equivalent to the global ajaxStart event: + // start: function (e) {}, // .on('fileuploadstart', func); + + // Callback for uploads stop, equivalent to the global ajaxStop event: + // stop: function (e) {}, // .on('fileuploadstop', func); + + // Callback for change events of the fileInput(s): + // change: function (e, data) {}, // .on('fileuploadchange', func); + + // Callback for paste events to the pasteZone(s): + // paste: function (e, data) {}, // .on('fileuploadpaste', func); + + // Callback for drop events of the dropZone(s): + // drop: function (e, data) {}, // .on('fileuploaddrop', func); + + // Callback for dragover events of the dropZone(s): + // dragover: function (e) {}, // .on('fileuploaddragover', func); + + // Callback before the start of each chunk upload request (before form data initialization): + // chunkbeforesend: function (e, data) {}, // .on('fileuploadchunkbeforesend', func); + + // Callback for the start of each chunk upload request: + // chunksend: function (e, data) {}, // .on('fileuploadchunksend', func); + + // Callback for successful chunk uploads: + // chunkdone: function (e, data) {}, // .on('fileuploadchunkdone', func); + + // Callback for failed (abort or error) chunk uploads: + // chunkfail: function (e, data) {}, // .on('fileuploadchunkfail', func); + + // Callback for completed (success, abort or error) chunk upload requests: + // chunkalways: function (e, data) {}, // .on('fileuploadchunkalways', func); + + // The plugin options are used as settings object for the ajax calls. + // The following are jQuery ajax settings required for the file uploads: + processData: false, + contentType: false, + cache: false, + timeout: 0 + }, + // jQuery versions before 1.8 require promise.pipe if the return value is + // used, as promise.then in older versions has a different behavior, see: + // https://blog.jquery.com/2012/08/09/jquery-1-8-released/ + // https://bugs.jquery.com/ticket/11010 + // https://github.com/blueimp/jQuery-File-Upload/pull/3435 + _promisePipe: function () { + var parts = $.fn.jquery.split('.'); + return Number(parts[0]) > 1 || Number(parts[1]) > 7 ? 'then' : 'pipe'; + }(), + // A list of options that require reinitializing event listeners and/or + // special initialization code: + _specialOptions: ['fileInput', 'dropZone', 'pasteZone', 'multipart', 'forceIframeTransport'], + _blobSlice: $.support.blobSlice && function () { + var slice = this.slice || this.webkitSlice || this.mozSlice; + return slice.apply(this, arguments); + }, + _BitrateTimer: function _BitrateTimer() { + this.timestamp = Date.now ? Date.now() : new Date().getTime(); + this.loaded = 0; + this.bitrate = 0; + this.getBitrate = function (now, loaded, interval) { + var timeDiff = now - this.timestamp; + if (!this.bitrate || !interval || timeDiff > interval) { + this.bitrate = (loaded - this.loaded) * (1000 / timeDiff) * 8; + this.loaded = loaded; + this.timestamp = now; + } + return this.bitrate; + }; + }, + _isXHRUpload: function _isXHRUpload(options) { + return !options.forceIframeTransport && (!options.multipart && $.support.xhrFileUpload || $.support.xhrFormDataFileUpload); + }, + _getFormData: function _getFormData(options) { + var formData; + if ($.type(options.formData) === 'function') { + return options.formData(options.form); + } + if ($.isArray(options.formData)) { + return options.formData; + } + if ($.type(options.formData) === 'object') { + formData = []; + $.each(options.formData, function (name, value) { + formData.push({ + name: name, + value: value }); - if (!localStorage.getItem('mediaApplicationPrefs')) { - self.selectedFolder = _root; - return; + }); + return formData; + } + return []; + }, + _getTotal: function _getTotal(files) { + var total = 0; + $.each(files, function (index, file) { + total += file.size || 1; + }); + return total; + }, + _initProgressObject: function _initProgressObject(obj) { + var progress = { + loaded: 0, + total: 0, + bitrate: 0 + }; + if (obj._progress) { + $.extend(obj._progress, progress); + } else { + obj._progress = progress; + } + }, + _initResponseObject: function _initResponseObject(obj) { + var prop; + if (obj._response) { + for (prop in obj._response) { + if (Object.prototype.hasOwnProperty.call(obj._response, prop)) { + delete obj._response[prop]; } - self.currentPrefs = JSON.parse(localStorage.getItem('mediaApplicationPrefs')); - }, - computed: { - isHome: function isHome() { - return this.selectedFolder == _root; - }, - parents: function parents() { - var p = []; - parentFolder = this.selectedFolder; - while (parentFolder && parentFolder.path != '') { - p.unshift(parentFolder); - parentFolder = parentFolder.parent; - } - return p; - }, - root: function root() { - return _root; - }, - filteredMediaItems: function filteredMediaItems() { - var self = this; - self.selectedMedias = []; - var filtered = self.mediaItems.filter(function (item) { - return item.name.toLowerCase().indexOf(self.mediaFilter.toLowerCase()) > -1; - }); - switch (self.sortBy) { - case 'size': - filtered.sort(function (a, b) { - return self.sortAsc ? a.size - b.size : b.size - a.size; - }); - break; - case 'mime': - filtered.sort(function (a, b) { - return self.sortAsc ? a.mime.toLowerCase().localeCompare(b.mime.toLowerCase()) : b.mime.toLowerCase().localeCompare(a.mime.toLowerCase()); - }); - break; - case 'lastModify': - filtered.sort(function (a, b) { - return self.sortAsc ? a.lastModify - b.lastModify : b.lastModify - a.lastModify; - }); - break; - default: - filtered.sort(function (a, b) { - return self.sortAsc ? a.name.toLowerCase().localeCompare(b.name.toLowerCase()) : b.name.toLowerCase().localeCompare(a.name.toLowerCase()); - }); - } - return filtered; - }, - hiddenCount: function hiddenCount() { - var result = 0; - result = this.mediaItems.length - this.filteredMediaItems.length; - return result; - }, - thumbSize: function thumbSize() { - return this.smallThumbs ? 100 : 240; - }, - currentPrefs: { - get: function get() { - return { - smallThumbs: this.smallThumbs, - selectedFolder: this.selectedFolder, - gridView: this.gridView - }; - }, - set: function set(newPrefs) { - if (!newPrefs) { - return; - } - this.smallThumbs = newPrefs.smallThumbs; - this.selectedFolder = newPrefs.selectedFolder; - this.gridView = newPrefs.gridView; - } - } - }, - watch: { - currentPrefs: function currentPrefs(newPrefs) { - localStorage.setItem('mediaApplicationPrefs', JSON.stringify(newPrefs)); - }, - selectedFolder: function selectedFolder(newFolder) { - this.mediaFilter = ''; - this.selectedFolder = newFolder; - this.loadFolder(newFolder); - } - }, - mounted: function mounted() { - this.$refs.rootFolder.toggle(); - }, - methods: { - uploadUrl: function uploadUrl() { - if (!this.selectedFolder) { - return null; - } - var urlValue = $('#uploadFiles').val(); - return urlValue + (urlValue.indexOf('?') == -1 ? '?' : '&') + "path=" + encodeURIComponent(this.selectedFolder.path); - }, - selectRoot: function selectRoot() { - this.selectedFolder = this.root; - }, - loadFolder: function loadFolder(folder) { - this.errors = []; - this.selectedMedias = []; - var self = this; - var mediaUrl = $('#getMediaItemsUrl').val(); - console.log(folder.path); - $.ajax({ - url: mediaUrl + (mediaUrl.indexOf('?') == -1 ? '?' : '&') + "path=" + encodeURIComponent(folder.path), - method: 'GET', - success: function success(data) { - data.forEach(function (item) { - item.open = false; - }); - self.mediaItems = data; - self.selectedMedias = []; - self.sortBy = ''; - self.sortAsc = true; - }, - error: function error(_error) { - console.log('error loading folder:' + folder.path); - self.selectRoot(); - } + } + } else { + obj._response = {}; + } + }, + _onProgress: function _onProgress(e, data) { + if (e.lengthComputable) { + var now = Date.now ? Date.now() : new Date().getTime(), + loaded; + if (data._time && data.progressInterval && now - data._time < data.progressInterval && e.loaded !== e.total) { + return; + } + data._time = now; + loaded = Math.floor(e.loaded / e.total * (data.chunkSize || data._progress.total)) + (data.uploadedBytes || 0); + // Add the difference from the previously loaded state + // to the global loaded counter: + this._progress.loaded += loaded - data._progress.loaded; + this._progress.bitrate = this._bitrateTimer.getBitrate(now, this._progress.loaded, data.bitrateInterval); + data._progress.loaded = data.loaded = loaded; + data._progress.bitrate = data.bitrate = data._bitrateTimer.getBitrate(now, loaded, data.bitrateInterval); + // Trigger a custom progress event with a total data property set + // to the file size(s) of the current upload and a loaded data + // property calculated accordingly: + this._trigger('progress', $.Event('progress', { + delegatedEvent: e + }), data); + // Trigger a global progress event for all current file uploads, + // including ajax calls queued for sequential file uploads: + this._trigger('progressall', $.Event('progressall', { + delegatedEvent: e + }), this._progress); + } + }, + _initProgressListener: function _initProgressListener(options) { + var that = this, + xhr = options.xhr ? options.xhr() : $.ajaxSettings.xhr(); + // Access to the native XHR object is required to add event listeners + // for the upload progress event: + if (xhr.upload) { + $(xhr.upload).on('progress', function (e) { + var oe = e.originalEvent; + // Make sure the progress event properties get copied over: + e.lengthComputable = oe.lengthComputable; + e.loaded = oe.loaded; + e.total = oe.total; + that._onProgress(e, options); + }); + options.xhr = function () { + return xhr; + }; + } + }, + _deinitProgressListener: function _deinitProgressListener(options) { + var xhr = options.xhr ? options.xhr() : $.ajaxSettings.xhr(); + if (xhr.upload) { + $(xhr.upload).off('progress'); + } + }, + _isInstanceOf: function _isInstanceOf(type, obj) { + // Cross-frame instanceof check + return Object.prototype.toString.call(obj) === '[object ' + type + ']'; + }, + _getUniqueFilename: function _getUniqueFilename(name, map) { + // eslint-disable-next-line no-param-reassign + name = String(name); + if (map[name]) { + // eslint-disable-next-line no-param-reassign + name = name.replace(/(?: \(([\d]+)\))?(\.[^.]+)?$/, function (_, p1, p2) { + var index = p1 ? Number(p1) + 1 : 1; + var ext = p2 || ''; + return ' (' + index + ')' + ext; + }); + return this._getUniqueFilename(name, map); + } + map[name] = true; + return name; + }, + _initXHRData: function _initXHRData(options) { + var that = this, + formData, + file = options.files[0], + // Ignore non-multipart setting if not supported: + multipart = options.multipart || !$.support.xhrFileUpload, + paramName = $.type(options.paramName) === 'array' ? options.paramName[0] : options.paramName; + options.headers = $.extend({}, options.headers); + if (options.contentRange) { + options.headers['Content-Range'] = options.contentRange; + } + if (!multipart || options.blob || !this._isInstanceOf('File', file)) { + options.headers['Content-Disposition'] = 'attachment; filename="' + encodeURI(file.uploadName || file.name) + '"'; + } + if (!multipart) { + options.contentType = file.type || 'application/octet-stream'; + options.data = options.blob || file; + } else if ($.support.xhrFormDataFileUpload) { + if (options.postMessage) { + // window.postMessage does not allow sending FormData + // objects, so we just add the File/Blob objects to + // the formData array and let the postMessage window + // create the FormData object out of this array: + formData = this._getFormData(options); + if (options.blob) { + formData.push({ + name: paramName, + value: options.blob }); - }, - selectAll: function selectAll() { - this.selectedMedias = []; - for (var i = 0; i < this.filteredMediaItems.length; i++) { - this.selectedMedias.push(this.filteredMediaItems[i]); - } - }, - unSelectAll: function unSelectAll() { - this.selectedMedias = []; - }, - invertSelection: function invertSelection() { - var temp = []; - for (var i = 0; i < this.filteredMediaItems.length; i++) { - if (this.isMediaSelected(this.filteredMediaItems[i]) == false) { - temp.push(this.filteredMediaItems[i]); - } - } - this.selectedMedias = temp; - }, - toggleSelectionOfMedia: function toggleSelectionOfMedia(media) { - if (this.isMediaSelected(media) == true) { - this.selectedMedias.splice(this.selectedMedias.indexOf(media), 1); - } else { - this.selectedMedias.push(media); - } - }, - isMediaSelected: function isMediaSelected(media) { - var result = this.selectedMedias.some(function (element, index, array) { - return element.url.toLowerCase() === media.url.toLowerCase(); + } else { + $.each(options.files, function (index, file) { + formData.push({ + name: $.type(options.paramName) === 'array' && options.paramName[index] || paramName, + value: file + }); }); - return result; - }, - deleteFolder: function deleteFolder() { - var folder = this.selectedFolder; - var self = this; - // The root folder can't be deleted - if (folder == this.root.model) { - return; - } - confirmDialog(_objectSpread(_objectSpread({}, $("#deleteFolder").data()), {}, { - callback: function callback(resp) { - if (resp) { - $.ajax({ - url: $('#deleteFolderUrl').val() + "?path=" + encodeURIComponent(folder.path), - method: 'POST', - data: { - __RequestVerificationToken: $("input[name='__RequestVerificationToken']").val() - }, - success: function success(data) { - bus.$emit('deleteFolder', folder); - }, - error: function error(_error2) { - console.error(_error2.responseText); - } - }); + } + } else { + if (that._isInstanceOf('FormData', options.formData)) { + formData = options.formData; + } else { + formData = new FormData(); + $.each(this._getFormData(options), function (index, field) { + formData.append(field.name, field.value); + }); + } + if (options.blob) { + formData.append(paramName, options.blob, file.uploadName || file.name); + } else { + $.each(options.files, function (index, file) { + // This check allows the tests to run with + // dummy objects: + if (that._isInstanceOf('File', file) || that._isInstanceOf('Blob', file)) { + var fileName = file.uploadName || file.name; + if (options.uniqueFilenames) { + fileName = that._getUniqueFilename(fileName, options.uniqueFilenames); } + formData.append($.type(options.paramName) === 'array' && options.paramName[index] || paramName, file, fileName); } - })); - }, - createFolder: function createFolder() { - $('#createFolderModal-errors').empty(); - var modal = bootstrap.Modal.getOrCreateInstance($('#createFolderModal')); - modal.show(); - $('#createFolderModal .modal-body input').val('').focus(); - }, - renameMedia: function renameMedia(media) { - $('#renameMediaModal-errors').empty(); - var modal = bootstrap.Modal.getOrCreateInstance($('#renameMediaModal')); - modal.show(); - $('#old-item-name').val(media.name); - $('#renameMediaModal .modal-body input').val(media.name).focus(); - }, - selectAndDeleteMedia: function selectAndDeleteMedia(media) { - this.deleteMedia(); - }, - deleteMediaList: function deleteMediaList() { - var mediaList = this.selectedMedias; - var self = this; - if (mediaList.length < 1) { - return; - } - confirmDialog(_objectSpread(_objectSpread({}, $("#deleteMedia").data()), {}, { - callback: function callback(resp) { - if (resp) { - var paths = []; - for (var i = 0; i < mediaList.length; i++) { - paths.push(mediaList[i].mediaPath); - } - $.ajax({ - url: $('#deleteMediaListUrl').val(), - method: 'POST', - data: { - __RequestVerificationToken: $("input[name='__RequestVerificationToken']").val(), - paths: paths - }, - success: function success(data) { - for (var i = 0; i < self.selectedMedias.length; i++) { - var index = self.mediaItems && self.mediaItems.indexOf(self.selectedMedias[i]); - if (index > -1) { - self.mediaItems.splice(index, 1); - bus.$emit('mediaDeleted', self.selectedMedias[i]); - } - } - self.selectedMedias = []; - }, - error: function error(_error3) { - console.error(_error3.responseText); - } - }); - } - } - })); - }, - deleteMediaItem: function deleteMediaItem(media) { - var self = this; - if (!media) { - return; - } - confirmDialog(_objectSpread(_objectSpread({}, $("#deleteMedia").data()), {}, { - callback: function callback(resp) { - if (resp) { - $.ajax({ - url: $('#deleteMediaUrl').val() + "?path=" + encodeURIComponent(media.mediaPath), - method: 'POST', - data: { - __RequestVerificationToken: $("input[name='__RequestVerificationToken']").val() - }, - success: function success(data) { - var index = self.mediaItems && self.mediaItems.indexOf(media); - if (index > -1) { - self.mediaItems.splice(index, 1); - bus.$emit('mediaDeleted', media); - } - //self.selectedMedia = null; - }, - - error: function error(_error4) { - console.error(_error4.responseText); - } - }); - } - } - })); - }, - handleDragStart: function handleDragStart(media, e) { - // first part of move media to folder: - // prepare the data that will be handled by the folder component on drop event - var mediaNames = []; - this.selectedMedias.forEach(function (item) { - mediaNames.push(item.name); }); - - // in case the user drags an unselected item, we select it first - if (this.isMediaSelected(media) == false) { - mediaNames.push(media.name); - this.selectedMedias.push(media); - } - e.dataTransfer.setData('mediaNames', JSON.stringify(mediaNames)); - e.dataTransfer.setData('sourceFolder', this.selectedFolder.path); - e.dataTransfer.setDragImage(this.dragDropThumbnail, 10, 10); - e.dataTransfer.effectAllowed = 'move'; - }, - handleScrollWhileDrag: function handleScrollWhileDrag(e) { - if (e.clientY < 150) { - window.scrollBy(0, -10); - } - if (e.clientY > window.innerHeight - 100) { - window.scrollBy(0, 10); - } - }, - changeSort: function changeSort(newSort) { - if (this.sortBy == newSort) { - this.sortAsc = !this.sortAsc; - } else { - this.sortAsc = true; - this.sortBy = newSort; - } } } - }); - $('#create-folder-name').keypress(function (e) { - var key = e.which; - if (key == 13) { - // the enter key code - $('#modalFooterOk').click(); - return false; + options.data = formData; + } + // Blob reference is not needed anymore, free memory: + options.blob = null; + }, + _initIframeSettings: function _initIframeSettings(options) { + var targetHost = $('').prop('href', options.url).prop('host'); + // Setting the dataType to iframe enables the iframe transport: + options.dataType = 'iframe ' + (options.dataType || ''); + // The iframe transport accepts a serialized array as form data: + options.formData = this._getFormData(options); + // Add redirect url to form data on cross-domain uploads: + if (options.redirect && targetHost && targetHost !== location.host) { + options.formData.push({ + name: options.redirectParamName || 'redirect', + value: options.redirect + }); + } + }, + _initDataSettings: function _initDataSettings(options) { + if (this._isXHRUpload(options)) { + if (!this._chunkedUpload(options, true)) { + if (!options.data) { + this._initXHRData(options); + } + this._initProgressListener(options); } - }); - $('#modalFooterOk').on('click', function (e) { - var name = $('#create-folder-name').val(); - if (name === "") { - return; + if (options.postMessage) { + // Setting the dataType to postmessage enables the + // postMessage transport: + options.dataType = 'postmessage ' + (options.dataType || ''); } - $.ajax({ - url: $('#createFolderUrl').val() + "?path=" + encodeURIComponent(mediaApp.selectedFolder.path) + "&name=" + encodeURIComponent(name), - method: 'POST', - data: { - __RequestVerificationToken: $("input[name='__RequestVerificationToken']").val() - }, - success: function success(data) { - bus.$emit('addFolder', mediaApp.selectedFolder, data); - var modal = bootstrap.Modal.getOrCreateInstance($('#createFolderModal')); - modal.hide(); - }, - error: function error(_error5) { - $('#createFolderModal-errors').empty(); - var errorMessage = JSON.parse(_error5.responseText).value; - $('').text(errorMessage).appendTo($('#createFolderModal-errors')); + } else { + this._initIframeSettings(options); + } + }, + _getParamName: function _getParamName(options) { + var fileInput = $(options.fileInput), + paramName = options.paramName; + if (!paramName) { + paramName = []; + fileInput.each(function () { + var input = $(this), + name = input.prop('name') || 'files[]', + i = (input.prop('files') || [1]).length; + while (i) { + paramName.push(name); + i -= 1; } }); - }); - $('#renameMediaModalFooterOk').on('click', function (e) { - var newName = $('#new-item-name').val(); - var oldName = $('#old-item-name').val(); - if (newName === "") { - return; - } - var currentFolder = mediaApp.selectedFolder.path + "/"; - if (currentFolder === "/") { - currentFolder = ""; + if (!paramName.length) { + paramName = [fileInput.prop('name') || 'files[]']; } - var newPath = currentFolder + newName; - var oldPath = currentFolder + oldName; - if (newPath.toLowerCase() === oldPath.toLowerCase()) { - var modal = bootstrap.Modal.getOrCreateInstance($('#renameMediaModal')); - modal.hide(); - return; + } else if (!$.isArray(paramName)) { + paramName = [paramName]; + } + return paramName; + }, + _initFormSettings: function _initFormSettings(options) { + // Retrieve missing options from the input field and the + // associated form, if available: + if (!options.form || !options.form.length) { + options.form = $(options.fileInput.prop('form')); + // If the given file input doesn't have an associated form, + // use the default widget file input's form: + if (!options.form.length) { + options.form = $(this.options.fileInput.prop('form')); } - $.ajax({ - url: $('#renameMediaUrl').val() + "?oldPath=" + encodeURIComponent(oldPath) + "&newPath=" + encodeURIComponent(newPath), - method: 'POST', - data: { - __RequestVerificationToken: $("input[name='__RequestVerificationToken']").val() - }, - success: function success(data) { - var modal = bootstrap.Modal.getOrCreateInstance($('#renameMediaModal')); - modal.hide(); - bus.$emit('mediaRenamed', newName, newPath, oldPath, data.newUrl); - }, - error: function error(_error6) { - $('#renameMediaModal-errors').empty(); - var errorMessage = JSON.parse(_error6.responseText).value; - $('').text(errorMessage).appendTo($('#renameMediaModal-errors')); - } - }); - }); - if (displayMediaApplication) { - document.getElementById('mediaApp').style.display = ""; } - $(document).trigger('mediaApp:ready'); + options.paramName = this._getParamName(options); + if (!options.url) { + options.url = options.form.prop('action') || location.href; + } + // The HTTP request method must be "POST" or "PUT": + options.type = (options.type || $.type(options.form.prop('method')) === 'string' && options.form.prop('method') || '').toUpperCase(); + if (options.type !== 'POST' && options.type !== 'PUT' && options.type !== 'PATCH') { + options.type = 'POST'; + } + if (!options.formAcceptCharset) { + options.formAcceptCharset = options.form.attr('accept-charset'); + } }, - error: function error(_error7) { - console.error(_error7.responseText); - } - }); -} -$(document).on('mediaApp:ready', function () { - var chunkedFileUploadId = randomUUID(); - $('#fileupload').fileupload({ - dropZone: $('#mediaApp'), - limitConcurrentUploads: 20, - dataType: 'json', - url: $('#uploadFiles').val(), - maxChunkSize: Number($('#maxUploadChunkSize').val() || 0), - formData: function formData() { - var antiForgeryToken = $("input[name=__RequestVerificationToken]").val(); - return [{ - name: 'path', - value: mediaApp.selectedFolder.path - }, { - name: '__RequestVerificationToken', - value: antiForgeryToken - }, { - name: '__chunkedFileUploadId', - value: chunkedFileUploadId - }]; - }, - done: function done(e, data) { - $.each(data.result.files, function (index, file) { - if (!file.error) { - mediaApp.mediaItems.push(file); - } - }); - } - }).on('fileuploadchunkbeforesend', function (e, options) { - var file = options.files[0]; - // Here we replace the blob with a File object to ensure the file name and others are preserved for the backend. - options.blob = new File([options.blob], file.name, { - type: file.type, - lastModified: file.lastModified - }); - }); -}); -$(document).bind('dragover', function (e) { - var dt = e.originalEvent.dataTransfer; - if (dt.types && (dt.types.indexOf ? dt.types.indexOf('Files') != -1 : dt.types.contains('Files'))) { - var dropZone = $('#customdropzone'), - timeout = window.dropZoneTimeout; - if (timeout) { - clearTimeout(timeout); - } else { - dropZone.addClass('in'); - } - var hoveredDropZone = $(e.target).closest(dropZone); - window.dropZoneTimeout = setTimeout(function () { - window.dropZoneTimeout = null; - dropZone.removeClass('in'); - }, 100); - } -}); -function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); } -function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } -function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } -function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } -function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return _typeof(key) === "symbol" ? key : String(key); } -function _toPrimitive(input, hint) { if (_typeof(input) !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (_typeof(res) !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); } -// component -Vue.component('folder', { - template: "\n
  • \n \n
      \n \n \n
    \n
  • \n "), - props: { - model: Object, - selectedInMediaApp: Object, - level: Number - }, - data: function data() { - return { - open: false, - children: null, - // not initialized state (for lazy-loading) - parent: null, - isHovered: false, - padding: 0 - }; - }, - computed: { - empty: function empty() { - return !this.children || this.children.length == 0; - }, - isSelected: function isSelected() { - return this.selectedInMediaApp.name == this.model.name && this.selectedInMediaApp.path == this.model.path; - }, - isRoot: function isRoot() { - return this.model.path === ''; - }, - canCreateFolder: function canCreateFolder() { - return this.model.canCreateFolder !== undefined ? this.model.canCreateFolder : true; + _getAJAXSettings: function _getAJAXSettings(data) { + var options = $.extend({}, this.options, data); + this._initFormSettings(options); + this._initDataSettings(options); + return options; }, - canDeleteFolder: function canDeleteFolder() { - return this.model.canDeleteFolder !== undefined ? this.model.canDeleteFolder : true; - } - }, - mounted: function mounted() { - if (this.isRoot == false && this.isAncestorOfSelectedFolder()) { - this.toggle(); - } - this.padding = this.level < 3 ? 16 : 16 + this.level * 8; - }, - created: function created() { - var self = this; - bus.$on('deleteFolder', function (folder) { - if (self.children) { - var index = self.children && self.children.indexOf(folder); - if (index > -1) { - self.children.splice(index, 1); - bus.$emit('folderDeleted'); - } - } - }); - bus.$on('addFolder', function (target, folder) { - if (self.model == target) { - if (self.children !== null) { - self.children.push(folder); - } - folder.parent = self.model; - bus.$emit('folderAdded', folder); + // jQuery 1.6 doesn't provide .state(), + // while jQuery 1.8+ removed .isRejected() and .isResolved(): + _getDeferredState: function _getDeferredState(deferred) { + if (deferred.state) { + return deferred.state(); } - }); - }, - methods: { - isAncestorOfSelectedFolder: function isAncestorOfSelectedFolder() { - parentFolder = mediaApp.selectedFolder; - while (parentFolder) { - if (parentFolder.path == this.model.path) { - return true; - } - parentFolder = parentFolder.parent; + if (deferred.isResolved()) { + return 'resolved'; } - return false; - }, - toggle: function toggle() { - this.open = !this.open; - if (this.open && !this.children) { - this.loadChildren(); + if (deferred.isRejected()) { + return 'rejected'; } + return 'pending'; }, - select: function select() { - bus.$emit('folderSelected', this.model); - this.loadChildren(); - }, - createFolder: function createFolder() { - bus.$emit('createFolderRequested'); - }, - deleteFolder: function deleteFolder() { - bus.$emit('deleteFolderRequested'); + // Maps jqXHR callbacks to the equivalent + // methods of the given Promise object: + _enhancePromise: function _enhancePromise(promise) { + promise.success = promise.done; + promise.error = promise.fail; + promise.complete = promise.always; + return promise; }, - loadChildren: function loadChildren() { - var self = this; - if (this.open == false) { - this.open = true; + // Creates and returns a Promise object enhanced with + // the jqXHR methods abort, success, error and complete: + _getXHRPromise: function _getXHRPromise(resolveOrReject, context, args) { + var dfd = $.Deferred(), + promise = dfd.promise(); + // eslint-disable-next-line no-param-reassign + context = context || this.options.context || promise; + if (resolveOrReject === true) { + dfd.resolveWith(context, args); + } else if (resolveOrReject === false) { + dfd.rejectWith(context, args); } - $.ajax({ - url: $('#getFoldersUrl').val() + "?path=" + encodeURIComponent(self.model.path), - method: 'GET', - success: function success(data) { - self.children = data; - self.children.forEach(function (c) { - c.parent = self.model; - }); - }, - error: function error(_error) { - emtpy = false; - console.error(_error.responseText); - } - }); + promise.abort = dfd.promise; + return this._enhancePromise(promise); }, - handleDragOver: function handleDragOver(e) { - this.isHovered = true; + // Adds convenience methods to the data callback argument: + _addConvenienceMethods: function _addConvenienceMethods(e, data) { + var that = this, + getPromise = function getPromise(args) { + return $.Deferred().resolveWith(that, args).promise(); + }; + data.process = function (resolveFunc, rejectFunc) { + if (resolveFunc || rejectFunc) { + data._processQueue = this._processQueue = (this._processQueue || getPromise([this]))[that._promisePipe](function () { + if (data.errorThrown) { + return $.Deferred().rejectWith(that, [data]).promise(); + } + return getPromise(arguments); + })[that._promisePipe](resolveFunc, rejectFunc); + } + return this._processQueue || getPromise([this]); + }; + data.submit = function () { + if (this.state() !== 'pending') { + data.jqXHR = this.jqXHR = that._trigger('submit', $.Event('submit', { + delegatedEvent: e + }), this) !== false && that._onSend(e, this); + } + return this.jqXHR || that._getXHRPromise(); + }; + data.abort = function () { + if (this.jqXHR) { + return this.jqXHR.abort(); + } + this.errorThrown = 'abort'; + that._trigger('fail', null, this); + return that._getXHRPromise(false); + }; + data.state = function () { + if (this.jqXHR) { + return that._getDeferredState(this.jqXHR); + } + if (this._processQueue) { + return that._getDeferredState(this._processQueue); + } + }; + data.processing = function () { + return !this.jqXHR && this._processQueue && that._getDeferredState(this._processQueue) === 'pending'; + }; + data.progress = function () { + return this._progress; + }; + data.response = function () { + return this._response; + }; }, - handleDragLeave: function handleDragLeave(e) { - this.isHovered = false; + // Parses the Range header from the server response + // and returns the uploaded bytes: + _getUploadedBytes: function _getUploadedBytes(jqXHR) { + var range = jqXHR.getResponseHeader('Range'), + parts = range && range.split('-'), + upperBytesPos = parts && parts.length > 1 && parseInt(parts[1], 10); + return upperBytesPos && upperBytesPos + 1; }, - moveMediaToFolder: function moveMediaToFolder(folder, e) { - var self = this; - self.isHovered = false; - var mediaNames = JSON.parse(e.dataTransfer.getData('mediaNames')); - if (mediaNames.length < 1) { - return; - } - var sourceFolder = e.dataTransfer.getData('sourceFolder'); - var targetFolder = folder.path; - if (sourceFolder === '') { - sourceFolder = 'root'; + // Uploads a file in multiple, sequential requests + // by splitting the file up in multiple blob chunks. + // If the second parameter is true, only tests if the file + // should be uploaded in chunks, but does not invoke any + // upload requests: + _chunkedUpload: function _chunkedUpload(options, testOnly) { + options.uploadedBytes = options.uploadedBytes || 0; + var that = this, + file = options.files[0], + fs = file.size, + ub = options.uploadedBytes, + mcs = options.maxChunkSize || fs, + slice = this._blobSlice, + dfd = $.Deferred(), + promise = dfd.promise(), + jqXHR, + _upload; + if (!(this._isXHRUpload(options) && slice && (ub || ($.type(mcs) === 'function' ? mcs(options) : mcs) < fs)) || options.data) { + return false; } - if (targetFolder === '') { - targetFolder = 'root'; + if (testOnly) { + return true; } - if (sourceFolder === targetFolder) { - alert($('#sameFolderMessage').val()); - return; + if (ub >= fs) { + file.error = options.i18n('uploadedBytes'); + return this._getXHRPromise(false, options.context, [null, 'error', file.error]); } - confirmDialog(_objectSpread(_objectSpread({}, $("#moveMedia").data()), {}, { - callback: function callback(resp) { - if (resp) { - $.ajax({ - url: $('#moveMediaListUrl').val(), - method: 'POST', - data: { - __RequestVerificationToken: $("input[name='__RequestVerificationToken']").val(), - mediaNames: mediaNames, - sourceFolder: sourceFolder, - targetFolder: targetFolder - }, - success: function success() { - bus.$emit('mediaListMoved'); // MediaApp will listen to this, and then it will reload page so the moved medias won't be there anymore - }, - - error: function error(_error2) { - console.error(_error2.responseText); - bus.$emit('mediaListMoved', _error2.responseText); - } - }); + // The chunk upload method: + _upload = function upload() { + // Clone the options object for each chunk upload: + var o = $.extend({}, options), + currentLoaded = o._progress.loaded; + o.blob = slice.call(file, ub, ub + ($.type(mcs) === 'function' ? mcs(o) : mcs), file.type); + // Store the current chunk size, as the blob itself + // will be dereferenced after data processing: + o.chunkSize = o.blob.size; + // Expose the chunk bytes position range: + o.contentRange = 'bytes ' + ub + '-' + (ub + o.chunkSize - 1) + '/' + fs; + // Trigger chunkbeforesend to allow form data to be updated for this chunk + that._trigger('chunkbeforesend', null, o); + // Process the upload data (the blob and potential form data): + that._initXHRData(o); + // Add progress listeners for this chunk upload: + that._initProgressListener(o); + jqXHR = (that._trigger('chunksend', null, o) !== false && $.ajax(o) || that._getXHRPromise(false, o.context)).done(function (result, textStatus, jqXHR) { + ub = that._getUploadedBytes(jqXHR) || ub + o.chunkSize; + // Create a progress event if no final progress event + // with loaded equaling total has been triggered + // for this chunk: + if (currentLoaded + o.chunkSize - o._progress.loaded) { + that._onProgress($.Event('progress', { + lengthComputable: true, + loaded: ub - o.uploadedBytes, + total: ub - o.uploadedBytes + }), o); } - } - })); - } - } -}); -// https://github.com/spatie/font-awesome-filetypes - -var faIcons = { - image: 'fa-regular fa-image', - pdf: 'fa-regular fa-file-pdf', - word: 'fa-regular fa-file-word', - powerpoint: 'fa-regular fa-file-powerpoint', - excel: 'fa-regular fa-file-excel', - csv: 'fa-regular fa-file', - audio: 'fa-regular fa-file-audio', - video: 'fa-regular fa-file-video', - archive: 'fa-regular fa-file-zipper', - code: 'fa-regular fa-file-code', - text: 'fa-regular fa-file-lines', - file: 'fa-regular fa-file' -}; -var faThumbnails = { - gif: faIcons.image, - jpeg: faIcons.image, - jpg: faIcons.image, - png: faIcons.image, - pdf: faIcons.pdf, - doc: faIcons.word, - docx: faIcons.word, - ppt: faIcons.powerpoint, - pptx: faIcons.powerpoint, - xls: faIcons.excel, - xlsx: faIcons.excel, - csv: faIcons.csv, - aac: faIcons.audio, - mp3: faIcons.audio, - ogg: faIcons.audio, - avi: faIcons.video, - flv: faIcons.video, - mkv: faIcons.video, - mp4: faIcons.video, - webm: faIcons.video, - gz: faIcons.archive, - zip: faIcons.archive, - css: faIcons.code, - html: faIcons.code, - js: faIcons.code, - txt: faIcons.text -}; -function getClassNameForExtension(extension) { - return faThumbnails[extension.toLowerCase()] || faIcons.file; -} -function getExtensionForFilename(filename) { - return filename.slice((filename.lastIndexOf('.') - 1 >>> 0) + 2); -} -function getClassNameForFilename(filename) { - return getClassNameForExtension(getExtensionForFilename(filename)); -} -// component -Vue.component('media-items-grid', { - template: "\n
      \n
    1. \n
      \n \n \n
      \n
      \n \n \n \n {{ media.name }}\n
      \n
    2. \n
    \n ", - data: function data() { - return { - T: {} - }; - }, - props: { - filteredMediaItems: Array, - selectedMedias: Array, - thumbSize: Number - }, - created: function created() { - var self = this; - // retrieving localized strings from view - self.T.editButton = $('#t-edit-button').val(); - self.T.deleteButton = $('#t-delete-button').val(); - }, - methods: { - isMediaSelected: function isMediaSelected(media) { - var result = this.selectedMedias.some(function (element, index, array) { - return element.url.toLowerCase() === media.url.toLowerCase(); - }); - return result; - }, - buildMediaUrl: function buildMediaUrl(url, thumbSize) { - return url + (url.indexOf('?') == -1 ? '?' : '&') + 'width=' + thumbSize + '&height=' + thumbSize; + options.uploadedBytes = o.uploadedBytes = ub; + o.result = result; + o.textStatus = textStatus; + o.jqXHR = jqXHR; + that._trigger('chunkdone', null, o); + that._trigger('chunkalways', null, o); + if (ub < fs) { + // File upload not yet complete, + // continue with the next chunk: + _upload(); + } else { + dfd.resolveWith(o.context, [result, textStatus, jqXHR]); + } + }).fail(function (jqXHR, textStatus, errorThrown) { + o.jqXHR = jqXHR; + o.textStatus = textStatus; + o.errorThrown = errorThrown; + that._trigger('chunkfail', null, o); + that._trigger('chunkalways', null, o); + dfd.rejectWith(o.context, [jqXHR, textStatus, errorThrown]); + }).always(function () { + that._deinitProgressListener(o); + }); + }; + this._enhancePromise(promise); + promise.abort = function () { + return jqXHR.abort(); + }; + _upload(); + return promise; }, - toggleSelectionOfMedia: function toggleSelectionOfMedia(media) { - bus.$emit('mediaToggleRequested', media); + _beforeSend: function _beforeSend(e, data) { + if (this._active === 0) { + // the start callback is triggered when an upload starts + // and no other uploads are currently running, + // equivalent to the global ajaxStart event: + this._trigger('start'); + // Set timer for global bitrate progress calculation: + this._bitrateTimer = new this._BitrateTimer(); + // Reset the global progress values: + this._progress.loaded = this._progress.total = 0; + this._progress.bitrate = 0; + } + // Make sure the container objects for the .response() and + // .progress() methods on the data object are available + // and reset to their initial state: + this._initResponseObject(data); + this._initProgressObject(data); + data._progress.loaded = data.loaded = data.uploadedBytes || 0; + data._progress.total = data.total = this._getTotal(data.files) || 1; + data._progress.bitrate = data.bitrate = 0; + this._active += 1; + // Initialize the global progress values: + this._progress.loaded += data.loaded; + this._progress.total += data.total; }, - renameMedia: function renameMedia(media) { - bus.$emit('renameMediaRequested', media); + _onDone: function _onDone(result, textStatus, jqXHR, options) { + var total = options._progress.total, + response = options._response; + if (options._progress.loaded < total) { + // Create a progress event if no final progress event + // with loaded equaling total has been triggered: + this._onProgress($.Event('progress', { + lengthComputable: true, + loaded: total, + total: total + }), options); + } + response.result = options.result = result; + response.textStatus = options.textStatus = textStatus; + response.jqXHR = options.jqXHR = jqXHR; + this._trigger('done', null, options); }, - deleteMedia: function deleteMedia(media) { - bus.$emit('deleteMediaRequested', media); + _onFail: function _onFail(jqXHR, textStatus, errorThrown, options) { + var response = options._response; + if (options.recalculateProgress) { + // Remove the failed (error or abort) file upload from + // the global progress calculation: + this._progress.loaded -= options._progress.loaded; + this._progress.total -= options._progress.total; + } + response.jqXHR = options.jqXHR = jqXHR; + response.textStatus = options.textStatus = textStatus; + response.errorThrown = options.errorThrown = errorThrown; + this._trigger('fail', null, options); }, - dragStart: function dragStart(media, e) { - bus.$emit('mediaDragStartRequested', media, e); + _onAlways: function _onAlways(jqXHRorResult, textStatus, jqXHRorError, options) { + // jqXHRorResult, textStatus and jqXHRorError are added to the + // options object via done and fail callbacks + this._trigger('always', null, options); }, - getfontAwesomeClassNameForFileName: function getfontAwesomeClassNameForFilename(filename, thumbsize) { - return getClassNameForFilename(filename) + ' ' + thumbsize; - } - } -}); -// component -Vue.component('media-items-table', { - template: "\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
    {{ T.imageHeader }}\n {{ T.nameHeader }}\n \n \n {{ T.lastModifyHeader }} \n \n \n \n {{ T.sizeHeader }}\n \n \n \n \n {{ T.typeHeader }}\n \n \n
    \n
    \n \n \n
    \n
    \n \n \n
    {{ printDateTime(media.lastModify) }}
    \n
    \n
    {{ isNaN(media.size)? 0 : Math.round(media.size / 1024) }} KB
    \n
    \n
    {{ media.mime }}
    \n
    \n ", - data: function data() { - return { - T: {} - }; - }, - props: { - sortBy: String, - sortAsc: Boolean, - filteredMediaItems: Array, - selectedMedias: Array, - thumbSize: Number - }, - created: function created() { - var self = this; - self.T.imageHeader = $('#t-image-header').val(); - self.T.nameHeader = $('#t-name-header').val(); - self.T.lastModifyHeader = $('#t-lastModify-header').val(); - self.T.sizeHeader = $('#t-size-header').val(); - self.T.typeHeader = $('#t-type-header').val(); - self.T.editButton = $('#t-edit-button').val(); - self.T.deleteButton = $('#t-delete-button').val(); - self.T.viewButton = $('#t-view-button').val(); - }, - methods: { - isMediaSelected: function isMediaSelected(media) { - var result = this.selectedMedias.some(function (element, index, array) { - return element.url.toLowerCase() === media.url.toLowerCase(); + _onSend: function _onSend(e, data) { + if (!data.submit) { + this._addConvenienceMethods(e, data); + } + var that = this, + jqXHR, + aborted, + slot, + pipe, + options = that._getAJAXSettings(data), + send = function send() { + that._sending += 1; + // Set timer for bitrate progress calculation: + options._bitrateTimer = new that._BitrateTimer(); + jqXHR = jqXHR || ((aborted || that._trigger('send', $.Event('send', { + delegatedEvent: e + }), options) === false) && that._getXHRPromise(false, options.context, aborted) || that._chunkedUpload(options) || $.ajax(options)).done(function (result, textStatus, jqXHR) { + that._onDone(result, textStatus, jqXHR, options); + }).fail(function (jqXHR, textStatus, errorThrown) { + that._onFail(jqXHR, textStatus, errorThrown, options); + }).always(function (jqXHRorResult, textStatus, jqXHRorError) { + that._deinitProgressListener(options); + that._onAlways(jqXHRorResult, textStatus, jqXHRorError, options); + that._sending -= 1; + that._active -= 1; + if (options.limitConcurrentUploads && options.limitConcurrentUploads > that._sending) { + // Start the next queued upload, + // that has not been aborted: + var nextSlot = that._slots.shift(); + while (nextSlot) { + if (that._getDeferredState(nextSlot) === 'pending') { + nextSlot.resolve(); + break; + } + nextSlot = that._slots.shift(); + } + } + if (that._active === 0) { + // The stop callback is triggered when all uploads have + // been completed, equivalent to the global ajaxStop event: + that._trigger('stop'); + } + }); + return jqXHR; + }; + this._beforeSend(e, options); + if (this.options.sequentialUploads || this.options.limitConcurrentUploads && this.options.limitConcurrentUploads <= this._sending) { + if (this.options.limitConcurrentUploads > 1) { + slot = $.Deferred(); + this._slots.push(slot); + pipe = slot[that._promisePipe](send); + } else { + this._sequence = this._sequence[that._promisePipe](send, send); + pipe = this._sequence; + } + // Return the piped Promise object, enhanced with an abort method, + // which is delegated to the jqXHR object of the current upload, + // and jqXHR callbacks mapped to the equivalent Promise methods: + pipe.abort = function () { + aborted = [undefined, 'abort', 'abort']; + if (!jqXHR) { + if (slot) { + slot.rejectWith(options.context, aborted); + } + return send(); + } + return jqXHR.abort(); + }; + return this._enhancePromise(pipe); + } + return send(); + }, + _onAdd: function _onAdd(e, data) { + var that = this, + result = true, + options = $.extend({}, this.options, data), + files = data.files, + filesLength = files.length, + limit = options.limitMultiFileUploads, + limitSize = options.limitMultiFileUploadSize, + overhead = options.limitMultiFileUploadSizeOverhead, + batchSize = 0, + paramName = this._getParamName(options), + paramNameSet, + paramNameSlice, + fileSet, + i, + j = 0; + if (!filesLength) { + return false; + } + if (limitSize && files[0].size === undefined) { + limitSize = undefined; + } + if (!(options.singleFileUploads || limit || limitSize) || !this._isXHRUpload(options)) { + fileSet = [files]; + paramNameSet = [paramName]; + } else if (!(options.singleFileUploads || limitSize) && limit) { + fileSet = []; + paramNameSet = []; + for (i = 0; i < filesLength; i += limit) { + fileSet.push(files.slice(i, i + limit)); + paramNameSlice = paramName.slice(i, i + limit); + if (!paramNameSlice.length) { + paramNameSlice = paramName; + } + paramNameSet.push(paramNameSlice); + } + } else if (!options.singleFileUploads && limitSize) { + fileSet = []; + paramNameSet = []; + for (i = 0; i < filesLength; i = i + 1) { + batchSize += files[i].size + overhead; + if (i + 1 === filesLength || batchSize + files[i + 1].size + overhead > limitSize || limit && i + 1 - j >= limit) { + fileSet.push(files.slice(j, i + 1)); + paramNameSlice = paramName.slice(j, i + 1); + if (!paramNameSlice.length) { + paramNameSlice = paramName; + } + paramNameSet.push(paramNameSlice); + j = i + 1; + batchSize = 0; + } + } + } else { + paramNameSet = paramName; + } + data.originalFiles = files; + $.each(fileSet || files, function (index, element) { + var newData = $.extend({}, data); + newData.files = fileSet ? element : [element]; + newData.paramName = paramNameSet[index]; + that._initResponseObject(newData); + that._initProgressObject(newData); + that._addConvenienceMethods(e, newData); + result = that._trigger('add', $.Event('add', { + delegatedEvent: e + }), newData); + return result; }); return result; }, - buildMediaUrl: function buildMediaUrl(url, thumbSize) { - return url + (url.indexOf('?') == -1 ? '?' : '&') + 'width=' + thumbSize + '&height=' + thumbSize; - }, - changeSort: function changeSort(newSort) { - bus.$emit('sortChangeRequested', newSort); - }, - toggleSelectionOfMedia: function toggleSelectionOfMedia(media) { - bus.$emit('mediaToggleRequested', media); - }, - renameMedia: function renameMedia(media) { - bus.$emit('renameMediaRequested', media); - }, - deleteMedia: function deleteMedia(media) { - bus.$emit('deleteMediaRequested', media); - }, - dragStart: function dragStart(media, e) { - bus.$emit('mediaDragStartRequested', media, e); - }, - printDateTime: function printDateTime(datemillis) { - var d = new Date(datemillis); - return d.toLocaleString(); + _replaceFileInput: function _replaceFileInput(data) { + var input = data.fileInput, + inputClone = input.clone(true), + restoreFocus = input.is(document.activeElement); + // Add a reference for the new cloned file input to the data argument: + data.fileInputClone = inputClone; + $('
    ').append(inputClone)[0].reset(); + // Detaching allows to insert the fileInput on another form + // without losing the file input value: + input.after(inputClone).detach(); + // If the fileInput had focus before it was detached, + // restore focus to the inputClone. + if (restoreFocus) { + inputClone.trigger('focus'); + } + // Avoid memory leaks with the detached file input: + $.cleanData(input.off('remove')); + // Replace the original file input element in the fileInput + // elements set with the clone, which has been copied including + // event handlers: + this.options.fileInput = this.options.fileInput.map(function (i, el) { + if (el === input[0]) { + return inputClone[0]; + } + return el; + }); + // If the widget has been initialized on the file input itself, + // override this.element with the file input clone: + if (input[0] === this.element[0]) { + this.element = inputClone; + } }, - getfontAwesomeClassNameForFileName: function getfontAwesomeClassNameForFilename(filename, thumbsize) { - return getClassNameForFilename(filename) + ' ' + thumbsize; - } - } -}); -// This component receives a list of all the items, unpaged. -// As the user interacts with the pager, it raises events with the items in the current page. -// It's the parent's responsibility to listen for these events and display the received items -// component -Vue.component('pager', { - template: "\n
    \n \n \n
    \n ", - props: { - sourceItems: Array - }, - data: function data() { - return { - pageSize: 10, - pageSizeOptions: [10, 30, 50, 100], - current: 0, - T: {} - }; - }, - created: function created() { - var self = this; - - // retrieving localized strings from view - self.T.pagerFirstButton = $('#t-pager-first-button').val(); - self.T.pagerPreviousButton = $('#t-pager-previous-button').val(); - self.T.pagerNextButton = $('#t-pager-next-button').val(); - self.T.pagerLastButton = $('#t-pager-last-button').val(); - self.T.pagerPageSizeLabel = $('#t-pager-page-size-label').val(); - self.T.pagerPageLabel = $('#t-pager-page-label').val(); - self.T.pagerTotalLabel = $('#t-pager-total-label').val(); - }, - methods: { - next: function next() { - this.current = this.current + 1; - }, - previous: function previous() { - this.current = this.current - 1; + _handleFileTreeEntry: function _handleFileTreeEntry(entry, path) { + var that = this, + dfd = $.Deferred(), + entries = [], + dirReader, + errorHandler = function errorHandler(e) { + if (e && !e.entry) { + e.entry = entry; + } + // Since $.when returns immediately if one + // Deferred is rejected, we use resolve instead. + // This allows valid files and invalid items + // to be returned together in one set: + dfd.resolve([e]); + }, + successHandler = function successHandler(entries) { + that._handleFileTreeEntries(entries, path + entry.name + '/').done(function (files) { + dfd.resolve(files); + }).fail(errorHandler); + }, + readEntries = function readEntries() { + dirReader.readEntries(function (results) { + if (!results.length) { + successHandler(entries); + } else { + entries = entries.concat(results); + readEntries(); + } + }, errorHandler); + }; + // eslint-disable-next-line no-param-reassign + path = path || ''; + if (entry.isFile) { + if (entry._file) { + // Workaround for Chrome bug #149735 + entry._file.relativePath = path; + dfd.resolve(entry._file); + } else { + entry.file(function (file) { + file.relativePath = path; + dfd.resolve(file); + }, errorHandler); + } + } else if (entry.isDirectory) { + dirReader = entry.createReader(); + readEntries(); + } else { + // Return an empty list for file system items + // other than files or directories: + dfd.resolve([]); + } + return dfd.promise(); }, - goFirst: function goFirst() { - this.current = 0; + _handleFileTreeEntries: function _handleFileTreeEntries(entries, path) { + var that = this; + return $.when.apply($, $.map(entries, function (entry) { + return that._handleFileTreeEntry(entry, path); + }))[this._promisePipe](function () { + return Array.prototype.concat.apply([], arguments); + }); }, - goLast: function goLast() { - this.current = this.totalPages - 1; + _getDroppedFiles: function _getDroppedFiles(dataTransfer) { + // eslint-disable-next-line no-param-reassign + dataTransfer = dataTransfer || {}; + var items = dataTransfer.items; + if (items && items.length && (items[0].webkitGetAsEntry || items[0].getAsEntry)) { + return this._handleFileTreeEntries($.map(items, function (item) { + var entry; + if (item.webkitGetAsEntry) { + entry = item.webkitGetAsEntry(); + if (entry) { + // Workaround for Chrome bug #149735: + entry._file = item.getAsFile(); + } + return entry; + } + return item.getAsEntry(); + })); + } + return $.Deferred().resolve($.makeArray(dataTransfer.files)).promise(); }, - goTo: function goTo(targetPage) { - this.current = targetPage; - } - }, - computed: { - total: function total() { - return this.sourceItems ? this.sourceItems.length : 0; + _getSingleFileInputFiles: function _getSingleFileInputFiles(fileInput) { + // eslint-disable-next-line no-param-reassign + fileInput = $(fileInput); + var entries = fileInput.prop('entries'), + files, + value; + if (entries && entries.length) { + return this._handleFileTreeEntries(entries); + } + files = $.makeArray(fileInput.prop('files')); + if (!files.length) { + value = fileInput.prop('value'); + if (!value) { + return $.Deferred().resolve([]).promise(); + } + // If the files property is not available, the browser does not + // support the File API and we add a pseudo File object with + // the input value as name with path information removed: + files = [{ + name: value.replace(/^.*\\/, '') + }]; + } else if (files[0].name === undefined && files[0].fileName) { + // File normalization for Safari 4 and Firefox 3: + $.each(files, function (index, file) { + file.name = file.fileName; + file.size = file.fileSize; + }); + } + return $.Deferred().resolve(files).promise(); }, - totalPages: function totalPages() { - var pages = Math.ceil(this.total / this.pageSize); - return pages > 0 ? pages : 1; + _getFileInputFiles: function _getFileInputFiles(fileInput) { + if (!(fileInput instanceof $) || fileInput.length === 1) { + return this._getSingleFileInputFiles(fileInput); + } + return $.when.apply($, $.map(fileInput, this._getSingleFileInputFiles))[this._promisePipe](function () { + return Array.prototype.concat.apply([], arguments); + }); }, - isLastPage: function isLastPage() { - return this.current + 1 >= this.totalPages; + _onChange: function _onChange(e) { + var that = this, + data = { + fileInput: $(e.target), + form: $(e.target.form) + }; + this._getFileInputFiles(data.fileInput).always(function (files) { + data.files = files; + if (that.options.replaceFileInput) { + that._replaceFileInput(data); + } + if (that._trigger('change', $.Event('change', { + delegatedEvent: e + }), data) !== false) { + that._onAdd(e, data); + } + }); }, - isFirstPage: function isFirstPage() { - return this.current === 0; + _onPaste: function _onPaste(e) { + var items = e.originalEvent && e.originalEvent.clipboardData && e.originalEvent.clipboardData.items, + data = { + files: [] + }; + if (items && items.length) { + $.each(items, function (index, item) { + var file = item.getAsFile && item.getAsFile(); + if (file) { + data.files.push(file); + } + }); + if (this._trigger('paste', $.Event('paste', { + delegatedEvent: e + }), data) !== false) { + this._onAdd(e, data); + } + } }, - canDoNext: function canDoNext() { - return !this.isLastPage; + _onDrop: function _onDrop(e) { + e.dataTransfer = e.originalEvent && e.originalEvent.dataTransfer; + var that = this, + dataTransfer = e.dataTransfer, + data = {}; + if (dataTransfer && dataTransfer.files && dataTransfer.files.length) { + e.preventDefault(); + this._getDroppedFiles(dataTransfer).always(function (files) { + data.files = files; + if (that._trigger('drop', $.Event('drop', { + delegatedEvent: e + }), data) !== false) { + that._onAdd(e, data); + } + }); + } }, - canDoPrev: function canDoPrev() { - return !this.isFirstPage; + _onDragOver: getDragHandler('dragover'), + _onDragEnter: getDragHandler('dragenter'), + _onDragLeave: getDragHandler('dragleave'), + _initEventHandlers: function _initEventHandlers() { + if (this._isXHRUpload(this.options)) { + this._on(this.options.dropZone, { + dragover: this._onDragOver, + drop: this._onDrop, + // event.preventDefault() on dragenter is required for IE10+: + dragenter: this._onDragEnter, + // dragleave is not required, but added for completeness: + dragleave: this._onDragLeave + }); + this._on(this.options.pasteZone, { + paste: this._onPaste + }); + } + if ($.support.fileInput) { + this._on(this.options.fileInput, { + change: this._onChange + }); + } }, - canDoFirst: function canDoFirst() { - return !this.isFirstPage; + _destroyEventHandlers: function _destroyEventHandlers() { + this._off(this.options.dropZone, 'dragenter dragleave dragover drop'); + this._off(this.options.pasteZone, 'paste'); + this._off(this.options.fileInput, 'change'); }, - canDoLast: function canDoLast() { - return !this.isLastPage; + _destroy: function _destroy() { + this._destroyEventHandlers(); }, - // this computed is only to have a central place where we detect changes and leverage Vue JS reactivity to raise our event. - // That event will be handled by the parent media app to display the items in the page. - // this logic will not run if the computed property is not used in the template. We use a dummy "data-computed-trigger" attribute for that. - itemsInCurrentPage: function itemsInCurrentPage() { - var start = this.pageSize * this.current; - var end = start + this.pageSize; - var result = this.sourceItems.slice(start, end); - bus.$emit('pagerEvent', result); - return result; + _setOption: function _setOption(key, value) { + var reinit = $.inArray(key, this._specialOptions) !== -1; + if (reinit) { + this._destroyEventHandlers(); + } + this._super(key, value); + if (reinit) { + this._initSpecialOptions(); + this._initEventHandlers(); + } }, - pageLinks: function pageLinks() { - var links = []; - links.push(this.current + 1); - - // Add 2 items before current - var beforeCurrent = this.current > 0 ? this.current : -1; - links.unshift(beforeCurrent); - var beforeBeforeCurrent = this.current > 1 ? this.current - 1 : -1; - links.unshift(beforeBeforeCurrent); - - // Add 2 items after current - var afterCurrent = this.totalPages - this.current > 1 ? this.current + 2 : -1; - links.push(afterCurrent); - var afterAfterCurrent = this.totalPages - this.current > 2 ? this.current + 3 : -1; - links.push(afterAfterCurrent); - return links; - } - }, - watch: { - sourceItems: function sourceItems() { - this.current = 0; // resetting current page after receiving a new list of unpaged items + _initSpecialOptions: function _initSpecialOptions() { + var options = this.options; + if (options.fileInput === undefined) { + options.fileInput = this.element.is('input[type="file"]') ? this.element : this.element.find('input[type="file"]'); + } else if (!(options.fileInput instanceof $)) { + options.fileInput = $(options.fileInput); + } + if (!(options.dropZone instanceof $)) { + options.dropZone = $(options.dropZone); + } + if (!(options.pasteZone instanceof $)) { + options.pasteZone = $(options.pasteZone); + } }, - - pageSize: function pageSize() { - this.current = 0; - } - } -}); -// component -Vue.component('sortIndicator', { - template: "\n
    \n \n \n
    \n ", - props: { - colname: String, - selectedcolname: String, - asc: Boolean - }, - computed: { - isActive: function isActive() { - return this.colname.toLowerCase() == this.selectedcolname.toLowerCase(); - } - } -}); -function initializeAttachedMediaField(el, idOfUploadButton, uploadAction, mediaItemUrl, allowMultiple, allowMediaText, allowAnchors, tempUploadFolder, maxUploadChunkSize) { - var target = $(document.getElementById($(el).data('for'))); - var initialPaths = target.data("init"); - var mediaFieldEditor = $(el); - var idprefix = mediaFieldEditor.attr("id"); - var mediaFieldApp; - mediaFieldApps.push(mediaFieldApp = new Vue({ - el: mediaFieldEditor.get(0), - data: { - mediaItems: [], - selectedMedia: null, - smallThumbs: false, - idPrefix: idprefix, - initialized: false, - allowMediaText: allowMediaText, - backupMediaText: '', - allowAnchors: allowAnchors, - backupAnchor: null, - mediaTextmodal: null, - anchoringModal: null + _getRegExp: function _getRegExp(str) { + var parts = str.split('/'), + modifiers = parts.pop(); + parts.shift(); + return new RegExp(parts.join('/'), modifiers); }, - created: function created() { - var self = this; - self.currentPrefs = JSON.parse(localStorage.getItem('mediaFieldPrefs')); + _isRegExpOption: function _isRegExpOption(key, value) { + return key !== 'url' && $.type(value) === 'string' && /^\/.*\/[igm]{0,3}$/.test(value); }, - computed: { - paths: { - get: function get() { - var mediaPaths = []; - if (!this.initialized) { - return JSON.stringify(initialPaths); + _initDataAttributes: function _initDataAttributes() { + var that = this, + options = this.options, + data = this.element.data(); + // Initialize options set via HTML5 data-attributes: + $.each(this.element[0].attributes, function (index, attr) { + var key = attr.name.toLowerCase(), + value; + if (/^data-/.test(key)) { + // Convert hyphen-ated key to camelCase: + key = key.slice(5).replace(/-[a-z]/g, function (str) { + return str.charAt(1).toUpperCase(); + }); + value = data[key]; + if (that._isRegExpOption(key, value)) { + value = that._getRegExp(value); } - this.mediaItems.forEach(function (x) { - if (x.mediaPath === 'not-found') { + options[key] = value; + } + }); + }, + _create: function _create() { + this._initDataAttributes(); + this._initSpecialOptions(); + this._slots = []; + this._sequence = this._getXHRPromise(true); + this._sending = this._active = 0; + this._initProgressObject(this); + this._initEventHandlers(); + }, + // This method is exposed to the widget API and allows to query + // the number of active uploads: + active: function active() { + return this._active; + }, + // This method is exposed to the widget API and allows to query + // the widget upload progress. + // It returns an object with loaded, total and bitrate properties + // for the running uploads: + progress: function progress() { + return this._progress; + }, + // This method is exposed to the widget API and allows adding files + // using the fileupload API. The data parameter accepts an object which + // must have a files property and can contain additional options: + // .fileupload('add', {files: filesList}); + add: function add(data) { + var that = this; + if (!data || this.options.disabled) { + return; + } + if (data.fileInput && !data.files) { + this._getFileInputFiles(data.fileInput).always(function (files) { + data.files = files; + that._onAdd(null, data); + }); + } else { + data.files = $.makeArray(data.files); + this._onAdd(null, data); + } + }, + // This method is exposed to the widget API and allows sending files + // using the fileupload API. The data parameter accepts an object which + // must have a files or fileInput property and can contain additional options: + // .fileupload('send', {files: filesList}); + // The method returns a Promise object for the file upload call. + send: function send(data) { + if (data && !this.options.disabled) { + if (data.fileInput && !data.files) { + var that = this, + dfd = $.Deferred(), + promise = dfd.promise(), + jqXHR, + aborted; + promise.abort = function () { + aborted = true; + if (jqXHR) { + return jqXHR.abort(); + } + dfd.reject(null, 'abort', 'abort'); + return promise; + }; + this._getFileInputFiles(data.fileInput).always(function (files) { + if (aborted) { return; } - mediaPaths.push({ - path: x.mediaPath, - isRemoved: x.isRemoved, - isNew: x.isNew, - mediaText: x.mediaText, - anchor: x.anchor, - attachedFileName: x.attachedFileName - }); - }); - return JSON.stringify(mediaPaths); - }, - set: function set(values) { - var self = this; - var mediaPaths = values || []; - var signal = $.Deferred(); - var items = []; - var length = 0; - mediaPaths.forEach(function (x, i) { - items.push({ - name: ' ' + x.path, - mime: '', - mediaPath: '', - anchor: x.anchor, - attachedFileName: x.attachedFileName - }); // don't remove the space. Something different is needed or it wont react when the real name arrives. - promise = $.when(signal).done(function () { - $.ajax({ - url: mediaItemUrl + "?path=" + encodeURIComponent(x.path), - method: 'GET', - success: function success(data) { - data.vuekey = data.name + i.toString(); // Because a unique key is required by Vue on v-for - data.mediaText = x.mediaText; // This value is not returned from the ajax call. - data.anchor = x.anchor; // This value is not returned from the ajax call. - data.attachedFileName = x.attachedFileName; // This value is not returned from the ajax call. - items.splice(i, 1, data); - if (items.length === ++length) { - items.forEach(function (x) { - self.mediaItems.push(x); - }); - self.initialized = true; - } - }, - error: function error(_error) { - console.log(JSON.stringify(_error)); - items.splice(i, 1, { - name: x.path, - mime: '', - mediaPath: 'not-found', - mediaText: '', - anchor: { - x: 0.5, - y: 0.5 - }, - attachedFileName: x.attachedFileName - }); - if (items.length === ++length) { - items.forEach(function (x) { - self.mediaItems.push(x); - }); - self.initialized = true; - } - } - }); + if (!files.length) { + dfd.reject(); + return; + } + data.files = files; + jqXHR = that._onSend(null, data); + jqXHR.then(function (result, textStatus, jqXHR) { + dfd.resolve(result, textStatus, jqXHR); + }, function (jqXHR, textStatus, errorThrown) { + dfd.reject(jqXHR, textStatus, errorThrown); }); }); - signal.resolve(); + return this._enhancePromise(promise); } - }, - fileSize: function fileSize() { - return Math.round(this.selectedMedia.size / 1024); - }, - canAddMedia: function canAddMedia() { - var nonRemovedMediaItems = []; - for (var i = 0; i < this.mediaItems.length; i++) { - if (!this.mediaItems[i].isRemoved) { - nonRemovedMediaItems.push(this.mediaItems[i]); - } - } - return nonRemovedMediaItems.length === 0 || nonRemovedMediaItems.length > 0 && allowMultiple; - }, - thumbSize: function thumbSize() { - return this.smallThumbs ? 120 : 240; - }, - currentPrefs: { - get: function get() { - return { - smallThumbs: this.smallThumbs - }; - }, - set: function set(newPrefs) { - if (!newPrefs) { - return; - } - this.smallThumbs = newPrefs.smallThumbs; + data.files = $.makeArray(data.files); + if (data.files.length) { + return this._onSend(null, data); } } - }, - mounted: function mounted() { - var self = this; - self.paths = initialPaths; - self.$on('selectAndDeleteMediaRequested', function (media) { - self.selectAndDeleteMedia(media); - }); - self.$on('selectMediaRequested', function (media) { - self.selectMedia(media); - }); - var selector = '#' + idOfUploadButton; - var editorId = mediaFieldEditor.attr('id'); - var chunkedFileUploadId = randomUUID(); - $(selector).fileupload({ - limitConcurrentUploads: 20, - dropZone: $('#' + editorId), - dataType: 'json', - url: uploadAction, - maxChunkSize: maxUploadChunkSize, - add: function add(e, data) { - var count = data.files.length; - var i; - for (i = 0; i < count; i++) { - data.files[i].uploadName = self.getUniqueId() + data.files[i].name; - data.files[i].attachedFileName = data.files[i].name; + return this._getXHRPromise(false, data && data.context); + } + }); +}); +function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); } +/* + * jQuery Iframe Transport Plugin + * https://github.com/blueimp/jQuery-File-Upload + * + * Copyright 2011, Sebastian Tschan + * https://blueimp.net + * + * Licensed under the MIT license: + * https://opensource.org/licenses/MIT + */ + +/* global define, require */ + +(function (factory) { + 'use strict'; + + if (typeof define === 'function' && define.amd) { + // Register as an anonymous AMD module: + define(['jquery'], factory); + } else if ((typeof exports === "undefined" ? "undefined" : _typeof(exports)) === 'object') { + // Node/CommonJS: + factory(require('jquery')); + } else { + // Browser globals: + factory(window.jQuery); + } +})(function ($) { + 'use strict'; + + // Helper variable to create unique names for the transport iframes: + var counter = 0, + jsonAPI = $, + jsonParse = 'parseJSON'; + if ('JSON' in window && 'parse' in JSON) { + jsonAPI = JSON; + jsonParse = 'parse'; + } + + // The iframe transport accepts four additional options: + // options.fileInput: a jQuery collection of file input fields + // options.paramName: the parameter name for the file form data, + // overrides the name property of the file input field(s), + // can be a string or an array of strings. + // options.formData: an array of objects with name and value properties, + // equivalent to the return data of .serializeArray(), e.g.: + // [{name: 'a', value: 1}, {name: 'b', value: 2}] + // options.initialIframeSrc: the URL of the initial iframe src, + // by default set to "javascript:false;" + $.ajaxTransport('iframe', function (options) { + if (options.async) { + // javascript:false as initial iframe src + // prevents warning popups on HTTPS in IE6: + // eslint-disable-next-line no-script-url + var initialIframeSrc = options.initialIframeSrc || 'javascript:false;', + form, + iframe, + addParamChar; + return { + send: function send(_, completeCallback) { + form = $('
    '); + form.attr('accept-charset', options.formAcceptCharset); + addParamChar = /\?/.test(options.url) ? '&' : '?'; + // XDomainRequest only supports GET and POST: + if (options.type === 'DELETE') { + options.url = options.url + addParamChar + '_method=DELETE'; + options.type = 'POST'; + } else if (options.type === 'PUT') { + options.url = options.url + addParamChar + '_method=PUT'; + options.type = 'POST'; + } else if (options.type === 'PATCH') { + options.url = options.url + addParamChar + '_method=PATCH'; + options.type = 'POST'; } - data.submit(); - }, - formData: function formData() { - var antiForgeryToken = $("input[name=__RequestVerificationToken]").val(); - return [{ - name: 'path', - value: tempUploadFolder - }, { - name: '__RequestVerificationToken', - value: antiForgeryToken - }, { - name: '__chunkedFileUploadId', - value: chunkedFileUploadId - }]; - }, - done: function done(e, data) { - var newMediaItems = []; - var errormsg = ""; - if (data.result.files.length > 0) { - for (var i = 0; i < data.result.files.length; i++) { - data.result.files[i].isNew = true; - //if error is defined probably the file type is not allowed - if (data.result.files[i].error === undefined || data.result.files[i].error === null) { - data.result.files[i].attachedFileName = data.files[i].attachedFileName; - newMediaItems.push(data.result.files[i]); - } else errormsg += data.result.files[i].error + "\n"; + // IE versions below IE8 cannot set the name property of + // elements that have already been added to the DOM, + // so we set the name along with the iframe HTML markup: + counter += 1; + iframe = $('').on('load', function () { + var fileInputClones, + paramNames = $.isArray(options.paramName) ? options.paramName : [options.paramName]; + iframe.off('load').on('load', function () { + var response; + // Wrap in a try/catch block to catch exceptions thrown + // when trying to access cross-domain iframe contents: + try { + response = iframe.contents(); + // Google Chrome and Firefox do not throw an + // exception when calling iframe.contents() on + // cross-domain requests, so we unify the response: + if (!response.length || !response[0].firstChild) { + throw new Error(); + } + } catch (e) { + response = undefined; + } + // The complete callback returns the + // iframe content document as response object: + completeCallback(200, 'success', { + iframe: response + }); + // Fix for IE endless progress bar activity bug + // (happens on form submits to iframe targets): + $('').appendTo(form); + window.setTimeout(function () { + // Removing the form in a setTimeout call + // allows Chrome's developer tools to display + // the response result + form.remove(); + }, 0); + }); + form.prop('target', iframe.prop('name')).prop('action', options.url).prop('method', options.type); + if (options.formData) { + $.each(options.formData, function (index, field) { + $('').prop('name', field.name).val(field.value).appendTo(form); + }); } + if (options.fileInput && options.fileInput.length && options.type === 'POST') { + fileInputClones = options.fileInput.clone(); + // Insert a clone for each file input field: + options.fileInput.after(function (index) { + return fileInputClones[index]; + }); + if (options.paramName) { + options.fileInput.each(function (index) { + $(this).prop('name', paramNames[index] || options.paramName); + }); + } + // Appending the file input fields to the hidden form + // removes them from their original location: + form.append(options.fileInput).prop('enctype', 'multipart/form-data') + // enctype must be set as encoding for IE: + .prop('encoding', 'multipart/form-data'); + // Remove the HTML5 form attribute from the input(s): + options.fileInput.removeAttr('form'); + } + window.setTimeout(function () { + // Submitting the form in a setTimeout call fixes an issue with + // Safari 13 not triggering the iframe load event after resetting + // the load event handler, see also: + // https://github.com/blueimp/jQuery-File-Upload/issues/3633 + form.submit(); + // Insert the file input fields at their original location + // by replacing the clones with the originals: + if (fileInputClones && fileInputClones.length) { + options.fileInput.each(function (index, input) { + var clone = $(fileInputClones[index]); + // Restore the original name and form properties: + $(input).prop('name', clone.prop('name')).attr('form', clone.attr('form')); + clone.replaceWith(input); + }); + } + }, 0); + }); + form.append(iframe).appendTo(document.body); + }, + abort: function abort() { + if (iframe) { + // javascript:false as iframe src aborts the request + // and prevents warning popups on HTTPS in IE6. + iframe.off('load').prop('src', initialIframeSrc); } - if (errormsg !== "") { - alert(errormsg); - return; - } - console.log(newMediaItems); - if (newMediaItems.length > 1 && allowMultiple === false) { - alert($('#onlyOneItemMessage').val()); - mediaFieldApp.mediaItems.push(newMediaItems[0]); - mediaFieldApp.initialized = true; - } else { - mediaFieldApp.mediaItems = mediaFieldApp.mediaItems.concat(newMediaItems); - mediaFieldApp.initialized = true; + if (form) { + form.remove(); } - }, - error: function error(jqXHR, textStatus, errorThrown) { - console.log('Error on upload.'); - console.log(jqXHR); - console.log(textStatus); - console.log(errorThrown); } - }).on('fileuploadchunkbeforesend', function (e, options) { - var file = options.files[0]; - // Here we replace the blob with a File object to ensure the file name and others are preserved for the backend. - options.blob = new File([options.blob], file.name, { - type: file.type, - lastModified: file.lastModified - }); - }); - }, - methods: { - selectMedia: function selectMedia(media) { - this.selectedMedia = media; - }, - getUniqueId: function getUniqueId() { - return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { - var r = Math.random() * 16 | 0, - v = c === 'x' ? r : r & 0x3 | 0x8; - return v.toString(16); - }); - }, - removeSelected: function removeSelected(event) { - var removed = {}; - if (this.selectedMedia) { - var index = this.mediaItems && this.mediaItems.indexOf(this.selectedMedia); - if (index > -1) { - removed = this.mediaItems[index]; - removed.isRemoved = true; - //this.mediaItems.splice([index], 1, removed); - this.mediaItems.splice(index, 1); - } - } else { - // The remove button can also remove a unique media item - if (this.mediaItems.length === 1) { - removed = this.mediaItems[index]; - removed.isRemoved = true; - //this.mediaItems.splice(0, 1, removed); - this.mediaItems.splice(0, 1); - } - } - this.selectedMedia = null; - }, - showMediaTextModal: function showMediaTextModal(event) { - this.mediaTextModal = new bootstrap.Modal(this.$refs.mediaTextModal); - this.mediaTextModal.show(); - this.backupMediaText = this.selectedMedia.mediaText; - }, - cancelMediaTextModal: function cancelMediaTextModal(event) { - this.mediaTextModal.hide(); - this.selectedMedia.mediaText = this.backupMediaText; - }, - showAnchorModal: function showAnchorModal(event) { - this.anchoringModal = new bootstrap.Modal(this.$refs.anchoringModal); - this.anchoringModal.show(); - // Cause a refresh to recalc heights. - this.selectedMedia.anchor = { - x: this.selectedMedia.anchor.x, - y: this.selectedMedia.anchor.y - }; - this.backupAnchor = this.selectedMedia.anchor; - }, - cancelAnchoringModal: function cancelAnchoringModal(event) { - this.anchoringModal.hide(); - this.selectedMedia.anchor = this.backupAnchor; - }, - resetAnchor: function resetAnchor(event) { - this.selectedMedia.anchor = { - x: 0.5, - y: 0.5 - }; - }, - onAnchorDrop: function onAnchorDrop(event) { - var image = this.$refs.anchorImage; - this.selectedMedia.anchor = { - x: event.offsetX / image.clientWidth, - y: event.offsetY / image.clientHeight - }; - }, - anchorLeft: function anchorLeft() { - if (this.$refs.anchorImage && this.$refs.modalBody && this.selectedMedia) { - // When image is shrunk compare against the modal body. - var offset = (this.$refs.modalBody.clientWidth - this.$refs.anchorImage.clientWidth) / 2; - var position = this.selectedMedia.anchor.x * this.$refs.anchorImage.clientWidth + offset; - if (position < 17) { - // Adjust so the target doesn't show outside image. - position = 17; - } else { - position = position - 8; // Adjust to hit the mouse pointer. - } - - return position + 'px'; - } else { - return '0'; - } - }, - anchorTop: function anchorTop() { - if (this.$refs.anchorImage && this.selectedMedia) { - var position = this.selectedMedia.anchor.y * this.$refs.anchorImage.clientHeight; - if (position < 15) { - // Adjustment so the target doesn't show outside image. - position = 15; - } else { - position = position + 5; // Adjust to hit the mouse pointer. - } + }; + } + }); - return position + 'px'; - } else { - return '0'; - } + // The iframe transport returns the iframe content document as response. + // The following adds converters from iframe to text, json, html, xml + // and script. + // Please note that the Content-Type for JSON responses has to be text/plain + // or text/html, if the browser doesn't include application/json in the + // Accept header, else IE will show a download dialog. + // The Content-Type for XML responses on the other hand has to be always + // application/xml or text/xml, so IE properly parses the XML response. + // See also + // https://github.com/blueimp/jQuery-File-Upload/wiki/Setup#content-type-negotiation + $.ajaxSetup({ + converters: { + 'iframe text': function iframeText(iframe) { + return iframe && $(iframe[0].body).text(); }, - setAnchor: function setAnchor(event) { - var image = this.$refs.anchorImage; - this.selectedMedia.anchor = { - x: event.offsetX / image.clientWidth, - y: event.offsetY / image.clientHeight - }; + 'iframe json': function iframeJson(iframe) { + return iframe && jsonAPI[jsonParse]($(iframe[0].body).text()); }, - addMediaFiles: function addMediaFiles(files) { - if (files.length > 1 && allowMultiple === false) { - alert($('#onlyOneItemMessage').val()); - mediaFieldApp.mediaItems.push(files[0]); - mediaFieldApp.initialized = true; - } else { - mediaFieldApp.mediaItems = mediaFieldApp.mediaItems.concat(files); - mediaFieldApp.initialized = true; - } + 'iframe html': function iframeHtml(iframe) { + return iframe && $(iframe[0].body).html(); }, - selectAndDeleteMedia: function selectAndDeleteMedia(media) { - var self = this; - self.selectedMedia = media; - // setTimeout because sometimes - // removeSelected was called even before the media was set. - setTimeout(function () { - self.removeSelected(); - }, 100); - } - }, - watch: { - mediaItems: { - deep: true, - handler: function handler() { - // Trigger preview rendering - setTimeout(function () { - $(document).trigger('contentpreview:render'); - }, 100); - } + 'iframe xml': function iframeXml(iframe) { + var xmlDoc = iframe && iframe[0]; + return xmlDoc && $.isXMLDoc(xmlDoc) ? xmlDoc : $.parseXML(xmlDoc.XMLDocument && xmlDoc.XMLDocument.xml || $(xmlDoc.body).html()); }, - currentPrefs: function currentPrefs(newPrefs) { - localStorage.setItem('mediaFieldPrefs', JSON.stringify(newPrefs)); + 'iframe script': function iframeScript(iframe) { + return iframe && $.globalEval($(iframe[0].body).text()); } } - })); -} -// component -// different media field editors share this component to present the thumbs. -Vue.component('mediaFieldThumbsContainer', { - template: '\ -
    \ -
    \ -
    \ - {{T.noImages}}\ -
    \ -
    \ - \ -
  • \ -
    \ -
    \ - \ - \ -
    \ -
    \ - \ - \ - {{ media.isNew ? media.name.substr(36) : media.name }}\ -
    \ -
    \ -
    \ -
    \ - \ - {{ T.mediaNotFound }}\ - {{ T.discardWarning }}\ -
    \ -
    \ - \ - {{ media.name }}\ -
    \ -
    \ -
  • \ -
    \ -
    \ - ', - data: function data() { - return { - T: {} - }; - }, - props: { - mediaItems: Array, - selectedMedia: Object, - thumbSize: Number, - idPrefix: String - }, - created: function created() { - var self = this; - - // retrieving localized strings from view - self.T.mediaNotFound = $('#t-media-not-found').val(); - self.T.discardWarning = $('#t-discard-warning').val(); - self.T.noImages = $('#t-no-images').val(); - }, - methods: { - selectAndDeleteMedia: function selectAndDeleteMedia(media) { - this.$parent.$emit('selectAndDeleteMediaRequested', media); - }, - selectMedia: function selectMedia(media) { - this.$parent.$emit('selectMediaRequested', media); - }, - buildMediaUrl: function buildMediaUrl(url, thumbSize) { - return url + (url.indexOf('?') == -1 ? '?' : '&') + 'width=' + thumbSize + '&height=' + thumbSize; - }, - getfontAwesomeClassNameForFileName: function getfontAwesomeClassNameForFilename(filename, thumbsize) { - return getClassNameForFilename(filename) + ' ' + thumbsize; - } - } + }); }); -function initializeMediaField(el, modalBodyElement, mediaItemUrl, allowMultiple, allowMediaText, allowAnchors) { - //BagPart create a script section without other DOM elements - if (el === null) return; - var target = $(document.getElementById($(el).data('for'))); - var initialPaths = target.data("init"); - var mediaFieldEditor = $(el); - var idprefix = mediaFieldEditor.attr("id"); - var mediaFieldApp; - - //when hide modal detach media app to avoid issue on BagPart - modalBodyElement.addEventListener('hidden.bs.modal', function (event) { - $("#mediaApp").appendTo('body'); - $("#mediaApp").hide(); +function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); } +function randomUUID() { + if ((typeof crypto === "undefined" ? "undefined" : _typeof(crypto)) === 'object' && typeof crypto.randomUUID === 'function') { + return crypto.randomUUID(); + } + return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, function (c) { + return (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16); }); - mediaFieldApps.push(mediaFieldApp = new Vue({ - el: mediaFieldEditor.get(0), - data: { - mediaItems: [], - selectedMedia: null, - smallThumbs: false, - idPrefix: idprefix, - initialized: false, - allowMediaText: allowMediaText, - backupMediaText: '', - allowAnchors: allowAnchors, - backupAnchor: null, - mediaTextModal: null, - anchoringModal: null - }, - created: function created() { - var self = this; - self.currentPrefs = JSON.parse(localStorage.getItem('mediaFieldPrefs')); - }, - computed: { - paths: { - get: function get() { - var mediaPaths = []; - if (!this.initialized) { - return JSON.stringify(initialPaths); - } - this.mediaItems.forEach(function (x) { - if (x.mediaPath === 'not-found') { - return; - } - mediaPaths.push({ - path: x.mediaPath, - mediaText: x.mediaText, - anchor: x.anchor - }); - }); - return JSON.stringify(mediaPaths); +} +function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); } +function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } +function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } +function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } +function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return _typeof(key) === "symbol" ? key : String(key); } +function _toPrimitive(input, hint) { if (_typeof(input) !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (_typeof(res) !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); } +var initialized; +var mediaApp; +var bus = new Vue(); +function initializeMediaApplication(displayMediaApplication, mediaApplicationUrl, pathBase) { + if (initialized) { + return; + } + initialized = true; + if (!mediaApplicationUrl) { + console.error('mediaApplicationUrl variable is not defined'); + } + $.ajax({ + url: mediaApplicationUrl, + method: 'GET', + success: function success(content) { + $('.ta-content').append(content); + $(document).trigger('mediaapplication:ready'); + var _root = { + name: $('#t-mediaLibrary').text(), + path: '', + folder: '', + isDirectory: true, + canCreateFolder: $('#allowNewRootFolders').val() === 'true' + }; + mediaApp = new Vue({ + el: '#mediaApp', + data: { + selectedFolder: {}, + mediaItems: [], + selectedMedias: [], + errors: [], + dragDropThumbnail: new Image(), + smallThumbs: false, + gridView: false, + mediaFilter: '', + sortBy: '', + sortAsc: true, + itemsInPage: [] }, - set: function set(values) { + created: function created() { var self = this; - var mediaPaths = values || []; - var signal = $.Deferred(); - var items = []; - var length = 0; - mediaPaths.forEach(function (x, i) { - items.push({ - name: ' ' + x.path, - mime: '', - mediaPath: '' - }); // don't remove the space. Something different is needed or it wont react when the real name arrives. - promise = $.when(signal).done(function () { - $.ajax({ - url: mediaItemUrl + "?path=" + encodeURIComponent(x.path), - method: 'GET', - success: function success(data) { - data.vuekey = data.name + i.toString(); - data.mediaText = x.mediaText; // This value is not returned from the ajax call. - data.anchor = x.anchor; // This value is not returned from the ajax call. - items.splice(i, 1, data); - if (items.length === ++length) { - items.forEach(function (y) { - self.mediaItems.push(y); - }); - self.initialized = true; - } - }, - error: function error(_error) { - console.log(_error); - items.splice(i, 1, { - name: x.path, - mime: '', - mediaPath: 'not-found', - mediaText: '', - anchor: { - x: 0, - y: 0 - } - }); - if (items.length === ++length) { - items.forEach(function (x) { - self.mediaItems.push(x); - }); - self.initialized = true; - } - } - }); - }); + self.dragDropThumbnail.src = (pathBase || '') + '/OrchardCore.Media/Images/drag-thumbnail.png'; + bus.$on('folderSelected', function (folder) { + self.selectedFolder = folder; + }); + bus.$on('folderDeleted', function () { + self.selectRoot(); + }); + bus.$on('folderAdded', function (folder) { + self.selectedFolder = folder; + folder.selected = true; + }); + bus.$on('mediaListMoved', function (errorInfo) { + self.loadFolder(self.selectedFolder); + if (errorInfo) { + self.errors.push(errorInfo); + } + }); + bus.$on('mediaRenamed', function (newName, newPath, oldPath, newUrl) { + var media = self.mediaItems.filter(function (item) { + return item.mediaPath === oldPath; + })[0]; + media.mediaPath = newPath; + media.name = newName; + media.url = newUrl; + }); + bus.$on('createFolderRequested', function (media) { + self.createFolder(); + }); + bus.$on('deleteFolderRequested', function (media) { + self.deleteFolder(); }); - signal.resolve(); - } - }, - fileSize: function fileSize() { - return Math.round(this.selectedMedia.size / 1024); - }, - canAddMedia: function canAddMedia() { - return this.mediaItems.length === 0 || this.mediaItems.length > 0 && allowMultiple; - }, - thumbSize: function thumbSize() { - return this.smallThumbs ? 120 : 240; - }, - currentPrefs: { - get: function get() { - return { - smallThumbs: this.smallThumbs - }; - }, - set: function set(newPrefs) { - if (!newPrefs) { - return; - } - this.smallThumbs = newPrefs.smallThumbs; - } - } - }, - mounted: function mounted() { - var self = this; - self.paths = initialPaths; - self.$on('selectAndDeleteMediaRequested', function (media) { - self.selectAndDeleteMedia(media); - }); - self.$on('selectMediaRequested', function (media) { - self.selectMedia(media); - }); - self.$on('filesUploaded', function (files) { - self.addMediaFiles(files); - }); - }, - methods: { - selectMedia: function selectMedia(media) { - this.selectedMedia = media; - }, - showModal: function showModal(event) { - var self = this; - if (self.canAddMedia) { - $("#mediaApp").appendTo($(modalBodyElement).find('.modal-body')); - $("#mediaApp").show(); - var modal = new bootstrap.Modal(modalBodyElement); - modal.show(); - $(modalBodyElement).find('.mediaFieldSelectButton').off('click').on('click', function (v) { - self.addMediaFiles(mediaApp.selectedMedias); - // we don't want the included medias to be still selected the next time we open the modal. - mediaApp.selectedMedias = []; - modal.hide(); - return true; + // common handlers for actions in both grid and table view. + bus.$on('sortChangeRequested', function (newSort) { + self.changeSort(newSort); }); - } - }, - showMediaTextModal: function showMediaTextModal(event) { - this.mediaTextModal = new bootstrap.Modal(this.$refs.mediaTextModal); - this.mediaTextModal.show(); - this.backupMediaText = this.selectedMedia.mediaText; - }, - cancelMediaTextModal: function cancelMediaTextModal(event) { - this.mediaTextModal.hide(); - this.selectedMedia.mediaText = this.backupMediaText; - }, - showAnchorModal: function showAnchorModal(event) { - this.anchoringModal = new bootstrap.Modal(this.$refs.anchoringModal); - this.anchoringModal.show(); - // Cause a refresh to recalc heights. - this.selectedMedia.anchor = { - x: this.selectedMedia.anchor.x, - y: this.selectedMedia.anchor.y - }; - this.backupAnchor = this.selectedMedia.anchor; - }, - cancelAnchoringModal: function cancelAnchoringModal(event) { - this.anchoringModal.hide(); - this.selectedMedia.anchor = this.backupAnchor; - }, - resetAnchor: function resetAnchor(event) { - this.selectedMedia.anchor = { - x: 0.5, - y: 0.5 - }; - }, - onAnchorDrop: function onAnchorDrop(event) { - var image = this.$refs.anchorImage; - this.selectedMedia.anchor = { - x: event.offsetX / image.clientWidth, - y: event.offsetY / image.clientHeight - }; - }, - anchorLeft: function anchorLeft() { - if (this.$refs.anchorImage && this.$refs.modalBody && this.selectedMedia) { - // When image is shrunk compare against the modal body. - var offset = (this.$refs.modalBody.clientWidth - this.$refs.anchorImage.clientWidth) / 2; - var position = this.selectedMedia.anchor.x * this.$refs.anchorImage.clientWidth + offset; - var anchorIcon = Math.round(this.$refs.modalBody.querySelector('.icon-media-anchor').clientWidth); - if (Number.isInteger(anchorIcon)) { - position = position - anchorIcon / 2; - } - return position + 'px'; - } else { - return '0'; - } - }, - anchorTop: function anchorTop() { - if (this.$refs.anchorImage && this.selectedMedia) { - var position = this.selectedMedia.anchor.y * this.$refs.anchorImage.clientHeight; - return position + 'px'; - } else { - return '0'; - } - }, - setAnchor: function setAnchor(event) { - var image = this.$refs.anchorImage; - this.selectedMedia.anchor = { - x: event.offsetX / image.clientWidth, - y: event.offsetY / image.clientHeight - }; - }, - addMediaFiles: function addMediaFiles(files) { - if (files.length > 1 && allowMultiple === false) { - alert($('#onlyOneItemMessage').val()); - mediaFieldApp.mediaItems.push(files[0]); - mediaFieldApp.initialized = true; - } else { - mediaFieldApp.mediaItems = mediaFieldApp.mediaItems.concat(files); - mediaFieldApp.initialized = true; - } - }, - removeSelected: function removeSelected(event) { - if (this.selectedMedia) { - var index = this.mediaItems && this.mediaItems.indexOf(this.selectedMedia); - if (index > -1) { - this.mediaItems.splice(index, 1); - } - } else { - // The remove button can also remove a unique media item - if (this.mediaItems.length === 1) { - this.mediaItems.splice(0, 1); - } - } - this.selectedMedia = null; - }, - selectAndDeleteMedia: function selectAndDeleteMedia(media) { - var self = this; - self.selectedMedia = media; - // setTimeout because sometimes removeSelected was called even before the media was set. - setTimeout(function () { - self.removeSelected(); - }, 100); - } - }, - watch: { - mediaItems: { - deep: true, - handler: function handler() { - // Trigger preview rendering - setTimeout(function () { - $(document).trigger('contentpreview:render'); - }, 100); - } - }, - currentPrefs: function currentPrefs(newPrefs) { - localStorage.setItem('mediaFieldPrefs', JSON.stringify(newPrefs)); - } - } - })); -} -// different media field editors will add themselves to this array -var mediaFieldApps = []; -// component -Vue.component('upload', { - template: '\ -
    \ - \ -

    {{ model.name }}

    \ -
    \ - \ - Error: {{ model.errorMessage }} \ -
    \ -
    \ - ', - props: { - model: Object, - uploadInputId: String - }, - mounted: function mounted() { - var _self$uploadInputId; - var self = this; - var uploadInput = document.getElementById((_self$uploadInputId = self.uploadInputId) !== null && _self$uploadInputId !== void 0 ? _self$uploadInputId : 'fileupload'); - $(uploadInput).bind('fileuploadprogress', function (e, data) { - if (data.files[0].name !== self.model.name) { - return; - } - self.model.percentage = parseInt(data.loaded / data.total * 100, 10); - }); - $(uploadInput).bind('fileuploaddone', function (e, data) { - if (data.files[0].name !== self.model.name) { - return; - } - if (data.result.files[0].error) { - self.handleFailure(data.files[0].name, data.result.files[0].error); - } else { - bus.$emit('removalRequest', self.model); - } - }); - $(uploadInput).bind('fileuploadfail', function (e, data) { - if (data.files[0].name !== self.model.name) { - return; - } - self.handleFailure(data.files[0].name, $('#t-error').val()); - }); - }, - methods: { - handleFailure: function handleFailure(fileName, message) { - if (fileName !== this.model.name) { - return; - } - this.model.errorMessage = message; - bus.$emit('ErrorOnUpload', this.model); - }, - dismissWarning: function dismissWarning() { - bus.$emit('removalRequest', this.model); - } - } -}); -// component -Vue.component('uploadList', { - template: '\ -
    \ -
    \ - {{ T.uploads }} \ - (Pending: {{ pendingCount }}) \ - ( {{ T.errors }}: {{ errorCount }} / {{ T.clearErrors }} ) \ -
    \ -
    \ - \ -
    \ -
    \ - \ -
    \ -
    \ -
    \ -
    \ -
    \ - \ -
    \ -
    \ -
    \ - ', - data: function data() { - return { - files: [], - T: {}, - expanded: false, - pendingCount: 0, - errorCount: 0 - }; - }, - props: { - uploadInputId: String - }, - created: function created() { - var self = this; - // retrieving localized strings from view - self.T.uploads = $('#t-uploads').val(); - self.T.errors = $('#t-errors').val(); - self.T.clearErrors = $('#t-clear-errors').val(); - }, - computed: { - fileCount: function fileCount() { - return this.files.length; - } - }, - mounted: function mounted() { - var _self$uploadInputId; - var self = this; - var uploadInput = document.getElementById((_self$uploadInputId = self.uploadInputId) !== null && _self$uploadInputId !== void 0 ? _self$uploadInputId : 'fileupload'); - $(uploadInput).bind('fileuploadadd', function (e, data) { - if (!data.files) { - return; - } - data.files.forEach(function (newFile) { - var alreadyInList = self.files.some(function (f) { - return f.name == newFile.name; - }); - if (!alreadyInList) { - self.files.push({ - name: newFile.name, - percentage: 0, - errorMessage: '' - }); - } else { - console.error('A file with the same name is already on the queue:' + newFile.name); - } - }); - }); - bus.$on('removalRequest', function (fileUpload) { - self.files.forEach(function (item, index, array) { - if (item.name == fileUpload.name) { - array.splice(index, 1); - } - }); - }); - bus.$on('ErrorOnUpload', function (fileUpload) { - self.updateCount(); - }); - }, - methods: { - updateCount: function updateCount() { - this.errorCount = this.files.filter(function (item) { - return item.errorMessage != ''; - }).length; - this.pendingCount = this.files.length - this.errorCount; - if (this.files.length < 1) { - this.expanded = false; - } - }, - clearErrors: function clearErrors() { - this.files = this.files.filter(function (item) { - return item.errorMessage == ''; - }); - } - }, - watch: { - files: function files() { - this.updateCount(); - } - } -}); -function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); } -function randomUUID() { - if ((typeof crypto === "undefined" ? "undefined" : _typeof(crypto)) === 'object' && typeof crypto.randomUUID === 'function') { - return crypto.randomUUID(); - } - return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, function (c) { - return (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16); - }); -} -function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); } -/* - * jQuery File Upload Plugin - * https://github.com/blueimp/jQuery-File-Upload - * - * Copyright 2010, Sebastian Tschan - * https://blueimp.net - * - * Licensed under the MIT license: - * https://opensource.org/licenses/MIT - */ - -/* global define, require */ -/* eslint-disable new-cap */ - -(function (factory) { - 'use strict'; - - if (typeof define === 'function' && define.amd) { - // Register as an anonymous AMD module: - define(['jquery', 'jquery-ui/ui/widget'], factory); - } else if ((typeof exports === "undefined" ? "undefined" : _typeof(exports)) === 'object') { - // Node/CommonJS: - factory(require('jquery'), require('./vendor/jquery.ui.widget')); - } else { - // Browser globals: - factory(window.jQuery); - } -})(function ($) { - 'use strict'; - - // Detect file input support, based on - // https://viljamis.com/2012/file-upload-support-on-mobile/ - $.support.fileInput = !(new RegExp( - // Handle devices which give false positives for the feature detection: - '(Android (1\\.[0156]|2\\.[01]))' + '|(Windows Phone (OS 7|8\\.0))|(XBLWP)|(ZuneWP)|(WPDesktop)' + '|(w(eb)?OSBrowser)|(webOS)' + '|(Kindle/(1\\.0|2\\.[05]|3\\.0))').test(window.navigator.userAgent) || - // Feature detection for all other devices: - $('').prop('disabled')); - - // The FileReader API is not actually used, but works as feature detection, - // as some Safari versions (5?) support XHR file uploads via the FormData API, - // but not non-multipart XHR file uploads. - // window.XMLHttpRequestUpload is not available on IE10, so we check for - // window.ProgressEvent instead to detect XHR2 file upload capability: - $.support.xhrFileUpload = !!(window.ProgressEvent && window.FileReader); - $.support.xhrFormDataFileUpload = !!window.FormData; - - // Detect support for Blob slicing (required for chunked uploads): - $.support.blobSlice = window.Blob && (Blob.prototype.slice || Blob.prototype.webkitSlice || Blob.prototype.mozSlice); - - /** - * Helper function to create drag handlers for dragover/dragenter/dragleave - * - * @param {string} type Event type - * @returns {Function} Drag handler - */ - function getDragHandler(type) { - var isDragOver = type === 'dragover'; - return function (e) { - e.dataTransfer = e.originalEvent && e.originalEvent.dataTransfer; - var dataTransfer = e.dataTransfer; - if (dataTransfer && $.inArray('Files', dataTransfer.types) !== -1 && this._trigger(type, $.Event(type, { - delegatedEvent: e - })) !== false) { - e.preventDefault(); - if (isDragOver) { - dataTransfer.dropEffect = 'copy'; - } - } - }; - } - - // The fileupload widget listens for change events on file input fields defined - // via fileInput setting and paste or drop events of the given dropZone. - // In addition to the default jQuery Widget methods, the fileupload widget - // exposes the "add" and "send" methods, to add or directly send files using - // the fileupload API. - // By default, files added via file input selection, paste, drag & drop or - // "add" method are uploaded immediately, but it is possible to override - // the "add" callback option to queue file uploads. - $.widget('blueimp.fileupload', { - options: { - // The drop target element(s), by the default the complete document. - // Set to null to disable drag & drop support: - dropZone: $(document), - // The paste target element(s), by the default undefined. - // Set to a DOM node or jQuery object to enable file pasting: - pasteZone: undefined, - // The file input field(s), that are listened to for change events. - // If undefined, it is set to the file input fields inside - // of the widget element on plugin initialization. - // Set to null to disable the change listener. - fileInput: undefined, - // By default, the file input field is replaced with a clone after - // each input field change event. This is required for iframe transport - // queues and allows change events to be fired for the same file - // selection, but can be disabled by setting the following option to false: - replaceFileInput: true, - // The parameter name for the file form data (the request argument name). - // If undefined or empty, the name property of the file input field is - // used, or "files[]" if the file input name property is also empty, - // can be a string or an array of strings: - paramName: undefined, - // By default, each file of a selection is uploaded using an individual - // request for XHR type uploads. Set to false to upload file - // selections in one request each: - singleFileUploads: true, - // To limit the number of files uploaded with one XHR request, - // set the following option to an integer greater than 0: - limitMultiFileUploads: undefined, - // The following option limits the number of files uploaded with one - // XHR request to keep the request size under or equal to the defined - // limit in bytes: - limitMultiFileUploadSize: undefined, - // Multipart file uploads add a number of bytes to each uploaded file, - // therefore the following option adds an overhead for each file used - // in the limitMultiFileUploadSize configuration: - limitMultiFileUploadSizeOverhead: 512, - // Set the following option to true to issue all file upload requests - // in a sequential order: - sequentialUploads: false, - // To limit the number of concurrent uploads, - // set the following option to an integer greater than 0: - limitConcurrentUploads: undefined, - // Set the following option to true to force iframe transport uploads: - forceIframeTransport: false, - // Set the following option to the location of a redirect url on the - // origin server, for cross-domain iframe transport uploads: - redirect: undefined, - // The parameter name for the redirect url, sent as part of the form - // data and set to 'redirect' if this option is empty: - redirectParamName: undefined, - // Set the following option to the location of a postMessage window, - // to enable postMessage transport uploads: - postMessage: undefined, - // By default, XHR file uploads are sent as multipart/form-data. - // The iframe transport is always using multipart/form-data. - // Set to false to enable non-multipart XHR uploads: - multipart: true, - // To upload large files in smaller chunks, set the following option - // to a preferred maximum chunk size. If set to 0, null or undefined, - // or the browser does not support the required Blob API, files will - // be uploaded as a whole. - maxChunkSize: undefined, - // When a non-multipart upload or a chunked multipart upload has been - // aborted, this option can be used to resume the upload by setting - // it to the size of the already uploaded bytes. This option is most - // useful when modifying the options object inside of the "add" or - // "send" callbacks, as the options are cloned for each file upload. - uploadedBytes: undefined, - // By default, failed (abort or error) file uploads are removed from the - // global progress calculation. Set the following option to false to - // prevent recalculating the global progress data: - recalculateProgress: true, - // Interval in milliseconds to calculate and trigger progress events: - progressInterval: 100, - // Interval in milliseconds to calculate progress bitrate: - bitrateInterval: 500, - // By default, uploads are started automatically when adding files: - autoUpload: true, - // By default, duplicate file names are expected to be handled on - // the server-side. If this is not possible (e.g. when uploading - // files directly to Amazon S3), the following option can be set to - // an empty object or an object mapping existing filenames, e.g.: - // { "image.jpg": true, "image (1).jpg": true } - // If it is set, all files will be uploaded with unique filenames, - // adding increasing number suffixes if necessary, e.g.: - // "image (2).jpg" - uniqueFilenames: undefined, - // Error and info messages: - messages: { - uploadedBytes: 'Uploaded bytes exceed file size' - }, - // Translation function, gets the message key to be translated - // and an object with context specific data as arguments: - i18n: function i18n(message, context) { - // eslint-disable-next-line no-param-reassign - message = this.messages[message] || message.toString(); - if (context) { - $.each(context, function (key, value) { - // eslint-disable-next-line no-param-reassign - message = message.replace('{' + key + '}', value); + bus.$on('mediaToggleRequested', function (media) { + self.toggleSelectionOfMedia(media); }); - } - return message; - }, - // Additional form data to be sent along with the file uploads can be set - // using this option, which accepts an array of objects with name and - // value properties, a function returning such an array, a FormData - // object (for XHR file uploads), or a simple object. - // The form of the first fileInput is given as parameter to the function: - formData: function formData(form) { - return form.serializeArray(); - }, - // The add callback is invoked as soon as files are added to the fileupload - // widget (via file input selection, drag & drop, paste or add API call). - // If the singleFileUploads option is enabled, this callback will be - // called once for each file in the selection for XHR file uploads, else - // once for each file selection. - // - // The upload starts when the submit method is invoked on the data parameter. - // The data object contains a files property holding the added files - // and allows you to override plugin options as well as define ajax settings. - // - // Listeners for this callback can also be bound the following way: - // .on('fileuploadadd', func); - // - // data.submit() returns a Promise object and allows to attach additional - // handlers using jQuery's Deferred callbacks: - // data.submit().done(func).fail(func).always(func); - add: function add(e, data) { - if (e.isDefaultPrevented()) { - return false; - } - if (data.autoUpload || data.autoUpload !== false && $(this).fileupload('option', 'autoUpload')) { - data.process().done(function () { - data.submit(); + bus.$on('renameMediaRequested', function (media) { + self.renameMedia(media); }); - } - }, - // Other callbacks: - - // Callback for the submit event of each file upload: - // submit: function (e, data) {}, // .on('fileuploadsubmit', func); - - // Callback for the start of each file upload request: - // send: function (e, data) {}, // .on('fileuploadsend', func); - - // Callback for successful uploads: - // done: function (e, data) {}, // .on('fileuploaddone', func); - - // Callback for failed (abort or error) uploads: - // fail: function (e, data) {}, // .on('fileuploadfail', func); - - // Callback for completed (success, abort or error) requests: - // always: function (e, data) {}, // .on('fileuploadalways', func); - - // Callback for upload progress events: - // progress: function (e, data) {}, // .on('fileuploadprogress', func); - - // Callback for global upload progress events: - // progressall: function (e, data) {}, // .on('fileuploadprogressall', func); - - // Callback for uploads start, equivalent to the global ajaxStart event: - // start: function (e) {}, // .on('fileuploadstart', func); - - // Callback for uploads stop, equivalent to the global ajaxStop event: - // stop: function (e) {}, // .on('fileuploadstop', func); - - // Callback for change events of the fileInput(s): - // change: function (e, data) {}, // .on('fileuploadchange', func); - - // Callback for paste events to the pasteZone(s): - // paste: function (e, data) {}, // .on('fileuploadpaste', func); - - // Callback for drop events of the dropZone(s): - // drop: function (e, data) {}, // .on('fileuploaddrop', func); - - // Callback for dragover events of the dropZone(s): - // dragover: function (e) {}, // .on('fileuploaddragover', func); - - // Callback before the start of each chunk upload request (before form data initialization): - // chunkbeforesend: function (e, data) {}, // .on('fileuploadchunkbeforesend', func); - - // Callback for the start of each chunk upload request: - // chunksend: function (e, data) {}, // .on('fileuploadchunksend', func); - - // Callback for successful chunk uploads: - // chunkdone: function (e, data) {}, // .on('fileuploadchunkdone', func); - - // Callback for failed (abort or error) chunk uploads: - // chunkfail: function (e, data) {}, // .on('fileuploadchunkfail', func); - - // Callback for completed (success, abort or error) chunk upload requests: - // chunkalways: function (e, data) {}, // .on('fileuploadchunkalways', func); - - // The plugin options are used as settings object for the ajax calls. - // The following are jQuery ajax settings required for the file uploads: - processData: false, - contentType: false, - cache: false, - timeout: 0 - }, - // jQuery versions before 1.8 require promise.pipe if the return value is - // used, as promise.then in older versions has a different behavior, see: - // https://blog.jquery.com/2012/08/09/jquery-1-8-released/ - // https://bugs.jquery.com/ticket/11010 - // https://github.com/blueimp/jQuery-File-Upload/pull/3435 - _promisePipe: function () { - var parts = $.fn.jquery.split('.'); - return Number(parts[0]) > 1 || Number(parts[1]) > 7 ? 'then' : 'pipe'; - }(), - // A list of options that require reinitializing event listeners and/or - // special initialization code: - _specialOptions: ['fileInput', 'dropZone', 'pasteZone', 'multipart', 'forceIframeTransport'], - _blobSlice: $.support.blobSlice && function () { - var slice = this.slice || this.webkitSlice || this.mozSlice; - return slice.apply(this, arguments); - }, - _BitrateTimer: function _BitrateTimer() { - this.timestamp = Date.now ? Date.now() : new Date().getTime(); - this.loaded = 0; - this.bitrate = 0; - this.getBitrate = function (now, loaded, interval) { - var timeDiff = now - this.timestamp; - if (!this.bitrate || !interval || timeDiff > interval) { - this.bitrate = (loaded - this.loaded) * (1000 / timeDiff) * 8; - this.loaded = loaded; - this.timestamp = now; - } - return this.bitrate; - }; - }, - _isXHRUpload: function _isXHRUpload(options) { - return !options.forceIframeTransport && (!options.multipart && $.support.xhrFileUpload || $.support.xhrFormDataFileUpload); - }, - _getFormData: function _getFormData(options) { - var formData; - if ($.type(options.formData) === 'function') { - return options.formData(options.form); - } - if ($.isArray(options.formData)) { - return options.formData; - } - if ($.type(options.formData) === 'object') { - formData = []; - $.each(options.formData, function (name, value) { - formData.push({ - name: name, - value: value + bus.$on('deleteMediaRequested', function (media) { + self.deleteMediaItem(media); }); - }); - return formData; - } - return []; - }, - _getTotal: function _getTotal(files) { - var total = 0; - $.each(files, function (index, file) { - total += file.size || 1; - }); - return total; - }, - _initProgressObject: function _initProgressObject(obj) { - var progress = { - loaded: 0, - total: 0, - bitrate: 0 - }; - if (obj._progress) { - $.extend(obj._progress, progress); - } else { - obj._progress = progress; - } - }, - _initResponseObject: function _initResponseObject(obj) { - var prop; - if (obj._response) { - for (prop in obj._response) { - if (Object.prototype.hasOwnProperty.call(obj._response, prop)) { - delete obj._response[prop]; + bus.$on('mediaDragStartRequested', function (media, e) { + self.handleDragStart(media, e); + }); + + // handler for pager events + bus.$on('pagerEvent', function (itemsInPage) { + self.itemsInPage = itemsInPage; + self.selectedMedias = []; + }); + if (!localStorage.getItem('mediaApplicationPrefs')) { + self.selectedFolder = _root; + return; } - } - } else { - obj._response = {}; - } - }, - _onProgress: function _onProgress(e, data) { - if (e.lengthComputable) { - var now = Date.now ? Date.now() : new Date().getTime(), - loaded; - if (data._time && data.progressInterval && now - data._time < data.progressInterval && e.loaded !== e.total) { - return; - } - data._time = now; - loaded = Math.floor(e.loaded / e.total * (data.chunkSize || data._progress.total)) + (data.uploadedBytes || 0); - // Add the difference from the previously loaded state - // to the global loaded counter: - this._progress.loaded += loaded - data._progress.loaded; - this._progress.bitrate = this._bitrateTimer.getBitrate(now, this._progress.loaded, data.bitrateInterval); - data._progress.loaded = data.loaded = loaded; - data._progress.bitrate = data.bitrate = data._bitrateTimer.getBitrate(now, loaded, data.bitrateInterval); - // Trigger a custom progress event with a total data property set - // to the file size(s) of the current upload and a loaded data - // property calculated accordingly: - this._trigger('progress', $.Event('progress', { - delegatedEvent: e - }), data); - // Trigger a global progress event for all current file uploads, - // including ajax calls queued for sequential file uploads: - this._trigger('progressall', $.Event('progressall', { - delegatedEvent: e - }), this._progress); - } - }, - _initProgressListener: function _initProgressListener(options) { - var that = this, - xhr = options.xhr ? options.xhr() : $.ajaxSettings.xhr(); - // Access to the native XHR object is required to add event listeners - // for the upload progress event: - if (xhr.upload) { - $(xhr.upload).on('progress', function (e) { - var oe = e.originalEvent; - // Make sure the progress event properties get copied over: - e.lengthComputable = oe.lengthComputable; - e.loaded = oe.loaded; - e.total = oe.total; - that._onProgress(e, options); - }); - options.xhr = function () { - return xhr; - }; - } - }, - _deinitProgressListener: function _deinitProgressListener(options) { - var xhr = options.xhr ? options.xhr() : $.ajaxSettings.xhr(); - if (xhr.upload) { - $(xhr.upload).off('progress'); - } - }, - _isInstanceOf: function _isInstanceOf(type, obj) { - // Cross-frame instanceof check - return Object.prototype.toString.call(obj) === '[object ' + type + ']'; - }, - _getUniqueFilename: function _getUniqueFilename(name, map) { - // eslint-disable-next-line no-param-reassign - name = String(name); - if (map[name]) { - // eslint-disable-next-line no-param-reassign - name = name.replace(/(?: \(([\d]+)\))?(\.[^.]+)?$/, function (_, p1, p2) { - var index = p1 ? Number(p1) + 1 : 1; - var ext = p2 || ''; - return ' (' + index + ')' + ext; - }); - return this._getUniqueFilename(name, map); - } - map[name] = true; - return name; - }, - _initXHRData: function _initXHRData(options) { - var that = this, - formData, - file = options.files[0], - // Ignore non-multipart setting if not supported: - multipart = options.multipart || !$.support.xhrFileUpload, - paramName = $.type(options.paramName) === 'array' ? options.paramName[0] : options.paramName; - options.headers = $.extend({}, options.headers); - if (options.contentRange) { - options.headers['Content-Range'] = options.contentRange; - } - if (!multipart || options.blob || !this._isInstanceOf('File', file)) { - options.headers['Content-Disposition'] = 'attachment; filename="' + encodeURI(file.uploadName || file.name) + '"'; - } - if (!multipart) { - options.contentType = file.type || 'application/octet-stream'; - options.data = options.blob || file; - } else if ($.support.xhrFormDataFileUpload) { - if (options.postMessage) { - // window.postMessage does not allow sending FormData - // objects, so we just add the File/Blob objects to - // the formData array and let the postMessage window - // create the FormData object out of this array: - formData = this._getFormData(options); - if (options.blob) { - formData.push({ - name: paramName, - value: options.blob - }); - } else { - $.each(options.files, function (index, file) { - formData.push({ - name: $.type(options.paramName) === 'array' && options.paramName[index] || paramName, - value: file - }); + self.currentPrefs = JSON.parse(localStorage.getItem('mediaApplicationPrefs')); + }, + computed: { + isHome: function isHome() { + return this.selectedFolder == _root; + }, + parents: function parents() { + var p = []; + parentFolder = this.selectedFolder; + while (parentFolder && parentFolder.path != '') { + p.unshift(parentFolder); + parentFolder = parentFolder.parent; + } + return p; + }, + root: function root() { + return _root; + }, + filteredMediaItems: function filteredMediaItems() { + var self = this; + self.selectedMedias = []; + var filtered = self.mediaItems.filter(function (item) { + return item.name.toLowerCase().indexOf(self.mediaFilter.toLowerCase()) > -1; }); + switch (self.sortBy) { + case 'size': + filtered.sort(function (a, b) { + return self.sortAsc ? a.size - b.size : b.size - a.size; + }); + break; + case 'mime': + filtered.sort(function (a, b) { + return self.sortAsc ? a.mime.toLowerCase().localeCompare(b.mime.toLowerCase()) : b.mime.toLowerCase().localeCompare(a.mime.toLowerCase()); + }); + break; + case 'lastModify': + filtered.sort(function (a, b) { + return self.sortAsc ? a.lastModify - b.lastModify : b.lastModify - a.lastModify; + }); + break; + default: + filtered.sort(function (a, b) { + return self.sortAsc ? a.name.toLowerCase().localeCompare(b.name.toLowerCase()) : b.name.toLowerCase().localeCompare(a.name.toLowerCase()); + }); + } + return filtered; + }, + hiddenCount: function hiddenCount() { + var result = 0; + result = this.mediaItems.length - this.filteredMediaItems.length; + return result; + }, + thumbSize: function thumbSize() { + return this.smallThumbs ? 100 : 240; + }, + currentPrefs: { + get: function get() { + return { + smallThumbs: this.smallThumbs, + selectedFolder: this.selectedFolder, + gridView: this.gridView + }; + }, + set: function set(newPrefs) { + if (!newPrefs) { + return; + } + this.smallThumbs = newPrefs.smallThumbs; + this.selectedFolder = newPrefs.selectedFolder; + this.gridView = newPrefs.gridView; + } } - } else { - if (that._isInstanceOf('FormData', options.formData)) { - formData = options.formData; - } else { - formData = new FormData(); - $.each(this._getFormData(options), function (index, field) { - formData.append(field.name, field.value); + }, + watch: { + currentPrefs: function currentPrefs(newPrefs) { + localStorage.setItem('mediaApplicationPrefs', JSON.stringify(newPrefs)); + }, + selectedFolder: function selectedFolder(newFolder) { + this.mediaFilter = ''; + this.selectedFolder = newFolder; + this.loadFolder(newFolder); + } + }, + mounted: function mounted() { + this.$refs.rootFolder.toggle(); + }, + methods: { + uploadUrl: function uploadUrl() { + if (!this.selectedFolder) { + return null; + } + var urlValue = $('#uploadFiles').val(); + return urlValue + (urlValue.indexOf('?') == -1 ? '?' : '&') + "path=" + encodeURIComponent(this.selectedFolder.path); + }, + selectRoot: function selectRoot() { + this.selectedFolder = this.root; + }, + loadFolder: function loadFolder(folder) { + this.errors = []; + this.selectedMedias = []; + var self = this; + var mediaUrl = $('#getMediaItemsUrl').val(); + console.log(folder.path); + $.ajax({ + url: mediaUrl + (mediaUrl.indexOf('?') == -1 ? '?' : '&') + "path=" + encodeURIComponent(folder.path), + method: 'GET', + success: function success(data) { + data.forEach(function (item) { + item.open = false; + }); + self.mediaItems = data; + self.selectedMedias = []; + self.sortBy = ''; + self.sortAsc = true; + }, + error: function error(_error) { + console.log('error loading folder:' + folder.path); + self.selectRoot(); + } + }); + }, + selectAll: function selectAll() { + this.selectedMedias = []; + for (var i = 0; i < this.filteredMediaItems.length; i++) { + this.selectedMedias.push(this.filteredMediaItems[i]); + } + }, + unSelectAll: function unSelectAll() { + this.selectedMedias = []; + }, + invertSelection: function invertSelection() { + var temp = []; + for (var i = 0; i < this.filteredMediaItems.length; i++) { + if (this.isMediaSelected(this.filteredMediaItems[i]) == false) { + temp.push(this.filteredMediaItems[i]); + } + } + this.selectedMedias = temp; + }, + toggleSelectionOfMedia: function toggleSelectionOfMedia(media) { + if (this.isMediaSelected(media) == true) { + this.selectedMedias.splice(this.selectedMedias.indexOf(media), 1); + } else { + this.selectedMedias.push(media); + } + }, + isMediaSelected: function isMediaSelected(media) { + var result = this.selectedMedias.some(function (element, index, array) { + return element.url.toLowerCase() === media.url.toLowerCase(); }); - } - if (options.blob) { - formData.append(paramName, options.blob, file.uploadName || file.name); - } else { - $.each(options.files, function (index, file) { - // This check allows the tests to run with - // dummy objects: - if (that._isInstanceOf('File', file) || that._isInstanceOf('Blob', file)) { - var fileName = file.uploadName || file.name; - if (options.uniqueFilenames) { - fileName = that._getUniqueFilename(fileName, options.uniqueFilenames); + return result; + }, + deleteFolder: function deleteFolder() { + var folder = this.selectedFolder; + var self = this; + // The root folder can't be deleted + if (folder == this.root.model) { + return; + } + confirmDialog(_objectSpread(_objectSpread({}, $("#deleteFolder").data()), {}, { + callback: function callback(resp) { + if (resp) { + $.ajax({ + url: $('#deleteFolderUrl').val() + "?path=" + encodeURIComponent(folder.path), + method: 'POST', + data: { + __RequestVerificationToken: $("input[name='__RequestVerificationToken']").val() + }, + success: function success(data) { + bus.$emit('deleteFolder', folder); + }, + error: function error(_error2) { + console.error(_error2.responseText); + } + }); } - formData.append($.type(options.paramName) === 'array' && options.paramName[index] || paramName, file, fileName); } - }); - } - } - options.data = formData; - } - // Blob reference is not needed anymore, free memory: - options.blob = null; - }, - _initIframeSettings: function _initIframeSettings(options) { - var targetHost = $('').prop('href', options.url).prop('host'); - // Setting the dataType to iframe enables the iframe transport: - options.dataType = 'iframe ' + (options.dataType || ''); - // The iframe transport accepts a serialized array as form data: - options.formData = this._getFormData(options); - // Add redirect url to form data on cross-domain uploads: - if (options.redirect && targetHost && targetHost !== location.host) { - options.formData.push({ - name: options.redirectParamName || 'redirect', - value: options.redirect - }); - } - }, - _initDataSettings: function _initDataSettings(options) { - if (this._isXHRUpload(options)) { - if (!this._chunkedUpload(options, true)) { - if (!options.data) { - this._initXHRData(options); - } - this._initProgressListener(options); - } - if (options.postMessage) { - // Setting the dataType to postmessage enables the - // postMessage transport: - options.dataType = 'postmessage ' + (options.dataType || ''); - } - } else { - this._initIframeSettings(options); - } - }, - _getParamName: function _getParamName(options) { - var fileInput = $(options.fileInput), - paramName = options.paramName; - if (!paramName) { - paramName = []; - fileInput.each(function () { - var input = $(this), - name = input.prop('name') || 'files[]', - i = (input.prop('files') || [1]).length; - while (i) { - paramName.push(name); - i -= 1; - } - }); - if (!paramName.length) { - paramName = [fileInput.prop('name') || 'files[]']; - } - } else if (!$.isArray(paramName)) { - paramName = [paramName]; - } - return paramName; - }, - _initFormSettings: function _initFormSettings(options) { - // Retrieve missing options from the input field and the - // associated form, if available: - if (!options.form || !options.form.length) { - options.form = $(options.fileInput.prop('form')); - // If the given file input doesn't have an associated form, - // use the default widget file input's form: - if (!options.form.length) { - options.form = $(this.options.fileInput.prop('form')); - } - } - options.paramName = this._getParamName(options); - if (!options.url) { - options.url = options.form.prop('action') || location.href; - } - // The HTTP request method must be "POST" or "PUT": - options.type = (options.type || $.type(options.form.prop('method')) === 'string' && options.form.prop('method') || '').toUpperCase(); - if (options.type !== 'POST' && options.type !== 'PUT' && options.type !== 'PATCH') { - options.type = 'POST'; - } - if (!options.formAcceptCharset) { - options.formAcceptCharset = options.form.attr('accept-charset'); - } - }, - _getAJAXSettings: function _getAJAXSettings(data) { - var options = $.extend({}, this.options, data); - this._initFormSettings(options); - this._initDataSettings(options); - return options; - }, - // jQuery 1.6 doesn't provide .state(), - // while jQuery 1.8+ removed .isRejected() and .isResolved(): - _getDeferredState: function _getDeferredState(deferred) { - if (deferred.state) { - return deferred.state(); - } - if (deferred.isResolved()) { - return 'resolved'; - } - if (deferred.isRejected()) { - return 'rejected'; - } - return 'pending'; - }, - // Maps jqXHR callbacks to the equivalent - // methods of the given Promise object: - _enhancePromise: function _enhancePromise(promise) { - promise.success = promise.done; - promise.error = promise.fail; - promise.complete = promise.always; - return promise; - }, - // Creates and returns a Promise object enhanced with - // the jqXHR methods abort, success, error and complete: - _getXHRPromise: function _getXHRPromise(resolveOrReject, context, args) { - var dfd = $.Deferred(), - promise = dfd.promise(); - // eslint-disable-next-line no-param-reassign - context = context || this.options.context || promise; - if (resolveOrReject === true) { - dfd.resolveWith(context, args); - } else if (resolveOrReject === false) { - dfd.rejectWith(context, args); - } - promise.abort = dfd.promise; - return this._enhancePromise(promise); - }, - // Adds convenience methods to the data callback argument: - _addConvenienceMethods: function _addConvenienceMethods(e, data) { - var that = this, - getPromise = function getPromise(args) { - return $.Deferred().resolveWith(that, args).promise(); - }; - data.process = function (resolveFunc, rejectFunc) { - if (resolveFunc || rejectFunc) { - data._processQueue = this._processQueue = (this._processQueue || getPromise([this]))[that._promisePipe](function () { - if (data.errorThrown) { - return $.Deferred().rejectWith(that, [data]).promise(); + })); + }, + createFolder: function createFolder() { + $('#createFolderModal-errors').empty(); + var modal = bootstrap.Modal.getOrCreateInstance($('#createFolderModal')); + modal.show(); + $('#createFolderModal .modal-body input').val('').focus(); + }, + renameMedia: function renameMedia(media) { + $('#renameMediaModal-errors').empty(); + var modal = bootstrap.Modal.getOrCreateInstance($('#renameMediaModal')); + modal.show(); + $('#old-item-name').val(media.name); + $('#renameMediaModal .modal-body input').val(media.name).focus(); + }, + selectAndDeleteMedia: function selectAndDeleteMedia(media) { + this.deleteMedia(); + }, + deleteMediaList: function deleteMediaList() { + var mediaList = this.selectedMedias; + var self = this; + if (mediaList.length < 1) { + return; + } + confirmDialog(_objectSpread(_objectSpread({}, $("#deleteMedia").data()), {}, { + callback: function callback(resp) { + if (resp) { + var paths = []; + for (var i = 0; i < mediaList.length; i++) { + paths.push(mediaList[i].mediaPath); + } + $.ajax({ + url: $('#deleteMediaListUrl').val(), + method: 'POST', + data: { + __RequestVerificationToken: $("input[name='__RequestVerificationToken']").val(), + paths: paths + }, + success: function success(data) { + for (var i = 0; i < self.selectedMedias.length; i++) { + var index = self.mediaItems && self.mediaItems.indexOf(self.selectedMedias[i]); + if (index > -1) { + self.mediaItems.splice(index, 1); + bus.$emit('mediaDeleted', self.selectedMedias[i]); + } + } + self.selectedMedias = []; + }, + error: function error(_error3) { + console.error(_error3.responseText); + } + }); + } + } + })); + }, + deleteMediaItem: function deleteMediaItem(media) { + var self = this; + if (!media) { + return; + } + confirmDialog(_objectSpread(_objectSpread({}, $("#deleteMedia").data()), {}, { + callback: function callback(resp) { + if (resp) { + $.ajax({ + url: $('#deleteMediaUrl').val() + "?path=" + encodeURIComponent(media.mediaPath), + method: 'POST', + data: { + __RequestVerificationToken: $("input[name='__RequestVerificationToken']").val() + }, + success: function success(data) { + var index = self.mediaItems && self.mediaItems.indexOf(media); + if (index > -1) { + self.mediaItems.splice(index, 1); + bus.$emit('mediaDeleted', media); + } + //self.selectedMedia = null; + }, + + error: function error(_error4) { + console.error(_error4.responseText); + } + }); + } + } + })); + }, + handleDragStart: function handleDragStart(media, e) { + // first part of move media to folder: + // prepare the data that will be handled by the folder component on drop event + var mediaNames = []; + this.selectedMedias.forEach(function (item) { + mediaNames.push(item.name); + }); + + // in case the user drags an unselected item, we select it first + if (this.isMediaSelected(media) == false) { + mediaNames.push(media.name); + this.selectedMedias.push(media); } - return getPromise(arguments); - })[that._promisePipe](resolveFunc, rejectFunc); - } - return this._processQueue || getPromise([this]); - }; - data.submit = function () { - if (this.state() !== 'pending') { - data.jqXHR = this.jqXHR = that._trigger('submit', $.Event('submit', { - delegatedEvent: e - }), this) !== false && that._onSend(e, this); - } - return this.jqXHR || that._getXHRPromise(); - }; - data.abort = function () { - if (this.jqXHR) { - return this.jqXHR.abort(); + e.dataTransfer.setData('mediaNames', JSON.stringify(mediaNames)); + e.dataTransfer.setData('sourceFolder', this.selectedFolder.path); + e.dataTransfer.setDragImage(this.dragDropThumbnail, 10, 10); + e.dataTransfer.effectAllowed = 'move'; + }, + handleScrollWhileDrag: function handleScrollWhileDrag(e) { + if (e.clientY < 150) { + window.scrollBy(0, -10); + } + if (e.clientY > window.innerHeight - 100) { + window.scrollBy(0, 10); + } + }, + changeSort: function changeSort(newSort) { + if (this.sortBy == newSort) { + this.sortAsc = !this.sortAsc; + } else { + this.sortAsc = true; + this.sortBy = newSort; + } + } } - this.errorThrown = 'abort'; - that._trigger('fail', null, this); - return that._getXHRPromise(false); - }; - data.state = function () { - if (this.jqXHR) { - return that._getDeferredState(this.jqXHR); + }); + $('#create-folder-name').keypress(function (e) { + var key = e.which; + if (key == 13) { + // the enter key code + $('#modalFooterOk').click(); + return false; } - if (this._processQueue) { - return that._getDeferredState(this._processQueue); + }); + $('#modalFooterOk').on('click', function (e) { + var name = $('#create-folder-name').val(); + if (name === "") { + return; } - }; - data.processing = function () { - return !this.jqXHR && this._processQueue && that._getDeferredState(this._processQueue) === 'pending'; - }; - data.progress = function () { - return this._progress; - }; - data.response = function () { - return this._response; - }; - }, - // Parses the Range header from the server response - // and returns the uploaded bytes: - _getUploadedBytes: function _getUploadedBytes(jqXHR) { - var range = jqXHR.getResponseHeader('Range'), - parts = range && range.split('-'), - upperBytesPos = parts && parts.length > 1 && parseInt(parts[1], 10); - return upperBytesPos && upperBytesPos + 1; - }, - // Uploads a file in multiple, sequential requests - // by splitting the file up in multiple blob chunks. - // If the second parameter is true, only tests if the file - // should be uploaded in chunks, but does not invoke any - // upload requests: - _chunkedUpload: function _chunkedUpload(options, testOnly) { - options.uploadedBytes = options.uploadedBytes || 0; - var that = this, - file = options.files[0], - fs = file.size, - ub = options.uploadedBytes, - mcs = options.maxChunkSize || fs, - slice = this._blobSlice, - dfd = $.Deferred(), - promise = dfd.promise(), - jqXHR, - _upload; - if (!(this._isXHRUpload(options) && slice && (ub || ($.type(mcs) === 'function' ? mcs(options) : mcs) < fs)) || options.data) { - return false; - } - if (testOnly) { - return true; - } - if (ub >= fs) { - file.error = options.i18n('uploadedBytes'); - return this._getXHRPromise(false, options.context, [null, 'error', file.error]); - } - // The chunk upload method: - _upload = function upload() { - // Clone the options object for each chunk upload: - var o = $.extend({}, options), - currentLoaded = o._progress.loaded; - o.blob = slice.call(file, ub, ub + ($.type(mcs) === 'function' ? mcs(o) : mcs), file.type); - // Store the current chunk size, as the blob itself - // will be dereferenced after data processing: - o.chunkSize = o.blob.size; - // Expose the chunk bytes position range: - o.contentRange = 'bytes ' + ub + '-' + (ub + o.chunkSize - 1) + '/' + fs; - // Trigger chunkbeforesend to allow form data to be updated for this chunk - that._trigger('chunkbeforesend', null, o); - // Process the upload data (the blob and potential form data): - that._initXHRData(o); - // Add progress listeners for this chunk upload: - that._initProgressListener(o); - jqXHR = (that._trigger('chunksend', null, o) !== false && $.ajax(o) || that._getXHRPromise(false, o.context)).done(function (result, textStatus, jqXHR) { - ub = that._getUploadedBytes(jqXHR) || ub + o.chunkSize; - // Create a progress event if no final progress event - // with loaded equaling total has been triggered - // for this chunk: - if (currentLoaded + o.chunkSize - o._progress.loaded) { - that._onProgress($.Event('progress', { - lengthComputable: true, - loaded: ub - o.uploadedBytes, - total: ub - o.uploadedBytes - }), o); - } - options.uploadedBytes = o.uploadedBytes = ub; - o.result = result; - o.textStatus = textStatus; - o.jqXHR = jqXHR; - that._trigger('chunkdone', null, o); - that._trigger('chunkalways', null, o); - if (ub < fs) { - // File upload not yet complete, - // continue with the next chunk: - _upload(); - } else { - dfd.resolveWith(o.context, [result, textStatus, jqXHR]); + $.ajax({ + url: $('#createFolderUrl').val() + "?path=" + encodeURIComponent(mediaApp.selectedFolder.path) + "&name=" + encodeURIComponent(name), + method: 'POST', + data: { + __RequestVerificationToken: $("input[name='__RequestVerificationToken']").val() + }, + success: function success(data) { + bus.$emit('addFolder', mediaApp.selectedFolder, data); + var modal = bootstrap.Modal.getOrCreateInstance($('#createFolderModal')); + modal.hide(); + }, + error: function error(_error5) { + $('#createFolderModal-errors').empty(); + var errorMessage = JSON.parse(_error5.responseText).value; + $('').text(errorMessage).appendTo($('#createFolderModal-errors')); } - }).fail(function (jqXHR, textStatus, errorThrown) { - o.jqXHR = jqXHR; - o.textStatus = textStatus; - o.errorThrown = errorThrown; - that._trigger('chunkfail', null, o); - that._trigger('chunkalways', null, o); - dfd.rejectWith(o.context, [jqXHR, textStatus, errorThrown]); - }).always(function () { - that._deinitProgressListener(o); }); - }; - this._enhancePromise(promise); - promise.abort = function () { - return jqXHR.abort(); - }; - _upload(); - return promise; - }, - _beforeSend: function _beforeSend(e, data) { - if (this._active === 0) { - // the start callback is triggered when an upload starts - // and no other uploads are currently running, - // equivalent to the global ajaxStart event: - this._trigger('start'); - // Set timer for global bitrate progress calculation: - this._bitrateTimer = new this._BitrateTimer(); - // Reset the global progress values: - this._progress.loaded = this._progress.total = 0; - this._progress.bitrate = 0; + }); + $('#renameMediaModalFooterOk').on('click', function (e) { + var newName = $('#new-item-name').val(); + var oldName = $('#old-item-name').val(); + if (newName === "") { + return; + } + var currentFolder = mediaApp.selectedFolder.path + "/"; + if (currentFolder === "/") { + currentFolder = ""; + } + var newPath = currentFolder + newName; + var oldPath = currentFolder + oldName; + if (newPath.toLowerCase() === oldPath.toLowerCase()) { + var modal = bootstrap.Modal.getOrCreateInstance($('#renameMediaModal')); + modal.hide(); + return; + } + $.ajax({ + url: $('#renameMediaUrl').val() + "?oldPath=" + encodeURIComponent(oldPath) + "&newPath=" + encodeURIComponent(newPath), + method: 'POST', + data: { + __RequestVerificationToken: $("input[name='__RequestVerificationToken']").val() + }, + success: function success(data) { + var modal = bootstrap.Modal.getOrCreateInstance($('#renameMediaModal')); + modal.hide(); + bus.$emit('mediaRenamed', newName, newPath, oldPath, data.newUrl); + }, + error: function error(_error6) { + $('#renameMediaModal-errors').empty(); + var errorMessage = JSON.parse(_error6.responseText).value; + $('').text(errorMessage).appendTo($('#renameMediaModal-errors')); + } + }); + }); + if (displayMediaApplication) { + document.getElementById('mediaApp').style.display = ""; } - // Make sure the container objects for the .response() and - // .progress() methods on the data object are available - // and reset to their initial state: - this._initResponseObject(data); - this._initProgressObject(data); - data._progress.loaded = data.loaded = data.uploadedBytes || 0; - data._progress.total = data.total = this._getTotal(data.files) || 1; - data._progress.bitrate = data.bitrate = 0; - this._active += 1; - // Initialize the global progress values: - this._progress.loaded += data.loaded; - this._progress.total += data.total; + $(document).trigger('mediaApp:ready'); }, - _onDone: function _onDone(result, textStatus, jqXHR, options) { - var total = options._progress.total, - response = options._response; - if (options._progress.loaded < total) { - // Create a progress event if no final progress event - // with loaded equaling total has been triggered: - this._onProgress($.Event('progress', { - lengthComputable: true, - loaded: total, - total: total - }), options); - } - response.result = options.result = result; - response.textStatus = options.textStatus = textStatus; - response.jqXHR = options.jqXHR = jqXHR; - this._trigger('done', null, options); + error: function error(_error7) { + console.error(_error7.responseText); + } + }); +} +$(document).on('mediaApp:ready', function () { + var chunkedFileUploadId = randomUUID(); + $('#fileupload').fileupload({ + dropZone: $('#mediaApp'), + limitConcurrentUploads: 20, + dataType: 'json', + url: $('#uploadFiles').val(), + maxChunkSize: Number($('#maxUploadChunkSize').val() || 0), + formData: function formData() { + var antiForgeryToken = $("input[name=__RequestVerificationToken]").val(); + return [{ + name: 'path', + value: mediaApp.selectedFolder.path + }, { + name: '__RequestVerificationToken', + value: antiForgeryToken + }, { + name: '__chunkedFileUploadId', + value: chunkedFileUploadId + }]; }, - _onFail: function _onFail(jqXHR, textStatus, errorThrown, options) { - var response = options._response; - if (options.recalculateProgress) { - // Remove the failed (error or abort) file upload from - // the global progress calculation: - this._progress.loaded -= options._progress.loaded; - this._progress.total -= options._progress.total; - } - response.jqXHR = options.jqXHR = jqXHR; - response.textStatus = options.textStatus = textStatus; - response.errorThrown = options.errorThrown = errorThrown; - this._trigger('fail', null, options); + done: function done(e, data) { + $.each(data.result.files, function (index, file) { + if (!file.error) { + mediaApp.mediaItems.push(file); + } + }); + } + }).on('fileuploadchunkbeforesend', function (e, options) { + var file = options.files[0]; + // Here we replace the blob with a File object to ensure the file name and others are preserved for the backend. + options.blob = new File([options.blob], file.name, { + type: file.type, + lastModified: file.lastModified + }); + }); +}); +$(document).bind('dragover', function (e) { + var dt = e.originalEvent.dataTransfer; + if (dt.types && (dt.types.indexOf ? dt.types.indexOf('Files') != -1 : dt.types.contains('Files'))) { + var dropZone = $('#customdropzone'), + timeout = window.dropZoneTimeout; + if (timeout) { + clearTimeout(timeout); + } else { + dropZone.addClass('in'); + } + var hoveredDropZone = $(e.target).closest(dropZone); + window.dropZoneTimeout = setTimeout(function () { + window.dropZoneTimeout = null; + dropZone.removeClass('in'); + }, 100); + } +}); +function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); } +function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } +function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } +function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } +function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return _typeof(key) === "symbol" ? key : String(key); } +function _toPrimitive(input, hint) { if (_typeof(input) !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (_typeof(res) !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); } +// component +Vue.component('folder', { + template: "\n
  • \n \n
      \n \n \n
    \n
  • \n "), + props: { + model: Object, + selectedInMediaApp: Object, + level: Number + }, + data: function data() { + return { + open: false, + children: null, + // not initialized state (for lazy-loading) + parent: null, + isHovered: false, + padding: 0 + }; + }, + computed: { + empty: function empty() { + return !this.children || this.children.length == 0; }, - _onAlways: function _onAlways(jqXHRorResult, textStatus, jqXHRorError, options) { - // jqXHRorResult, textStatus and jqXHRorError are added to the - // options object via done and fail callbacks - this._trigger('always', null, options); + isSelected: function isSelected() { + return this.selectedInMediaApp.name == this.model.name && this.selectedInMediaApp.path == this.model.path; }, - _onSend: function _onSend(e, data) { - if (!data.submit) { - this._addConvenienceMethods(e, data); + isRoot: function isRoot() { + return this.model.path === ''; + }, + canCreateFolder: function canCreateFolder() { + return this.model.canCreateFolder !== undefined ? this.model.canCreateFolder : true; + }, + canDeleteFolder: function canDeleteFolder() { + return this.model.canDeleteFolder !== undefined ? this.model.canDeleteFolder : true; + } + }, + mounted: function mounted() { + if (this.isRoot == false && this.isAncestorOfSelectedFolder()) { + this.toggle(); + } + this.padding = this.level < 3 ? 16 : 16 + this.level * 8; + }, + created: function created() { + var self = this; + bus.$on('deleteFolder', function (folder) { + if (self.children) { + var index = self.children && self.children.indexOf(folder); + if (index > -1) { + self.children.splice(index, 1); + bus.$emit('folderDeleted'); + } } - var that = this, - jqXHR, - aborted, - slot, - pipe, - options = that._getAJAXSettings(data), - send = function send() { - that._sending += 1; - // Set timer for bitrate progress calculation: - options._bitrateTimer = new that._BitrateTimer(); - jqXHR = jqXHR || ((aborted || that._trigger('send', $.Event('send', { - delegatedEvent: e - }), options) === false) && that._getXHRPromise(false, options.context, aborted) || that._chunkedUpload(options) || $.ajax(options)).done(function (result, textStatus, jqXHR) { - that._onDone(result, textStatus, jqXHR, options); - }).fail(function (jqXHR, textStatus, errorThrown) { - that._onFail(jqXHR, textStatus, errorThrown, options); - }).always(function (jqXHRorResult, textStatus, jqXHRorError) { - that._deinitProgressListener(options); - that._onAlways(jqXHRorResult, textStatus, jqXHRorError, options); - that._sending -= 1; - that._active -= 1; - if (options.limitConcurrentUploads && options.limitConcurrentUploads > that._sending) { - // Start the next queued upload, - // that has not been aborted: - var nextSlot = that._slots.shift(); - while (nextSlot) { - if (that._getDeferredState(nextSlot) === 'pending') { - nextSlot.resolve(); - break; - } - nextSlot = that._slots.shift(); - } - } - if (that._active === 0) { - // The stop callback is triggered when all uploads have - // been completed, equivalent to the global ajaxStop event: - that._trigger('stop'); - } - }); - return jqXHR; - }; - this._beforeSend(e, options); - if (this.options.sequentialUploads || this.options.limitConcurrentUploads && this.options.limitConcurrentUploads <= this._sending) { - if (this.options.limitConcurrentUploads > 1) { - slot = $.Deferred(); - this._slots.push(slot); - pipe = slot[that._promisePipe](send); - } else { - this._sequence = this._sequence[that._promisePipe](send, send); - pipe = this._sequence; + }); + bus.$on('addFolder', function (target, folder) { + if (self.model == target) { + if (self.children !== null) { + self.children.push(folder); } - // Return the piped Promise object, enhanced with an abort method, - // which is delegated to the jqXHR object of the current upload, - // and jqXHR callbacks mapped to the equivalent Promise methods: - pipe.abort = function () { - aborted = [undefined, 'abort', 'abort']; - if (!jqXHR) { - if (slot) { - slot.rejectWith(options.context, aborted); - } - return send(); - } - return jqXHR.abort(); - }; - return this._enhancePromise(pipe); + folder.parent = self.model; + bus.$emit('folderAdded', folder); + } + }); + }, + methods: { + isAncestorOfSelectedFolder: function isAncestorOfSelectedFolder() { + parentFolder = mediaApp.selectedFolder; + while (parentFolder) { + if (parentFolder.path == this.model.path) { + return true; + } + parentFolder = parentFolder.parent; + } + return false; + }, + toggle: function toggle() { + this.open = !this.open; + if (this.open && !this.children) { + this.loadChildren(); } - return send(); }, - _onAdd: function _onAdd(e, data) { - var that = this, - result = true, - options = $.extend({}, this.options, data), - files = data.files, - filesLength = files.length, - limit = options.limitMultiFileUploads, - limitSize = options.limitMultiFileUploadSize, - overhead = options.limitMultiFileUploadSizeOverhead, - batchSize = 0, - paramName = this._getParamName(options), - paramNameSet, - paramNameSlice, - fileSet, - i, - j = 0; - if (!filesLength) { - return false; - } - if (limitSize && files[0].size === undefined) { - limitSize = undefined; + select: function select() { + bus.$emit('folderSelected', this.model); + this.loadChildren(); + }, + createFolder: function createFolder() { + bus.$emit('createFolderRequested'); + }, + deleteFolder: function deleteFolder() { + bus.$emit('deleteFolderRequested'); + }, + loadChildren: function loadChildren() { + var self = this; + if (this.open == false) { + this.open = true; } - if (!(options.singleFileUploads || limit || limitSize) || !this._isXHRUpload(options)) { - fileSet = [files]; - paramNameSet = [paramName]; - } else if (!(options.singleFileUploads || limitSize) && limit) { - fileSet = []; - paramNameSet = []; - for (i = 0; i < filesLength; i += limit) { - fileSet.push(files.slice(i, i + limit)); - paramNameSlice = paramName.slice(i, i + limit); - if (!paramNameSlice.length) { - paramNameSlice = paramName; - } - paramNameSet.push(paramNameSlice); + $.ajax({ + url: $('#getFoldersUrl').val() + "?path=" + encodeURIComponent(self.model.path), + method: 'GET', + success: function success(data) { + self.children = data; + self.children.forEach(function (c) { + c.parent = self.model; + }); + }, + error: function error(_error) { + emtpy = false; + console.error(_error.responseText); } - } else if (!options.singleFileUploads && limitSize) { - fileSet = []; - paramNameSet = []; - for (i = 0; i < filesLength; i = i + 1) { - batchSize += files[i].size + overhead; - if (i + 1 === filesLength || batchSize + files[i + 1].size + overhead > limitSize || limit && i + 1 - j >= limit) { - fileSet.push(files.slice(j, i + 1)); - paramNameSlice = paramName.slice(j, i + 1); - if (!paramNameSlice.length) { - paramNameSlice = paramName; - } - paramNameSet.push(paramNameSlice); - j = i + 1; - batchSize = 0; + }); + }, + handleDragOver: function handleDragOver(e) { + this.isHovered = true; + }, + handleDragLeave: function handleDragLeave(e) { + this.isHovered = false; + }, + moveMediaToFolder: function moveMediaToFolder(folder, e) { + var self = this; + self.isHovered = false; + var mediaNames = JSON.parse(e.dataTransfer.getData('mediaNames')); + if (mediaNames.length < 1) { + return; + } + var sourceFolder = e.dataTransfer.getData('sourceFolder'); + var targetFolder = folder.path; + if (sourceFolder === '') { + sourceFolder = 'root'; + } + if (targetFolder === '') { + targetFolder = 'root'; + } + if (sourceFolder === targetFolder) { + alert($('#sameFolderMessage').val()); + return; + } + confirmDialog(_objectSpread(_objectSpread({}, $("#moveMedia").data()), {}, { + callback: function callback(resp) { + if (resp) { + $.ajax({ + url: $('#moveMediaListUrl').val(), + method: 'POST', + data: { + __RequestVerificationToken: $("input[name='__RequestVerificationToken']").val(), + mediaNames: mediaNames, + sourceFolder: sourceFolder, + targetFolder: targetFolder + }, + success: function success() { + bus.$emit('mediaListMoved'); // MediaApp will listen to this, and then it will reload page so the moved medias won't be there anymore + }, + + error: function error(_error2) { + console.error(_error2.responseText); + bus.$emit('mediaListMoved', _error2.responseText); + } + }); } } - } else { - paramNameSet = paramName; - } - data.originalFiles = files; - $.each(fileSet || files, function (index, element) { - var newData = $.extend({}, data); - newData.files = fileSet ? element : [element]; - newData.paramName = paramNameSet[index]; - that._initResponseObject(newData); - that._initProgressObject(newData); - that._addConvenienceMethods(e, newData); - result = that._trigger('add', $.Event('add', { - delegatedEvent: e - }), newData); - return result; + })); + } + } +}); +// https://github.com/spatie/font-awesome-filetypes + +var faIcons = { + image: 'fa-regular fa-image', + pdf: 'fa-regular fa-file-pdf', + word: 'fa-regular fa-file-word', + powerpoint: 'fa-regular fa-file-powerpoint', + excel: 'fa-regular fa-file-excel', + csv: 'fa-regular fa-file', + audio: 'fa-regular fa-file-audio', + video: 'fa-regular fa-file-video', + archive: 'fa-regular fa-file-zipper', + code: 'fa-regular fa-file-code', + text: 'fa-regular fa-file-lines', + file: 'fa-regular fa-file' +}; +var faThumbnails = { + gif: faIcons.image, + jpeg: faIcons.image, + jpg: faIcons.image, + png: faIcons.image, + pdf: faIcons.pdf, + doc: faIcons.word, + docx: faIcons.word, + ppt: faIcons.powerpoint, + pptx: faIcons.powerpoint, + xls: faIcons.excel, + xlsx: faIcons.excel, + csv: faIcons.csv, + aac: faIcons.audio, + mp3: faIcons.audio, + ogg: faIcons.audio, + avi: faIcons.video, + flv: faIcons.video, + mkv: faIcons.video, + mp4: faIcons.video, + webm: faIcons.video, + gz: faIcons.archive, + zip: faIcons.archive, + css: faIcons.code, + html: faIcons.code, + js: faIcons.code, + txt: faIcons.text +}; +function getClassNameForExtension(extension) { + return faThumbnails[extension.toLowerCase()] || faIcons.file; +} +function getExtensionForFilename(filename) { + return filename.slice((filename.lastIndexOf('.') - 1 >>> 0) + 2); +} +function getClassNameForFilename(filename) { + return getClassNameForExtension(getExtensionForFilename(filename)); +} +// component +Vue.component('media-items-grid', { + template: "\n
      \n
    1. \n
      \n \n \n
      \n
      \n \n \n \n {{ media.name }}\n
      \n
    2. \n
    \n ", + data: function data() { + return { + T: {} + }; + }, + props: { + filteredMediaItems: Array, + selectedMedias: Array, + thumbSize: Number + }, + created: function created() { + var self = this; + // retrieving localized strings from view + self.T.editButton = $('#t-edit-button').val(); + self.T.deleteButton = $('#t-delete-button').val(); + }, + methods: { + isMediaSelected: function isMediaSelected(media) { + var result = this.selectedMedias.some(function (element, index, array) { + return element.url.toLowerCase() === media.url.toLowerCase(); + }); + return result; + }, + buildMediaUrl: function buildMediaUrl(url, thumbSize) { + return url + (url.indexOf('?') == -1 ? '?' : '&') + 'width=' + thumbSize + '&height=' + thumbSize; + }, + toggleSelectionOfMedia: function toggleSelectionOfMedia(media) { + bus.$emit('mediaToggleRequested', media); + }, + renameMedia: function renameMedia(media) { + bus.$emit('renameMediaRequested', media); + }, + deleteMedia: function deleteMedia(media) { + bus.$emit('deleteMediaRequested', media); + }, + dragStart: function dragStart(media, e) { + bus.$emit('mediaDragStartRequested', media, e); + }, + getfontAwesomeClassNameForFileName: function getfontAwesomeClassNameForFilename(filename, thumbsize) { + return getClassNameForFilename(filename) + ' ' + thumbsize; + } + } +}); +// component +Vue.component('media-items-table', { + template: "\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
    {{ T.imageHeader }}\n {{ T.nameHeader }}\n \n \n {{ T.lastModifyHeader }} \n \n \n \n {{ T.sizeHeader }}\n \n \n \n \n {{ T.typeHeader }}\n \n \n
    \n
    \n \n \n
    \n
    \n \n \n
    {{ printDateTime(media.lastModify) }}
    \n
    \n
    {{ isNaN(media.size)? 0 : Math.round(media.size / 1024) }} KB
    \n
    \n
    {{ media.mime }}
    \n
    \n ", + data: function data() { + return { + T: {} + }; + }, + props: { + sortBy: String, + sortAsc: Boolean, + filteredMediaItems: Array, + selectedMedias: Array, + thumbSize: Number + }, + created: function created() { + var self = this; + self.T.imageHeader = $('#t-image-header').val(); + self.T.nameHeader = $('#t-name-header').val(); + self.T.lastModifyHeader = $('#t-lastModify-header').val(); + self.T.sizeHeader = $('#t-size-header').val(); + self.T.typeHeader = $('#t-type-header').val(); + self.T.editButton = $('#t-edit-button').val(); + self.T.deleteButton = $('#t-delete-button').val(); + self.T.viewButton = $('#t-view-button').val(); + }, + methods: { + isMediaSelected: function isMediaSelected(media) { + var result = this.selectedMedias.some(function (element, index, array) { + return element.url.toLowerCase() === media.url.toLowerCase(); }); return result; }, - _replaceFileInput: function _replaceFileInput(data) { - var input = data.fileInput, - inputClone = input.clone(true), - restoreFocus = input.is(document.activeElement); - // Add a reference for the new cloned file input to the data argument: - data.fileInputClone = inputClone; - $('
    ').append(inputClone)[0].reset(); - // Detaching allows to insert the fileInput on another form - // without losing the file input value: - input.after(inputClone).detach(); - // If the fileInput had focus before it was detached, - // restore focus to the inputClone. - if (restoreFocus) { - inputClone.trigger('focus'); - } - // Avoid memory leaks with the detached file input: - $.cleanData(input.off('remove')); - // Replace the original file input element in the fileInput - // elements set with the clone, which has been copied including - // event handlers: - this.options.fileInput = this.options.fileInput.map(function (i, el) { - if (el === input[0]) { - return inputClone[0]; - } - return el; - }); - // If the widget has been initialized on the file input itself, - // override this.element with the file input clone: - if (input[0] === this.element[0]) { - this.element = inputClone; - } + buildMediaUrl: function buildMediaUrl(url, thumbSize) { + return url + (url.indexOf('?') == -1 ? '?' : '&') + 'width=' + thumbSize + '&height=' + thumbSize; }, - _handleFileTreeEntry: function _handleFileTreeEntry(entry, path) { - var that = this, - dfd = $.Deferred(), - entries = [], - dirReader, - errorHandler = function errorHandler(e) { - if (e && !e.entry) { - e.entry = entry; - } - // Since $.when returns immediately if one - // Deferred is rejected, we use resolve instead. - // This allows valid files and invalid items - // to be returned together in one set: - dfd.resolve([e]); - }, - successHandler = function successHandler(entries) { - that._handleFileTreeEntries(entries, path + entry.name + '/').done(function (files) { - dfd.resolve(files); - }).fail(errorHandler); - }, - readEntries = function readEntries() { - dirReader.readEntries(function (results) { - if (!results.length) { - successHandler(entries); - } else { - entries = entries.concat(results); - readEntries(); - } - }, errorHandler); - }; - // eslint-disable-next-line no-param-reassign - path = path || ''; - if (entry.isFile) { - if (entry._file) { - // Workaround for Chrome bug #149735 - entry._file.relativePath = path; - dfd.resolve(entry._file); - } else { - entry.file(function (file) { - file.relativePath = path; - dfd.resolve(file); - }, errorHandler); - } - } else if (entry.isDirectory) { - dirReader = entry.createReader(); - readEntries(); - } else { - // Return an empty list for file system items - // other than files or directories: - dfd.resolve([]); - } - return dfd.promise(); + changeSort: function changeSort(newSort) { + bus.$emit('sortChangeRequested', newSort); }, - _handleFileTreeEntries: function _handleFileTreeEntries(entries, path) { - var that = this; - return $.when.apply($, $.map(entries, function (entry) { - return that._handleFileTreeEntry(entry, path); - }))[this._promisePipe](function () { - return Array.prototype.concat.apply([], arguments); - }); + toggleSelectionOfMedia: function toggleSelectionOfMedia(media) { + bus.$emit('mediaToggleRequested', media); }, - _getDroppedFiles: function _getDroppedFiles(dataTransfer) { - // eslint-disable-next-line no-param-reassign - dataTransfer = dataTransfer || {}; - var items = dataTransfer.items; - if (items && items.length && (items[0].webkitGetAsEntry || items[0].getAsEntry)) { - return this._handleFileTreeEntries($.map(items, function (item) { - var entry; - if (item.webkitGetAsEntry) { - entry = item.webkitGetAsEntry(); - if (entry) { - // Workaround for Chrome bug #149735: - entry._file = item.getAsFile(); - } - return entry; - } - return item.getAsEntry(); - })); - } - return $.Deferred().resolve($.makeArray(dataTransfer.files)).promise(); + renameMedia: function renameMedia(media) { + bus.$emit('renameMediaRequested', media); }, - _getSingleFileInputFiles: function _getSingleFileInputFiles(fileInput) { - // eslint-disable-next-line no-param-reassign - fileInput = $(fileInput); - var entries = fileInput.prop('entries'), - files, - value; - if (entries && entries.length) { - return this._handleFileTreeEntries(entries); - } - files = $.makeArray(fileInput.prop('files')); - if (!files.length) { - value = fileInput.prop('value'); - if (!value) { - return $.Deferred().resolve([]).promise(); - } - // If the files property is not available, the browser does not - // support the File API and we add a pseudo File object with - // the input value as name with path information removed: - files = [{ - name: value.replace(/^.*\\/, '') - }]; - } else if (files[0].name === undefined && files[0].fileName) { - // File normalization for Safari 4 and Firefox 3: - $.each(files, function (index, file) { - file.name = file.fileName; - file.size = file.fileSize; - }); - } - return $.Deferred().resolve(files).promise(); + deleteMedia: function deleteMedia(media) { + bus.$emit('deleteMediaRequested', media); }, - _getFileInputFiles: function _getFileInputFiles(fileInput) { - if (!(fileInput instanceof $) || fileInput.length === 1) { - return this._getSingleFileInputFiles(fileInput); - } - return $.when.apply($, $.map(fileInput, this._getSingleFileInputFiles))[this._promisePipe](function () { - return Array.prototype.concat.apply([], arguments); - }); + dragStart: function dragStart(media, e) { + bus.$emit('mediaDragStartRequested', media, e); }, - _onChange: function _onChange(e) { - var that = this, - data = { - fileInput: $(e.target), - form: $(e.target.form) - }; - this._getFileInputFiles(data.fileInput).always(function (files) { - data.files = files; - if (that.options.replaceFileInput) { - that._replaceFileInput(data); - } - if (that._trigger('change', $.Event('change', { - delegatedEvent: e - }), data) !== false) { - that._onAdd(e, data); - } - }); + printDateTime: function printDateTime(datemillis) { + var d = new Date(datemillis); + return d.toLocaleString(); + }, + getfontAwesomeClassNameForFileName: function getfontAwesomeClassNameForFilename(filename, thumbsize) { + return getClassNameForFilename(filename) + ' ' + thumbsize; + } + } +}); +// This component receives a list of all the items, unpaged. +// As the user interacts with the pager, it raises events with the items in the current page. +// It's the parent's responsibility to listen for these events and display the received items +// component +Vue.component('pager', { + template: "\n
    \n \n \n
    \n ", + props: { + sourceItems: Array + }, + data: function data() { + return { + pageSize: 10, + pageSizeOptions: [10, 30, 50, 100], + current: 0, + T: {} + }; + }, + created: function created() { + var self = this; + + // retrieving localized strings from view + self.T.pagerFirstButton = $('#t-pager-first-button').val(); + self.T.pagerPreviousButton = $('#t-pager-previous-button').val(); + self.T.pagerNextButton = $('#t-pager-next-button').val(); + self.T.pagerLastButton = $('#t-pager-last-button').val(); + self.T.pagerPageSizeLabel = $('#t-pager-page-size-label').val(); + self.T.pagerPageLabel = $('#t-pager-page-label').val(); + self.T.pagerTotalLabel = $('#t-pager-total-label').val(); + }, + methods: { + next: function next() { + this.current = this.current + 1; + }, + previous: function previous() { + this.current = this.current - 1; + }, + goFirst: function goFirst() { + this.current = 0; + }, + goLast: function goLast() { + this.current = this.totalPages - 1; + }, + goTo: function goTo(targetPage) { + this.current = targetPage; + } + }, + computed: { + total: function total() { + return this.sourceItems ? this.sourceItems.length : 0; + }, + totalPages: function totalPages() { + var pages = Math.ceil(this.total / this.pageSize); + return pages > 0 ? pages : 1; + }, + isLastPage: function isLastPage() { + return this.current + 1 >= this.totalPages; + }, + isFirstPage: function isFirstPage() { + return this.current === 0; }, - _onPaste: function _onPaste(e) { - var items = e.originalEvent && e.originalEvent.clipboardData && e.originalEvent.clipboardData.items, - data = { - files: [] - }; - if (items && items.length) { - $.each(items, function (index, item) { - var file = item.getAsFile && item.getAsFile(); - if (file) { - data.files.push(file); - } - }); - if (this._trigger('paste', $.Event('paste', { - delegatedEvent: e - }), data) !== false) { - this._onAdd(e, data); - } - } + canDoNext: function canDoNext() { + return !this.isLastPage; }, - _onDrop: function _onDrop(e) { - e.dataTransfer = e.originalEvent && e.originalEvent.dataTransfer; - var that = this, - dataTransfer = e.dataTransfer, - data = {}; - if (dataTransfer && dataTransfer.files && dataTransfer.files.length) { - e.preventDefault(); - this._getDroppedFiles(dataTransfer).always(function (files) { - data.files = files; - if (that._trigger('drop', $.Event('drop', { - delegatedEvent: e - }), data) !== false) { - that._onAdd(e, data); - } - }); - } + canDoPrev: function canDoPrev() { + return !this.isFirstPage; }, - _onDragOver: getDragHandler('dragover'), - _onDragEnter: getDragHandler('dragenter'), - _onDragLeave: getDragHandler('dragleave'), - _initEventHandlers: function _initEventHandlers() { - if (this._isXHRUpload(this.options)) { - this._on(this.options.dropZone, { - dragover: this._onDragOver, - drop: this._onDrop, - // event.preventDefault() on dragenter is required for IE10+: - dragenter: this._onDragEnter, - // dragleave is not required, but added for completeness: - dragleave: this._onDragLeave - }); - this._on(this.options.pasteZone, { - paste: this._onPaste - }); - } - if ($.support.fileInput) { - this._on(this.options.fileInput, { - change: this._onChange - }); - } + canDoFirst: function canDoFirst() { + return !this.isFirstPage; }, - _destroyEventHandlers: function _destroyEventHandlers() { - this._off(this.options.dropZone, 'dragenter dragleave dragover drop'); - this._off(this.options.pasteZone, 'paste'); - this._off(this.options.fileInput, 'change'); + canDoLast: function canDoLast() { + return !this.isLastPage; }, - _destroy: function _destroy() { - this._destroyEventHandlers(); + // this computed is only to have a central place where we detect changes and leverage Vue JS reactivity to raise our event. + // That event will be handled by the parent media app to display the items in the page. + // this logic will not run if the computed property is not used in the template. We use a dummy "data-computed-trigger" attribute for that. + itemsInCurrentPage: function itemsInCurrentPage() { + var start = this.pageSize * this.current; + var end = start + this.pageSize; + var result = this.sourceItems.slice(start, end); + bus.$emit('pagerEvent', result); + return result; }, - _setOption: function _setOption(key, value) { - var reinit = $.inArray(key, this._specialOptions) !== -1; - if (reinit) { - this._destroyEventHandlers(); - } - this._super(key, value); - if (reinit) { - this._initSpecialOptions(); - this._initEventHandlers(); - } + pageLinks: function pageLinks() { + var links = []; + links.push(this.current + 1); + + // Add 2 items before current + var beforeCurrent = this.current > 0 ? this.current : -1; + links.unshift(beforeCurrent); + var beforeBeforeCurrent = this.current > 1 ? this.current - 1 : -1; + links.unshift(beforeBeforeCurrent); + + // Add 2 items after current + var afterCurrent = this.totalPages - this.current > 1 ? this.current + 2 : -1; + links.push(afterCurrent); + var afterAfterCurrent = this.totalPages - this.current > 2 ? this.current + 3 : -1; + links.push(afterAfterCurrent); + return links; + } + }, + watch: { + sourceItems: function sourceItems() { + this.current = 0; // resetting current page after receiving a new list of unpaged items }, - _initSpecialOptions: function _initSpecialOptions() { - var options = this.options; - if (options.fileInput === undefined) { - options.fileInput = this.element.is('input[type="file"]') ? this.element : this.element.find('input[type="file"]'); - } else if (!(options.fileInput instanceof $)) { - options.fileInput = $(options.fileInput); - } - if (!(options.dropZone instanceof $)) { - options.dropZone = $(options.dropZone); - } - if (!(options.pasteZone instanceof $)) { - options.pasteZone = $(options.pasteZone); + + pageSize: function pageSize() { + this.current = 0; + } + } +}); +// component +Vue.component('sortIndicator', { + template: "\n
    \n \n \n
    \n ", + props: { + colname: String, + selectedcolname: String, + asc: Boolean + }, + computed: { + isActive: function isActive() { + return this.colname.toLowerCase() == this.selectedcolname.toLowerCase(); + } + } +}); +function initializeAttachedMediaField(el, idOfUploadButton, uploadAction, mediaItemUrl, allowMultiple, allowMediaText, allowAnchors, tempUploadFolder, maxUploadChunkSize) { + var target = $(document.getElementById($(el).data('for'))); + var initialPaths = target.data("init"); + var mediaFieldEditor = $(el); + var idprefix = mediaFieldEditor.attr("id"); + var mediaFieldApp; + mediaFieldApps.push(mediaFieldApp = new Vue({ + el: mediaFieldEditor.get(0), + data: { + mediaItems: [], + selectedMedia: null, + smallThumbs: false, + idPrefix: idprefix, + initialized: false, + allowMediaText: allowMediaText, + backupMediaText: '', + allowAnchors: allowAnchors, + backupAnchor: null, + mediaTextmodal: null, + anchoringModal: null + }, + created: function created() { + var self = this; + self.currentPrefs = JSON.parse(localStorage.getItem('mediaFieldPrefs')); + }, + computed: { + paths: { + get: function get() { + var mediaPaths = []; + if (!this.initialized) { + return JSON.stringify(initialPaths); + } + this.mediaItems.forEach(function (x) { + if (x.mediaPath === 'not-found') { + return; + } + mediaPaths.push({ + path: x.mediaPath, + isRemoved: x.isRemoved, + isNew: x.isNew, + mediaText: x.mediaText, + anchor: x.anchor, + attachedFileName: x.attachedFileName + }); + }); + return JSON.stringify(mediaPaths); + }, + set: function set(values) { + var self = this; + var mediaPaths = values || []; + var signal = $.Deferred(); + var items = []; + var length = 0; + mediaPaths.forEach(function (x, i) { + items.push({ + name: ' ' + x.path, + mime: '', + mediaPath: '', + anchor: x.anchor, + attachedFileName: x.attachedFileName + }); // don't remove the space. Something different is needed or it wont react when the real name arrives. + promise = $.when(signal).done(function () { + $.ajax({ + url: mediaItemUrl + "?path=" + encodeURIComponent(x.path), + method: 'GET', + success: function success(data) { + data.vuekey = data.name + i.toString(); // Because a unique key is required by Vue on v-for + data.mediaText = x.mediaText; // This value is not returned from the ajax call. + data.anchor = x.anchor; // This value is not returned from the ajax call. + data.attachedFileName = x.attachedFileName; // This value is not returned from the ajax call. + items.splice(i, 1, data); + if (items.length === ++length) { + items.forEach(function (x) { + self.mediaItems.push(x); + }); + self.initialized = true; + } + }, + error: function error(_error) { + console.log(JSON.stringify(_error)); + items.splice(i, 1, { + name: x.path, + mime: '', + mediaPath: 'not-found', + mediaText: '', + anchor: { + x: 0.5, + y: 0.5 + }, + attachedFileName: x.attachedFileName + }); + if (items.length === ++length) { + items.forEach(function (x) { + self.mediaItems.push(x); + }); + self.initialized = true; + } + } + }); + }); + }); + signal.resolve(); + } + }, + fileSize: function fileSize() { + return Math.round(this.selectedMedia.size / 1024); + }, + canAddMedia: function canAddMedia() { + var nonRemovedMediaItems = []; + for (var i = 0; i < this.mediaItems.length; i++) { + if (!this.mediaItems[i].isRemoved) { + nonRemovedMediaItems.push(this.mediaItems[i]); + } + } + return nonRemovedMediaItems.length === 0 || nonRemovedMediaItems.length > 0 && allowMultiple; + }, + thumbSize: function thumbSize() { + return this.smallThumbs ? 120 : 240; + }, + currentPrefs: { + get: function get() { + return { + smallThumbs: this.smallThumbs + }; + }, + set: function set(newPrefs) { + if (!newPrefs) { + return; + } + this.smallThumbs = newPrefs.smallThumbs; + } } }, - _getRegExp: function _getRegExp(str) { - var parts = str.split('/'), - modifiers = parts.pop(); - parts.shift(); - return new RegExp(parts.join('/'), modifiers); - }, - _isRegExpOption: function _isRegExpOption(key, value) { - return key !== 'url' && $.type(value) === 'string' && /^\/.*\/[igm]{0,3}$/.test(value); - }, - _initDataAttributes: function _initDataAttributes() { - var that = this, - options = this.options, - data = this.element.data(); - // Initialize options set via HTML5 data-attributes: - $.each(this.element[0].attributes, function (index, attr) { - var key = attr.name.toLowerCase(), - value; - if (/^data-/.test(key)) { - // Convert hyphen-ated key to camelCase: - key = key.slice(5).replace(/-[a-z]/g, function (str) { - return str.charAt(1).toUpperCase(); - }); - value = data[key]; - if (that._isRegExpOption(key, value)) { - value = that._getRegExp(value); + mounted: function mounted() { + var self = this; + self.paths = initialPaths; + self.$on('selectAndDeleteMediaRequested', function (media) { + self.selectAndDeleteMedia(media); + }); + self.$on('selectMediaRequested', function (media) { + self.selectMedia(media); + }); + var selector = '#' + idOfUploadButton; + var editorId = mediaFieldEditor.attr('id'); + var chunkedFileUploadId = randomUUID(); + $(selector).fileupload({ + limitConcurrentUploads: 20, + dropZone: $('#' + editorId), + dataType: 'json', + url: uploadAction, + maxChunkSize: maxUploadChunkSize, + add: function add(e, data) { + var count = data.files.length; + var i; + for (i = 0; i < count; i++) { + data.files[i].uploadName = self.getUniqueId() + data.files[i].name; + data.files[i].attachedFileName = data.files[i].name; } - options[key] = value; + data.submit(); + }, + formData: function formData() { + var antiForgeryToken = $("input[name=__RequestVerificationToken]").val(); + return [{ + name: 'path', + value: tempUploadFolder + }, { + name: '__RequestVerificationToken', + value: antiForgeryToken + }, { + name: '__chunkedFileUploadId', + value: chunkedFileUploadId + }]; + }, + done: function done(e, data) { + var newMediaItems = []; + var errormsg = ""; + if (data.result.files.length > 0) { + for (var i = 0; i < data.result.files.length; i++) { + data.result.files[i].isNew = true; + //if error is defined probably the file type is not allowed + if (data.result.files[i].error === undefined || data.result.files[i].error === null) { + data.result.files[i].attachedFileName = data.files[i].attachedFileName; + newMediaItems.push(data.result.files[i]); + } else errormsg += data.result.files[i].error + "\n"; + } + } + if (errormsg !== "") { + alert(errormsg); + return; + } + console.log(newMediaItems); + if (newMediaItems.length > 1 && allowMultiple === false) { + alert($('#onlyOneItemMessage').val()); + mediaFieldApp.mediaItems.push(newMediaItems[0]); + mediaFieldApp.initialized = true; + } else { + mediaFieldApp.mediaItems = mediaFieldApp.mediaItems.concat(newMediaItems); + mediaFieldApp.initialized = true; + } + }, + error: function error(jqXHR, textStatus, errorThrown) { + console.log('Error on upload.'); + console.log(jqXHR); + console.log(textStatus); + console.log(errorThrown); } + }).on('fileuploadchunkbeforesend', function (e, options) { + var file = options.files[0]; + // Here we replace the blob with a File object to ensure the file name and others are preserved for the backend. + options.blob = new File([options.blob], file.name, { + type: file.type, + lastModified: file.lastModified + }); }); }, - _create: function _create() { - this._initDataAttributes(); - this._initSpecialOptions(); - this._slots = []; - this._sequence = this._getXHRPromise(true); - this._sending = this._active = 0; - this._initProgressObject(this); - this._initEventHandlers(); - }, - // This method is exposed to the widget API and allows to query - // the number of active uploads: - active: function active() { - return this._active; - }, - // This method is exposed to the widget API and allows to query - // the widget upload progress. - // It returns an object with loaded, total and bitrate properties - // for the running uploads: - progress: function progress() { - return this._progress; - }, - // This method is exposed to the widget API and allows adding files - // using the fileupload API. The data parameter accepts an object which - // must have a files property and can contain additional options: - // .fileupload('add', {files: filesList}); - add: function add(data) { - var that = this; - if (!data || this.options.disabled) { - return; - } - if (data.fileInput && !data.files) { - this._getFileInputFiles(data.fileInput).always(function (files) { - data.files = files; - that._onAdd(null, data); + methods: { + selectMedia: function selectMedia(media) { + this.selectedMedia = media; + }, + getUniqueId: function getUniqueId() { + return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { + var r = Math.random() * 16 | 0, + v = c === 'x' ? r : r & 0x3 | 0x8; + return v.toString(16); }); - } else { - data.files = $.makeArray(data.files); - this._onAdd(null, data); + }, + removeSelected: function removeSelected(event) { + var removed = {}; + if (this.selectedMedia) { + var index = this.mediaItems && this.mediaItems.indexOf(this.selectedMedia); + if (index > -1) { + removed = this.mediaItems[index]; + removed.isRemoved = true; + //this.mediaItems.splice([index], 1, removed); + this.mediaItems.splice(index, 1); + } + } else { + // The remove button can also remove a unique media item + if (this.mediaItems.length === 1) { + removed = this.mediaItems[index]; + removed.isRemoved = true; + //this.mediaItems.splice(0, 1, removed); + this.mediaItems.splice(0, 1); + } + } + this.selectedMedia = null; + }, + showMediaTextModal: function showMediaTextModal(event) { + this.mediaTextModal = new bootstrap.Modal(this.$refs.mediaTextModal); + this.mediaTextModal.show(); + this.backupMediaText = this.selectedMedia.mediaText; + }, + cancelMediaTextModal: function cancelMediaTextModal(event) { + this.mediaTextModal.hide(); + this.selectedMedia.mediaText = this.backupMediaText; + }, + showAnchorModal: function showAnchorModal(event) { + this.anchoringModal = new bootstrap.Modal(this.$refs.anchoringModal); + this.anchoringModal.show(); + // Cause a refresh to recalc heights. + this.selectedMedia.anchor = { + x: this.selectedMedia.anchor.x, + y: this.selectedMedia.anchor.y + }; + this.backupAnchor = this.selectedMedia.anchor; + }, + cancelAnchoringModal: function cancelAnchoringModal(event) { + this.anchoringModal.hide(); + this.selectedMedia.anchor = this.backupAnchor; + }, + resetAnchor: function resetAnchor(event) { + this.selectedMedia.anchor = { + x: 0.5, + y: 0.5 + }; + }, + onAnchorDrop: function onAnchorDrop(event) { + var image = this.$refs.anchorImage; + this.selectedMedia.anchor = { + x: event.offsetX / image.clientWidth, + y: event.offsetY / image.clientHeight + }; + }, + anchorLeft: function anchorLeft() { + if (this.$refs.anchorImage && this.$refs.modalBody && this.selectedMedia) { + // When image is shrunk compare against the modal body. + var offset = (this.$refs.modalBody.clientWidth - this.$refs.anchorImage.clientWidth) / 2; + var position = this.selectedMedia.anchor.x * this.$refs.anchorImage.clientWidth + offset; + if (position < 17) { + // Adjust so the target doesn't show outside image. + position = 17; + } else { + position = position - 8; // Adjust to hit the mouse pointer. + } + + return position + 'px'; + } else { + return '0'; + } + }, + anchorTop: function anchorTop() { + if (this.$refs.anchorImage && this.selectedMedia) { + var position = this.selectedMedia.anchor.y * this.$refs.anchorImage.clientHeight; + if (position < 15) { + // Adjustment so the target doesn't show outside image. + position = 15; + } else { + position = position + 5; // Adjust to hit the mouse pointer. + } + + return position + 'px'; + } else { + return '0'; + } + }, + setAnchor: function setAnchor(event) { + var image = this.$refs.anchorImage; + this.selectedMedia.anchor = { + x: event.offsetX / image.clientWidth, + y: event.offsetY / image.clientHeight + }; + }, + addMediaFiles: function addMediaFiles(files) { + if (files.length > 1 && allowMultiple === false) { + alert($('#onlyOneItemMessage').val()); + mediaFieldApp.mediaItems.push(files[0]); + mediaFieldApp.initialized = true; + } else { + mediaFieldApp.mediaItems = mediaFieldApp.mediaItems.concat(files); + mediaFieldApp.initialized = true; + } + }, + selectAndDeleteMedia: function selectAndDeleteMedia(media) { + var self = this; + self.selectedMedia = media; + // setTimeout because sometimes + // removeSelected was called even before the media was set. + setTimeout(function () { + self.removeSelected(); + }, 100); } }, - // This method is exposed to the widget API and allows sending files - // using the fileupload API. The data parameter accepts an object which - // must have a files or fileInput property and can contain additional options: - // .fileupload('send', {files: filesList}); - // The method returns a Promise object for the file upload call. - send: function send(data) { - if (data && !this.options.disabled) { - if (data.fileInput && !data.files) { - var that = this, - dfd = $.Deferred(), - promise = dfd.promise(), - jqXHR, - aborted; - promise.abort = function () { - aborted = true; - if (jqXHR) { - return jqXHR.abort(); - } - dfd.reject(null, 'abort', 'abort'); - return promise; - }; - this._getFileInputFiles(data.fileInput).always(function (files) { - if (aborted) { - return; - } - if (!files.length) { - dfd.reject(); - return; - } - data.files = files; - jqXHR = that._onSend(null, data); - jqXHR.then(function (result, textStatus, jqXHR) { - dfd.resolve(result, textStatus, jqXHR); - }, function (jqXHR, textStatus, errorThrown) { - dfd.reject(jqXHR, textStatus, errorThrown); - }); - }); - return this._enhancePromise(promise); - } - data.files = $.makeArray(data.files); - if (data.files.length) { - return this._onSend(null, data); + watch: { + mediaItems: { + deep: true, + handler: function handler() { + // Trigger preview rendering + setTimeout(function () { + $(document).trigger('contentpreview:render'); + }, 100); } + }, + currentPrefs: function currentPrefs(newPrefs) { + localStorage.setItem('mediaFieldPrefs', JSON.stringify(newPrefs)); } - return this._getXHRPromise(false, data && data.context); } - }); -}); -function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); } -/* - * jQuery Iframe Transport Plugin - * https://github.com/blueimp/jQuery-File-Upload - * - * Copyright 2011, Sebastian Tschan - * https://blueimp.net - * - * Licensed under the MIT license: - * https://opensource.org/licenses/MIT - */ - -/* global define, require */ - -(function (factory) { - 'use strict'; - - if (typeof define === 'function' && define.amd) { - // Register as an anonymous AMD module: - define(['jquery'], factory); - } else if ((typeof exports === "undefined" ? "undefined" : _typeof(exports)) === 'object') { - // Node/CommonJS: - factory(require('jquery')); - } else { - // Browser globals: - factory(window.jQuery); - } -})(function ($) { - 'use strict'; + })); +} +// component +// different media field editors share this component to present the thumbs. +Vue.component('mediaFieldThumbsContainer', { + template: '\ +
    \ +
    \ +
    \ + {{T.noImages}}\ +
    \ +
    \ + \ +
  • \ +
    \ +
    \ + \ + \ +
    \ +
    \ + \ + \ + {{ media.isNew ? media.name.substr(36) : media.name }}\ +
    \ +
    \ +
    \ +
    \ + \ + {{ T.mediaNotFound }}\ + {{ T.discardWarning }}\ +
    \ +
    \ + \ + {{ media.name }}\ +
    \ +
    \ +
  • \ +
    \ +
    \ + ', + data: function data() { + return { + T: {} + }; + }, + props: { + mediaItems: Array, + selectedMedia: Object, + thumbSize: Number, + idPrefix: String + }, + created: function created() { + var self = this; - // Helper variable to create unique names for the transport iframes: - var counter = 0, - jsonAPI = $, - jsonParse = 'parseJSON'; - if ('JSON' in window && 'parse' in JSON) { - jsonAPI = JSON; - jsonParse = 'parse'; + // retrieving localized strings from view + self.T.mediaNotFound = $('#t-media-not-found').val(); + self.T.discardWarning = $('#t-discard-warning').val(); + self.T.noImages = $('#t-no-images').val(); + }, + methods: { + selectAndDeleteMedia: function selectAndDeleteMedia(media) { + this.$parent.$emit('selectAndDeleteMediaRequested', media); + }, + selectMedia: function selectMedia(media) { + this.$parent.$emit('selectMediaRequested', media); + }, + buildMediaUrl: function buildMediaUrl(url, thumbSize) { + return url + (url.indexOf('?') == -1 ? '?' : '&') + 'width=' + thumbSize + '&height=' + thumbSize; + }, + getfontAwesomeClassNameForFileName: function getfontAwesomeClassNameForFilename(filename, thumbsize) { + return getClassNameForFilename(filename) + ' ' + thumbsize; + } } +}); +function initializeMediaField(el, modalBodyElement, mediaItemUrl, allowMultiple, allowMediaText, allowAnchors) { + //BagPart create a script section without other DOM elements + if (el === null) return; + var target = $(document.getElementById($(el).data('for'))); + var initialPaths = target.data("init"); + var mediaFieldEditor = $(el); + var idprefix = mediaFieldEditor.attr("id"); + var mediaFieldApp; - // The iframe transport accepts four additional options: - // options.fileInput: a jQuery collection of file input fields - // options.paramName: the parameter name for the file form data, - // overrides the name property of the file input field(s), - // can be a string or an array of strings. - // options.formData: an array of objects with name and value properties, - // equivalent to the return data of .serializeArray(), e.g.: - // [{name: 'a', value: 1}, {name: 'b', value: 2}] - // options.initialIframeSrc: the URL of the initial iframe src, - // by default set to "javascript:false;" - $.ajaxTransport('iframe', function (options) { - if (options.async) { - // javascript:false as initial iframe src - // prevents warning popups on HTTPS in IE6: - // eslint-disable-next-line no-script-url - var initialIframeSrc = options.initialIframeSrc || 'javascript:false;', - form, - iframe, - addParamChar; - return { - send: function send(_, completeCallback) { - form = $('
    '); - form.attr('accept-charset', options.formAcceptCharset); - addParamChar = /\?/.test(options.url) ? '&' : '?'; - // XDomainRequest only supports GET and POST: - if (options.type === 'DELETE') { - options.url = options.url + addParamChar + '_method=DELETE'; - options.type = 'POST'; - } else if (options.type === 'PUT') { - options.url = options.url + addParamChar + '_method=PUT'; - options.type = 'POST'; - } else if (options.type === 'PATCH') { - options.url = options.url + addParamChar + '_method=PATCH'; - options.type = 'POST'; + //when hide modal detach media app to avoid issue on BagPart + modalBodyElement.addEventListener('hidden.bs.modal', function (event) { + $("#mediaApp").appendTo('body'); + $("#mediaApp").hide(); + }); + mediaFieldApps.push(mediaFieldApp = new Vue({ + el: mediaFieldEditor.get(0), + data: { + mediaItems: [], + selectedMedia: null, + smallThumbs: false, + idPrefix: idprefix, + initialized: false, + allowMediaText: allowMediaText, + backupMediaText: '', + allowAnchors: allowAnchors, + backupAnchor: null, + mediaTextModal: null, + anchoringModal: null + }, + created: function created() { + var self = this; + self.currentPrefs = JSON.parse(localStorage.getItem('mediaFieldPrefs')); + }, + computed: { + paths: { + get: function get() { + var mediaPaths = []; + if (!this.initialized) { + return JSON.stringify(initialPaths); } - // IE versions below IE8 cannot set the name property of - // elements that have already been added to the DOM, - // so we set the name along with the iframe HTML markup: - counter += 1; - iframe = $('').on('load', function () { - var fileInputClones, - paramNames = $.isArray(options.paramName) ? options.paramName : [options.paramName]; - iframe.off('load').on('load', function () { - var response; - // Wrap in a try/catch block to catch exceptions thrown - // when trying to access cross-domain iframe contents: - try { - response = iframe.contents(); - // Google Chrome and Firefox do not throw an - // exception when calling iframe.contents() on - // cross-domain requests, so we unify the response: - if (!response.length || !response[0].firstChild) { - throw new Error(); + this.mediaItems.forEach(function (x) { + if (x.mediaPath === 'not-found') { + return; + } + mediaPaths.push({ + path: x.mediaPath, + mediaText: x.mediaText, + anchor: x.anchor + }); + }); + return JSON.stringify(mediaPaths); + }, + set: function set(values) { + var self = this; + var mediaPaths = values || []; + var signal = $.Deferred(); + var items = []; + var length = 0; + mediaPaths.forEach(function (x, i) { + items.push({ + name: ' ' + x.path, + mime: '', + mediaPath: '' + }); // don't remove the space. Something different is needed or it wont react when the real name arrives. + promise = $.when(signal).done(function () { + $.ajax({ + url: mediaItemUrl + "?path=" + encodeURIComponent(x.path), + method: 'GET', + success: function success(data) { + data.vuekey = data.name + i.toString(); + data.mediaText = x.mediaText; // This value is not returned from the ajax call. + data.anchor = x.anchor; // This value is not returned from the ajax call. + items.splice(i, 1, data); + if (items.length === ++length) { + items.forEach(function (y) { + self.mediaItems.push(y); + }); + self.initialized = true; + } + }, + error: function error(_error) { + console.log(_error); + items.splice(i, 1, { + name: x.path, + mime: '', + mediaPath: 'not-found', + mediaText: '', + anchor: { + x: 0, + y: 0 + } + }); + if (items.length === ++length) { + items.forEach(function (x) { + self.mediaItems.push(x); + }); + self.initialized = true; + } } - } catch (e) { - response = undefined; - } - // The complete callback returns the - // iframe content document as response object: - completeCallback(200, 'success', { - iframe: response }); - // Fix for IE endless progress bar activity bug - // (happens on form submits to iframe targets): - $('').appendTo(form); - window.setTimeout(function () { - // Removing the form in a setTimeout call - // allows Chrome's developer tools to display - // the response result - form.remove(); - }, 0); }); - form.prop('target', iframe.prop('name')).prop('action', options.url).prop('method', options.type); - if (options.formData) { - $.each(options.formData, function (index, field) { - $('').prop('name', field.name).val(field.value).appendTo(form); - }); - } - if (options.fileInput && options.fileInput.length && options.type === 'POST') { - fileInputClones = options.fileInput.clone(); - // Insert a clone for each file input field: - options.fileInput.after(function (index) { - return fileInputClones[index]; - }); - if (options.paramName) { - options.fileInput.each(function (index) { - $(this).prop('name', paramNames[index] || options.paramName); - }); - } - // Appending the file input fields to the hidden form - // removes them from their original location: - form.append(options.fileInput).prop('enctype', 'multipart/form-data') - // enctype must be set as encoding for IE: - .prop('encoding', 'multipart/form-data'); - // Remove the HTML5 form attribute from the input(s): - options.fileInput.removeAttr('form'); - } - window.setTimeout(function () { - // Submitting the form in a setTimeout call fixes an issue with - // Safari 13 not triggering the iframe load event after resetting - // the load event handler, see also: - // https://github.com/blueimp/jQuery-File-Upload/issues/3633 - form.submit(); - // Insert the file input fields at their original location - // by replacing the clones with the originals: - if (fileInputClones && fileInputClones.length) { - options.fileInput.each(function (index, input) { - var clone = $(fileInputClones[index]); - // Restore the original name and form properties: - $(input).prop('name', clone.prop('name')).attr('form', clone.attr('form')); - clone.replaceWith(input); - }); - } - }, 0); }); - form.append(iframe).appendTo(document.body); + signal.resolve(); + } + }, + fileSize: function fileSize() { + return Math.round(this.selectedMedia.size / 1024); + }, + canAddMedia: function canAddMedia() { + return this.mediaItems.length === 0 || this.mediaItems.length > 0 && allowMultiple; + }, + thumbSize: function thumbSize() { + return this.smallThumbs ? 120 : 240; + }, + currentPrefs: { + get: function get() { + return { + smallThumbs: this.smallThumbs + }; }, - abort: function abort() { - if (iframe) { - // javascript:false as iframe src aborts the request - // and prevents warning popups on HTTPS in IE6. - iframe.off('load').prop('src', initialIframeSrc); + set: function set(newPrefs) { + if (!newPrefs) { + return; } - if (form) { - form.remove(); + this.smallThumbs = newPrefs.smallThumbs; + } + } + }, + mounted: function mounted() { + var self = this; + self.paths = initialPaths; + self.$on('selectAndDeleteMediaRequested', function (media) { + self.selectAndDeleteMedia(media); + }); + self.$on('selectMediaRequested', function (media) { + self.selectMedia(media); + }); + self.$on('filesUploaded', function (files) { + self.addMediaFiles(files); + }); + }, + methods: { + selectMedia: function selectMedia(media) { + this.selectedMedia = media; + }, + showModal: function showModal(event) { + var self = this; + if (self.canAddMedia) { + $("#mediaApp").appendTo($(modalBodyElement).find('.modal-body')); + $("#mediaApp").show(); + var modal = new bootstrap.Modal(modalBodyElement); + modal.show(); + $(modalBodyElement).find('.mediaFieldSelectButton').off('click').on('click', function (v) { + self.addMediaFiles(mediaApp.selectedMedias); + + // we don't want the included medias to be still selected the next time we open the modal. + mediaApp.selectedMedias = []; + modal.hide(); + return true; + }); + } + }, + showMediaTextModal: function showMediaTextModal(event) { + this.mediaTextModal = new bootstrap.Modal(this.$refs.mediaTextModal); + this.mediaTextModal.show(); + this.backupMediaText = this.selectedMedia.mediaText; + }, + cancelMediaTextModal: function cancelMediaTextModal(event) { + this.mediaTextModal.hide(); + this.selectedMedia.mediaText = this.backupMediaText; + }, + showAnchorModal: function showAnchorModal(event) { + this.anchoringModal = new bootstrap.Modal(this.$refs.anchoringModal); + this.anchoringModal.show(); + // Cause a refresh to recalc heights. + this.selectedMedia.anchor = { + x: this.selectedMedia.anchor.x, + y: this.selectedMedia.anchor.y + }; + this.backupAnchor = this.selectedMedia.anchor; + }, + cancelAnchoringModal: function cancelAnchoringModal(event) { + this.anchoringModal.hide(); + this.selectedMedia.anchor = this.backupAnchor; + }, + resetAnchor: function resetAnchor(event) { + this.selectedMedia.anchor = { + x: 0.5, + y: 0.5 + }; + }, + onAnchorDrop: function onAnchorDrop(event) { + var image = this.$refs.anchorImage; + this.selectedMedia.anchor = { + x: event.offsetX / image.clientWidth, + y: event.offsetY / image.clientHeight + }; + }, + anchorLeft: function anchorLeft() { + if (this.$refs.anchorImage && this.$refs.modalBody && this.selectedMedia) { + // When image is shrunk compare against the modal body. + var offset = (this.$refs.modalBody.clientWidth - this.$refs.anchorImage.clientWidth) / 2; + var position = this.selectedMedia.anchor.x * this.$refs.anchorImage.clientWidth + offset; + var anchorIcon = Math.round(this.$refs.modalBody.querySelector('.icon-media-anchor').clientWidth); + if (Number.isInteger(anchorIcon)) { + position = position - anchorIcon / 2; } + return position + 'px'; + } else { + return '0'; } - }; - } - }); - - // The iframe transport returns the iframe content document as response. - // The following adds converters from iframe to text, json, html, xml - // and script. - // Please note that the Content-Type for JSON responses has to be text/plain - // or text/html, if the browser doesn't include application/json in the - // Accept header, else IE will show a download dialog. - // The Content-Type for XML responses on the other hand has to be always - // application/xml or text/xml, so IE properly parses the XML response. - // See also - // https://github.com/blueimp/jQuery-File-Upload/wiki/Setup#content-type-negotiation - $.ajaxSetup({ - converters: { - 'iframe text': function iframeText(iframe) { - return iframe && $(iframe[0].body).text(); }, - 'iframe json': function iframeJson(iframe) { - return iframe && jsonAPI[jsonParse]($(iframe[0].body).text()); + anchorTop: function anchorTop() { + if (this.$refs.anchorImage && this.selectedMedia) { + var position = this.selectedMedia.anchor.y * this.$refs.anchorImage.clientHeight; + return position + 'px'; + } else { + return '0'; + } }, - 'iframe html': function iframeHtml(iframe) { - return iframe && $(iframe[0].body).html(); + setAnchor: function setAnchor(event) { + var image = this.$refs.anchorImage; + this.selectedMedia.anchor = { + x: event.offsetX / image.clientWidth, + y: event.offsetY / image.clientHeight + }; }, - 'iframe xml': function iframeXml(iframe) { - var xmlDoc = iframe && iframe[0]; - return xmlDoc && $.isXMLDoc(xmlDoc) ? xmlDoc : $.parseXML(xmlDoc.XMLDocument && xmlDoc.XMLDocument.xml || $(xmlDoc.body).html()); + addMediaFiles: function addMediaFiles(files) { + if (files.length > 1 && allowMultiple === false) { + alert($('#onlyOneItemMessage').val()); + mediaFieldApp.mediaItems.push(files[0]); + mediaFieldApp.initialized = true; + } else { + mediaFieldApp.mediaItems = mediaFieldApp.mediaItems.concat(files); + mediaFieldApp.initialized = true; + } }, - 'iframe script': function iframeScript(iframe) { - return iframe && $.globalEval($(iframe[0].body).text()); + removeSelected: function removeSelected(event) { + if (this.selectedMedia) { + var index = this.mediaItems && this.mediaItems.indexOf(this.selectedMedia); + if (index > -1) { + this.mediaItems.splice(index, 1); + } + } else { + // The remove button can also remove a unique media item + if (this.mediaItems.length === 1) { + this.mediaItems.splice(0, 1); + } + } + this.selectedMedia = null; + }, + selectAndDeleteMedia: function selectAndDeleteMedia(media) { + var self = this; + self.selectedMedia = media; + // setTimeout because sometimes removeSelected was called even before the media was set. + setTimeout(function () { + self.removeSelected(); + }, 100); + } + }, + watch: { + mediaItems: { + deep: true, + handler: function handler() { + // Trigger preview rendering + setTimeout(function () { + $(document).trigger('contentpreview:render'); + }, 100); + } + }, + currentPrefs: function currentPrefs(newPrefs) { + localStorage.setItem('mediaFieldPrefs', JSON.stringify(newPrefs)); } } - }); + })); +} +// different media field editors will add themselves to this array +var mediaFieldApps = []; +// component +Vue.component('upload', { + template: '\ +
    \ + \ +

    {{ model.name }}

    \ +
    \ + \ + Error: {{ model.errorMessage }} \ +
    \ +
    \ + ', + props: { + model: Object, + uploadInputId: String + }, + mounted: function mounted() { + var _self$uploadInputId; + var self = this; + var uploadInput = document.getElementById((_self$uploadInputId = self.uploadInputId) !== null && _self$uploadInputId !== void 0 ? _self$uploadInputId : 'fileupload'); + $(uploadInput).bind('fileuploadprogress', function (e, data) { + if (data.files[0].name !== self.model.name) { + return; + } + self.model.percentage = parseInt(data.loaded / data.total * 100, 10); + }); + $(uploadInput).bind('fileuploaddone', function (e, data) { + if (data.files[0].name !== self.model.name) { + return; + } + if (data.result.files[0].error) { + self.handleFailure(data.files[0].name, data.result.files[0].error); + } else { + bus.$emit('removalRequest', self.model); + } + }); + $(uploadInput).bind('fileuploadfail', function (e, data) { + if (data.files[0].name !== self.model.name) { + return; + } + self.handleFailure(data.files[0].name, $('#t-error').val()); + }); + }, + methods: { + handleFailure: function handleFailure(fileName, message) { + if (fileName !== this.model.name) { + return; + } + this.model.errorMessage = message; + bus.$emit('ErrorOnUpload', this.model); + }, + dismissWarning: function dismissWarning() { + bus.$emit('removalRequest', this.model); + } + } +}); +// component +Vue.component('uploadList', { + template: '\ +
    \ +
    \ + {{ T.uploads }} \ + (Pending: {{ pendingCount }}) \ + ( {{ T.errors }}: {{ errorCount }} / {{ T.clearErrors }} ) \ +
    \ +
    \ + \ +
    \ +
    \ + \ +
    \ +
    \ +
    \ +
    \ +
    \ + \ +
    \ +
    \ +
    \ + ', + data: function data() { + return { + files: [], + T: {}, + expanded: false, + pendingCount: 0, + errorCount: 0 + }; + }, + props: { + uploadInputId: String + }, + created: function created() { + var self = this; + // retrieving localized strings from view + self.T.uploads = $('#t-uploads').val(); + self.T.errors = $('#t-errors').val(); + self.T.clearErrors = $('#t-clear-errors').val(); + }, + computed: { + fileCount: function fileCount() { + return this.files.length; + } + }, + mounted: function mounted() { + var _self$uploadInputId; + var self = this; + var uploadInput = document.getElementById((_self$uploadInputId = self.uploadInputId) !== null && _self$uploadInputId !== void 0 ? _self$uploadInputId : 'fileupload'); + $(uploadInput).bind('fileuploadadd', function (e, data) { + if (!data.files) { + return; + } + data.files.forEach(function (newFile) { + var alreadyInList = self.files.some(function (f) { + return f.name == newFile.name; + }); + if (!alreadyInList) { + self.files.push({ + name: newFile.name, + percentage: 0, + errorMessage: '' + }); + } else { + console.error('A file with the same name is already on the queue:' + newFile.name); + } + }); + }); + bus.$on('removalRequest', function (fileUpload) { + self.files.forEach(function (item, index, array) { + if (item.name == fileUpload.name) { + array.splice(index, 1); + } + }); + }); + bus.$on('ErrorOnUpload', function (fileUpload) { + self.updateCount(); + }); + }, + methods: { + updateCount: function updateCount() { + this.errorCount = this.files.filter(function (item) { + return item.errorMessage != ''; + }).length; + this.pendingCount = this.files.length - this.errorCount; + if (this.files.length < 1) { + this.expanded = false; + } + }, + clearErrors: function clearErrors() { + this.files = this.files.filter(function (item) { + return item.errorMessage == ''; + }); + } + }, + watch: { + files: function files() { + this.updateCount(); + } + } }); \ No newline at end of file diff --git a/src/OrchardCore.Modules/OrchardCore.Media/wwwroot/Scripts/media.min.js b/src/OrchardCore.Modules/OrchardCore.Media/wwwroot/Scripts/media.min.js index 370f38585d3..1d75e8cc62a 100644 --- a/src/OrchardCore.Modules/OrchardCore.Media/wwwroot/Scripts/media.min.js +++ b/src/OrchardCore.Modules/OrchardCore.Media/wwwroot/Scripts/media.min.js @@ -1 +1 @@ -function _typeof(e){return _typeof="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},_typeof(e)}function ownKeys(e,t){var i=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),i.push.apply(i,n)}return i}function _objectSpread(e){for(var t=1;t-1}));switch(e.sortBy){case"size":t.sort((function(t,i){return e.sortAsc?t.size-i.size:i.size-t.size}));break;case"mime":t.sort((function(t,i){return e.sortAsc?t.mime.toLowerCase().localeCompare(i.mime.toLowerCase()):i.mime.toLowerCase().localeCompare(t.mime.toLowerCase())}));break;case"lastModify":t.sort((function(t,i){return e.sortAsc?t.lastModify-i.lastModify:i.lastModify-t.lastModify}));break;default:t.sort((function(t,i){return e.sortAsc?t.name.toLowerCase().localeCompare(i.name.toLowerCase()):i.name.toLowerCase().localeCompare(t.name.toLowerCase())}))}return t},hiddenCount:function(){return this.mediaItems.length-this.filteredMediaItems.length},thumbSize:function(){return this.smallThumbs?100:240},currentPrefs:{get:function(){return{smallThumbs:this.smallThumbs,selectedFolder:this.selectedFolder,gridView:this.gridView}},set:function(e){e&&(this.smallThumbs=e.smallThumbs,this.selectedFolder=e.selectedFolder,this.gridView=e.gridView)}}},watch:{currentPrefs:function(e){localStorage.setItem("mediaApplicationPrefs",JSON.stringify(e))},selectedFolder:function(e){this.mediaFilter="",this.selectedFolder=e,this.loadFolder(e)}},mounted:function(){this.$refs.rootFolder.toggle()},methods:{uploadUrl:function(){if(!this.selectedFolder)return null;var e=$("#uploadFiles").val();return e+(-1==e.indexOf("?")?"?":"&")+"path="+encodeURIComponent(this.selectedFolder.path)},selectRoot:function(){this.selectedFolder=this.root},loadFolder:function(e){this.errors=[],this.selectedMedias=[];var t=this,i=$("#getMediaItemsUrl").val();console.log(e.path),$.ajax({url:i+(-1==i.indexOf("?")?"?":"&")+"path="+encodeURIComponent(e.path),method:"GET",success:function(e){e.forEach((function(e){e.open=!1})),t.mediaItems=e,t.selectedMedias=[],t.sortBy="",t.sortAsc=!0},error:function(i){console.log("error loading folder:"+e.path),t.selectRoot()}})},selectAll:function(){this.selectedMedias=[];for(var e=0;e-1&&(t.mediaItems.splice(n,1),bus.$emit("mediaDeleted",t.selectedMedias[i]))}t.selectedMedias=[]},error:function(e){console.error(e.responseText)}})}}}))},deleteMediaItem:function(e){var t=this;e&&confirmDialog(_objectSpread(_objectSpread({},$("#deleteMedia").data()),{},{callback:function(i){i&&$.ajax({url:$("#deleteMediaUrl").val()+"?path="+encodeURIComponent(e.mediaPath),method:"POST",data:{__RequestVerificationToken:$("input[name='__RequestVerificationToken']").val()},success:function(i){var n=t.mediaItems&&t.mediaItems.indexOf(e);n>-1&&(t.mediaItems.splice(n,1),bus.$emit("mediaDeleted",e))},error:function(e){console.error(e.responseText)}})}}))},handleDragStart:function(e,t){var i=[];this.selectedMedias.forEach((function(e){i.push(e.name)})),0==this.isMediaSelected(e)&&(i.push(e.name),this.selectedMedias.push(e)),t.dataTransfer.setData("mediaNames",JSON.stringify(i)),t.dataTransfer.setData("sourceFolder",this.selectedFolder.path),t.dataTransfer.setDragImage(this.dragDropThumbnail,10,10),t.dataTransfer.effectAllowed="move"},handleScrollWhileDrag:function(e){e.clientY<150&&window.scrollBy(0,-10),e.clientY>window.innerHeight-100&&window.scrollBy(0,10)},changeSort:function(e){this.sortBy==e?this.sortAsc=!this.sortAsc:(this.sortAsc=!0,this.sortBy=e)}}}),$("#create-folder-name").keypress((function(e){if(13==e.which)return $("#modalFooterOk").click(),!1})),$("#modalFooterOk").on("click",(function(e){var t=$("#create-folder-name").val();""!==t&&$.ajax({url:$("#createFolderUrl").val()+"?path="+encodeURIComponent(mediaApp.selectedFolder.path)+"&name="+encodeURIComponent(t),method:"POST",data:{__RequestVerificationToken:$("input[name='__RequestVerificationToken']").val()},success:function(e){bus.$emit("addFolder",mediaApp.selectedFolder,e),bootstrap.Modal.getOrCreateInstance($("#createFolderModal")).hide()},error:function(e){$("#createFolderModal-errors").empty();var t=JSON.parse(e.responseText).value;$('').text(t).appendTo($("#createFolderModal-errors"))}})})),$("#renameMediaModalFooterOk").on("click",(function(e){var t=$("#new-item-name").val(),i=$("#old-item-name").val();if(""!==t){var n=mediaApp.selectedFolder.path+"/";"/"===n&&(n="");var a=n+t,o=n+i;if(a.toLowerCase()!==o.toLowerCase())$.ajax({url:$("#renameMediaUrl").val()+"?oldPath="+encodeURIComponent(o)+"&newPath="+encodeURIComponent(a),method:"POST",data:{__RequestVerificationToken:$("input[name='__RequestVerificationToken']").val()},success:function(e){bootstrap.Modal.getOrCreateInstance($("#renameMediaModal")).hide(),bus.$emit("mediaRenamed",t,a,o,e.newUrl)},error:function(e){$("#renameMediaModal-errors").empty();var t=JSON.parse(e.responseText).value;$('').text(t).appendTo($("#renameMediaModal-errors"))}});else bootstrap.Modal.getOrCreateInstance($("#renameMediaModal")).hide()}})),e&&(document.getElementById("mediaApp").style.display=""),$(document).trigger("mediaApp:ready")},error:function(e){console.error(e.responseText)}}))}function _typeof(e){return _typeof="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},_typeof(e)}function ownKeys(e,t){var i=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),i.push.apply(i,n)}return i}function _objectSpread(e){for(var t=1;t\n \n
      \n \n \n
    \n \n '),props:{model:Object,selectedInMediaApp:Object,level:Number},data:function(){return{open:!1,children:null,parent:null,isHovered:!1,padding:0}},computed:{empty:function(){return!this.children||0==this.children.length},isSelected:function(){return this.selectedInMediaApp.name==this.model.name&&this.selectedInMediaApp.path==this.model.path},isRoot:function(){return""===this.model.path},canCreateFolder:function(){return void 0===this.model.canCreateFolder||this.model.canCreateFolder},canDeleteFolder:function(){return void 0===this.model.canDeleteFolder||this.model.canDeleteFolder}},mounted:function(){0==this.isRoot&&this.isAncestorOfSelectedFolder()&&this.toggle(),this.padding=this.level<3?16:16+8*this.level},created:function(){var e=this;bus.$on("deleteFolder",(function(t){if(e.children){var i=e.children&&e.children.indexOf(t);i>-1&&(e.children.splice(i,1),bus.$emit("folderDeleted"))}})),bus.$on("addFolder",(function(t,i){e.model==t&&(null!==e.children&&e.children.push(i),i.parent=e.model,bus.$emit("folderAdded",i))}))},methods:{isAncestorOfSelectedFolder:function(){for(parentFolder=mediaApp.selectedFolder;parentFolder;){if(parentFolder.path==this.model.path)return!0;parentFolder=parentFolder.parent}return!1},toggle:function(){this.open=!this.open,this.open&&!this.children&&this.loadChildren()},select:function(){bus.$emit("folderSelected",this.model),this.loadChildren()},createFolder:function(){bus.$emit("createFolderRequested")},deleteFolder:function(){bus.$emit("deleteFolderRequested")},loadChildren:function(){var e=this;0==this.open&&(this.open=!0),$.ajax({url:$("#getFoldersUrl").val()+"?path="+encodeURIComponent(e.model.path),method:"GET",success:function(t){e.children=t,e.children.forEach((function(t){t.parent=e.model}))},error:function(e){emtpy=!1,console.error(e.responseText)}})},handleDragOver:function(e){this.isHovered=!0},handleDragLeave:function(e){this.isHovered=!1},moveMediaToFolder:function(e,t){this.isHovered=!1;var i=JSON.parse(t.dataTransfer.getData("mediaNames"));if(!(i.length<1)){var n=t.dataTransfer.getData("sourceFolder"),a=e.path;""===n&&(n="root"),""===a&&(a="root"),n!==a?confirmDialog(_objectSpread(_objectSpread({},$("#moveMedia").data()),{},{callback:function(e){e&&$.ajax({url:$("#moveMediaListUrl").val(),method:"POST",data:{__RequestVerificationToken:$("input[name='__RequestVerificationToken']").val(),mediaNames:i,sourceFolder:n,targetFolder:a},success:function(){bus.$emit("mediaListMoved")},error:function(e){console.error(e.responseText),bus.$emit("mediaListMoved",e.responseText)}})}})):alert($("#sameFolderMessage").val())}}}});var faIcons={image:"fa-regular fa-image",pdf:"fa-regular fa-file-pdf",word:"fa-regular fa-file-word",powerpoint:"fa-regular fa-file-powerpoint",excel:"fa-regular fa-file-excel",csv:"fa-regular fa-file",audio:"fa-regular fa-file-audio",video:"fa-regular fa-file-video",archive:"fa-regular fa-file-zipper",code:"fa-regular fa-file-code",text:"fa-regular fa-file-lines",file:"fa-regular fa-file"},faThumbnails={gif:faIcons.image,jpeg:faIcons.image,jpg:faIcons.image,png:faIcons.image,pdf:faIcons.pdf,doc:faIcons.word,docx:faIcons.word,ppt:faIcons.powerpoint,pptx:faIcons.powerpoint,xls:faIcons.excel,xlsx:faIcons.excel,csv:faIcons.csv,aac:faIcons.audio,mp3:faIcons.audio,ogg:faIcons.audio,avi:faIcons.video,flv:faIcons.video,mkv:faIcons.video,mp4:faIcons.video,webm:faIcons.video,gz:faIcons.archive,zip:faIcons.archive,css:faIcons.code,html:faIcons.code,js:faIcons.code,txt:faIcons.text};function getClassNameForExtension(e){return faThumbnails[e.toLowerCase()]||faIcons.file}function getExtensionForFilename(e){return e.slice(2+(e.lastIndexOf(".")-1>>>0))}function getClassNameForFilename(e){return getClassNameForExtension(getExtensionForFilename(e))}function initializeAttachedMediaField(e,t,i,n,a,o,r,s,l){var d,c=$(document.getElementById($(e).data("for"))).data("init"),u=$(e),m=u.attr("id");mediaFieldApps.push(d=new Vue({el:u.get(0),data:{mediaItems:[],selectedMedia:null,smallThumbs:!1,idPrefix:m,initialized:!1,allowMediaText:o,backupMediaText:"",allowAnchors:r,backupAnchor:null,mediaTextmodal:null,anchoringModal:null},created:function(){this.currentPrefs=JSON.parse(localStorage.getItem("mediaFieldPrefs"))},computed:{paths:{get:function(){var e=[];return this.initialized?(this.mediaItems.forEach((function(t){"not-found"!==t.mediaPath&&e.push({path:t.mediaPath,isRemoved:t.isRemoved,isNew:t.isNew,mediaText:t.mediaText,anchor:t.anchor,attachedFileName:t.attachedFileName})})),JSON.stringify(e)):JSON.stringify(c)},set:function(e){var t=this,i=e||[],a=$.Deferred(),o=[],r=0;i.forEach((function(e,i){o.push({name:" "+e.path,mime:"",mediaPath:"",anchor:e.anchor,attachedFileName:e.attachedFileName}),promise=$.when(a).done((function(){$.ajax({url:n+"?path="+encodeURIComponent(e.path),method:"GET",success:function(n){n.vuekey=n.name+i.toString(),n.mediaText=e.mediaText,n.anchor=e.anchor,n.attachedFileName=e.attachedFileName,o.splice(i,1,n),o.length===++r&&(o.forEach((function(e){t.mediaItems.push(e)})),t.initialized=!0)},error:function(n){console.log(JSON.stringify(n)),o.splice(i,1,{name:e.path,mime:"",mediaPath:"not-found",mediaText:"",anchor:{x:.5,y:.5},attachedFileName:e.attachedFileName}),o.length===++r&&(o.forEach((function(e){t.mediaItems.push(e)})),t.initialized=!0)}})}))})),a.resolve()}},fileSize:function(){return Math.round(this.selectedMedia.size/1024)},canAddMedia:function(){for(var e=[],t=0;t0&&a},thumbSize:function(){return this.smallThumbs?120:240},currentPrefs:{get:function(){return{smallThumbs:this.smallThumbs}},set:function(e){e&&(this.smallThumbs=e.smallThumbs)}}},mounted:function(){var e=this;e.paths=c,e.$on("selectAndDeleteMediaRequested",(function(t){e.selectAndDeleteMedia(t)})),e.$on("selectMediaRequested",(function(t){e.selectMedia(t)}));var n="#"+t,o=u.attr("id"),r=randomUUID();$(n).fileupload({limitConcurrentUploads:20,dropZone:$("#"+o),dataType:"json",url:i,maxChunkSize:l,add:function(t,i){var n,a=i.files.length;for(n=0;n0)for(var o=0;o1&&!1===a?(alert($("#onlyOneItemMessage").val()),d.mediaItems.push(i[0]),d.initialized=!0):(d.mediaItems=d.mediaItems.concat(i),d.initialized=!0)):alert(n)},error:function(e,t,i){console.log("Error on upload."),console.log(e),console.log(t),console.log(i)}}).on("fileuploadchunkbeforesend",(function(e,t){var i=t.files[0];t.blob=new File([t.blob],i.name,{type:i.type,lastModified:i.lastModified})}))},methods:{selectMedia:function(e){this.selectedMedia=e},getUniqueId:function(){return"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,(function(e){var t=16*Math.random()|0;return("x"===e?t:3&t|8).toString(16)}))},removeSelected:function(e){if(this.selectedMedia){var t=this.mediaItems&&this.mediaItems.indexOf(this.selectedMedia);t>-1&&(this.mediaItems[t].isRemoved=!0,this.mediaItems.splice(t,1))}else 1===this.mediaItems.length&&(this.mediaItems[t].isRemoved=!0,this.mediaItems.splice(0,1));this.selectedMedia=null},showMediaTextModal:function(e){this.mediaTextModal=new bootstrap.Modal(this.$refs.mediaTextModal),this.mediaTextModal.show(),this.backupMediaText=this.selectedMedia.mediaText},cancelMediaTextModal:function(e){this.mediaTextModal.hide(),this.selectedMedia.mediaText=this.backupMediaText},showAnchorModal:function(e){this.anchoringModal=new bootstrap.Modal(this.$refs.anchoringModal),this.anchoringModal.show(),this.selectedMedia.anchor={x:this.selectedMedia.anchor.x,y:this.selectedMedia.anchor.y},this.backupAnchor=this.selectedMedia.anchor},cancelAnchoringModal:function(e){this.anchoringModal.hide(),this.selectedMedia.anchor=this.backupAnchor},resetAnchor:function(e){this.selectedMedia.anchor={x:.5,y:.5}},onAnchorDrop:function(e){var t=this.$refs.anchorImage;this.selectedMedia.anchor={x:e.offsetX/t.clientWidth,y:e.offsetY/t.clientHeight}},anchorLeft:function(){if(this.$refs.anchorImage&&this.$refs.modalBody&&this.selectedMedia){var e=(this.$refs.modalBody.clientWidth-this.$refs.anchorImage.clientWidth)/2,t=this.selectedMedia.anchor.x*this.$refs.anchorImage.clientWidth+e;return t<17?t=17:t-=8,t+"px"}return"0"},anchorTop:function(){if(this.$refs.anchorImage&&this.selectedMedia){var e=this.selectedMedia.anchor.y*this.$refs.anchorImage.clientHeight;return e<15?e=15:e+=5,e+"px"}return"0"},setAnchor:function(e){var t=this.$refs.anchorImage;this.selectedMedia.anchor={x:e.offsetX/t.clientWidth,y:e.offsetY/t.clientHeight}},addMediaFiles:function(e){e.length>1&&!1===a?(alert($("#onlyOneItemMessage").val()),d.mediaItems.push(e[0]),d.initialized=!0):(d.mediaItems=d.mediaItems.concat(e),d.initialized=!0)},selectAndDeleteMedia:function(e){var t=this;t.selectedMedia=e,setTimeout((function(){t.removeSelected()}),100)}},watch:{mediaItems:{deep:!0,handler:function(){setTimeout((function(){$(document).trigger("contentpreview:render")}),100)}},currentPrefs:function(e){localStorage.setItem("mediaFieldPrefs",JSON.stringify(e))}}}))}function initializeMediaField(e,t,i,n,a,o){if(null!==e){var r,s=$(document.getElementById($(e).data("for"))).data("init"),l=$(e),d=l.attr("id");t.addEventListener("hidden.bs.modal",(function(e){$("#mediaApp").appendTo("body"),$("#mediaApp").hide()})),mediaFieldApps.push(r=new Vue({el:l.get(0),data:{mediaItems:[],selectedMedia:null,smallThumbs:!1,idPrefix:d,initialized:!1,allowMediaText:a,backupMediaText:"",allowAnchors:o,backupAnchor:null,mediaTextModal:null,anchoringModal:null},created:function(){this.currentPrefs=JSON.parse(localStorage.getItem("mediaFieldPrefs"))},computed:{paths:{get:function(){var e=[];return this.initialized?(this.mediaItems.forEach((function(t){"not-found"!==t.mediaPath&&e.push({path:t.mediaPath,mediaText:t.mediaText,anchor:t.anchor})})),JSON.stringify(e)):JSON.stringify(s)},set:function(e){var t=this,n=e||[],a=$.Deferred(),o=[],r=0;n.forEach((function(e,n){o.push({name:" "+e.path,mime:"",mediaPath:""}),promise=$.when(a).done((function(){$.ajax({url:i+"?path="+encodeURIComponent(e.path),method:"GET",success:function(i){i.vuekey=i.name+n.toString(),i.mediaText=e.mediaText,i.anchor=e.anchor,o.splice(n,1,i),o.length===++r&&(o.forEach((function(e){t.mediaItems.push(e)})),t.initialized=!0)},error:function(i){console.log(i),o.splice(n,1,{name:e.path,mime:"",mediaPath:"not-found",mediaText:"",anchor:{x:0,y:0}}),o.length===++r&&(o.forEach((function(e){t.mediaItems.push(e)})),t.initialized=!0)}})}))})),a.resolve()}},fileSize:function(){return Math.round(this.selectedMedia.size/1024)},canAddMedia:function(){return 0===this.mediaItems.length||this.mediaItems.length>0&&n},thumbSize:function(){return this.smallThumbs?120:240},currentPrefs:{get:function(){return{smallThumbs:this.smallThumbs}},set:function(e){e&&(this.smallThumbs=e.smallThumbs)}}},mounted:function(){var e=this;e.paths=s,e.$on("selectAndDeleteMediaRequested",(function(t){e.selectAndDeleteMedia(t)})),e.$on("selectMediaRequested",(function(t){e.selectMedia(t)})),e.$on("filesUploaded",(function(t){e.addMediaFiles(t)}))},methods:{selectMedia:function(e){this.selectedMedia=e},showModal:function(e){var i=this;if(i.canAddMedia){$("#mediaApp").appendTo($(t).find(".modal-body")),$("#mediaApp").show();var n=new bootstrap.Modal(t);n.show(),$(t).find(".mediaFieldSelectButton").off("click").on("click",(function(e){return i.addMediaFiles(mediaApp.selectedMedias),mediaApp.selectedMedias=[],n.hide(),!0}))}},showMediaTextModal:function(e){this.mediaTextModal=new bootstrap.Modal(this.$refs.mediaTextModal),this.mediaTextModal.show(),this.backupMediaText=this.selectedMedia.mediaText},cancelMediaTextModal:function(e){this.mediaTextModal.hide(),this.selectedMedia.mediaText=this.backupMediaText},showAnchorModal:function(e){this.anchoringModal=new bootstrap.Modal(this.$refs.anchoringModal),this.anchoringModal.show(),this.selectedMedia.anchor={x:this.selectedMedia.anchor.x,y:this.selectedMedia.anchor.y},this.backupAnchor=this.selectedMedia.anchor},cancelAnchoringModal:function(e){this.anchoringModal.hide(),this.selectedMedia.anchor=this.backupAnchor},resetAnchor:function(e){this.selectedMedia.anchor={x:.5,y:.5}},onAnchorDrop:function(e){var t=this.$refs.anchorImage;this.selectedMedia.anchor={x:e.offsetX/t.clientWidth,y:e.offsetY/t.clientHeight}},anchorLeft:function(){if(this.$refs.anchorImage&&this.$refs.modalBody&&this.selectedMedia){var e=(this.$refs.modalBody.clientWidth-this.$refs.anchorImage.clientWidth)/2,t=this.selectedMedia.anchor.x*this.$refs.anchorImage.clientWidth+e,i=Math.round(this.$refs.modalBody.querySelector(".icon-media-anchor").clientWidth);return Number.isInteger(i)&&(t-=i/2),t+"px"}return"0"},anchorTop:function(){return this.$refs.anchorImage&&this.selectedMedia?this.selectedMedia.anchor.y*this.$refs.anchorImage.clientHeight+"px":"0"},setAnchor:function(e){var t=this.$refs.anchorImage;this.selectedMedia.anchor={x:e.offsetX/t.clientWidth,y:e.offsetY/t.clientHeight}},addMediaFiles:function(e){e.length>1&&!1===n?(alert($("#onlyOneItemMessage").val()),r.mediaItems.push(e[0]),r.initialized=!0):(r.mediaItems=r.mediaItems.concat(e),r.initialized=!0)},removeSelected:function(e){if(this.selectedMedia){var t=this.mediaItems&&this.mediaItems.indexOf(this.selectedMedia);t>-1&&this.mediaItems.splice(t,1)}else 1===this.mediaItems.length&&this.mediaItems.splice(0,1);this.selectedMedia=null},selectAndDeleteMedia:function(e){var t=this;t.selectedMedia=e,setTimeout((function(){t.removeSelected()}),100)}},watch:{mediaItems:{deep:!0,handler:function(){setTimeout((function(){$(document).trigger("contentpreview:render")}),100)}},currentPrefs:function(e){localStorage.setItem("mediaFieldPrefs",JSON.stringify(e))}}}))}}Vue.component("media-items-grid",{template:'\n
      \n
    1. \n
      \n \n \n
      \n
      \n \n \n \n {{ media.name }}\n
      \n
    2. \n
    \n ',data:function(){return{T:{}}},props:{filteredMediaItems:Array,selectedMedias:Array,thumbSize:Number},created:function(){this.T.editButton=$("#t-edit-button").val(),this.T.deleteButton=$("#t-delete-button").val()},methods:{isMediaSelected:function(e){return this.selectedMedias.some((function(t,i,n){return t.url.toLowerCase()===e.url.toLowerCase()}))},buildMediaUrl:function(e,t){return e+(-1==e.indexOf("?")?"?":"&")+"width="+t+"&height="+t},toggleSelectionOfMedia:function(e){bus.$emit("mediaToggleRequested",e)},renameMedia:function(e){bus.$emit("renameMediaRequested",e)},deleteMedia:function(e){bus.$emit("deleteMediaRequested",e)},dragStart:function(e,t){bus.$emit("mediaDragStartRequested",e,t)},getfontAwesomeClassNameForFileName:function(e,t){return getClassNameForFilename(e)+" "+t}}}),Vue.component("media-items-table",{template:'\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
    {{ T.imageHeader }}\n {{ T.nameHeader }}\n \n \n {{ T.lastModifyHeader }} \n \n \n \n {{ T.sizeHeader }}\n \n \n \n \n {{ T.typeHeader }}\n \n \n
    \n
    \n \n \n
    \n
    \n \n \n
    {{ printDateTime(media.lastModify) }}
    \n
    \n
    {{ isNaN(media.size)? 0 : Math.round(media.size / 1024) }} KB
    \n
    \n
    {{ media.mime }}
    \n
    \n ',data:function(){return{T:{}}},props:{sortBy:String,sortAsc:Boolean,filteredMediaItems:Array,selectedMedias:Array,thumbSize:Number},created:function(){var e=this;e.T.imageHeader=$("#t-image-header").val(),e.T.nameHeader=$("#t-name-header").val(),e.T.lastModifyHeader=$("#t-lastModify-header").val(),e.T.sizeHeader=$("#t-size-header").val(),e.T.typeHeader=$("#t-type-header").val(),e.T.editButton=$("#t-edit-button").val(),e.T.deleteButton=$("#t-delete-button").val(),e.T.viewButton=$("#t-view-button").val()},methods:{isMediaSelected:function(e){return this.selectedMedias.some((function(t,i,n){return t.url.toLowerCase()===e.url.toLowerCase()}))},buildMediaUrl:function(e,t){return e+(-1==e.indexOf("?")?"?":"&")+"width="+t+"&height="+t},changeSort:function(e){bus.$emit("sortChangeRequested",e)},toggleSelectionOfMedia:function(e){bus.$emit("mediaToggleRequested",e)},renameMedia:function(e){bus.$emit("renameMediaRequested",e)},deleteMedia:function(e){bus.$emit("deleteMediaRequested",e)},dragStart:function(e,t){bus.$emit("mediaDragStartRequested",e,t)},printDateTime:function(e){return new Date(e).toLocaleString()},getfontAwesomeClassNameForFileName:function(e,t){return getClassNameForFilename(e)+" "+t}}}),Vue.component("pager",{template:'\n
    \n \n \n
    \n ',props:{sourceItems:Array},data:function(){return{pageSize:10,pageSizeOptions:[10,30,50,100],current:0,T:{}}},created:function(){var e=this;e.T.pagerFirstButton=$("#t-pager-first-button").val(),e.T.pagerPreviousButton=$("#t-pager-previous-button").val(),e.T.pagerNextButton=$("#t-pager-next-button").val(),e.T.pagerLastButton=$("#t-pager-last-button").val(),e.T.pagerPageSizeLabel=$("#t-pager-page-size-label").val(),e.T.pagerPageLabel=$("#t-pager-page-label").val(),e.T.pagerTotalLabel=$("#t-pager-total-label").val()},methods:{next:function(){this.current=this.current+1},previous:function(){this.current=this.current-1},goFirst:function(){this.current=0},goLast:function(){this.current=this.totalPages-1},goTo:function(e){this.current=e}},computed:{total:function(){return this.sourceItems?this.sourceItems.length:0},totalPages:function(){var e=Math.ceil(this.total/this.pageSize);return e>0?e:1},isLastPage:function(){return this.current+1>=this.totalPages},isFirstPage:function(){return 0===this.current},canDoNext:function(){return!this.isLastPage},canDoPrev:function(){return!this.isFirstPage},canDoFirst:function(){return!this.isFirstPage},canDoLast:function(){return!this.isLastPage},itemsInCurrentPage:function(){var e=this.pageSize*this.current,t=e+this.pageSize,i=this.sourceItems.slice(e,t);return bus.$emit("pagerEvent",i),i},pageLinks:function(){var e=[];e.push(this.current+1);var t=this.current>0?this.current:-1;e.unshift(t);var i=this.current>1?this.current-1:-1;e.unshift(i);var n=this.totalPages-this.current>1?this.current+2:-1;e.push(n);var a=this.totalPages-this.current>2?this.current+3:-1;return e.push(a),e}},watch:{sourceItems:function(){this.current=0},pageSize:function(){this.current=0}}}),Vue.component("sortIndicator",{template:'\n
    \n \n \n
    \n ',props:{colname:String,selectedcolname:String,asc:Boolean},computed:{isActive:function(){return this.colname.toLowerCase()==this.selectedcolname.toLowerCase()}}}),Vue.component("mediaFieldThumbsContainer",{template:'
    {{T.noImages}}
  • {{ media.isNew ? media.name.substr(36) : media.name }}
    {{ T.mediaNotFound }} {{ T.discardWarning }}
    {{ media.name }}
  • ',data:function(){return{T:{}}},props:{mediaItems:Array,selectedMedia:Object,thumbSize:Number,idPrefix:String},created:function(){var e=this;e.T.mediaNotFound=$("#t-media-not-found").val(),e.T.discardWarning=$("#t-discard-warning").val(),e.T.noImages=$("#t-no-images").val()},methods:{selectAndDeleteMedia:function(e){this.$parent.$emit("selectAndDeleteMediaRequested",e)},selectMedia:function(e){this.$parent.$emit("selectMediaRequested",e)},buildMediaUrl:function(e,t){return e+(-1==e.indexOf("?")?"?":"&")+"width="+t+"&height="+t},getfontAwesomeClassNameForFileName:function(e,t){return getClassNameForFilename(e)+" "+t}}});var mediaFieldApps=[];function _typeof(e){return _typeof="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},_typeof(e)}function randomUUID(){return"object"===("undefined"==typeof crypto?"undefined":_typeof(crypto))&&"function"==typeof crypto.randomUUID?crypto.randomUUID():([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g,(function(e){return(e^crypto.getRandomValues(new Uint8Array(1))[0]&15>>e/4).toString(16)}))}function _typeof(e){return _typeof="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},_typeof(e)}function _typeof(e){return _typeof="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},_typeof(e)}Vue.component("upload",{template:'

    {{ model.name }}

    Error: {{ model.errorMessage }}
    ',props:{model:Object,uploadInputId:String},mounted:function(){var e,t=this,i=document.getElementById(null!==(e=t.uploadInputId)&&void 0!==e?e:"fileupload");$(i).bind("fileuploadprogress",(function(e,i){i.files[0].name===t.model.name&&(t.model.percentage=parseInt(i.loaded/i.total*100,10))})),$(i).bind("fileuploaddone",(function(e,i){i.files[0].name===t.model.name&&(i.result.files[0].error?t.handleFailure(i.files[0].name,i.result.files[0].error):bus.$emit("removalRequest",t.model))})),$(i).bind("fileuploadfail",(function(e,i){i.files[0].name===t.model.name&&t.handleFailure(i.files[0].name,$("#t-error").val())}))},methods:{handleFailure:function(e,t){e===this.model.name&&(this.model.errorMessage=t,bus.$emit("ErrorOnUpload",this.model))},dismissWarning:function(){bus.$emit("removalRequest",this.model)}}}),Vue.component("uploadList",{template:'
    {{ T.uploads }} (Pending: {{ pendingCount }}) ( {{ T.errors }}: {{ errorCount }} / {{ T.clearErrors }} )
    ',data:function(){return{files:[],T:{},expanded:!1,pendingCount:0,errorCount:0}},props:{uploadInputId:String},created:function(){var e=this;e.T.uploads=$("#t-uploads").val(),e.T.errors=$("#t-errors").val(),e.T.clearErrors=$("#t-clear-errors").val()},computed:{fileCount:function(){return this.files.length}},mounted:function(){var e,t=this,i=document.getElementById(null!==(e=t.uploadInputId)&&void 0!==e?e:"fileupload");$(i).bind("fileuploadadd",(function(e,i){i.files&&i.files.forEach((function(e){t.files.some((function(t){return t.name==e.name}))?console.error("A file with the same name is already on the queue:"+e.name):t.files.push({name:e.name,percentage:0,errorMessage:""})}))})),bus.$on("removalRequest",(function(e){t.files.forEach((function(t,i,n){t.name==e.name&&n.splice(i,1)}))})),bus.$on("ErrorOnUpload",(function(e){t.updateCount()}))},methods:{updateCount:function(){this.errorCount=this.files.filter((function(e){return""!=e.errorMessage})).length,this.pendingCount=this.files.length-this.errorCount,this.files.length<1&&(this.expanded=!1)},clearErrors:function(){this.files=this.files.filter((function(e){return""==e.errorMessage}))}},watch:{files:function(){this.updateCount()}}}),function(e){"use strict";"function"==typeof define&&define.amd?define(["jquery","jquery-ui/ui/widget"],e):"object"===("undefined"==typeof exports?"undefined":_typeof(exports))?e(require("jquery"),require("./vendor/jquery.ui.widget")):e(window.jQuery)}((function(e){"use strict";function t(t){var i="dragover"===t;return function(n){n.dataTransfer=n.originalEvent&&n.originalEvent.dataTransfer;var a=n.dataTransfer;a&&-1!==e.inArray("Files",a.types)&&!1!==this._trigger(t,e.Event(t,{delegatedEvent:n}))&&(n.preventDefault(),i&&(a.dropEffect="copy"))}}var i;e.support.fileInput=!(new RegExp("(Android (1\\.[0156]|2\\.[01]))|(Windows Phone (OS 7|8\\.0))|(XBLWP)|(ZuneWP)|(WPDesktop)|(w(eb)?OSBrowser)|(webOS)|(Kindle/(1\\.0|2\\.[05]|3\\.0))").test(window.navigator.userAgent)||e('').prop("disabled")),e.support.xhrFileUpload=!(!window.ProgressEvent||!window.FileReader),e.support.xhrFormDataFileUpload=!!window.FormData,e.support.blobSlice=window.Blob&&(Blob.prototype.slice||Blob.prototype.webkitSlice||Blob.prototype.mozSlice),e.widget("blueimp.fileupload",{options:{dropZone:e(document),pasteZone:void 0,fileInput:void 0,replaceFileInput:!0,paramName:void 0,singleFileUploads:!0,limitMultiFileUploads:void 0,limitMultiFileUploadSize:void 0,limitMultiFileUploadSizeOverhead:512,sequentialUploads:!1,limitConcurrentUploads:void 0,forceIframeTransport:!1,redirect:void 0,redirectParamName:void 0,postMessage:void 0,multipart:!0,maxChunkSize:void 0,uploadedBytes:void 0,recalculateProgress:!0,progressInterval:100,bitrateInterval:500,autoUpload:!0,uniqueFilenames:void 0,messages:{uploadedBytes:"Uploaded bytes exceed file size"},i18n:function(t,i){return t=this.messages[t]||t.toString(),i&&e.each(i,(function(e,i){t=t.replace("{"+e+"}",i)})),t},formData:function(e){return e.serializeArray()},add:function(t,i){if(t.isDefaultPrevented())return!1;(i.autoUpload||!1!==i.autoUpload&&e(this).fileupload("option","autoUpload"))&&i.process().done((function(){i.submit()}))},processData:!1,contentType:!1,cache:!1,timeout:0},_promisePipe:(i=e.fn.jquery.split("."),Number(i[0])>1||Number(i[1])>7?"then":"pipe"),_specialOptions:["fileInput","dropZone","pasteZone","multipart","forceIframeTransport"],_blobSlice:e.support.blobSlice&&function(){return(this.slice||this.webkitSlice||this.mozSlice).apply(this,arguments)},_BitrateTimer:function(){this.timestamp=Date.now?Date.now():(new Date).getTime(),this.loaded=0,this.bitrate=0,this.getBitrate=function(e,t,i){var n=e-this.timestamp;return(!this.bitrate||!i||n>i)&&(this.bitrate=(t-this.loaded)*(1e3/n)*8,this.loaded=t,this.timestamp=e),this.bitrate}},_isXHRUpload:function(t){return!t.forceIframeTransport&&(!t.multipart&&e.support.xhrFileUpload||e.support.xhrFormDataFileUpload)},_getFormData:function(t){var i;return"function"===e.type(t.formData)?t.formData(t.form):e.isArray(t.formData)?t.formData:"object"===e.type(t.formData)?(i=[],e.each(t.formData,(function(e,t){i.push({name:e,value:t})})),i):[]},_getTotal:function(t){var i=0;return e.each(t,(function(e,t){i+=t.size||1})),i},_initProgressObject:function(t){var i={loaded:0,total:0,bitrate:0};t._progress?e.extend(t._progress,i):t._progress=i},_initResponseObject:function(e){var t;if(e._response)for(t in e._response)Object.prototype.hasOwnProperty.call(e._response,t)&&delete e._response[t];else e._response={}},_onProgress:function(t,i){if(t.lengthComputable){var n,a=Date.now?Date.now():(new Date).getTime();if(i._time&&i.progressInterval&&a-i._time").prop("href",t.url).prop("host");t.dataType="iframe "+(t.dataType||""),t.formData=this._getFormData(t),t.redirect&&i&&i!==location.host&&t.formData.push({name:t.redirectParamName||"redirect",value:t.redirect})},_initDataSettings:function(e){this._isXHRUpload(e)?(this._chunkedUpload(e,!0)||(e.data||this._initXHRData(e),this._initProgressListener(e)),e.postMessage&&(e.dataType="postmessage "+(e.dataType||""))):this._initIframeSettings(e)},_getParamName:function(t){var i=e(t.fileInput),n=t.paramName;return n?e.isArray(n)||(n=[n]):(n=[],i.each((function(){for(var t=e(this),i=t.prop("name")||"files[]",a=(t.prop("files")||[1]).length;a;)n.push(i),a-=1})),n.length||(n=[i.prop("name")||"files[]"])),n},_initFormSettings:function(t){t.form&&t.form.length||(t.form=e(t.fileInput.prop("form")),t.form.length||(t.form=e(this.options.fileInput.prop("form")))),t.paramName=this._getParamName(t),t.url||(t.url=t.form.prop("action")||location.href),t.type=(t.type||"string"===e.type(t.form.prop("method"))&&t.form.prop("method")||"").toUpperCase(),"POST"!==t.type&&"PUT"!==t.type&&"PATCH"!==t.type&&(t.type="POST"),t.formAcceptCharset||(t.formAcceptCharset=t.form.attr("accept-charset"))},_getAJAXSettings:function(t){var i=e.extend({},this.options,t);return this._initFormSettings(i),this._initDataSettings(i),i},_getDeferredState:function(e){return e.state?e.state():e.isResolved()?"resolved":e.isRejected()?"rejected":"pending"},_enhancePromise:function(e){return e.success=e.done,e.error=e.fail,e.complete=e.always,e},_getXHRPromise:function(t,i,n){var a=e.Deferred(),o=a.promise();return i=i||this.options.context||o,!0===t?a.resolveWith(i,n):!1===t&&a.rejectWith(i,n),o.abort=a.promise,this._enhancePromise(o)},_addConvenienceMethods:function(t,i){var n=this,a=function(t){return e.Deferred().resolveWith(n,t).promise()};i.process=function(t,o){return(t||o)&&(i._processQueue=this._processQueue=(this._processQueue||a([this]))[n._promisePipe]((function(){return i.errorThrown?e.Deferred().rejectWith(n,[i]).promise():a(arguments)}))[n._promisePipe](t,o)),this._processQueue||a([this])},i.submit=function(){return"pending"!==this.state()&&(i.jqXHR=this.jqXHR=!1!==n._trigger("submit",e.Event("submit",{delegatedEvent:t}),this)&&n._onSend(t,this)),this.jqXHR||n._getXHRPromise()},i.abort=function(){return this.jqXHR?this.jqXHR.abort():(this.errorThrown="abort",n._trigger("fail",null,this),n._getXHRPromise(!1))},i.state=function(){return this.jqXHR?n._getDeferredState(this.jqXHR):this._processQueue?n._getDeferredState(this._processQueue):void 0},i.processing=function(){return!this.jqXHR&&this._processQueue&&"pending"===n._getDeferredState(this._processQueue)},i.progress=function(){return this._progress},i.response=function(){return this._response}},_getUploadedBytes:function(e){var t=e.getResponseHeader("Range"),i=t&&t.split("-"),n=i&&i.length>1&&parseInt(i[1],10);return n&&n+1},_chunkedUpload:function(t,i){t.uploadedBytes=t.uploadedBytes||0;var n,a,o=this,r=t.files[0],s=r.size,l=t.uploadedBytes,d=t.maxChunkSize||s,c=this._blobSlice,u=e.Deferred(),m=u.promise();return!(!(this._isXHRUpload(t)&&c&&(l||("function"===e.type(d)?d(t):d)=s?(r.error=t.i18n("uploadedBytes"),this._getXHRPromise(!1,t.context,[null,"error",r.error])):(a=function(){var i=e.extend({},t),m=i._progress.loaded;i.blob=c.call(r,l,l+("function"===e.type(d)?d(i):d),r.type),i.chunkSize=i.blob.size,i.contentRange="bytes "+l+"-"+(l+i.chunkSize-1)+"/"+s,o._trigger("chunkbeforesend",null,i),o._initXHRData(i),o._initProgressListener(i),n=(!1!==o._trigger("chunksend",null,i)&&e.ajax(i)||o._getXHRPromise(!1,i.context)).done((function(n,r,d){l=o._getUploadedBytes(d)||l+i.chunkSize,m+i.chunkSize-i._progress.loaded&&o._onProgress(e.Event("progress",{lengthComputable:!0,loaded:l-i.uploadedBytes,total:l-i.uploadedBytes}),i),t.uploadedBytes=i.uploadedBytes=l,i.result=n,i.textStatus=r,i.jqXHR=d,o._trigger("chunkdone",null,i),o._trigger("chunkalways",null,i),ls._sending)for(var n=s._slots.shift();n;){if("pending"===s._getDeferredState(n)){n.resolve();break}n=s._slots.shift()}0===s._active&&s._trigger("stop")}))};return this._beforeSend(t,l),this.options.sequentialUploads||this.options.limitConcurrentUploads&&this.options.limitConcurrentUploads<=this._sending?(this.options.limitConcurrentUploads>1?(o=e.Deferred(),this._slots.push(o),r=o[s._promisePipe](d)):(this._sequence=this._sequence[s._promisePipe](d,d),r=this._sequence),r.abort=function(){return a=[void 0,"abort","abort"],n?n.abort():(o&&o.rejectWith(l.context,a),d())},this._enhancePromise(r)):d()},_onAdd:function(t,i){var n,a,o,r,s=this,l=!0,d=e.extend({},this.options,i),c=i.files,u=c.length,m=d.limitMultiFileUploads,p=d.limitMultiFileUploadSize,f=d.limitMultiFileUploadSizeOverhead,h=0,g=this._getParamName(d),v=0;if(!u)return!1;if(p&&void 0===c[0].size&&(p=void 0),(d.singleFileUploads||m||p)&&this._isXHRUpload(d))if(d.singleFileUploads||p||!m)if(!d.singleFileUploads&&p)for(o=[],n=[],r=0;rp||m&&r+1-v>=m)&&(o.push(c.slice(v,r+1)),(a=g.slice(v,r+1)).length||(a=g),n.push(a),v=r+1,h=0);else n=g;else for(o=[],n=[],r=0;r").append(n)[0].reset(),i.after(n).detach(),a&&n.trigger("focus"),e.cleanData(i.off("remove")),this.options.fileInput=this.options.fileInput.map((function(e,t){return t===i[0]?n[0]:t})),i[0]===this.element[0]&&(this.element=n)},_handleFileTreeEntry:function(t,i){var n,a=this,o=e.Deferred(),r=[],s=function(e){e&&!e.entry&&(e.entry=t),o.resolve([e])};return i=i||"",t.isFile?t._file?(t._file.relativePath=i,o.resolve(t._file)):t.file((function(e){e.relativePath=i,o.resolve(e)}),s):t.isDirectory?(n=t.createReader(),function e(){n.readEntries((function(n){n.length?(r=r.concat(n),e()):function(e){a._handleFileTreeEntries(e,i+t.name+"/").done((function(e){o.resolve(e)})).fail(s)}(r)}),s)}()):o.resolve([]),o.promise()},_handleFileTreeEntries:function(t,i){var n=this;return e.when.apply(e,e.map(t,(function(e){return n._handleFileTreeEntry(e,i)})))[this._promisePipe]((function(){return Array.prototype.concat.apply([],arguments)}))},_getDroppedFiles:function(t){var i=(t=t||{}).items;return i&&i.length&&(i[0].webkitGetAsEntry||i[0].getAsEntry)?this._handleFileTreeEntries(e.map(i,(function(e){var t;return e.webkitGetAsEntry?((t=e.webkitGetAsEntry())&&(t._file=e.getAsFile()),t):e.getAsEntry()}))):e.Deferred().resolve(e.makeArray(t.files)).promise()},_getSingleFileInputFiles:function(t){var i,n,a=(t=e(t)).prop("entries");if(a&&a.length)return this._handleFileTreeEntries(a);if((i=e.makeArray(t.prop("files"))).length)void 0===i[0].name&&i[0].fileName&&e.each(i,(function(e,t){t.name=t.fileName,t.size=t.fileSize}));else{if(!(n=t.prop("value")))return e.Deferred().resolve([]).promise();i=[{name:n.replace(/^.*\\/,"")}]}return e.Deferred().resolve(i).promise()},_getFileInputFiles:function(t){return t instanceof e&&1!==t.length?e.when.apply(e,e.map(t,this._getSingleFileInputFiles))[this._promisePipe]((function(){return Array.prototype.concat.apply([],arguments)})):this._getSingleFileInputFiles(t)},_onChange:function(t){var i=this,n={fileInput:e(t.target),form:e(t.target.form)};this._getFileInputFiles(n.fileInput).always((function(a){n.files=a,i.options.replaceFileInput&&i._replaceFileInput(n),!1!==i._trigger("change",e.Event("change",{delegatedEvent:t}),n)&&i._onAdd(t,n)}))},_onPaste:function(t){var i=t.originalEvent&&t.originalEvent.clipboardData&&t.originalEvent.clipboardData.items,n={files:[]};i&&i.length&&(e.each(i,(function(e,t){var i=t.getAsFile&&t.getAsFile();i&&n.files.push(i)})),!1!==this._trigger("paste",e.Event("paste",{delegatedEvent:t}),n)&&this._onAdd(t,n))},_onDrop:function(t){t.dataTransfer=t.originalEvent&&t.originalEvent.dataTransfer;var i=this,n=t.dataTransfer,a={};n&&n.files&&n.files.length&&(t.preventDefault(),this._getDroppedFiles(n).always((function(n){a.files=n,!1!==i._trigger("drop",e.Event("drop",{delegatedEvent:t}),a)&&i._onAdd(t,a)})))},_onDragOver:t("dragover"),_onDragEnter:t("dragenter"),_onDragLeave:t("dragleave"),_initEventHandlers:function(){this._isXHRUpload(this.options)&&(this._on(this.options.dropZone,{dragover:this._onDragOver,drop:this._onDrop,dragenter:this._onDragEnter,dragleave:this._onDragLeave}),this._on(this.options.pasteZone,{paste:this._onPaste})),e.support.fileInput&&this._on(this.options.fileInput,{change:this._onChange})},_destroyEventHandlers:function(){this._off(this.options.dropZone,"dragenter dragleave dragover drop"),this._off(this.options.pasteZone,"paste"),this._off(this.options.fileInput,"change")},_destroy:function(){this._destroyEventHandlers()},_setOption:function(t,i){var n=-1!==e.inArray(t,this._specialOptions);n&&this._destroyEventHandlers(),this._super(t,i),n&&(this._initSpecialOptions(),this._initEventHandlers())},_initSpecialOptions:function(){var t=this.options;void 0===t.fileInput?t.fileInput=this.element.is('input[type="file"]')?this.element:this.element.find('input[type="file"]'):t.fileInput instanceof e||(t.fileInput=e(t.fileInput)),t.dropZone instanceof e||(t.dropZone=e(t.dropZone)),t.pasteZone instanceof e||(t.pasteZone=e(t.pasteZone))},_getRegExp:function(e){var t=e.split("/"),i=t.pop();return t.shift(),new RegExp(t.join("/"),i)},_isRegExpOption:function(t,i){return"url"!==t&&"string"===e.type(i)&&/^\/.*\/[igm]{0,3}$/.test(i)},_initDataAttributes:function(){var t=this,i=this.options,n=this.element.data();e.each(this.element[0].attributes,(function(e,a){var o,r=a.name.toLowerCase();/^data-/.test(r)&&(r=r.slice(5).replace(/-[a-z]/g,(function(e){return e.charAt(1).toUpperCase()})),o=n[r],t._isRegExpOption(r,o)&&(o=t._getRegExp(o)),i[r]=o)}))},_create:function(){this._initDataAttributes(),this._initSpecialOptions(),this._slots=[],this._sequence=this._getXHRPromise(!0),this._sending=this._active=0,this._initProgressObject(this),this._initEventHandlers()},active:function(){return this._active},progress:function(){return this._progress},add:function(t){var i=this;t&&!this.options.disabled&&(t.fileInput&&!t.files?this._getFileInputFiles(t.fileInput).always((function(e){t.files=e,i._onAdd(null,t)})):(t.files=e.makeArray(t.files),this._onAdd(null,t)))},send:function(t){if(t&&!this.options.disabled){if(t.fileInput&&!t.files){var i,n,a=this,o=e.Deferred(),r=o.promise();return r.abort=function(){return n=!0,i?i.abort():(o.reject(null,"abort","abort"),r)},this._getFileInputFiles(t.fileInput).always((function(e){n||(e.length?(t.files=e,(i=a._onSend(null,t)).then((function(e,t,i){o.resolve(e,t,i)}),(function(e,t,i){o.reject(e,t,i)}))):o.reject())})),this._enhancePromise(r)}if(t.files=e.makeArray(t.files),t.files.length)return this._onSend(null,t)}return this._getXHRPromise(!1,t&&t.context)}})})),function(e){"use strict";"function"==typeof define&&define.amd?define(["jquery"],e):"object"===("undefined"==typeof exports?"undefined":_typeof(exports))?e(require("jquery")):e(window.jQuery)}((function(e){"use strict";var t=0,i=e,n="parseJSON";"JSON"in window&&"parse"in JSON&&(i=JSON,n="parse"),e.ajaxTransport("iframe",(function(i){if(i.async){var n,a,o,r=i.initialIframeSrc||"javascript:false;";return{send:function(s,l){(n=e('
    ')).attr("accept-charset",i.formAcceptCharset),o=/\?/.test(i.url)?"&":"?","DELETE"===i.type?(i.url=i.url+o+"_method=DELETE",i.type="POST"):"PUT"===i.type?(i.url=i.url+o+"_method=PUT",i.type="POST"):"PATCH"===i.type&&(i.url=i.url+o+"_method=PATCH",i.type="POST"),a=e('').on("load",(function(){var t,o=e.isArray(i.paramName)?i.paramName:[i.paramName];a.off("load").on("load",(function(){var t;try{if(!(t=a.contents()).length||!t[0].firstChild)throw new Error}catch(e){t=void 0}l(200,"success",{iframe:t}),e('').appendTo(n),window.setTimeout((function(){n.remove()}),0)})),n.prop("target",a.prop("name")).prop("action",i.url).prop("method",i.type),i.formData&&e.each(i.formData,(function(t,i){e('').prop("name",i.name).val(i.value).appendTo(n)})),i.fileInput&&i.fileInput.length&&"POST"===i.type&&(t=i.fileInput.clone(),i.fileInput.after((function(e){return t[e]})),i.paramName&&i.fileInput.each((function(t){e(this).prop("name",o[t]||i.paramName)})),n.append(i.fileInput).prop("enctype","multipart/form-data").prop("encoding","multipart/form-data"),i.fileInput.removeAttr("form")),window.setTimeout((function(){n.submit(),t&&t.length&&i.fileInput.each((function(i,n){var a=e(t[i]);e(n).prop("name",a.prop("name")).attr("form",a.attr("form")),a.replaceWith(n)}))}),0)})),n.append(a).appendTo(document.body)},abort:function(){a&&a.off("load").prop("src",r),n&&n.remove()}}}})),e.ajaxSetup({converters:{"iframe text":function(t){return t&&e(t[0].body).text()},"iframe json":function(t){return t&&i[n](e(t[0].body).text())},"iframe html":function(t){return t&&e(t[0].body).html()},"iframe xml":function(t){var i=t&&t[0];return i&&e.isXMLDoc(i)?i:e.parseXML(i.XMLDocument&&i.XMLDocument.xml||e(i.body).html())},"iframe script":function(t){return t&&e.globalEval(e(t[0].body).text())}}})})); +function _typeof(e){return _typeof="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},_typeof(e)}function _typeof(e){return _typeof="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},_typeof(e)}function _typeof(e){return _typeof="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},_typeof(e)}function randomUUID(){return"object"===("undefined"==typeof crypto?"undefined":_typeof(crypto))&&"function"==typeof crypto.randomUUID?crypto.randomUUID():([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g,(function(e){return(e^crypto.getRandomValues(new Uint8Array(1))[0]&15>>e/4).toString(16)}))}function _typeof(e){return _typeof="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},_typeof(e)}function ownKeys(e,t){var i=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),i.push.apply(i,n)}return i}function _objectSpread(e){for(var t=1;t').prop("disabled")),e.support.xhrFileUpload=!(!window.ProgressEvent||!window.FileReader),e.support.xhrFormDataFileUpload=!!window.FormData,e.support.blobSlice=window.Blob&&(Blob.prototype.slice||Blob.prototype.webkitSlice||Blob.prototype.mozSlice),e.widget("blueimp.fileupload",{options:{dropZone:e(document),pasteZone:void 0,fileInput:void 0,replaceFileInput:!0,paramName:void 0,singleFileUploads:!0,limitMultiFileUploads:void 0,limitMultiFileUploadSize:void 0,limitMultiFileUploadSizeOverhead:512,sequentialUploads:!1,limitConcurrentUploads:void 0,forceIframeTransport:!1,redirect:void 0,redirectParamName:void 0,postMessage:void 0,multipart:!0,maxChunkSize:void 0,uploadedBytes:void 0,recalculateProgress:!0,progressInterval:100,bitrateInterval:500,autoUpload:!0,uniqueFilenames:void 0,messages:{uploadedBytes:"Uploaded bytes exceed file size"},i18n:function(t,i){return t=this.messages[t]||t.toString(),i&&e.each(i,(function(e,i){t=t.replace("{"+e+"}",i)})),t},formData:function(e){return e.serializeArray()},add:function(t,i){if(t.isDefaultPrevented())return!1;(i.autoUpload||!1!==i.autoUpload&&e(this).fileupload("option","autoUpload"))&&i.process().done((function(){i.submit()}))},processData:!1,contentType:!1,cache:!1,timeout:0},_promisePipe:(i=e.fn.jquery.split("."),Number(i[0])>1||Number(i[1])>7?"then":"pipe"),_specialOptions:["fileInput","dropZone","pasteZone","multipart","forceIframeTransport"],_blobSlice:e.support.blobSlice&&function(){return(this.slice||this.webkitSlice||this.mozSlice).apply(this,arguments)},_BitrateTimer:function(){this.timestamp=Date.now?Date.now():(new Date).getTime(),this.loaded=0,this.bitrate=0,this.getBitrate=function(e,t,i){var n=e-this.timestamp;return(!this.bitrate||!i||n>i)&&(this.bitrate=(t-this.loaded)*(1e3/n)*8,this.loaded=t,this.timestamp=e),this.bitrate}},_isXHRUpload:function(t){return!t.forceIframeTransport&&(!t.multipart&&e.support.xhrFileUpload||e.support.xhrFormDataFileUpload)},_getFormData:function(t){var i;return"function"===e.type(t.formData)?t.formData(t.form):e.isArray(t.formData)?t.formData:"object"===e.type(t.formData)?(i=[],e.each(t.formData,(function(e,t){i.push({name:e,value:t})})),i):[]},_getTotal:function(t){var i=0;return e.each(t,(function(e,t){i+=t.size||1})),i},_initProgressObject:function(t){var i={loaded:0,total:0,bitrate:0};t._progress?e.extend(t._progress,i):t._progress=i},_initResponseObject:function(e){var t;if(e._response)for(t in e._response)Object.prototype.hasOwnProperty.call(e._response,t)&&delete e._response[t];else e._response={}},_onProgress:function(t,i){if(t.lengthComputable){var n,a=Date.now?Date.now():(new Date).getTime();if(i._time&&i.progressInterval&&a-i._time").prop("href",t.url).prop("host");t.dataType="iframe "+(t.dataType||""),t.formData=this._getFormData(t),t.redirect&&i&&i!==location.host&&t.formData.push({name:t.redirectParamName||"redirect",value:t.redirect})},_initDataSettings:function(e){this._isXHRUpload(e)?(this._chunkedUpload(e,!0)||(e.data||this._initXHRData(e),this._initProgressListener(e)),e.postMessage&&(e.dataType="postmessage "+(e.dataType||""))):this._initIframeSettings(e)},_getParamName:function(t){var i=e(t.fileInput),n=t.paramName;return n?e.isArray(n)||(n=[n]):(n=[],i.each((function(){for(var t=e(this),i=t.prop("name")||"files[]",a=(t.prop("files")||[1]).length;a;)n.push(i),a-=1})),n.length||(n=[i.prop("name")||"files[]"])),n},_initFormSettings:function(t){t.form&&t.form.length||(t.form=e(t.fileInput.prop("form")),t.form.length||(t.form=e(this.options.fileInput.prop("form")))),t.paramName=this._getParamName(t),t.url||(t.url=t.form.prop("action")||location.href),t.type=(t.type||"string"===e.type(t.form.prop("method"))&&t.form.prop("method")||"").toUpperCase(),"POST"!==t.type&&"PUT"!==t.type&&"PATCH"!==t.type&&(t.type="POST"),t.formAcceptCharset||(t.formAcceptCharset=t.form.attr("accept-charset"))},_getAJAXSettings:function(t){var i=e.extend({},this.options,t);return this._initFormSettings(i),this._initDataSettings(i),i},_getDeferredState:function(e){return e.state?e.state():e.isResolved()?"resolved":e.isRejected()?"rejected":"pending"},_enhancePromise:function(e){return e.success=e.done,e.error=e.fail,e.complete=e.always,e},_getXHRPromise:function(t,i,n){var a=e.Deferred(),o=a.promise();return i=i||this.options.context||o,!0===t?a.resolveWith(i,n):!1===t&&a.rejectWith(i,n),o.abort=a.promise,this._enhancePromise(o)},_addConvenienceMethods:function(t,i){var n=this,a=function(t){return e.Deferred().resolveWith(n,t).promise()};i.process=function(t,o){return(t||o)&&(i._processQueue=this._processQueue=(this._processQueue||a([this]))[n._promisePipe]((function(){return i.errorThrown?e.Deferred().rejectWith(n,[i]).promise():a(arguments)}))[n._promisePipe](t,o)),this._processQueue||a([this])},i.submit=function(){return"pending"!==this.state()&&(i.jqXHR=this.jqXHR=!1!==n._trigger("submit",e.Event("submit",{delegatedEvent:t}),this)&&n._onSend(t,this)),this.jqXHR||n._getXHRPromise()},i.abort=function(){return this.jqXHR?this.jqXHR.abort():(this.errorThrown="abort",n._trigger("fail",null,this),n._getXHRPromise(!1))},i.state=function(){return this.jqXHR?n._getDeferredState(this.jqXHR):this._processQueue?n._getDeferredState(this._processQueue):void 0},i.processing=function(){return!this.jqXHR&&this._processQueue&&"pending"===n._getDeferredState(this._processQueue)},i.progress=function(){return this._progress},i.response=function(){return this._response}},_getUploadedBytes:function(e){var t=e.getResponseHeader("Range"),i=t&&t.split("-"),n=i&&i.length>1&&parseInt(i[1],10);return n&&n+1},_chunkedUpload:function(t,i){t.uploadedBytes=t.uploadedBytes||0;var n,a,o=this,r=t.files[0],s=r.size,l=t.uploadedBytes,d=t.maxChunkSize||s,c=this._blobSlice,u=e.Deferred(),m=u.promise();return!(!(this._isXHRUpload(t)&&c&&(l||("function"===e.type(d)?d(t):d)=s?(r.error=t.i18n("uploadedBytes"),this._getXHRPromise(!1,t.context,[null,"error",r.error])):(a=function(){var i=e.extend({},t),m=i._progress.loaded;i.blob=c.call(r,l,l+("function"===e.type(d)?d(i):d),r.type),i.chunkSize=i.blob.size,i.contentRange="bytes "+l+"-"+(l+i.chunkSize-1)+"/"+s,o._trigger("chunkbeforesend",null,i),o._initXHRData(i),o._initProgressListener(i),n=(!1!==o._trigger("chunksend",null,i)&&e.ajax(i)||o._getXHRPromise(!1,i.context)).done((function(n,r,d){l=o._getUploadedBytes(d)||l+i.chunkSize,m+i.chunkSize-i._progress.loaded&&o._onProgress(e.Event("progress",{lengthComputable:!0,loaded:l-i.uploadedBytes,total:l-i.uploadedBytes}),i),t.uploadedBytes=i.uploadedBytes=l,i.result=n,i.textStatus=r,i.jqXHR=d,o._trigger("chunkdone",null,i),o._trigger("chunkalways",null,i),ls._sending)for(var n=s._slots.shift();n;){if("pending"===s._getDeferredState(n)){n.resolve();break}n=s._slots.shift()}0===s._active&&s._trigger("stop")}))};return this._beforeSend(t,l),this.options.sequentialUploads||this.options.limitConcurrentUploads&&this.options.limitConcurrentUploads<=this._sending?(this.options.limitConcurrentUploads>1?(o=e.Deferred(),this._slots.push(o),r=o[s._promisePipe](d)):(this._sequence=this._sequence[s._promisePipe](d,d),r=this._sequence),r.abort=function(){return a=[void 0,"abort","abort"],n?n.abort():(o&&o.rejectWith(l.context,a),d())},this._enhancePromise(r)):d()},_onAdd:function(t,i){var n,a,o,r,s=this,l=!0,d=e.extend({},this.options,i),c=i.files,u=c.length,m=d.limitMultiFileUploads,p=d.limitMultiFileUploadSize,f=d.limitMultiFileUploadSizeOverhead,h=0,g=this._getParamName(d),v=0;if(!u)return!1;if(p&&void 0===c[0].size&&(p=void 0),(d.singleFileUploads||m||p)&&this._isXHRUpload(d))if(d.singleFileUploads||p||!m)if(!d.singleFileUploads&&p)for(o=[],n=[],r=0;rp||m&&r+1-v>=m)&&(o.push(c.slice(v,r+1)),(a=g.slice(v,r+1)).length||(a=g),n.push(a),v=r+1,h=0);else n=g;else for(o=[],n=[],r=0;r").append(n)[0].reset(),i.after(n).detach(),a&&n.trigger("focus"),e.cleanData(i.off("remove")),this.options.fileInput=this.options.fileInput.map((function(e,t){return t===i[0]?n[0]:t})),i[0]===this.element[0]&&(this.element=n)},_handleFileTreeEntry:function(t,i){var n,a=this,o=e.Deferred(),r=[],s=function(e){e&&!e.entry&&(e.entry=t),o.resolve([e])};return i=i||"",t.isFile?t._file?(t._file.relativePath=i,o.resolve(t._file)):t.file((function(e){e.relativePath=i,o.resolve(e)}),s):t.isDirectory?(n=t.createReader(),function e(){n.readEntries((function(n){n.length?(r=r.concat(n),e()):function(e){a._handleFileTreeEntries(e,i+t.name+"/").done((function(e){o.resolve(e)})).fail(s)}(r)}),s)}()):o.resolve([]),o.promise()},_handleFileTreeEntries:function(t,i){var n=this;return e.when.apply(e,e.map(t,(function(e){return n._handleFileTreeEntry(e,i)})))[this._promisePipe]((function(){return Array.prototype.concat.apply([],arguments)}))},_getDroppedFiles:function(t){var i=(t=t||{}).items;return i&&i.length&&(i[0].webkitGetAsEntry||i[0].getAsEntry)?this._handleFileTreeEntries(e.map(i,(function(e){var t;return e.webkitGetAsEntry?((t=e.webkitGetAsEntry())&&(t._file=e.getAsFile()),t):e.getAsEntry()}))):e.Deferred().resolve(e.makeArray(t.files)).promise()},_getSingleFileInputFiles:function(t){var i,n,a=(t=e(t)).prop("entries");if(a&&a.length)return this._handleFileTreeEntries(a);if((i=e.makeArray(t.prop("files"))).length)void 0===i[0].name&&i[0].fileName&&e.each(i,(function(e,t){t.name=t.fileName,t.size=t.fileSize}));else{if(!(n=t.prop("value")))return e.Deferred().resolve([]).promise();i=[{name:n.replace(/^.*\\/,"")}]}return e.Deferred().resolve(i).promise()},_getFileInputFiles:function(t){return t instanceof e&&1!==t.length?e.when.apply(e,e.map(t,this._getSingleFileInputFiles))[this._promisePipe]((function(){return Array.prototype.concat.apply([],arguments)})):this._getSingleFileInputFiles(t)},_onChange:function(t){var i=this,n={fileInput:e(t.target),form:e(t.target.form)};this._getFileInputFiles(n.fileInput).always((function(a){n.files=a,i.options.replaceFileInput&&i._replaceFileInput(n),!1!==i._trigger("change",e.Event("change",{delegatedEvent:t}),n)&&i._onAdd(t,n)}))},_onPaste:function(t){var i=t.originalEvent&&t.originalEvent.clipboardData&&t.originalEvent.clipboardData.items,n={files:[]};i&&i.length&&(e.each(i,(function(e,t){var i=t.getAsFile&&t.getAsFile();i&&n.files.push(i)})),!1!==this._trigger("paste",e.Event("paste",{delegatedEvent:t}),n)&&this._onAdd(t,n))},_onDrop:function(t){t.dataTransfer=t.originalEvent&&t.originalEvent.dataTransfer;var i=this,n=t.dataTransfer,a={};n&&n.files&&n.files.length&&(t.preventDefault(),this._getDroppedFiles(n).always((function(n){a.files=n,!1!==i._trigger("drop",e.Event("drop",{delegatedEvent:t}),a)&&i._onAdd(t,a)})))},_onDragOver:t("dragover"),_onDragEnter:t("dragenter"),_onDragLeave:t("dragleave"),_initEventHandlers:function(){this._isXHRUpload(this.options)&&(this._on(this.options.dropZone,{dragover:this._onDragOver,drop:this._onDrop,dragenter:this._onDragEnter,dragleave:this._onDragLeave}),this._on(this.options.pasteZone,{paste:this._onPaste})),e.support.fileInput&&this._on(this.options.fileInput,{change:this._onChange})},_destroyEventHandlers:function(){this._off(this.options.dropZone,"dragenter dragleave dragover drop"),this._off(this.options.pasteZone,"paste"),this._off(this.options.fileInput,"change")},_destroy:function(){this._destroyEventHandlers()},_setOption:function(t,i){var n=-1!==e.inArray(t,this._specialOptions);n&&this._destroyEventHandlers(),this._super(t,i),n&&(this._initSpecialOptions(),this._initEventHandlers())},_initSpecialOptions:function(){var t=this.options;void 0===t.fileInput?t.fileInput=this.element.is('input[type="file"]')?this.element:this.element.find('input[type="file"]'):t.fileInput instanceof e||(t.fileInput=e(t.fileInput)),t.dropZone instanceof e||(t.dropZone=e(t.dropZone)),t.pasteZone instanceof e||(t.pasteZone=e(t.pasteZone))},_getRegExp:function(e){var t=e.split("/"),i=t.pop();return t.shift(),new RegExp(t.join("/"),i)},_isRegExpOption:function(t,i){return"url"!==t&&"string"===e.type(i)&&/^\/.*\/[igm]{0,3}$/.test(i)},_initDataAttributes:function(){var t=this,i=this.options,n=this.element.data();e.each(this.element[0].attributes,(function(e,a){var o,r=a.name.toLowerCase();/^data-/.test(r)&&(r=r.slice(5).replace(/-[a-z]/g,(function(e){return e.charAt(1).toUpperCase()})),o=n[r],t._isRegExpOption(r,o)&&(o=t._getRegExp(o)),i[r]=o)}))},_create:function(){this._initDataAttributes(),this._initSpecialOptions(),this._slots=[],this._sequence=this._getXHRPromise(!0),this._sending=this._active=0,this._initProgressObject(this),this._initEventHandlers()},active:function(){return this._active},progress:function(){return this._progress},add:function(t){var i=this;t&&!this.options.disabled&&(t.fileInput&&!t.files?this._getFileInputFiles(t.fileInput).always((function(e){t.files=e,i._onAdd(null,t)})):(t.files=e.makeArray(t.files),this._onAdd(null,t)))},send:function(t){if(t&&!this.options.disabled){if(t.fileInput&&!t.files){var i,n,a=this,o=e.Deferred(),r=o.promise();return r.abort=function(){return n=!0,i?i.abort():(o.reject(null,"abort","abort"),r)},this._getFileInputFiles(t.fileInput).always((function(e){n||(e.length?(t.files=e,(i=a._onSend(null,t)).then((function(e,t,i){o.resolve(e,t,i)}),(function(e,t,i){o.reject(e,t,i)}))):o.reject())})),this._enhancePromise(r)}if(t.files=e.makeArray(t.files),t.files.length)return this._onSend(null,t)}return this._getXHRPromise(!1,t&&t.context)}})})),function(e){"use strict";"function"==typeof define&&define.amd?define(["jquery"],e):"object"===("undefined"==typeof exports?"undefined":_typeof(exports))?e(require("jquery")):e(window.jQuery)}((function(e){"use strict";var t=0,i=e,n="parseJSON";"JSON"in window&&"parse"in JSON&&(i=JSON,n="parse"),e.ajaxTransport("iframe",(function(i){if(i.async){var n,a,o,r=i.initialIframeSrc||"javascript:false;";return{send:function(s,l){(n=e('
    ')).attr("accept-charset",i.formAcceptCharset),o=/\?/.test(i.url)?"&":"?","DELETE"===i.type?(i.url=i.url+o+"_method=DELETE",i.type="POST"):"PUT"===i.type?(i.url=i.url+o+"_method=PUT",i.type="POST"):"PATCH"===i.type&&(i.url=i.url+o+"_method=PATCH",i.type="POST"),a=e('').on("load",(function(){var t,o=e.isArray(i.paramName)?i.paramName:[i.paramName];a.off("load").on("load",(function(){var t;try{if(!(t=a.contents()).length||!t[0].firstChild)throw new Error}catch(e){t=void 0}l(200,"success",{iframe:t}),e('').appendTo(n),window.setTimeout((function(){n.remove()}),0)})),n.prop("target",a.prop("name")).prop("action",i.url).prop("method",i.type),i.formData&&e.each(i.formData,(function(t,i){e('').prop("name",i.name).val(i.value).appendTo(n)})),i.fileInput&&i.fileInput.length&&"POST"===i.type&&(t=i.fileInput.clone(),i.fileInput.after((function(e){return t[e]})),i.paramName&&i.fileInput.each((function(t){e(this).prop("name",o[t]||i.paramName)})),n.append(i.fileInput).prop("enctype","multipart/form-data").prop("encoding","multipart/form-data"),i.fileInput.removeAttr("form")),window.setTimeout((function(){n.submit(),t&&t.length&&i.fileInput.each((function(i,n){var a=e(t[i]);e(n).prop("name",a.prop("name")).attr("form",a.attr("form")),a.replaceWith(n)}))}),0)})),n.append(a).appendTo(document.body)},abort:function(){a&&a.off("load").prop("src",r),n&&n.remove()}}}})),e.ajaxSetup({converters:{"iframe text":function(t){return t&&e(t[0].body).text()},"iframe json":function(t){return t&&i[n](e(t[0].body).text())},"iframe html":function(t){return t&&e(t[0].body).html()},"iframe xml":function(t){var i=t&&t[0];return i&&e.isXMLDoc(i)?i:e.parseXML(i.XMLDocument&&i.XMLDocument.xml||e(i.body).html())},"iframe script":function(t){return t&&e.globalEval(e(t[0].body).text())}}})}));var bus=new Vue;function initializeMediaApplication(e,t,i){initialized||(initialized=!0,t||console.error("mediaApplicationUrl variable is not defined"),$.ajax({url:t,method:"GET",success:function(t){$(".ta-content").append(t),$(document).trigger("mediaapplication:ready");var n={name:$("#t-mediaLibrary").text(),path:"",folder:"",isDirectory:!0,canCreateFolder:"true"===$("#allowNewRootFolders").val()};mediaApp=new Vue({el:"#mediaApp",data:{selectedFolder:{},mediaItems:[],selectedMedias:[],errors:[],dragDropThumbnail:new Image,smallThumbs:!1,gridView:!1,mediaFilter:"",sortBy:"",sortAsc:!0,itemsInPage:[]},created:function(){var e=this;e.dragDropThumbnail.src=(i||"")+"/OrchardCore.Media/Images/drag-thumbnail.png",bus.$on("folderSelected",(function(t){e.selectedFolder=t})),bus.$on("folderDeleted",(function(){e.selectRoot()})),bus.$on("folderAdded",(function(t){e.selectedFolder=t,t.selected=!0})),bus.$on("mediaListMoved",(function(t){e.loadFolder(e.selectedFolder),t&&e.errors.push(t)})),bus.$on("mediaRenamed",(function(t,i,n,a){var o=e.mediaItems.filter((function(e){return e.mediaPath===n}))[0];o.mediaPath=i,o.name=t,o.url=a})),bus.$on("createFolderRequested",(function(t){e.createFolder()})),bus.$on("deleteFolderRequested",(function(t){e.deleteFolder()})),bus.$on("sortChangeRequested",(function(t){e.changeSort(t)})),bus.$on("mediaToggleRequested",(function(t){e.toggleSelectionOfMedia(t)})),bus.$on("renameMediaRequested",(function(t){e.renameMedia(t)})),bus.$on("deleteMediaRequested",(function(t){e.deleteMediaItem(t)})),bus.$on("mediaDragStartRequested",(function(t,i){e.handleDragStart(t,i)})),bus.$on("pagerEvent",(function(t){e.itemsInPage=t,e.selectedMedias=[]})),localStorage.getItem("mediaApplicationPrefs")?e.currentPrefs=JSON.parse(localStorage.getItem("mediaApplicationPrefs")):e.selectedFolder=n},computed:{isHome:function(){return this.selectedFolder==n},parents:function(){var e=[];for(parentFolder=this.selectedFolder;parentFolder&&""!=parentFolder.path;)e.unshift(parentFolder),parentFolder=parentFolder.parent;return e},root:function(){return n},filteredMediaItems:function(){var e=this;e.selectedMedias=[];var t=e.mediaItems.filter((function(t){return t.name.toLowerCase().indexOf(e.mediaFilter.toLowerCase())>-1}));switch(e.sortBy){case"size":t.sort((function(t,i){return e.sortAsc?t.size-i.size:i.size-t.size}));break;case"mime":t.sort((function(t,i){return e.sortAsc?t.mime.toLowerCase().localeCompare(i.mime.toLowerCase()):i.mime.toLowerCase().localeCompare(t.mime.toLowerCase())}));break;case"lastModify":t.sort((function(t,i){return e.sortAsc?t.lastModify-i.lastModify:i.lastModify-t.lastModify}));break;default:t.sort((function(t,i){return e.sortAsc?t.name.toLowerCase().localeCompare(i.name.toLowerCase()):i.name.toLowerCase().localeCompare(t.name.toLowerCase())}))}return t},hiddenCount:function(){return this.mediaItems.length-this.filteredMediaItems.length},thumbSize:function(){return this.smallThumbs?100:240},currentPrefs:{get:function(){return{smallThumbs:this.smallThumbs,selectedFolder:this.selectedFolder,gridView:this.gridView}},set:function(e){e&&(this.smallThumbs=e.smallThumbs,this.selectedFolder=e.selectedFolder,this.gridView=e.gridView)}}},watch:{currentPrefs:function(e){localStorage.setItem("mediaApplicationPrefs",JSON.stringify(e))},selectedFolder:function(e){this.mediaFilter="",this.selectedFolder=e,this.loadFolder(e)}},mounted:function(){this.$refs.rootFolder.toggle()},methods:{uploadUrl:function(){if(!this.selectedFolder)return null;var e=$("#uploadFiles").val();return e+(-1==e.indexOf("?")?"?":"&")+"path="+encodeURIComponent(this.selectedFolder.path)},selectRoot:function(){this.selectedFolder=this.root},loadFolder:function(e){this.errors=[],this.selectedMedias=[];var t=this,i=$("#getMediaItemsUrl").val();console.log(e.path),$.ajax({url:i+(-1==i.indexOf("?")?"?":"&")+"path="+encodeURIComponent(e.path),method:"GET",success:function(e){e.forEach((function(e){e.open=!1})),t.mediaItems=e,t.selectedMedias=[],t.sortBy="",t.sortAsc=!0},error:function(i){console.log("error loading folder:"+e.path),t.selectRoot()}})},selectAll:function(){this.selectedMedias=[];for(var e=0;e-1&&(t.mediaItems.splice(n,1),bus.$emit("mediaDeleted",t.selectedMedias[i]))}t.selectedMedias=[]},error:function(e){console.error(e.responseText)}})}}}))},deleteMediaItem:function(e){var t=this;e&&confirmDialog(_objectSpread(_objectSpread({},$("#deleteMedia").data()),{},{callback:function(i){i&&$.ajax({url:$("#deleteMediaUrl").val()+"?path="+encodeURIComponent(e.mediaPath),method:"POST",data:{__RequestVerificationToken:$("input[name='__RequestVerificationToken']").val()},success:function(i){var n=t.mediaItems&&t.mediaItems.indexOf(e);n>-1&&(t.mediaItems.splice(n,1),bus.$emit("mediaDeleted",e))},error:function(e){console.error(e.responseText)}})}}))},handleDragStart:function(e,t){var i=[];this.selectedMedias.forEach((function(e){i.push(e.name)})),0==this.isMediaSelected(e)&&(i.push(e.name),this.selectedMedias.push(e)),t.dataTransfer.setData("mediaNames",JSON.stringify(i)),t.dataTransfer.setData("sourceFolder",this.selectedFolder.path),t.dataTransfer.setDragImage(this.dragDropThumbnail,10,10),t.dataTransfer.effectAllowed="move"},handleScrollWhileDrag:function(e){e.clientY<150&&window.scrollBy(0,-10),e.clientY>window.innerHeight-100&&window.scrollBy(0,10)},changeSort:function(e){this.sortBy==e?this.sortAsc=!this.sortAsc:(this.sortAsc=!0,this.sortBy=e)}}}),$("#create-folder-name").keypress((function(e){if(13==e.which)return $("#modalFooterOk").click(),!1})),$("#modalFooterOk").on("click",(function(e){var t=$("#create-folder-name").val();""!==t&&$.ajax({url:$("#createFolderUrl").val()+"?path="+encodeURIComponent(mediaApp.selectedFolder.path)+"&name="+encodeURIComponent(t),method:"POST",data:{__RequestVerificationToken:$("input[name='__RequestVerificationToken']").val()},success:function(e){bus.$emit("addFolder",mediaApp.selectedFolder,e),bootstrap.Modal.getOrCreateInstance($("#createFolderModal")).hide()},error:function(e){$("#createFolderModal-errors").empty();var t=JSON.parse(e.responseText).value;$('').text(t).appendTo($("#createFolderModal-errors"))}})})),$("#renameMediaModalFooterOk").on("click",(function(e){var t=$("#new-item-name").val(),i=$("#old-item-name").val();if(""!==t){var n=mediaApp.selectedFolder.path+"/";"/"===n&&(n="");var a=n+t,o=n+i;if(a.toLowerCase()!==o.toLowerCase())$.ajax({url:$("#renameMediaUrl").val()+"?oldPath="+encodeURIComponent(o)+"&newPath="+encodeURIComponent(a),method:"POST",data:{__RequestVerificationToken:$("input[name='__RequestVerificationToken']").val()},success:function(e){bootstrap.Modal.getOrCreateInstance($("#renameMediaModal")).hide(),bus.$emit("mediaRenamed",t,a,o,e.newUrl)},error:function(e){$("#renameMediaModal-errors").empty();var t=JSON.parse(e.responseText).value;$('').text(t).appendTo($("#renameMediaModal-errors"))}});else bootstrap.Modal.getOrCreateInstance($("#renameMediaModal")).hide()}})),e&&(document.getElementById("mediaApp").style.display=""),$(document).trigger("mediaApp:ready")},error:function(e){console.error(e.responseText)}}))}function _typeof(e){return _typeof="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},_typeof(e)}function ownKeys(e,t){var i=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),i.push.apply(i,n)}return i}function _objectSpread(e){for(var t=1;t\n \n
      \n \n \n
    \n \n '),props:{model:Object,selectedInMediaApp:Object,level:Number},data:function(){return{open:!1,children:null,parent:null,isHovered:!1,padding:0}},computed:{empty:function(){return!this.children||0==this.children.length},isSelected:function(){return this.selectedInMediaApp.name==this.model.name&&this.selectedInMediaApp.path==this.model.path},isRoot:function(){return""===this.model.path},canCreateFolder:function(){return void 0===this.model.canCreateFolder||this.model.canCreateFolder},canDeleteFolder:function(){return void 0===this.model.canDeleteFolder||this.model.canDeleteFolder}},mounted:function(){0==this.isRoot&&this.isAncestorOfSelectedFolder()&&this.toggle(),this.padding=this.level<3?16:16+8*this.level},created:function(){var e=this;bus.$on("deleteFolder",(function(t){if(e.children){var i=e.children&&e.children.indexOf(t);i>-1&&(e.children.splice(i,1),bus.$emit("folderDeleted"))}})),bus.$on("addFolder",(function(t,i){e.model==t&&(null!==e.children&&e.children.push(i),i.parent=e.model,bus.$emit("folderAdded",i))}))},methods:{isAncestorOfSelectedFolder:function(){for(parentFolder=mediaApp.selectedFolder;parentFolder;){if(parentFolder.path==this.model.path)return!0;parentFolder=parentFolder.parent}return!1},toggle:function(){this.open=!this.open,this.open&&!this.children&&this.loadChildren()},select:function(){bus.$emit("folderSelected",this.model),this.loadChildren()},createFolder:function(){bus.$emit("createFolderRequested")},deleteFolder:function(){bus.$emit("deleteFolderRequested")},loadChildren:function(){var e=this;0==this.open&&(this.open=!0),$.ajax({url:$("#getFoldersUrl").val()+"?path="+encodeURIComponent(e.model.path),method:"GET",success:function(t){e.children=t,e.children.forEach((function(t){t.parent=e.model}))},error:function(e){emtpy=!1,console.error(e.responseText)}})},handleDragOver:function(e){this.isHovered=!0},handleDragLeave:function(e){this.isHovered=!1},moveMediaToFolder:function(e,t){this.isHovered=!1;var i=JSON.parse(t.dataTransfer.getData("mediaNames"));if(!(i.length<1)){var n=t.dataTransfer.getData("sourceFolder"),a=e.path;""===n&&(n="root"),""===a&&(a="root"),n!==a?confirmDialog(_objectSpread(_objectSpread({},$("#moveMedia").data()),{},{callback:function(e){e&&$.ajax({url:$("#moveMediaListUrl").val(),method:"POST",data:{__RequestVerificationToken:$("input[name='__RequestVerificationToken']").val(),mediaNames:i,sourceFolder:n,targetFolder:a},success:function(){bus.$emit("mediaListMoved")},error:function(e){console.error(e.responseText),bus.$emit("mediaListMoved",e.responseText)}})}})):alert($("#sameFolderMessage").val())}}}});var faIcons={image:"fa-regular fa-image",pdf:"fa-regular fa-file-pdf",word:"fa-regular fa-file-word",powerpoint:"fa-regular fa-file-powerpoint",excel:"fa-regular fa-file-excel",csv:"fa-regular fa-file",audio:"fa-regular fa-file-audio",video:"fa-regular fa-file-video",archive:"fa-regular fa-file-zipper",code:"fa-regular fa-file-code",text:"fa-regular fa-file-lines",file:"fa-regular fa-file"},faThumbnails={gif:faIcons.image,jpeg:faIcons.image,jpg:faIcons.image,png:faIcons.image,pdf:faIcons.pdf,doc:faIcons.word,docx:faIcons.word,ppt:faIcons.powerpoint,pptx:faIcons.powerpoint,xls:faIcons.excel,xlsx:faIcons.excel,csv:faIcons.csv,aac:faIcons.audio,mp3:faIcons.audio,ogg:faIcons.audio,avi:faIcons.video,flv:faIcons.video,mkv:faIcons.video,mp4:faIcons.video,webm:faIcons.video,gz:faIcons.archive,zip:faIcons.archive,css:faIcons.code,html:faIcons.code,js:faIcons.code,txt:faIcons.text};function getClassNameForExtension(e){return faThumbnails[e.toLowerCase()]||faIcons.file}function getExtensionForFilename(e){return e.slice(2+(e.lastIndexOf(".")-1>>>0))}function getClassNameForFilename(e){return getClassNameForExtension(getExtensionForFilename(e))}function initializeAttachedMediaField(e,t,i,n,a,o,r,s,l){var d,c=$(document.getElementById($(e).data("for"))).data("init"),u=$(e),m=u.attr("id");mediaFieldApps.push(d=new Vue({el:u.get(0),data:{mediaItems:[],selectedMedia:null,smallThumbs:!1,idPrefix:m,initialized:!1,allowMediaText:o,backupMediaText:"",allowAnchors:r,backupAnchor:null,mediaTextmodal:null,anchoringModal:null},created:function(){this.currentPrefs=JSON.parse(localStorage.getItem("mediaFieldPrefs"))},computed:{paths:{get:function(){var e=[];return this.initialized?(this.mediaItems.forEach((function(t){"not-found"!==t.mediaPath&&e.push({path:t.mediaPath,isRemoved:t.isRemoved,isNew:t.isNew,mediaText:t.mediaText,anchor:t.anchor,attachedFileName:t.attachedFileName})})),JSON.stringify(e)):JSON.stringify(c)},set:function(e){var t=this,i=e||[],a=$.Deferred(),o=[],r=0;i.forEach((function(e,i){o.push({name:" "+e.path,mime:"",mediaPath:"",anchor:e.anchor,attachedFileName:e.attachedFileName}),promise=$.when(a).done((function(){$.ajax({url:n+"?path="+encodeURIComponent(e.path),method:"GET",success:function(n){n.vuekey=n.name+i.toString(),n.mediaText=e.mediaText,n.anchor=e.anchor,n.attachedFileName=e.attachedFileName,o.splice(i,1,n),o.length===++r&&(o.forEach((function(e){t.mediaItems.push(e)})),t.initialized=!0)},error:function(n){console.log(JSON.stringify(n)),o.splice(i,1,{name:e.path,mime:"",mediaPath:"not-found",mediaText:"",anchor:{x:.5,y:.5},attachedFileName:e.attachedFileName}),o.length===++r&&(o.forEach((function(e){t.mediaItems.push(e)})),t.initialized=!0)}})}))})),a.resolve()}},fileSize:function(){return Math.round(this.selectedMedia.size/1024)},canAddMedia:function(){for(var e=[],t=0;t0&&a},thumbSize:function(){return this.smallThumbs?120:240},currentPrefs:{get:function(){return{smallThumbs:this.smallThumbs}},set:function(e){e&&(this.smallThumbs=e.smallThumbs)}}},mounted:function(){var e=this;e.paths=c,e.$on("selectAndDeleteMediaRequested",(function(t){e.selectAndDeleteMedia(t)})),e.$on("selectMediaRequested",(function(t){e.selectMedia(t)}));var n="#"+t,o=u.attr("id"),r=randomUUID();$(n).fileupload({limitConcurrentUploads:20,dropZone:$("#"+o),dataType:"json",url:i,maxChunkSize:l,add:function(t,i){var n,a=i.files.length;for(n=0;n0)for(var o=0;o1&&!1===a?(alert($("#onlyOneItemMessage").val()),d.mediaItems.push(i[0]),d.initialized=!0):(d.mediaItems=d.mediaItems.concat(i),d.initialized=!0)):alert(n)},error:function(e,t,i){console.log("Error on upload."),console.log(e),console.log(t),console.log(i)}}).on("fileuploadchunkbeforesend",(function(e,t){var i=t.files[0];t.blob=new File([t.blob],i.name,{type:i.type,lastModified:i.lastModified})}))},methods:{selectMedia:function(e){this.selectedMedia=e},getUniqueId:function(){return"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,(function(e){var t=16*Math.random()|0;return("x"===e?t:3&t|8).toString(16)}))},removeSelected:function(e){if(this.selectedMedia){var t=this.mediaItems&&this.mediaItems.indexOf(this.selectedMedia);t>-1&&(this.mediaItems[t].isRemoved=!0,this.mediaItems.splice(t,1))}else 1===this.mediaItems.length&&(this.mediaItems[t].isRemoved=!0,this.mediaItems.splice(0,1));this.selectedMedia=null},showMediaTextModal:function(e){this.mediaTextModal=new bootstrap.Modal(this.$refs.mediaTextModal),this.mediaTextModal.show(),this.backupMediaText=this.selectedMedia.mediaText},cancelMediaTextModal:function(e){this.mediaTextModal.hide(),this.selectedMedia.mediaText=this.backupMediaText},showAnchorModal:function(e){this.anchoringModal=new bootstrap.Modal(this.$refs.anchoringModal),this.anchoringModal.show(),this.selectedMedia.anchor={x:this.selectedMedia.anchor.x,y:this.selectedMedia.anchor.y},this.backupAnchor=this.selectedMedia.anchor},cancelAnchoringModal:function(e){this.anchoringModal.hide(),this.selectedMedia.anchor=this.backupAnchor},resetAnchor:function(e){this.selectedMedia.anchor={x:.5,y:.5}},onAnchorDrop:function(e){var t=this.$refs.anchorImage;this.selectedMedia.anchor={x:e.offsetX/t.clientWidth,y:e.offsetY/t.clientHeight}},anchorLeft:function(){if(this.$refs.anchorImage&&this.$refs.modalBody&&this.selectedMedia){var e=(this.$refs.modalBody.clientWidth-this.$refs.anchorImage.clientWidth)/2,t=this.selectedMedia.anchor.x*this.$refs.anchorImage.clientWidth+e;return t<17?t=17:t-=8,t+"px"}return"0"},anchorTop:function(){if(this.$refs.anchorImage&&this.selectedMedia){var e=this.selectedMedia.anchor.y*this.$refs.anchorImage.clientHeight;return e<15?e=15:e+=5,e+"px"}return"0"},setAnchor:function(e){var t=this.$refs.anchorImage;this.selectedMedia.anchor={x:e.offsetX/t.clientWidth,y:e.offsetY/t.clientHeight}},addMediaFiles:function(e){e.length>1&&!1===a?(alert($("#onlyOneItemMessage").val()),d.mediaItems.push(e[0]),d.initialized=!0):(d.mediaItems=d.mediaItems.concat(e),d.initialized=!0)},selectAndDeleteMedia:function(e){var t=this;t.selectedMedia=e,setTimeout((function(){t.removeSelected()}),100)}},watch:{mediaItems:{deep:!0,handler:function(){setTimeout((function(){$(document).trigger("contentpreview:render")}),100)}},currentPrefs:function(e){localStorage.setItem("mediaFieldPrefs",JSON.stringify(e))}}}))}function initializeMediaField(e,t,i,n,a,o){if(null!==e){var r,s=$(document.getElementById($(e).data("for"))).data("init"),l=$(e),d=l.attr("id");t.addEventListener("hidden.bs.modal",(function(e){$("#mediaApp").appendTo("body"),$("#mediaApp").hide()})),mediaFieldApps.push(r=new Vue({el:l.get(0),data:{mediaItems:[],selectedMedia:null,smallThumbs:!1,idPrefix:d,initialized:!1,allowMediaText:a,backupMediaText:"",allowAnchors:o,backupAnchor:null,mediaTextModal:null,anchoringModal:null},created:function(){this.currentPrefs=JSON.parse(localStorage.getItem("mediaFieldPrefs"))},computed:{paths:{get:function(){var e=[];return this.initialized?(this.mediaItems.forEach((function(t){"not-found"!==t.mediaPath&&e.push({path:t.mediaPath,mediaText:t.mediaText,anchor:t.anchor})})),JSON.stringify(e)):JSON.stringify(s)},set:function(e){var t=this,n=e||[],a=$.Deferred(),o=[],r=0;n.forEach((function(e,n){o.push({name:" "+e.path,mime:"",mediaPath:""}),promise=$.when(a).done((function(){$.ajax({url:i+"?path="+encodeURIComponent(e.path),method:"GET",success:function(i){i.vuekey=i.name+n.toString(),i.mediaText=e.mediaText,i.anchor=e.anchor,o.splice(n,1,i),o.length===++r&&(o.forEach((function(e){t.mediaItems.push(e)})),t.initialized=!0)},error:function(i){console.log(i),o.splice(n,1,{name:e.path,mime:"",mediaPath:"not-found",mediaText:"",anchor:{x:0,y:0}}),o.length===++r&&(o.forEach((function(e){t.mediaItems.push(e)})),t.initialized=!0)}})}))})),a.resolve()}},fileSize:function(){return Math.round(this.selectedMedia.size/1024)},canAddMedia:function(){return 0===this.mediaItems.length||this.mediaItems.length>0&&n},thumbSize:function(){return this.smallThumbs?120:240},currentPrefs:{get:function(){return{smallThumbs:this.smallThumbs}},set:function(e){e&&(this.smallThumbs=e.smallThumbs)}}},mounted:function(){var e=this;e.paths=s,e.$on("selectAndDeleteMediaRequested",(function(t){e.selectAndDeleteMedia(t)})),e.$on("selectMediaRequested",(function(t){e.selectMedia(t)})),e.$on("filesUploaded",(function(t){e.addMediaFiles(t)}))},methods:{selectMedia:function(e){this.selectedMedia=e},showModal:function(e){var i=this;if(i.canAddMedia){$("#mediaApp").appendTo($(t).find(".modal-body")),$("#mediaApp").show();var n=new bootstrap.Modal(t);n.show(),$(t).find(".mediaFieldSelectButton").off("click").on("click",(function(e){return i.addMediaFiles(mediaApp.selectedMedias),mediaApp.selectedMedias=[],n.hide(),!0}))}},showMediaTextModal:function(e){this.mediaTextModal=new bootstrap.Modal(this.$refs.mediaTextModal),this.mediaTextModal.show(),this.backupMediaText=this.selectedMedia.mediaText},cancelMediaTextModal:function(e){this.mediaTextModal.hide(),this.selectedMedia.mediaText=this.backupMediaText},showAnchorModal:function(e){this.anchoringModal=new bootstrap.Modal(this.$refs.anchoringModal),this.anchoringModal.show(),this.selectedMedia.anchor={x:this.selectedMedia.anchor.x,y:this.selectedMedia.anchor.y},this.backupAnchor=this.selectedMedia.anchor},cancelAnchoringModal:function(e){this.anchoringModal.hide(),this.selectedMedia.anchor=this.backupAnchor},resetAnchor:function(e){this.selectedMedia.anchor={x:.5,y:.5}},onAnchorDrop:function(e){var t=this.$refs.anchorImage;this.selectedMedia.anchor={x:e.offsetX/t.clientWidth,y:e.offsetY/t.clientHeight}},anchorLeft:function(){if(this.$refs.anchorImage&&this.$refs.modalBody&&this.selectedMedia){var e=(this.$refs.modalBody.clientWidth-this.$refs.anchorImage.clientWidth)/2,t=this.selectedMedia.anchor.x*this.$refs.anchorImage.clientWidth+e,i=Math.round(this.$refs.modalBody.querySelector(".icon-media-anchor").clientWidth);return Number.isInteger(i)&&(t-=i/2),t+"px"}return"0"},anchorTop:function(){return this.$refs.anchorImage&&this.selectedMedia?this.selectedMedia.anchor.y*this.$refs.anchorImage.clientHeight+"px":"0"},setAnchor:function(e){var t=this.$refs.anchorImage;this.selectedMedia.anchor={x:e.offsetX/t.clientWidth,y:e.offsetY/t.clientHeight}},addMediaFiles:function(e){e.length>1&&!1===n?(alert($("#onlyOneItemMessage").val()),r.mediaItems.push(e[0]),r.initialized=!0):(r.mediaItems=r.mediaItems.concat(e),r.initialized=!0)},removeSelected:function(e){if(this.selectedMedia){var t=this.mediaItems&&this.mediaItems.indexOf(this.selectedMedia);t>-1&&this.mediaItems.splice(t,1)}else 1===this.mediaItems.length&&this.mediaItems.splice(0,1);this.selectedMedia=null},selectAndDeleteMedia:function(e){var t=this;t.selectedMedia=e,setTimeout((function(){t.removeSelected()}),100)}},watch:{mediaItems:{deep:!0,handler:function(){setTimeout((function(){$(document).trigger("contentpreview:render")}),100)}},currentPrefs:function(e){localStorage.setItem("mediaFieldPrefs",JSON.stringify(e))}}}))}}Vue.component("media-items-grid",{template:'\n
      \n
    1. \n
      \n \n \n
      \n
      \n \n \n \n {{ media.name }}\n
      \n
    2. \n
    \n ',data:function(){return{T:{}}},props:{filteredMediaItems:Array,selectedMedias:Array,thumbSize:Number},created:function(){this.T.editButton=$("#t-edit-button").val(),this.T.deleteButton=$("#t-delete-button").val()},methods:{isMediaSelected:function(e){return this.selectedMedias.some((function(t,i,n){return t.url.toLowerCase()===e.url.toLowerCase()}))},buildMediaUrl:function(e,t){return e+(-1==e.indexOf("?")?"?":"&")+"width="+t+"&height="+t},toggleSelectionOfMedia:function(e){bus.$emit("mediaToggleRequested",e)},renameMedia:function(e){bus.$emit("renameMediaRequested",e)},deleteMedia:function(e){bus.$emit("deleteMediaRequested",e)},dragStart:function(e,t){bus.$emit("mediaDragStartRequested",e,t)},getfontAwesomeClassNameForFileName:function(e,t){return getClassNameForFilename(e)+" "+t}}}),Vue.component("media-items-table",{template:'\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
    {{ T.imageHeader }}\n {{ T.nameHeader }}\n \n \n {{ T.lastModifyHeader }} \n \n \n \n {{ T.sizeHeader }}\n \n \n \n \n {{ T.typeHeader }}\n \n \n
    \n
    \n \n \n
    \n
    \n \n \n
    {{ printDateTime(media.lastModify) }}
    \n
    \n
    {{ isNaN(media.size)? 0 : Math.round(media.size / 1024) }} KB
    \n
    \n
    {{ media.mime }}
    \n
    \n ',data:function(){return{T:{}}},props:{sortBy:String,sortAsc:Boolean,filteredMediaItems:Array,selectedMedias:Array,thumbSize:Number},created:function(){var e=this;e.T.imageHeader=$("#t-image-header").val(),e.T.nameHeader=$("#t-name-header").val(),e.T.lastModifyHeader=$("#t-lastModify-header").val(),e.T.sizeHeader=$("#t-size-header").val(),e.T.typeHeader=$("#t-type-header").val(),e.T.editButton=$("#t-edit-button").val(),e.T.deleteButton=$("#t-delete-button").val(),e.T.viewButton=$("#t-view-button").val()},methods:{isMediaSelected:function(e){return this.selectedMedias.some((function(t,i,n){return t.url.toLowerCase()===e.url.toLowerCase()}))},buildMediaUrl:function(e,t){return e+(-1==e.indexOf("?")?"?":"&")+"width="+t+"&height="+t},changeSort:function(e){bus.$emit("sortChangeRequested",e)},toggleSelectionOfMedia:function(e){bus.$emit("mediaToggleRequested",e)},renameMedia:function(e){bus.$emit("renameMediaRequested",e)},deleteMedia:function(e){bus.$emit("deleteMediaRequested",e)},dragStart:function(e,t){bus.$emit("mediaDragStartRequested",e,t)},printDateTime:function(e){return new Date(e).toLocaleString()},getfontAwesomeClassNameForFileName:function(e,t){return getClassNameForFilename(e)+" "+t}}}),Vue.component("pager",{template:'\n
    \n \n \n
    \n ',props:{sourceItems:Array},data:function(){return{pageSize:10,pageSizeOptions:[10,30,50,100],current:0,T:{}}},created:function(){var e=this;e.T.pagerFirstButton=$("#t-pager-first-button").val(),e.T.pagerPreviousButton=$("#t-pager-previous-button").val(),e.T.pagerNextButton=$("#t-pager-next-button").val(),e.T.pagerLastButton=$("#t-pager-last-button").val(),e.T.pagerPageSizeLabel=$("#t-pager-page-size-label").val(),e.T.pagerPageLabel=$("#t-pager-page-label").val(),e.T.pagerTotalLabel=$("#t-pager-total-label").val()},methods:{next:function(){this.current=this.current+1},previous:function(){this.current=this.current-1},goFirst:function(){this.current=0},goLast:function(){this.current=this.totalPages-1},goTo:function(e){this.current=e}},computed:{total:function(){return this.sourceItems?this.sourceItems.length:0},totalPages:function(){var e=Math.ceil(this.total/this.pageSize);return e>0?e:1},isLastPage:function(){return this.current+1>=this.totalPages},isFirstPage:function(){return 0===this.current},canDoNext:function(){return!this.isLastPage},canDoPrev:function(){return!this.isFirstPage},canDoFirst:function(){return!this.isFirstPage},canDoLast:function(){return!this.isLastPage},itemsInCurrentPage:function(){var e=this.pageSize*this.current,t=e+this.pageSize,i=this.sourceItems.slice(e,t);return bus.$emit("pagerEvent",i),i},pageLinks:function(){var e=[];e.push(this.current+1);var t=this.current>0?this.current:-1;e.unshift(t);var i=this.current>1?this.current-1:-1;e.unshift(i);var n=this.totalPages-this.current>1?this.current+2:-1;e.push(n);var a=this.totalPages-this.current>2?this.current+3:-1;return e.push(a),e}},watch:{sourceItems:function(){this.current=0},pageSize:function(){this.current=0}}}),Vue.component("sortIndicator",{template:'\n
    \n \n \n
    \n ',props:{colname:String,selectedcolname:String,asc:Boolean},computed:{isActive:function(){return this.colname.toLowerCase()==this.selectedcolname.toLowerCase()}}}),Vue.component("mediaFieldThumbsContainer",{template:'
    {{T.noImages}}
  • {{ media.isNew ? media.name.substr(36) : media.name }}
    {{ T.mediaNotFound }} {{ T.discardWarning }}
    {{ media.name }}
  • ',data:function(){return{T:{}}},props:{mediaItems:Array,selectedMedia:Object,thumbSize:Number,idPrefix:String},created:function(){var e=this;e.T.mediaNotFound=$("#t-media-not-found").val(),e.T.discardWarning=$("#t-discard-warning").val(),e.T.noImages=$("#t-no-images").val()},methods:{selectAndDeleteMedia:function(e){this.$parent.$emit("selectAndDeleteMediaRequested",e)},selectMedia:function(e){this.$parent.$emit("selectMediaRequested",e)},buildMediaUrl:function(e,t){return e+(-1==e.indexOf("?")?"?":"&")+"width="+t+"&height="+t},getfontAwesomeClassNameForFileName:function(e,t){return getClassNameForFilename(e)+" "+t}}});var mediaFieldApps=[];Vue.component("upload",{template:'

    {{ model.name }}

    Error: {{ model.errorMessage }}
    ',props:{model:Object,uploadInputId:String},mounted:function(){var e,t=this,i=document.getElementById(null!==(e=t.uploadInputId)&&void 0!==e?e:"fileupload");$(i).bind("fileuploadprogress",(function(e,i){i.files[0].name===t.model.name&&(t.model.percentage=parseInt(i.loaded/i.total*100,10))})),$(i).bind("fileuploaddone",(function(e,i){i.files[0].name===t.model.name&&(i.result.files[0].error?t.handleFailure(i.files[0].name,i.result.files[0].error):bus.$emit("removalRequest",t.model))})),$(i).bind("fileuploadfail",(function(e,i){i.files[0].name===t.model.name&&t.handleFailure(i.files[0].name,$("#t-error").val())}))},methods:{handleFailure:function(e,t){e===this.model.name&&(this.model.errorMessage=t,bus.$emit("ErrorOnUpload",this.model))},dismissWarning:function(){bus.$emit("removalRequest",this.model)}}}),Vue.component("uploadList",{template:'
    {{ T.uploads }} (Pending: {{ pendingCount }}) ( {{ T.errors }}: {{ errorCount }} / {{ T.clearErrors }} )
    ',data:function(){return{files:[],T:{},expanded:!1,pendingCount:0,errorCount:0}},props:{uploadInputId:String},created:function(){var e=this;e.T.uploads=$("#t-uploads").val(),e.T.errors=$("#t-errors").val(),e.T.clearErrors=$("#t-clear-errors").val()},computed:{fileCount:function(){return this.files.length}},mounted:function(){var e,t=this,i=document.getElementById(null!==(e=t.uploadInputId)&&void 0!==e?e:"fileupload");$(i).bind("fileuploadadd",(function(e,i){i.files&&i.files.forEach((function(e){t.files.some((function(t){return t.name==e.name}))?console.error("A file with the same name is already on the queue:"+e.name):t.files.push({name:e.name,percentage:0,errorMessage:""})}))})),bus.$on("removalRequest",(function(e){t.files.forEach((function(t,i,n){t.name==e.name&&n.splice(i,1)}))})),bus.$on("ErrorOnUpload",(function(e){t.updateCount()}))},methods:{updateCount:function(){this.errorCount=this.files.filter((function(e){return""!=e.errorMessage})).length,this.pendingCount=this.files.length-this.errorCount,this.files.length<1&&(this.expanded=!1)},clearErrors:function(){this.files=this.files.filter((function(e){return""==e.errorMessage}))}},watch:{files:function(){this.updateCount()}}});