diff --git a/.babelrc b/.babelrc
new file mode 100644
index 000000000..71464e186
--- /dev/null
+++ b/.babelrc
@@ -0,0 +1,13 @@
+{
+ "presets": ["@babel/preset-env"],
+ "plugins": [
+ [
+ "module-resolver", {
+ "root": ["."],
+ "alias": {
+ "helpers": "./tests/js/helpers"
+ }
+ }
+ ]
+ ]
+}
diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md
index d8d3638a2..021d7417a 100644
--- a/.github/CONTRIBUTING.md
+++ b/.github/CONTRIBUTING.md
@@ -1,10 +1,21 @@
# Contributing to OctoberCMS
-Thank you for your interest in contributing to the OctoberCMS project!
+Thank you for your interest in contributing to the OctoberCMS project. We appreciate any assistance that community members and users of OctoberCMS are willing to provide. You can contribute to the project in several different ways:
+
+- [Reporting a Security Vulnerability](#reporting-a-security-vulnerability)
+- [Reporting an issue with OctoberCMS](#reporting-an-issue-with-octobercms)
+ - [Reporting an issue with an OctoberCMS plugin](#reporting-an-issue-with-an-octobercms-plugin)
+- [Making a Feature Request](#making-a-feature-request)
+- [Making a Pull Request](#making-a-pull-request)
+- [Testing Pull Requests](#testing-a-pull-request)
+
+## Reporting a Security Vulnerability
+
+Please review [our security policy](https://github.com/octobercms/october/security/policy) on how to report security vulnerabilities.
## Reporting an issue with OctoberCMS
-**Please don't use the main GitHub for reporting issues with plugins.** If you have found a bug in a plugin, the best place to report it is with the [plugin author](https://octobercms.com/plugins).
+>**NOTE:** If your issue is related to an OctoberCMS plugin, please see the [Reporting an issue with an OctoberCMS plugin](#reporting-an-issue-with-an-octobercms-plugin) section below.
We work hard to process bugs that are reported, to assist with this please ensure the following details are always included:
@@ -16,7 +27,9 @@ We work hard to process bugs that are reported, to assist with this please ensur
- **Actual behavior**: What is the actual result on running above steps i.e. the bug behavior - **include any error messages**.
->**NOTE:** Screenshots and GIFs are very helpful in visuallizing what exactly is going wrong
+If possible, please provide any screenshots or GIFs of the issue occurring to provide us with additional context to determine the cause of the issue.
+
+>**NOTE**: If you're reporting an issue that you intend to fix yourself, you can skip the Issue step and just submit a Pull Request that fixes the issue (along with a detailed description of the original problem) instead.
#### Here's how to report an issue on GitHub
@@ -32,13 +45,21 @@ We work hard to process bugs that are reported, to assist with this please ensur
If you find out your bug is actually a duplicate of another bug and only notice that after you created it, please also close your bug with a short reference to the other issue that was there before.
-#### Reporting security issues
+#### Reporting an issue with an OctoberCMS plugin
-If you wish to contact us privately about any security exploits in OctoberCMS you may find, you can find our email on the [OctoberCMS website](https://octobercms.com).
+>Please don't use the main GitHub for reporting issues with plugins.
-## Feature requests
+If you have found a bug in a plugin, the best place to report it is with the [plugin author](https://octobercms.com/plugins).
-**Please don't use GitHub issues for suggesting a new feature.** If you have a feature idea, the best place to suggest it is the [OctoberCMS website forum](https://octobercms.com/forum/chan/feature-requests).
+If you are unable to contact the plugin author and the issue prevents the plugin from being used correctly, please feel free to email `hello@octobercms.com`, mentioning the plugin name, URL and the issue found. We will then determine if the plugin needs to be delisted.
+
+#### Escalation process
+
+We do our best to attend to all reported issues. If you have an important issue that requires attention, consider submitting a bounty using the [OctoberCMS Bounty Program](https://www.bountysource.com/teams/october).
+
+## Making a Feature Request
+
+>**NOTE:** Please don't use GitHub issues for suggesting a new feature. If you have a feature idea, the best place to suggest it is the [OctoberCMS website forum](https://octobercms.com/forum/chan/feature-requests).
Only use GitHub if you are planning on contributing a new feature and developing it. If you want to discuss your idea first, before "officially" posting it anywhere, you can always join us on [IRC](https://octobercms.com/chat) or [Slack](https://octobercms.slack.com).
@@ -48,7 +69,7 @@ Feature Requests submitted as GitHub Issues specifically mean *"I'd like to see
It's a great way to launch discussions on the developer side of things because both the core team and the community developer get a chance to talk about the technical side of the feature implementation. It's a great way to exchange ideas about how the logic could work in code.
-## Pull Requests
+## Making a Pull Request
Your contributions to the project are very welcome. If you would like to fix a bug or propose a new feature, you can submit a Pull Request.
@@ -61,6 +82,43 @@ To help us merge your Pull Request, please make sure you follow these points:
Thank you for your contributions!
+#### Best practices
+
+It is ideal to keep your development branch or fork synchronised with the core OctoberCMS `develop` branch when submitting Pull Requests, as this minimises the possibility of merge conflicts.
+
+To keep in sync with OctoberCMS, add the core OctoberCMS repository as a Git remote (ie. `upstream`) and pull changes from the OctoberCMS repository into your local `develop` branch as often as possible:
+
+```
+git remote add upstream git@github.com:octobercms/october.git
+git fetch upstream
+git checkout develop
+git pull upstream develop
+```
+
+This ensures that your local `develop` branch matches OctoberCMS. When developing a pull request, it is best to use your own development branch. For example, creating a fix to improve spelling on a language file could be made into a branch called `lang-en-spelling-fixes`, which can be branched off from the `develop` branch.
+
+```
+git checkout -b lang-en-spelling-fixes develop
+```
+
+When you wish to update your development branch with the latest changes from the `develop` branch, it is just a simple merge:
+
+```
+git merge develop
+```
+
+This will merge all the latest changes from the OctoberCMS `develop` branch into your development branch.
+
+#### Resolving merge conflicts
+
+Occassionally, you may encounter a merge conflict with your Pull Request. This most commonly occurs if another change made to the OctoberCMS repository was made to a file that your Pull Request has also changed.
+
+It is the responsibility of the author of the Pull Request to resolve any merge conflicts before their Pull Request is accepted.
+
+You should ensure that your local copy of OctoberCMS is synchronised with with the `develop` branch in the OctoberCMS repository. Please follow the [steps above](#best-practices) to synchronise the repositories.
+
+If Git reports that your changes have conflicts, you will need to resolve the changes in a way that includes the changes from the OctoberCMS repository as well as implementing your Pull Request's changes. See GitHub's guide to [resolving a merge conflict](https://help.github.com/en/articles/resolving-a-merge-conflict-using-the-command-line) for tips on resolving conflicts.
+
#### PSR Coding standards
Please ensure that your Pull Request satisfies the following coding standards:
@@ -69,10 +127,28 @@ Please ensure that your Pull Request satisfies the following coding standards:
- [PSR 1 Coding Style Guide](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-1-basic-coding-standard.md)
- [PSR 0 Coding Style Guide](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md)
+To validate your changes against our coding standards, you may run `./vendor/bin/phpcs -nq --extensions="php"` in your development folder.
+
#### Team rules
-The October team follows the [developer guidelines](https://octobercms.com/docs/help/developer-guide) as much as possible.
+The OctoberCMS team follows the [developer guidelines](https://octobercms.com/docs/help/developer-guide) as much as possible.
-#### Escalation process
+## Testing a Pull Request
-We do our best to attend to all reported issues. If you have an important issue that requires attention, consider submitting a bounty using the [OctoberCMS Bounty Program](https://www.bountysource.com/teams/october).
\ No newline at end of file
+Although we aim to test all pull requests made to the OctoberCMS repository, the maintainers of OctoberCMS are volunteers and may not be able to promptly attend to all pull requests.
+
+To help speed things up, any assistance with testing Pull Requests and fixes will be very appreciated. The best Pull Requests to test are those that are tagged as [**Testing Needed**](https://github.com/octobercms/october/pulls?q=is%3Apr+is%3Aopen+label%3A%22Testing+Needed%22) in the repository.
+
+To test a Pull Request, you can use the steps below in a terminal or command-line interface to create a fresh installation of OctoberCMS with the changes made in the Pull Request, ready to test. In this example, we have a user called `qwerty123` that has created a pull request with an ID of `#4509`.
+
+1. Check out a copy of the OctoberCMS repository to a folder that you can view in your web browser: `git clone git@github.com:octobercms/october.git`. This will add the files into a subfolder called `october`.
+
+2. Then, go to the `october` subfolder and check out **@qwerty123**'s changes in a branch in your local repository: `git fetch origin pull/4509/head:pr-4509`. This will pull their changes into a branch called `pr-4509`. You will then need to check out the branch: `git checkout pr-4509`.
+
+3. Next, get the Composer dependencies: `composer update`.
+
+4. Next, run `php artisan october:env` to create a `.env` file in your folder. This will contain the configuration values for the database and site.
+
+5. Finally, once you've populated that file with your database and site details, run `php artisan october:up` to install the necessary database tables.
+
+At this point, you should have a working copy of the Pull Request ready to test.
diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
new file mode 100644
index 000000000..bc7c4b4be
--- /dev/null
+++ b/.github/FUNDING.yml
@@ -0,0 +1,5 @@
+# These are supported funding model platforms
+custom: ['https://octobercms.com/fundraising']
+open_collective: octobercms
+github: LukeTowers
+patreon: LukeTowers
diff --git a/.github/ISSUE_TEMPLATE/0_IMMEDIATE_SUPPORT.md b/.github/ISSUE_TEMPLATE/0_IMMEDIATE_SUPPORT.md
new file mode 100644
index 000000000..96219a5f4
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/0_IMMEDIATE_SUPPORT.md
@@ -0,0 +1,15 @@
+---
+name: "🚨 Immediate Support"
+about: 'I use October and it just broke! Help me!'
+---
+
+This repository is only for reporting reproducible bugs or problems. If you need support, please use the following options:
+
+- Slack: https://octobercms.slack.com (Get an invite: https://octobercms-slack.herokuapp.com/)
+- Live chat (IRC): https://octobercms.com/chat - **Note:** Not as active as Slack
+- Forum: https://octobercms.com/forum
+- Stack Overflow: https://stackoverflow.com/questions/tagged/octobercms
+
+If you rely on OctoberCMS for your business consider purchasing a paid support plan! Send an email to octobercms@luketowers.ca to get started.
+
+Thanks!
\ No newline at end of file
diff --git a/.github/ISSUE_TEMPLATE/2_MARKETPLACE_SUPPORT.md b/.github/ISSUE_TEMPLATE/2_MARKETPLACE_SUPPORT.md
new file mode 100644
index 000000000..a2e76acef
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/2_MARKETPLACE_SUPPORT.md
@@ -0,0 +1,8 @@
+---
+name: "🛒 Marketplace Support"
+about: 'For reporting any issues with the marketplace, send an email to hello@octobercms.com'
+---
+
+All marketplace support issues will be addressed through email support.
+
+Thanks!
diff --git a/.github/ISSUE_TEMPLATE/2_SUPPORT_QUESTION.md b/.github/ISSUE_TEMPLATE/3_GENERAL_SUPPORT.md
similarity index 59%
rename from .github/ISSUE_TEMPLATE/2_SUPPORT_QUESTION.md
rename to .github/ISSUE_TEMPLATE/3_GENERAL_SUPPORT.md
index 3ea7271c1..a76dd57b1 100644
--- a/.github/ISSUE_TEMPLATE/2_SUPPORT_QUESTION.md
+++ b/.github/ISSUE_TEMPLATE/3_GENERAL_SUPPORT.md
@@ -1,12 +1,12 @@
---
-name: "⚠️ Support Question"
-about: 'This repository is only for reporting bugs or problems. If you need help, see: https://octobercms.com/support'
+name: "⚠️ General Support"
+about: 'This repository is only for reporting bugs or problems. If you need help using OctoberCMS, see: https://octobercms.com/support'
---
This repository is only for reporting bugs or problems. If you need support, please use the following options:
- Forum: https://octobercms.com/forum
-- Slack: https://octobercms.slack.com (Invite link: https://octobercms-slack.herokuapp.com/)
+- Slack: https://octobercms.slack.com (Get an invite: https://octobercms-slack.herokuapp.com/)
- Stack Overflow: https://stackoverflow.com/questions/tagged/octobercms
Thanks!
\ No newline at end of file
diff --git a/.github/ISSUE_TEMPLATE/3_FEATURE_REQUEST.md b/.github/ISSUE_TEMPLATE/4_FEATURE_REQUEST.md
similarity index 100%
rename from .github/ISSUE_TEMPLATE/3_FEATURE_REQUEST.md
rename to .github/ISSUE_TEMPLATE/4_FEATURE_REQUEST.md
diff --git a/.github/ISSUE_TEMPLATE/4_DOCUMENTATION.md b/.github/ISSUE_TEMPLATE/5_DOCUMENTATION.md
similarity index 100%
rename from .github/ISSUE_TEMPLATE/4_DOCUMENTATION.md
rename to .github/ISSUE_TEMPLATE/5_DOCUMENTATION.md
diff --git a/.github/ISSUE_TEMPLATE/5_SECURITY_ISSUES.md b/.github/ISSUE_TEMPLATE/5_SECURITY_ISSUES.md
deleted file mode 100644
index 53abbd023..000000000
--- a/.github/ISSUE_TEMPLATE/5_SECURITY_ISSUES.md
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: "🔒 Security Vulnerabilities"
-about: 'For reporting security-related issues, send an email to hello@octobercms.com'
----
-
-PLEASE DON'T DISCLOSE SECURITY-RELATED ISSUES PUBLICLY, SEE BELOW.
-
-If you discover a security vulnerability within OctoberCMS or dependencies, please send an e-mail to Samuel Georges & Luke Towers via hello@octobercms.com and octobercms@luketowers.ca respectively. All security vulnerabilities will be promptly addressed.
\ No newline at end of file
diff --git a/.github/workflows/archive.yml b/.github/workflows/archive.yml
new file mode 100644
index 000000000..a76ad0def
--- /dev/null
+++ b/.github/workflows/archive.yml
@@ -0,0 +1,21 @@
+name: Archive
+
+on:
+ schedule:
+ - cron: "0 0 * * *"
+
+jobs:
+ archive:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/stale@v1
+ with:
+ repo-token: ${{ secrets.GITHUB_TOKEN }}
+ days-before-stale: 30
+ days-before-close: 3
+ stale-issue-message: 'This issue will be closed and archived in 3 days, as there has been no activity in the last 30 days. If this issue is still relevant or you would like to see action on it, please respond and we will get the ball rolling.'
+ stale-pr-message: 'This pull request will be closed and archived in 3 days, as there has been no activity in the last 30 days. If this is still being worked on, please respond and we will re-open this pull request.'
+ stale-issue-label: 'Status: Archived'
+ stale-pr-label: 'Status: Archived'
+ exempt-issue-label: 'Status: In Progress'
+ exempt-pr-label: 'Status: In Progress'
diff --git a/.github/workflows/code-quality-pr.yaml b/.github/workflows/code-quality-pr.yaml
new file mode 100644
index 000000000..65a0f4646
--- /dev/null
+++ b/.github/workflows/code-quality-pr.yaml
@@ -0,0 +1,30 @@
+name: Code Quality
+
+on:
+ pull_request:
+
+jobs:
+ codeQuality:
+ runs-on: ubuntu-latest
+ name: PHP
+ steps:
+ - name: Checkout changes
+ uses: actions/checkout@v1
+ - name: Install PHP
+ uses: shivammathur/setup-php@master
+ with:
+ php-version: 7.2
+ - name: Install Composer dependencies
+ run: composer install --no-interaction --no-progress --no-suggest
+ - name: Reset October modules and library
+ run: |
+ git reset --hard HEAD
+ rm -rf ./vendor/october/rain
+ wget https://github.com/octobercms/library/archive/develop.zip -O ./vendor/october/develop.zip
+ unzip ./vendor/october/develop.zip -d ./vendor/october
+ mv ./vendor/october/library-develop ./vendor/october/rain
+ composer dump-autoload
+ - name: Run code quality checks
+ run: |
+ git config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*" && git fetch
+ ./vendor/bin/phpcs --colors -nq --report="full" --extensions="php" $(git diff --name-only --diff-filter=ACMR origin/${{ github.base_ref }} HEAD)
diff --git a/.github/workflows/code-quality-push.yaml b/.github/workflows/code-quality-push.yaml
new file mode 100644
index 000000000..3de3f6a97
--- /dev/null
+++ b/.github/workflows/code-quality-push.yaml
@@ -0,0 +1,31 @@
+name: Code Quality
+
+on:
+ push:
+ branches:
+ - master
+ - develop
+
+jobs:
+ codeQuality:
+ runs-on: ubuntu-latest
+ name: PHP
+ steps:
+ - name: Checkout changes
+ uses: actions/checkout@v1
+ - name: Install PHP
+ uses: shivammathur/setup-php@master
+ with:
+ php-version: 7.2
+ - name: Install Composer dependencies
+ run: composer install --no-interaction --no-progress --no-suggest
+ - name: Reset October modules and library
+ run: |
+ git reset --hard HEAD
+ rm -rf ./vendor/october/rain
+ wget https://github.com/octobercms/library/archive/develop.zip -O ./vendor/october/develop.zip
+ unzip ./vendor/october/develop.zip -d ./vendor/october
+ mv ./vendor/october/library-develop ./vendor/october/rain
+ composer dump-autoload
+ - name: Run code quality checks
+ run: ./vendor/bin/phpcs --colors -nq --report="full" --extensions="php" $(git show --name-only --pretty="" --diff-filter=ACMR ${{ github.sha }})
diff --git a/.github/workflows/frontend-tests.yaml b/.github/workflows/frontend-tests.yaml
new file mode 100644
index 000000000..9d0068a0a
--- /dev/null
+++ b/.github/workflows/frontend-tests.yaml
@@ -0,0 +1,24 @@
+name: Tests
+
+on:
+ push:
+ branches:
+ - master
+ - develop
+ pull_request:
+
+jobs:
+ frontendTests:
+ runs-on: ubuntu-latest
+ name: JavaScript
+ steps:
+ - name: Checkout changes
+ uses: actions/checkout@v1
+ - name: Install Node
+ uses: actions/setup-node@v1
+ with:
+ node-version: 8
+ - name: Install Node dependencies
+ run: npm install
+ - name: Run tests
+ run: npm run test
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
new file mode 100644
index 000000000..b3ce5ca08
--- /dev/null
+++ b/.github/workflows/tests.yml
@@ -0,0 +1,39 @@
+name: Tests
+
+on:
+ push:
+ branches:
+ - master
+ - develop
+ pull_request:
+
+jobs:
+ phpUnitTests:
+ runs-on: ubuntu-latest
+ strategy:
+ max-parallel: 6
+ matrix:
+ phpVersions: ['7.1', '7.2', '7.3']
+ fail-fast: false
+ name: PHP ${{ matrix.phpVersions }}
+ steps:
+ - name: Checkout changes
+ uses: actions/checkout@v1
+ - name: Install PHP
+ uses: shivammathur/setup-php@master
+ with:
+ php-version: ${{ matrix.phpVersions }}
+ - name: Install Composer dependencies
+ run: composer install --no-interaction --no-progress --no-suggest
+ - name: Reset October modules and library
+ run: |
+ git reset --hard HEAD
+ rm -rf ./vendor/october/rain
+ wget https://github.com/octobercms/library/archive/develop.zip -O ./vendor/october/develop.zip
+ unzip ./vendor/october/develop.zip -d ./vendor/october
+ mv ./vendor/october/library-develop ./vendor/october/rain
+ composer dump-autoload
+ - name: Run Linting and Tests
+ run: |
+ ./vendor/bin/parallel-lint --exclude vendor --exclude storage --exclude tests/fixtures/plugins/testvendor/goto/Plugin.php .
+ ./vendor/bin/phpunit
diff --git a/.github/workflows/wrong-branch-notification.yaml b/.github/workflows/wrong-branch-notification.yaml
new file mode 100644
index 000000000..ab67a9113
--- /dev/null
+++ b/.github/workflows/wrong-branch-notification.yaml
@@ -0,0 +1,29 @@
+name: Wrong Branch
+
+on:
+ pull_request:
+ types: [opened]
+ branches:
+ - master
+
+jobs:
+ wrongBranch:
+ runs-on: ubuntu-latest
+ name: Fix Wrong Branch
+ steps:
+ - name: Alert submitter
+ run: |
+ export ISSUE_NUMBER=$(echo '${{ github.ref }}' | cut -d'/' -f3)
+ curl -s --request POST \
+ --url https://api.github.com/repos/${{ github.repository }}/issues/${ISSUE_NUMBER}/comments \
+ --header 'authorization: Bearer ${{ secrets.GITHUB_TOKEN }}' \
+ --header 'content-type: application/json' \
+ --data '{"body": "This pull request has been made to the wrong branch. Please review [the contributing guidelines](https://github.com/octobercms/october/blob/master/.github/CONTRIBUTING.md#making-a-pull-request) as all PRs need to be made to the `develop` branch.\n\nWe'\''ll fix it for you this time, but please ensure you make any future PRs to the `develop` branch, not the `master` branch."}' > /dev/null
+ - name: Change base branch
+ run: |
+ export ISSUE_NUMBER=$(echo '${{ github.ref }}' | cut -d'/' -f3)
+ curl -s --request PATCH \
+ --url https://api.github.com/repos/${{ github.repository }}/pulls/${ISSUE_NUMBER} \
+ --header 'authorization: Bearer ${{ secrets.GITHUB_TOKEN }}' \
+ --header 'content-type: application/json' \
+ --data '{"base": "develop"}' > /dev/null
diff --git a/.gitignore b/.gitignore
index c5ebf3e67..4cd08cf9a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -16,6 +16,9 @@ sftp-config.json
.ftpconfig
selenium.php
composer.lock
+package-lock.json
+/node_modules
+_ide_helper.php
# for netbeans
nbproject
diff --git a/.jshintrc b/.jshintrc
new file mode 100644
index 000000000..bb55890a9
--- /dev/null
+++ b/.jshintrc
@@ -0,0 +1,5 @@
+{
+ "esversion": 6,
+ "curly": true,
+ "asi": true
+}
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index bac7f1100..000000000
--- a/.travis.yml
+++ /dev/null
@@ -1,22 +0,0 @@
-language: php
-
-php:
- - 7.0
- - 7.1
- - 7.2
- - 7.3
- - nightly
-
-matrix:
- allow_failures:
- - php: nightly
-
-sudo: false
-
-install:
- - composer self-update
- - travis_retry composer install --no-interaction --prefer-source
-
-before_script: git reset --hard HEAD
-
-script: vendor/bin/phpunit
diff --git a/README.md b/README.md
index ef85392f0..362c4aab1 100644
--- a/README.md
+++ b/README.md
@@ -2,20 +2,14 @@
-[October](http://octobercms.com) is a Content Management System (CMS) and web platform whose sole purpose is to make your development workflow simple again. It was born out of frustration with existing systems. We feel building websites has become a convoluted and confusing process that leaves developers unsatisfied. We want to turn you around to the simpler side and get back to basics.
+[October](https://octobercms.com) is a Content Management Framework (CMF) and web platform whose sole purpose is to make your development workflow simple again. It was born out of frustration with existing systems. We feel building websites has become a convoluted and confusing process that leaves developers unsatisfied. We want to turn you around to the simpler side and get back to basics.
October's mission is to show the world that web development is not rocket science.
[](https://travis-ci.org/octobercms/october)
[](https://packagist.org/packages/october/october)
-### Learning October
-
-The best place to learn October is by [reading the documentation](https://octobercms.com/docs) or [following some tutorials](https://octobercms.com/support/articles/tutorials).
-
-You may also watch these introductory videos for [beginners](https://vimeo.com/79963873) and [advanced users](https://vimeo.com/172202661).
-
-### Installing October
+## Installing October
Instructions on how to install October can be found at the [installation guide](https://octobercms.com/docs/setup/installation).
@@ -33,35 +27,54 @@ If you plan on using a database, run this command:
php artisan october:install
```
-### Development Team
+## Learning October
-October was created by [Alexey Bobkov](http://ca.linkedin.com/pub/aleksey-bobkov/2b/ba0/232) and [Samuel Georges](https://www.linkedin.com/in/samuel-georges-0a964131/), who (along with [Luke Towers](https://luketowers.ca/)) continue to develop the platform.
+The best place to learn October is by [reading the documentation](https://octobercms.com/docs) or [following some tutorials](https://octobercms.com/support/articles/tutorials).
-### Foundation library
+You may also watch these introductory videos for [beginners](https://vimeo.com/79963873) and [advanced users](https://vimeo.com/172202661). There is also the excellent video series by [Watch & Learn](https://watch-learn.com/series/making-websites-with-october-cms).
-The CMS uses [Laravel](https://laravel.com) as a foundation PHP framework.
-
-### Contact
-
-You can communicate with us using the following mediums:
-
-* [Follow us on Twitter](https://twitter.com/octobercms) for announcements and updates.
-* [Follow us on Facebook](https://facebook.com/octobercms) for announcements and updates.
-* [Join us on IRC](https://octobercms.com/chat) to chat with us.
-* [Join us on Slack](https://octobercms-slack.herokuapp.com/) to chat with us.
-
-### License
-
-The OctoberCMS platform is open-sourced software licensed under the [MIT license](https://opensource.org/licenses/MIT).
-
-### Contributing
+## Contributing
Before sending a Pull Request, be sure to review the [Contributing Guidelines](.github/CONTRIBUTING.md) first.
-### Coding standards
+### Help and support this project
+
+You can also help the project by reviewing and testing open Pull Requests with the "**Status: Testing Needed**" tag.
+[Read more...](https://github.com/octobercms/october/blob/master/.github/CONTRIBUTING.md#testing-pull-requests)
+
+## Coding standards
Please follow the following guides and code standards:
* [PSR 4 Coding Standards](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-4-autoloader.md)
* [PSR 2 Coding Style Guide](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md)
* [PSR 1 Coding Standards](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-1-basic-coding-standard.md)
+
+## Code of Conduct
+
+In order to ensure that the OctoberCMS community is welcoming to all, please review and abide by the [Code of Conduct](CODE_OF_CONDUCT.md).
+
+## Security Vulnerabilities
+
+Please review [our security policy](https://github.com/octobercms/october/security/policy) on how to report security vulnerabilities.
+
+## Development Team
+
+October was created by [Alexey Bobkov](http://ca.linkedin.com/pub/aleksey-bobkov/2b/ba0/232) and [Samuel Georges](https://www.linkedin.com/in/samuel-georges-0a964131/). The core maintainer is [Luke Towers](https://luketowers.ca/) and other maintainers include [Ben Thomson](https://github.com/bennothommo) and [Denis Denisov](https://github.com/w20k).
+
+## Foundation library
+
+The CMS uses [Laravel](https://laravel.com) as a foundation PHP framework.
+
+## Contact
+
+You can communicate with us using the following mediums:
+
+* [Follow us on Twitter](https://twitter.com/octobercms) for announcements and updates.
+* [Follow us on Facebook](https://facebook.com/octobercms) for announcements and updates.
+* [Join us on Slack](https://octobercms-slack.herokuapp.com/) to chat with us.
+* [Join us on IRC](https://octobercms.com/chat) to chat with us.
+
+## License
+
+The OctoberCMS platform is open-sourced software licensed under the [MIT license](https://opensource.org/licenses/MIT).
diff --git a/SECURITY.md b/SECURITY.md
new file mode 100644
index 000000000..dc9de11e8
--- /dev/null
+++ b/SECURITY.md
@@ -0,0 +1,11 @@
+# Security Policy
+
+**PLEASE DON'T DISCLOSE SECURITY-RELATED ISSUES PUBLICLY, [SEE BELOW](#reporting-a-vulnerability).**
+
+## Supported Versions
+
+October is evergreen, no one version is singled out for security fixes because there is no way to update just one version. Builds are continually released and security fixes will always be available in the latest build.
+
+## Reporting a Vulnerability
+
+If you discover a security vulnerability within OctoberCMS, please send an email to Samuel Georges at hello@octobercms.com and Luke Towers at octobercms@luketowers.ca. All security vulnerabilities will be promptly addressed.
diff --git a/composer.json b/composer.json
index 39af52963..e08f1cdde 100644
--- a/composer.json
+++ b/composer.json
@@ -1,7 +1,8 @@
{
"name": "october/october",
- "description": "October CMS",
+ "description": "OctoberCMS",
"homepage": "https://octobercms.com",
+ "type": "project",
"keywords": ["october", "cms", "octobercms", "laravel"],
"license": "MIT",
"authors": [
@@ -42,12 +43,16 @@
},
"require-dev": {
"fzaninotto/faker": "~1.7",
- "phpunit/phpunit": "~5.7",
+ "phpunit/phpunit": "~6.5",
"phpunit/phpunit-selenium": "~1.2",
- "meyfa/phpunit-assert-gd": "1.1.0"
+ "meyfa/phpunit-assert-gd": "1.1.0",
+ "squizlabs/php_codesniffer": "3.*",
+ "jakub-onderka/php-parallel-lint": "^1.0"
},
"autoload-dev": {
"classmap": [
+ "tests/concerns/InteractsWithAuthentication.php",
+ "tests/fixtures/backend/models/UserFixture.php",
"tests/TestCase.php",
"tests/UiTestCase.php",
"tests/PluginTestCase.php"
diff --git a/config/cms.php b/config/cms.php
index 75189b297..acb98db9a 100644
--- a/config/cms.php
+++ b/config/cms.php
@@ -93,6 +93,21 @@ return [
'backendSkin' => 'Backend\Skins\Standard',
+ /*
+ |--------------------------------------------------------------------------
+ | Automatically run migrations on login
+ |--------------------------------------------------------------------------
+ |
+ | If value is true, UpdateManager will be run on logging in to the backend.
+ | It's recommended to set this value to 'null' in production enviroments
+ | because it clears the cache every time a user logs in to the backend.
+ | If set to null, this setting is enabled when debug mode (app.debug) is enabled
+ | and disabled when debug mode is disabled.
+ |
+ */
+
+ 'runMigrationsOnLogin' => null,
+
/*
|--------------------------------------------------------------------------
| Determines which modules to load
@@ -359,8 +374,8 @@ return [
| Cross Site Request Forgery (CSRF) Protection
|--------------------------------------------------------------------------
|
- | If the CSRF protection is enabled, all "postback" requests are checked
- | for a valid security token.
+ | If the CSRF protection is enabled, all "postback" & AJAX requests are
+ | checked for a valid security token.
|
*/
@@ -413,4 +428,26 @@ return [
'restrictBaseDir' => true,
+ /*
+ |--------------------------------------------------------------------------
+ | Backend Service Worker
+ |--------------------------------------------------------------------------
+ |
+ | Allow plugins to run Service Workers in the backend.
+ |
+ | WARNING: This should always be disabled for security reasons as Service
+ | Workers can be hijacked and used to run XSS into the backend. Turning
+ | this feature on can create a conflict if you have a frontend Service
+ | Worker running. The 'scope' needs to be correctly set and not have a
+ | duplicate subfolder structure on the frontend, otherwise it will run
+ | on both the frontend and backend of your website.
+ |
+ | true - allow service workers to run in the backend
+ |
+ | false - disallow service workers to run in the backend
+ |
+ */
+
+ 'enableBackendServiceWorkers' => false,
+
];
diff --git a/config/develop.php b/config/develop.php
new file mode 100644
index 000000000..cd4aee7d7
--- /dev/null
+++ b/config/develop.php
@@ -0,0 +1,24 @@
+ false,
+
+];
diff --git a/config/filesystems.php b/config/filesystems.php
index a265cbb3e..4d843013c 100644
--- a/config/filesystems.php
+++ b/config/filesystems.php
@@ -46,6 +46,7 @@ return [
'local' => [
'driver' => 'local',
'root' => storage_path('app'),
+ 'url' => '/storage/app',
],
's3' => [
diff --git a/config/services.php b/config/services.php
index 5a2795a17..c2d453065 100644
--- a/config/services.php
+++ b/config/services.php
@@ -17,6 +17,7 @@ return [
'mailgun' => [
'domain' => '',
'secret' => '',
+ 'endpoint' => 'api.mailgun.net', // api.eu.mailgun.net for EU
],
'mandrill' => [
@@ -29,6 +30,10 @@ return [
'region' => 'us-east-1',
],
+ 'sparkpost' => [
+ 'secret' => '',
+ ],
+
'stripe' => [
'model' => 'User',
'secret' => '',
diff --git a/config/testing/cms.php b/config/testing/cms.php
index d29bbc3c3..8267ac3e4 100644
--- a/config/testing/cms.php
+++ b/config/testing/cms.php
@@ -109,4 +109,16 @@ return [
'themesPathLocal' => base_path('tests/fixtures/themes'),
+ /*
+ |--------------------------------------------------------------------------
+ | Cross Site Request Forgery (CSRF) Protection
+ |--------------------------------------------------------------------------
+ |
+ | If the CSRF protection is enabled, all "postback" requests are checked
+ | for a valid security token.
+ |
+ */
+
+ 'enableCsrfProtection' => false
+
];
diff --git a/modules/backend/ServiceProvider.php b/modules/backend/ServiceProvider.php
index 859c61ba7..60ef1b9e0 100644
--- a/modules/backend/ServiceProvider.php
+++ b/modules/backend/ServiceProvider.php
@@ -76,6 +76,8 @@ class ServiceProvider extends ModuleServiceProvider
$combiner->registerBundle('~/modules/backend/formwidgets/fileupload/assets/less/fileupload.less');
$combiner->registerBundle('~/modules/backend/formwidgets/nestedform/assets/less/nestedform.less');
$combiner->registerBundle('~/modules/backend/formwidgets/richeditor/assets/js/build-plugins.js');
+ $combiner->registerBundle('~/modules/backend/formwidgets/colorpicker/assets/less/colorpicker.less');
+ $combiner->registerBundle('~/modules/backend/formwidgets/permissioneditor/assets/less/permissioneditor.less');
/*
* Rich Editor is protected by DRM
diff --git a/modules/backend/assets/css/october.css b/modules/backend/assets/css/october.css
index f995f7ae2..fb572f7c5 100644
--- a/modules/backend/assets/css/october.css
+++ b/modules/backend/assets/css/october.css
@@ -169,9 +169,9 @@ html.mobile .control-scrollbar {overflow:auto;-webkit-overflow-scrolling:touch}
.control-filelist ul li.group >h4 a:after,
.control-filelist ul li.group >div.group >h4 a:after {width:10px;height:10px;display:block;position:absolute;top:1px}
.control-filelist ul li.group >h4 a:after,
-.control-filelist ul li.group >div.group >h4 a:after {left:33px;top:9px;font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em;content:"\f07b";color:#a1aab1;font-size:16px}
+.control-filelist ul li.group >div.group >h4 a:after {left:33px;top:9px;font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;content:"\f07b";color:#a1aab1;font-size:16px}
.control-filelist ul li.group >h4 a:before,
-.control-filelist ul li.group >div.group >h4 a:before {left:20px;top:9px;color:#cfcfcf;font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em;content:"\f0da";-webkit-transform:rotate(90deg) translate(5px,0);-ms-transform:rotate(90deg) translate(5px,0);transform:rotate(90deg) translate(5px,0);-webkit-transition:all 0.1s ease;transition:all 0.1s ease}
+.control-filelist ul li.group >div.group >h4 a:before {left:20px;top:9px;color:#cfcfcf;font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;content:"\f0da";-webkit-transform:rotate(90deg) translate(5px,0);-ms-transform:rotate(90deg) translate(5px,0);transform:rotate(90deg) translate(5px,0);-webkit-transition:all 0.1s ease;transition:all 0.1s ease}
.control-filelist ul li.group >ul >li >a {padding-left:52px}
.control-filelist ul li.group >ul >li.group {padding-left:20px}
.control-filelist ul li.group >ul >li.group >ul >li >a {padding-left:324px;margin-left:-270px}
@@ -276,10 +276,10 @@ html.mobile .control-scrollbar {overflow:auto;-webkit-overflow-scrolling:touch}
.control-treelist >ol >li >div.record:before {display:none}
.control-treelist li {margin:0;padding:0}
.control-treelist li >div.record {margin:0;font-size:12px;margin-bottom:5px;position:relative;display:block}
-.control-treelist li >div.record:before {color:#bdc3c7;font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em;content:"\f111";font-size:6px;position:absolute;left:-18px;top:11px}
+.control-treelist li >div.record:before {color:#bdc3c7;font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;content:"\f111";font-size:6px;position:absolute;left:-18px;top:11px}
.control-treelist li >div.record >a.move {display:inline-block;padding:7px 0 7px 10px;text-decoration:none;color:#bdc3c7}
.control-treelist li >div.record >a.move:hover {color:#4ea5e0}
-.control-treelist li >div.record >a.move:before {font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em;content:"\f0c9"}
+.control-treelist li >div.record >a.move:before {font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;content:"\f0c9"}
.control-treelist li >div.record >span {color:#666;display:inline-block;padding:7px 15px 7px 5px}
.control-treelist li.dragged {position:absolute;z-index:2000;width:auto !important;height:auto !important}
.control-treelist li.dragged >div.record {opacity:0.5;filter:alpha(opacity=50);background:#4ea5e0 !important}
@@ -287,7 +287,7 @@ html.mobile .control-scrollbar {overflow:auto;-webkit-overflow-scrolling:touch}
.control-treelist li.dragged >div.record >span {color:white}
.control-treelist li.dragged >div.record:before {display:none}
.control-treelist li.placeholder {display:inline-block;position:relative;background:#4ea5e0 !important;height:25px;margin-bottom:5px}
-.control-treelist li.placeholder:before {display:block;position:absolute;font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em;content:"\f053";color:#d35714;left:-10px;top:8px;z-index:2000}
+.control-treelist li.placeholder:before {display:block;position:absolute;font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;content:"\f053";color:#d35714;left:-10px;top:8px;z-index:2000}
.control-treeview {margin-bottom:40px}
.control-treeview ol {margin:0;padding:0;list-style:none;background:#fff}
.control-treeview ol >li {-webkit-transition:width 1s;transition:width 1s}
@@ -296,9 +296,9 @@ html.mobile .control-scrollbar {overflow:auto;-webkit-overflow-scrolling:touch}
.control-treeview ol >li >div:before {content:' ';background-image:url(../images/treeview-icons.png);background-position:0 -28px;background-repeat:no-repeat;background-size:42px auto;position:absolute;width:21px;height:22px;left:28px;top:15px}
.control-treeview ol >li >div span.comment {display:block;font-weight:400;color:#95a5a6;font-size:13px;margin-top:2px;overflow:hidden;text-overflow:ellipsis}
.control-treeview ol >li >div >span.expand {font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0;display:none;position:absolute;width:20px;height:20px;top:19px;left:2px;cursor:pointer;color:#bdc3c7;-webkit-transition:transform 0.1s ease;transition:transform 0.1s ease}
-.control-treeview ol >li >div >span.expand:before {font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em;content:"\f0da";line-height:100%;font-size:15px;position:relative;left:8px;top:2px}
+.control-treeview ol >li >div >span.expand:before {font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;content:"\f0da";line-height:100%;font-size:15px;position:relative;left:8px;top:2px}
.control-treeview ol >li >div >span.drag-handle {font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0;-webkit-transition:opacity 0.4s;transition:opacity 0.4s;position:absolute;right:9px;bottom:0;width:18px;height:19px;cursor:move;color:#bdc3c7;opacity:0;filter:alpha(opacity=0)}
-.control-treeview ol >li >div >span.drag-handle:before {font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em;content:"\f0c9";font-size:18px}
+.control-treeview ol >li >div >span.drag-handle:before {font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;content:"\f0c9";font-size:18px}
.control-treeview ol >li >div span.borders {font-size:0}
.control-treeview ol >li >div >ul.submenu {position:absolute;left:20px;bottom:-36.9px;padding:0;list-style:none;z-index:200;height:37px;display:none;margin-left:15px;background:transparent url(../images/treeview-submenu-tabs.png) repeat-x left -39px}
.control-treeview ol >li >div >ul.submenu:before,
@@ -449,7 +449,7 @@ body.dragging .control-treeview.treeview-light ol.dragging ol >li >div {backgrou
.sidenav-tree ul.top-level >li[data-status=collapsed] ul {display:none}
.sidenav-tree ul.top-level >li >div.group {position:relative}
.sidenav-tree ul.top-level >li >div.group h3 {background:rgba(0,0,0,0.15);color:#ecf0f1;text-transform:uppercase;font-size:15px;padding:15px 15px 15px 40px;margin:0;position:relative;cursor:pointer;font-weight:400}
-.sidenav-tree ul.top-level >li >div.group h3:before {display:block;position:absolute;width:10px;height:10px;left:16px;top:15px;color:#cfcfcf;font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em;content:"\f105";-webkit-transform:rotate(90deg) translate(5px,-3px);-ms-transform:rotate(90deg) translate(5px,-3px);transform:rotate(90deg) translate(5px,-3px);-webkit-transition:all 0.1s ease;transition:all 0.1s ease;font-size:16px}
+.sidenav-tree ul.top-level >li >div.group h3:before {display:block;position:absolute;width:10px;height:10px;left:16px;top:15px;color:#cfcfcf;font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;content:"\f105";-webkit-transform:rotate(90deg) translate(5px,-3px);-ms-transform:rotate(90deg) translate(5px,-3px);transform:rotate(90deg) translate(5px,-3px);-webkit-transition:all 0.1s ease;transition:all 0.1s ease;font-size:16px}
.sidenav-tree ul.top-level >li >div.group:before,
.sidenav-tree ul.top-level >li >div.group:after {content:'';display:block;width:0;height:0;border-left:7.5px solid transparent;border-right:7.5px solid transparent;border-top:8px solid #34495e;border-bottom-width:0;position:absolute;left:15px;bottom:-8px;z-index:101}
.sidenav-tree ul.top-level >li >div.group:after {content:'';display:block;width:0;height:0;border-left:7.5px solid transparent;border-right:7.5px solid transparent;border-top:8px solid rgba(0,0,0,0.15);border-bottom-width:0}
@@ -495,7 +495,7 @@ div.panel >label {margin-bottom:5px}
div.panel .nav.selector-group {margin:0 -20px 20px -20px}
ul.tree-path {list-style:none;padding:0;margin-bottom:0}
ul.tree-path li {display:inline-block;margin-right:1px;font-size:13px}
-ul.tree-path li:after {font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em;content:"\f105";display:inline-block;font-size:13px;margin-left:5px;position:relative;top:1px;color:#95a5a6}
+ul.tree-path li:after {font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;content:"\f105";display:inline-block;font-size:13px;margin-left:5px;position:relative;top:1px;color:#95a5a6}
ul.tree-path li:last-child a {cursor:default}
ul.tree-path li:last-child:after {display:none}
ul.tree-path li.go-up {font-size:12px;margin-right:7px}
@@ -685,7 +685,7 @@ nav#layout-mainmenu ul.mainmenu-toolbar li.mainmenu-preview a {position:relative
nav#layout-mainmenu ul.mainmenu-toolbar li.mainmenu-account {margin-right:0}
nav#layout-mainmenu ul.mainmenu-toolbar li.mainmenu-account >a {padding:0 15px 0 10px;font-size:13px;position:relative}
nav#layout-mainmenu ul.mainmenu-toolbar li.mainmenu-account.highlight >a {z-index:600}
-nav#layout-mainmenu ul.mainmenu-toolbar li.mainmenu-account img.account-avatar {width:45px}
+nav#layout-mainmenu ul.mainmenu-toolbar li.mainmenu-account img.account-avatar {width:45px;height:45px}
nav#layout-mainmenu ul.mainmenu-toolbar li.mainmenu-account .account-name {margin-right:15px}
nav#layout-mainmenu ul.mainmenu-toolbar li.mainmenu-account ul {line-height:23px}
html.svg nav#layout-mainmenu img.svg-icon,
@@ -778,7 +778,7 @@ nav#layout-mainmenu.navbar-mode-collapse .menu-toggle {display:inline-block;colo
.mainmenu-collapsed >div ul li a i {line-height:1;font-size:30px;vertical-align:middle}
.mainmenu-collapsed >div ul li a img.svg-icon {height:30px;width:30px;position:relative;top:0}
.mainmenu-collapsed .scroll-marker {position:absolute;left:0;width:100%;height:10px;display:none}
-.mainmenu-collapsed .scroll-marker:after {font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em;content:"\f141";display:block;position:absolute;left:50%;margin-left:-3px;top:0;height:9px;font-size:10px;color:rgba(255,255,255,0.6)}
+.mainmenu-collapsed .scroll-marker:after {font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;content:"\f141";display:block;position:absolute;left:50%;margin-left:-3px;top:0;height:9px;font-size:10px;color:rgba(255,255,255,0.6)}
.mainmenu-collapsed .scroll-marker.before {top:0}
.mainmenu-collapsed .scroll-marker.after {bottom:3px}
.mainmenu-collapsed .scroll-marker.after:after {top:2px}
@@ -940,7 +940,7 @@ body.breadcrumb-fancy .control-breadcrumb li:last-child:before,
.fancy-layout .control-tabs.master-tabs >div >div.tabs-container >ul.nav-tabs >li[data-modified] span.tab-close i,
.fancy-layout.control-tabs.master-tabs >div >div.tabs-container >ul.nav-tabs >li[data-modified] span.tab-close i {top:5px;font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}
.fancy-layout .control-tabs.master-tabs >div >div.tabs-container >ul.nav-tabs >li[data-modified] span.tab-close i:before,
-.fancy-layout.control-tabs.master-tabs >div >div.tabs-container >ul.nav-tabs >li[data-modified] span.tab-close i:before {font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em;content:"\f111";font-size:9px}
+.fancy-layout.control-tabs.master-tabs >div >div.tabs-container >ul.nav-tabs >li[data-modified] span.tab-close i:before {font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;content:"\f111";font-size:9px}
.fancy-layout .control-tabs.master-tabs >div >div.tabs-container >ul.nav-tabs >li:first-child,
.fancy-layout.control-tabs.master-tabs >div >div.tabs-container >ul.nav-tabs >li:first-child {margin-left:0}
.fancy-layout .control-tabs.master-tabs[data-closable] >div >div.tabs-container >ul.nav-tabs >li a >span.title,
diff --git a/modules/backend/assets/js/auth/uninstall-sw.js b/modules/backend/assets/js/auth/uninstall-sw.js
deleted file mode 100644
index eb48b3938..000000000
--- a/modules/backend/assets/js/auth/uninstall-sw.js
+++ /dev/null
@@ -1,10 +0,0 @@
-// Only run on HTTPS connections
-if (location.protocol === 'https:') {
- // Unregister all service workers before signing in to prevent cache issues
- navigator.serviceWorker.getRegistrations().then(
- function(registrations) {
- for (let registration of registrations) {
- registration.unregister();
- }
- });
-}
\ No newline at end of file
diff --git a/modules/backend/assets/js/october-min.js b/modules/backend/assets/js/october-min.js
index 3820594b4..a25834ef2 100644
--- a/modules/backend/assets/js/october-min.js
+++ b/modules/backend/assets/js/october-min.js
@@ -36,145 +36,211 @@ return(document.cookie=[encode(key),'=',stringifyCookieValue(value),options.expi
var result=key?undefined:{};var cookies=document.cookie?document.cookie.split('; '):[];for(var i=0,l=cookies.length;i1?_len-1:0),_key=1;_key<_len;_key++){args[_key-1]=arguments[_key];}
+for(var _iterator=callbacks,_isArray=true,_i=0,_iterator=_isArray?_iterator:_iterator[Symbol.iterator]();;){var _ref;if(_isArray){if(_i>=_iterator.length)break;_ref=_iterator[_i++];}else{_i=_iterator.next();if(_i.done)break;_ref=_i.value;}
+var callback=_ref;callback.apply(this,args);}}
+return this;}},{key:"off",value:function off(event,fn){if(!this._callbacks||arguments.length===0){this._callbacks={};return this;}
+var callbacks=this._callbacks[event];if(!callbacks){return this;}
if(arguments.length===1){delete this._callbacks[event];return this;}
-for(i=_i=0,_len=callbacks.length;_i<_len;i=++_i){callback=callbacks[i];if(callback===fn){callbacks.splice(i,1);break;}}
-return this;};return Emitter;})();Dropzone=(function(_super){var extend,resolveOption;__extends(Dropzone,_super);Dropzone.prototype.Emitter=Emitter;Dropzone.prototype.events=["drop","dragstart","dragend","dragenter","dragover","dragleave","addedfile","removedfile","thumbnail","error","errormultiple","processing","processingmultiple","uploadprogress","totaluploadprogress","sending","sendingmultiple","success","successmultiple","canceled","canceledmultiple","complete","completemultiple","reset","maxfilesexceeded","maxfilesreached","queuecomplete"];Dropzone.prototype.defaultOptions={url:null,method:"post",withCredentials:false,parallelUploads:2,uploadMultiple:false,maxFilesize:256,paramName:"file",createImageThumbnails:true,maxThumbnailFilesize:10,thumbnailWidth:120,thumbnailHeight:120,filesizeBase:1000,maxFiles:null,filesizeBase:1000,params:{},clickable:true,ignoreHiddenFiles:true,acceptedFiles:null,acceptedMimeTypes:null,autoProcessQueue:true,autoQueue:true,addRemoveLinks:false,previewsContainer:null,capture:null,dictDefaultMessage:"Drop files here to upload",dictFallbackMessage:"Your browser does not support drag'n'drop file uploads.",dictFallbackText:"Please use the fallback form below to upload your files like in the olden days.",dictFileTooBig:"File is too big ({{filesize}}MiB). Max filesize: {{maxFilesize}}MiB.",dictInvalidFileType:"You can't upload files of this type.",dictResponseError:"Server responded with {{statusCode}} code.",dictCancelUpload:"Cancel upload",dictCancelUploadConfirmation:"Are you sure you want to cancel this upload?",dictRemoveFile:"Remove file",dictRemoveFileConfirmation:null,dictMaxFilesExceeded:"You can not upload any more files.",accept:function(file,done){return done();},init:function(){return noop;},forceFallback:false,fallback:function(){var child,messageElement,span,_i,_len,_ref;this.element.className=""+this.element.className+" dz-browser-not-supported";_ref=this.element.getElementsByTagName("div");for(_i=0,_len=_ref.length;_i<_len;_i++){child=_ref[_i];if(/(^| )dz-message($| )/.test(child.className)){messageElement=child;child.className="dz-message";continue;}}
+for(var i=0;i=_iterator2.length)break;_ref2=_iterator2[_i2++];}else{_i2=_iterator2.next();if(_i2.done)break;_ref2=_i2.value;}
+var child=_ref2;if(/(^| )dz-message($| )/.test(child.className)){messageElement=child;child.className="dz-message";break;}}
if(!messageElement){messageElement=Dropzone.createElement("
',sweetWrap=document.createElement('div');sweetWrap.innerHTML=sweetHTML;document.body.appendChild(sweetWrap);}
window.sweetAlert=window.swal=function(){if(arguments[0]===undefined){window.console.error('sweetAlert expects at least 1 attribute!');return false;}
var params=extend({},defaultParams);switch(typeof arguments[0]){case'string':params.title=arguments[0];params.text=arguments[1]||'';params.type=arguments[2]||'';break;case'object':if(arguments[0].title===undefined){window.console.error('Missing "title" argument!');return false;}
params.title=arguments[0].title;params.text=arguments[0].text||defaultParams.text;params.type=arguments[0].type||defaultParams.type;params.allowOutsideClick=arguments[0].allowOutsideClick||defaultParams.allowOutsideClick;params.showCancelButton=arguments[0].showCancelButton!==undefined?arguments[0].showCancelButton:defaultParams.showCancelButton;params.showConfirmButton=arguments[0].showConfirmButton!==undefined?arguments[0].showConfirmButton:defaultParams.showConfirmButton;params.closeOnConfirm=arguments[0].closeOnConfirm!==undefined?arguments[0].closeOnConfirm:defaultParams.closeOnConfirm;params.closeOnCancel=arguments[0].closeOnCancel!==undefined?arguments[0].closeOnCancel:defaultParams.closeOnCancel;params.timer=arguments[0].timer||defaultParams.timer;params.confirmButtonText=(defaultParams.showCancelButton)?'Confirm':defaultParams.confirmButtonText;params.confirmButtonText=arguments[0].confirmButtonText||defaultParams.confirmButtonText;params.confirmButtonClass=arguments[0].confirmButtonClass||(arguments[0].type?'btn-'+arguments[0].type:null)||defaultParams.confirmButtonClass;params.cancelButtonText=arguments[0].cancelButtonText||defaultParams.cancelButtonText;params.cancelButtonClass=arguments[0].cancelButtonClass||defaultParams.cancelButtonClass;params.containerClass=arguments[0].containerClass||defaultParams.containerClass;params.titleClass=arguments[0].titleClass||defaultParams.titleClass;params.textClass=arguments[0].textClass||defaultParams.textClass;params.imageUrl=arguments[0].imageUrl||defaultParams.imageUrl;params.imageSize=arguments[0].imageSize||defaultParams.imageSize;params.doneFunction=arguments[1]||null;break;default:window.console.error('Unexpected type of argument! Expected "string" or "object", got '+typeof arguments[0]);return false;}
diff --git a/modules/backend/assets/js/october.alert.js b/modules/backend/assets/js/october.alert.js
index 71220d327..11d9e64c0 100644
--- a/modules/backend/assets/js/october.alert.js
+++ b/modules/backend/assets/js/october.alert.js
@@ -9,6 +9,7 @@
*
* Dependences:
* - Sweet Alert
+ * - Translations (october.lang.js)
*/
(function($){
diff --git a/modules/backend/assets/js/october.flyout.js b/modules/backend/assets/js/october.flyout.js
index 2f4992572..1d5c9b15a 100644
--- a/modules/backend/assets/js/october.flyout.js
+++ b/modules/backend/assets/js/october.flyout.js
@@ -172,7 +172,7 @@
}
Flyout.prototype.onDocumentKeydown = function(ev) {
- if (ev.which == 27) {
+ if (ev.key === 'Escape') {
this.hide();
}
}
diff --git a/modules/backend/assets/less/layout/mainmenu.less b/modules/backend/assets/less/layout/mainmenu.less
index 27b125c35..a1af75cc9 100644
--- a/modules/backend/assets/less/layout/mainmenu.less
+++ b/modules/backend/assets/less/layout/mainmenu.less
@@ -214,6 +214,7 @@ nav#layout-mainmenu {
img.account-avatar {
width: 45px;
+ height: 45px;
}
.account-name {
diff --git a/modules/backend/assets/vendor/dropzone/dropzone.js b/modules/backend/assets/vendor/dropzone/dropzone.js
index babbdd450..476c0550d 100644
--- a/modules/backend/assets/vendor/dropzone/dropzone.js
+++ b/modules/backend/assets/vendor/dropzone/dropzone.js
@@ -1,3 +1,16 @@
+/**
+ * DropZone V5.5.1 (non-minified) for testing on October CMS
+ */
+
+"use strict";
+
+var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
/*
*
@@ -25,581 +38,1270 @@
*
*/
-(function() {
- var Dropzone, Emitter, camelize, contentLoaded, detectVerticalSquash, drawImageIOSFix, noop, without,
- __slice = [].slice,
- __hasProp = {}.hasOwnProperty,
- __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
+// The Emitter class provides the ability to call `.on()` on Dropzone to listen
+// to events.
+// It is strongly based on component's emitter class, and I removed the
+// functionality because of the dependency hell with different frameworks.
+var Emitter = function () {
+ function Emitter() {
+ _classCallCheck(this, Emitter);
+ }
- noop = function() {};
+ _createClass(Emitter, [{
+ key: "on",
- Emitter = (function() {
- function Emitter() {}
-
- Emitter.prototype.addEventListener = Emitter.prototype.on;
-
- Emitter.prototype.on = function(event, fn) {
+ // Add an event listener for given event
+ value: function on(event, fn) {
this._callbacks = this._callbacks || {};
+ // Create namespace for this event
if (!this._callbacks[event]) {
this._callbacks[event] = [];
}
this._callbacks[event].push(fn);
return this;
- };
-
- Emitter.prototype.emit = function() {
- var args, callback, callbacks, event, _i, _len;
- event = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
+ }
+ }, {
+ key: "emit",
+ value: function emit(event) {
this._callbacks = this._callbacks || {};
- callbacks = this._callbacks[event];
+ var callbacks = this._callbacks[event];
+
if (callbacks) {
- for (_i = 0, _len = callbacks.length; _i < _len; _i++) {
- callback = callbacks[_i];
+ for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
+ args[_key - 1] = arguments[_key];
+ }
+
+ for (var _iterator = callbacks, _isArray = true, _i = 0, _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();;) {
+ var _ref;
+
+ if (_isArray) {
+ if (_i >= _iterator.length) break;
+ _ref = _iterator[_i++];
+ } else {
+ _i = _iterator.next();
+ if (_i.done) break;
+ _ref = _i.value;
+ }
+
+ var callback = _ref;
+
callback.apply(this, args);
}
}
+
return this;
- };
+ }
- Emitter.prototype.removeListener = Emitter.prototype.off;
+ // Remove event listener for given event. If fn is not provided, all event
+ // listeners for that event will be removed. If neither is provided, all
+ // event listeners will be removed.
- Emitter.prototype.removeAllListeners = Emitter.prototype.off;
-
- Emitter.prototype.removeEventListener = Emitter.prototype.off;
-
- Emitter.prototype.off = function(event, fn) {
- var callback, callbacks, i, _i, _len;
+ }, {
+ key: "off",
+ value: function off(event, fn) {
if (!this._callbacks || arguments.length === 0) {
this._callbacks = {};
return this;
}
- callbacks = this._callbacks[event];
+
+ // specific event
+ var callbacks = this._callbacks[event];
if (!callbacks) {
return this;
}
+
+ // remove all handlers
if (arguments.length === 1) {
delete this._callbacks[event];
return this;
}
- for (i = _i = 0, _len = callbacks.length; _i < _len; i = ++_i) {
- callback = callbacks[i];
+
+ // remove specific handler
+ for (var i = 0; i < callbacks.length; i++) {
+ var callback = callbacks[i];
if (callback === fn) {
callbacks.splice(i, 1);
break;
}
}
+
return this;
- };
+ }
+ }]);
- return Emitter;
+ return Emitter;
+}();
- })();
+var Dropzone = function (_Emitter) {
+ _inherits(Dropzone, _Emitter);
- Dropzone = (function(_super) {
- var extend, resolveOption;
+ _createClass(Dropzone, null, [{
+ key: "initClass",
+ value: function initClass() {
- __extends(Dropzone, _super);
-
- Dropzone.prototype.Emitter = Emitter;
-
-
- /*
- This is a list of all available events you can register on a dropzone object.
-
- You can register an event handler like this:
-
- dropzone.on("dragEnter", function() { });
- */
-
- Dropzone.prototype.events = ["drop", "dragstart", "dragend", "dragenter", "dragover", "dragleave", "addedfile", "removedfile", "thumbnail", "error", "errormultiple", "processing", "processingmultiple", "uploadprogress", "totaluploadprogress", "sending", "sendingmultiple", "success", "successmultiple", "canceled", "canceledmultiple", "complete", "completemultiple", "reset", "maxfilesexceeded", "maxfilesreached", "queuecomplete"];
-
- Dropzone.prototype.defaultOptions = {
- url: null,
- method: "post",
- withCredentials: false,
- parallelUploads: 2,
- uploadMultiple: false,
- maxFilesize: 256,
- paramName: "file",
- createImageThumbnails: true,
- maxThumbnailFilesize: 10,
- thumbnailWidth: 120,
- thumbnailHeight: 120,
- filesizeBase: 1000,
- maxFiles: null,
- filesizeBase: 1000,
- params: {},
- clickable: true,
- ignoreHiddenFiles: true,
- acceptedFiles: null,
- acceptedMimeTypes: null,
- autoProcessQueue: true,
- autoQueue: true,
- addRemoveLinks: false,
- previewsContainer: null,
- capture: null,
- dictDefaultMessage: "Drop files here to upload",
- dictFallbackMessage: "Your browser does not support drag'n'drop file uploads.",
- dictFallbackText: "Please use the fallback form below to upload your files like in the olden days.",
- dictFileTooBig: "File is too big ({{filesize}}MiB). Max filesize: {{maxFilesize}}MiB.",
- dictInvalidFileType: "You can't upload files of this type.",
- dictResponseError: "Server responded with {{statusCode}} code.",
- dictCancelUpload: "Cancel upload",
- dictCancelUploadConfirmation: "Are you sure you want to cancel this upload?",
- dictRemoveFile: "Remove file",
- dictRemoveFileConfirmation: null,
- dictMaxFilesExceeded: "You can not upload any more files.",
- accept: function(file, done) {
- return done();
- },
- init: function() {
- return noop;
- },
- forceFallback: false,
- fallback: function() {
- var child, messageElement, span, _i, _len, _ref;
- this.element.className = "" + this.element.className + " dz-browser-not-supported";
- _ref = this.element.getElementsByTagName("div");
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
- child = _ref[_i];
- if (/(^| )dz-message($| )/.test(child.className)) {
- messageElement = child;
- child.className = "dz-message";
- continue;
- }
- }
- if (!messageElement) {
- messageElement = Dropzone.createElement("
");
- this.element.appendChild(messageElement);
- }
- span = messageElement.getElementsByTagName("span")[0];
- if (span) {
- span.textContent = this.options.dictFallbackMessage;
- }
- return this.element.appendChild(this.getFallbackForm());
- },
- resize: function(file) {
- var info, srcRatio, trgRatio;
- info = {
- srcX: 0,
- srcY: 0,
- srcWidth: file.width,
- srcHeight: file.height
- };
- srcRatio = file.width / file.height;
- info.optWidth = this.options.thumbnailWidth;
- info.optHeight = this.options.thumbnailHeight;
- if ((info.optWidth == null) && (info.optHeight == null)) {
- info.optWidth = info.srcWidth;
- info.optHeight = info.srcHeight;
- } else if (info.optWidth == null) {
- info.optWidth = srcRatio * info.optHeight;
- } else if (info.optHeight == null) {
- info.optHeight = (1 / srcRatio) * info.optWidth;
- }
- trgRatio = info.optWidth / info.optHeight;
- if (file.height < info.optHeight || file.width < info.optWidth) {
- info.trgHeight = info.srcHeight;
- info.trgWidth = info.srcWidth;
- } else {
- if (srcRatio > trgRatio) {
- info.srcHeight = file.height;
- info.srcWidth = info.srcHeight * trgRatio;
- } else {
- info.srcWidth = file.width;
- info.srcHeight = info.srcWidth / trgRatio;
- }
- }
- info.srcX = (file.width - info.srcWidth) / 2;
- info.srcY = (file.height - info.srcHeight) / 2;
- return info;
- },
+ // Exposing the emitter class, mainly for tests
+ this.prototype.Emitter = Emitter;
/*
- Those functions register themselves to the events on init and handle all
- the user interface specific stuff. Overwriting them won't break the upload
- but can break the way it's displayed.
- You can overwrite them if you don't like the default behavior. If you just
- want to add an additional event handler, register it on the dropzone object
- and don't overwrite those options.
- */
- drop: function(e) {
- return this.element.classList.remove("dz-drag-hover");
- },
- dragstart: noop,
- dragend: function(e) {
- return this.element.classList.remove("dz-drag-hover");
- },
- dragenter: function(e) {
- return this.element.classList.add("dz-drag-hover");
- },
- dragover: function(e) {
- return this.element.classList.add("dz-drag-hover");
- },
- dragleave: function(e) {
- return this.element.classList.remove("dz-drag-hover");
- },
- paste: noop,
- reset: function() {
- return this.element.classList.remove("dz-started");
- },
- addedfile: function(file) {
- var node, removeFileEvent, removeLink, _i, _j, _k, _len, _len1, _len2, _ref, _ref1, _ref2, _results;
- if (this.element === this.previewsContainer) {
- this.element.classList.add("dz-started");
- }
- if (this.previewsContainer) {
- file.previewElement = Dropzone.createElement(this.options.previewTemplate.trim());
- file.previewTemplate = file.previewElement;
- this.previewsContainer.appendChild(file.previewElement);
- _ref = file.previewElement.querySelectorAll("[data-dz-name]");
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
- node = _ref[_i];
- node.textContent = file.name;
+ This is a list of all available events you can register on a dropzone object.
+ You can register an event handler like this:
+ dropzone.on("dragEnter", function() { });
+ */
+ this.prototype.events = ["drop", "dragstart", "dragend", "dragenter", "dragover", "dragleave", "addedfile", "addedfiles", "removedfile", "thumbnail", "error", "errormultiple", "processing", "processingmultiple", "uploadprogress", "totaluploadprogress", "sending", "sendingmultiple", "success", "successmultiple", "canceled", "canceledmultiple", "complete", "completemultiple", "reset", "maxfilesexceeded", "maxfilesreached", "queuecomplete"];
+
+ this.prototype.defaultOptions = {
+ /**
+ * Has to be specified on elements other than form (or when the form
+ * doesn't have an `action` attribute). You can also
+ * provide a function that will be called with `files` and
+ * must return the url (since `v3.12.0`)
+ */
+ url: null,
+
+ /**
+ * Can be changed to `"put"` if necessary. You can also provide a function
+ * that will be called with `files` and must return the method (since `v3.12.0`).
+ */
+ method: "post",
+
+ /**
+ * Will be set on the XHRequest.
+ */
+ withCredentials: false,
+
+ /**
+ * The timeout for the XHR requests in milliseconds (since `v4.4.0`).
+ */
+ timeout: 30000,
+
+ /**
+ * How many file uploads to process in parallel (See the
+ * Enqueuing file uploads* documentation section for more info)
+ */
+ parallelUploads: 2,
+
+ /**
+ * Whether to send multiple files in one request. If
+ * this it set to true, then the fallback file input element will
+ * have the `multiple` attribute as well. This option will
+ * also trigger additional events (like `processingmultiple`). See the events
+ * documentation section for more information.
+ */
+ uploadMultiple: false,
+
+ /**
+ * Whether you want files to be uploaded in chunks to your server. This can't be
+ * used in combination with `uploadMultiple`.
+ *
+ * See [chunksUploaded](#config-chunksUploaded) for the callback to finalise an upload.
+ */
+ chunking: false,
+
+ /**
+ * If `chunking` is enabled, this defines whether **every** file should be chunked,
+ * even if the file size is below chunkSize. This means, that the additional chunk
+ * form data will be submitted and the `chunksUploaded` callback will be invoked.
+ */
+ forceChunking: false,
+
+ /**
+ * If `chunking` is `true`, then this defines the chunk size in bytes.
+ */
+ chunkSize: 2000000,
+
+ /**
+ * If `true`, the individual chunks of a file are being uploaded simultaneously.
+ */
+ parallelChunkUploads: false,
+
+ /**
+ * Whether a chunk should be retried if it fails.
+ */
+ retryChunks: false,
+
+ /**
+ * If `retryChunks` is true, how many times should it be retried.
+ */
+ retryChunksLimit: 3,
+
+ /**
+ * If not `null` defines how many files this Dropzone handles. If it exceeds,
+ * the event `maxfilesexceeded` will be called. The dropzone element gets the
+ * class `dz-max-files-reached` accordingly so you can provide visual feedback.
+ */
+ maxFilesize: 256,
+
+ /**
+ * The name of the file param that gets transferred.
+ * **NOTE**: If you have the option `uploadMultiple` set to `true`, then
+ * Dropzone will append `[]` to the name.
+ */
+ paramName: "file",
+
+ /**
+ * Whether thumbnails for images should be generated
+ */
+ createImageThumbnails: true,
+
+ /**
+ * In MB. When the filename exceeds this limit, the thumbnail will not be generated.
+ */
+ maxThumbnailFilesize: 10,
+
+ /**
+ * If `null`, the ratio of the image will be used to calculate it.
+ */
+ thumbnailWidth: 120,
+
+ /**
+ * The same as `thumbnailWidth`. If both are null, images will not be resized.
+ */
+ thumbnailHeight: 120,
+
+ /**
+ * How the images should be scaled down in case both, `thumbnailWidth` and `thumbnailHeight` are provided.
+ * Can be either `contain` or `crop`.
+ */
+ thumbnailMethod: 'crop',
+
+ /**
+ * If set, images will be resized to these dimensions before being **uploaded**.
+ * If only one, `resizeWidth` **or** `resizeHeight` is provided, the original aspect
+ * ratio of the file will be preserved.
+ *
+ * The `options.transformFile` function uses these options, so if the `transformFile` function
+ * is overridden, these options don't do anything.
+ */
+ resizeWidth: null,
+
+ /**
+ * See `resizeWidth`.
+ */
+ resizeHeight: null,
+
+ /**
+ * The mime type of the resized image (before it gets uploaded to the server).
+ * If `null` the original mime type will be used. To force jpeg, for example, use `image/jpeg`.
+ * See `resizeWidth` for more information.
+ */
+ resizeMimeType: null,
+
+ /**
+ * The quality of the resized images. See `resizeWidth`.
+ */
+ resizeQuality: 0.8,
+
+ /**
+ * How the images should be scaled down in case both, `resizeWidth` and `resizeHeight` are provided.
+ * Can be either `contain` or `crop`.
+ */
+ resizeMethod: 'contain',
+
+ /**
+ * The base that is used to calculate the filesize. You can change this to
+ * 1024 if you would rather display kibibytes, mebibytes, etc...
+ * 1024 is technically incorrect, because `1024 bytes` are `1 kibibyte` not `1 kilobyte`.
+ * You can change this to `1024` if you don't care about validity.
+ */
+ filesizeBase: 1000,
+
+ /**
+ * Can be used to limit the maximum number of files that will be handled by this Dropzone
+ */
+ maxFiles: null,
+
+ /**
+ * An optional object to send additional headers to the server. Eg:
+ * `{ "My-Awesome-Header": "header value" }`
+ */
+ headers: null,
+
+ /**
+ * If `true`, the dropzone element itself will be clickable, if `false`
+ * nothing will be clickable.
+ *
+ * You can also pass an HTML element, a CSS selector (for multiple elements)
+ * or an array of those. In that case, all of those elements will trigger an
+ * upload when clicked.
+ */
+ clickable: true,
+
+ /**
+ * Whether hidden files in directories should be ignored.
+ */
+ ignoreHiddenFiles: true,
+
+ /**
+ * The default implementation of `accept` checks the file's mime type or
+ * extension against this list. This is a comma separated list of mime
+ * types or file extensions.
+ *
+ * Eg.: `image/*,application/pdf,.psd`
+ *
+ * If the Dropzone is `clickable` this option will also be used as
+ * [`accept`](https://developer.mozilla.org/en-US/docs/HTML/Element/input#attr-accept)
+ * parameter on the hidden file input as well.
+ */
+ acceptedFiles: null,
+
+ /**
+ * **Deprecated!**
+ * Use acceptedFiles instead.
+ */
+ acceptedMimeTypes: null,
+
+ /**
+ * If false, files will be added to the queue but the queue will not be
+ * processed automatically.
+ * This can be useful if you need some additional user input before sending
+ * files (or if you want want all files sent at once).
+ * If you're ready to send the file simply call `myDropzone.processQueue()`.
+ *
+ * See the [enqueuing file uploads](#enqueuing-file-uploads) documentation
+ * section for more information.
+ */
+ autoProcessQueue: true,
+
+ /**
+ * If false, files added to the dropzone will not be queued by default.
+ * You'll have to call `enqueueFile(file)` manually.
+ */
+ autoQueue: true,
+
+ /**
+ * If `true`, this will add a link to every file preview to remove or cancel (if
+ * already uploading) the file. The `dictCancelUpload`, `dictCancelUploadConfirmation`
+ * and `dictRemoveFile` options are used for the wording.
+ */
+ addRemoveLinks: false,
+
+ /**
+ * Defines where to display the file previews – if `null` the
+ * Dropzone element itself is used. Can be a plain `HTMLElement` or a CSS
+ * selector. The element should have the `dropzone-previews` class so
+ * the previews are displayed properly.
+ */
+ previewsContainer: null,
+
+ /**
+ * This is the element the hidden input field (which is used when clicking on the
+ * dropzone to trigger file selection) will be appended to. This might
+ * be important in case you use frameworks to switch the content of your page.
+ *
+ * Can be a selector string, or an element directly.
+ */
+ hiddenInputContainer: "body",
+
+ /**
+ * If null, no capture type will be specified
+ * If camera, mobile devices will skip the file selection and choose camera
+ * If microphone, mobile devices will skip the file selection and choose the microphone
+ * If camcorder, mobile devices will skip the file selection and choose the camera in video mode
+ * On apple devices multiple must be set to false. AcceptedFiles may need to
+ * be set to an appropriate mime type (e.g. "image/*", "audio/*", or "video/*").
+ */
+ capture: null,
+
+ /**
+ * **Deprecated**. Use `renameFile` instead.
+ */
+ renameFilename: null,
+
+ /**
+ * A function that is invoked before the file is uploaded to the server and renames the file.
+ * This function gets the `File` as argument and can use the `file.name`. The actual name of the
+ * file that gets used during the upload can be accessed through `file.upload.filename`.
+ */
+ renameFile: null,
+
+ /**
+ * If `true` the fallback will be forced. This is very useful to test your server
+ * implementations first and make sure that everything works as
+ * expected without dropzone if you experience problems, and to test
+ * how your fallbacks will look.
+ */
+ forceFallback: false,
+
+ /**
+ * The text used before any files are dropped.
+ */
+ dictDefaultMessage: "Drop files here to upload",
+
+ /**
+ * The text that replaces the default message text it the browser is not supported.
+ */
+ dictFallbackMessage: "Your browser does not support drag'n'drop file uploads.",
+
+ /**
+ * The text that will be added before the fallback form.
+ * If you provide a fallback element yourself, or if this option is `null` this will
+ * be ignored.
+ */
+ dictFallbackText: "Please use the fallback form below to upload your files like in the olden days.",
+
+ /**
+ * If the filesize is too big.
+ * `{{filesize}}` and `{{maxFilesize}}` will be replaced with the respective configuration values.
+ */
+ dictFileTooBig: "File is too big ({{filesize}}MiB). Max filesize: {{maxFilesize}}MiB.",
+
+ /**
+ * If the file doesn't match the file type.
+ */
+ dictInvalidFileType: "You can't upload files of this type.",
+
+ /**
+ * If the server response was invalid.
+ * `{{statusCode}}` will be replaced with the servers status code.
+ */
+ dictResponseError: "Server responded with {{statusCode}} code.",
+
+ /**
+ * If `addRemoveLinks` is true, the text to be used for the cancel upload link.
+ */
+ dictCancelUpload: "Cancel upload",
+
+ /**
+ * The text that is displayed if an upload was manually canceled
+ */
+ dictUploadCanceled: "Upload canceled.",
+
+ /**
+ * If `addRemoveLinks` is true, the text to be used for confirmation when cancelling upload.
+ */
+ dictCancelUploadConfirmation: "Are you sure you want to cancel this upload?",
+
+ /**
+ * If `addRemoveLinks` is true, the text to be used to remove a file.
+ */
+ dictRemoveFile: "Remove file",
+
+ /**
+ * If this is not null, then the user will be prompted before removing a file.
+ */
+ dictRemoveFileConfirmation: null,
+
+ /**
+ * Displayed if `maxFiles` is st and exceeded.
+ * The string `{{maxFiles}}` will be replaced by the configuration value.
+ */
+ dictMaxFilesExceeded: "You can not upload any more files.",
+
+ /**
+ * Allows you to translate the different units. Starting with `tb` for terabytes and going down to
+ * `b` for bytes.
+ */
+ dictFileSizeUnits: { tb: "TB", gb: "GB", mb: "MB", kb: "KB", b: "b" },
+ /**
+ * Called when dropzone initialized
+ * You can add event listeners here
+ */
+ init: function init() {},
+
+
+ /**
+ * Can be an **object** of additional parameters to transfer to the server, **or** a `Function`
+ * that gets invoked with the `files`, `xhr` and, if it's a chunked upload, `chunk` arguments. In case
+ * of a function, this needs to return a map.
+ *
+ * The default implementation does nothing for normal uploads, but adds relevant information for
+ * chunked uploads.
+ *
+ * This is the same as adding hidden input fields in the form element.
+ */
+ params: function params(files, xhr, chunk) {
+ if (chunk) {
+ return {
+ dzuuid: chunk.file.upload.uuid,
+ dzchunkindex: chunk.index,
+ dztotalfilesize: chunk.file.size,
+ dzchunksize: this.options.chunkSize,
+ dztotalchunkcount: chunk.file.upload.totalChunkCount,
+ dzchunkbyteoffset: chunk.index * this.options.chunkSize
+ };
}
- _ref1 = file.previewElement.querySelectorAll("[data-dz-size]");
- for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
- node = _ref1[_j];
- node.innerHTML = this.filesize(file.size);
+ },
+
+
+ /**
+ * A function that gets a [file](https://developer.mozilla.org/en-US/docs/DOM/File)
+ * and a `done` function as parameters.
+ *
+ * If the done function is invoked without arguments, the file is "accepted" and will
+ * be processed. If you pass an error message, the file is rejected, and the error
+ * message will be displayed.
+ * This function will not be called if the file is too big or doesn't match the mime types.
+ */
+ accept: function accept(file, done) {
+ return done();
+ },
+
+
+ /**
+ * The callback that will be invoked when all chunks have been uploaded for a file.
+ * It gets the file for which the chunks have been uploaded as the first parameter,
+ * and the `done` function as second. `done()` needs to be invoked when everything
+ * needed to finish the upload process is done.
+ */
+ chunksUploaded: function chunksUploaded(file, done) {
+ done();
+ },
+
+ /**
+ * Gets called when the browser is not supported.
+ * The default implementation shows the fallback input field and adds
+ * a text.
+ */
+ fallback: function fallback() {
+ // This code should pass in IE7... :(
+ var messageElement = void 0;
+ this.element.className = this.element.className + " dz-browser-not-supported";
+
+ for (var _iterator2 = this.element.getElementsByTagName("div"), _isArray2 = true, _i2 = 0, _iterator2 = _isArray2 ? _iterator2 : _iterator2[Symbol.iterator]();;) {
+ var _ref2;
+
+ if (_isArray2) {
+ if (_i2 >= _iterator2.length) break;
+ _ref2 = _iterator2[_i2++];
+ } else {
+ _i2 = _iterator2.next();
+ if (_i2.done) break;
+ _ref2 = _i2.value;
+ }
+
+ var child = _ref2;
+
+ if (/(^| )dz-message($| )/.test(child.className)) {
+ messageElement = child;
+ child.className = "dz-message"; // Removes the 'dz-default' class
+ break;
+ }
}
- if (this.options.addRemoveLinks) {
- file._removeLink = Dropzone.createElement("" + this.options.dictRemoveFile + "");
- file.previewElement.appendChild(file._removeLink);
+ if (!messageElement) {
+ messageElement = Dropzone.createElement("
");
+ this.element.appendChild(messageElement);
}
- removeFileEvent = (function(_this) {
- return function(e) {
+
+ var span = messageElement.getElementsByTagName("span")[0];
+ if (span) {
+ if (span.textContent != null) {
+ span.textContent = this.options.dictFallbackMessage;
+ } else if (span.innerText != null) {
+ span.innerText = this.options.dictFallbackMessage;
+ }
+ }
+
+ return this.element.appendChild(this.getFallbackForm());
+ },
+
+
+ /**
+ * Gets called to calculate the thumbnail dimensions.
+ *
+ * It gets `file`, `width` and `height` (both may be `null`) as parameters and must return an object containing:
+ *
+ * - `srcWidth` & `srcHeight` (required)
+ * - `trgWidth` & `trgHeight` (required)
+ * - `srcX` & `srcY` (optional, default `0`)
+ * - `trgX` & `trgY` (optional, default `0`)
+ *
+ * Those values are going to be used by `ctx.drawImage()`.
+ */
+ resize: function resize(file, width, height, resizeMethod) {
+ var info = {
+ srcX: 0,
+ srcY: 0,
+ srcWidth: file.width,
+ srcHeight: file.height
+ };
+
+ var srcRatio = file.width / file.height;
+
+ // Automatically calculate dimensions if not specified
+ if (width == null && height == null) {
+ width = info.srcWidth;
+ height = info.srcHeight;
+ } else if (width == null) {
+ width = height * srcRatio;
+ } else if (height == null) {
+ height = width / srcRatio;
+ }
+
+ // Make sure images aren't upscaled
+ width = Math.min(width, info.srcWidth);
+ height = Math.min(height, info.srcHeight);
+
+ var trgRatio = width / height;
+
+ if (info.srcWidth > width || info.srcHeight > height) {
+ // Image is bigger and needs rescaling
+ if (resizeMethod === 'crop') {
+ if (srcRatio > trgRatio) {
+ info.srcHeight = file.height;
+ info.srcWidth = info.srcHeight * trgRatio;
+ } else {
+ info.srcWidth = file.width;
+ info.srcHeight = info.srcWidth / trgRatio;
+ }
+ } else if (resizeMethod === 'contain') {
+ // Method 'contain'
+ if (srcRatio > trgRatio) {
+ height = width / srcRatio;
+ } else {
+ width = height * srcRatio;
+ }
+ } else {
+ throw new Error("Unknown resizeMethod '" + resizeMethod + "'");
+ }
+ }
+
+ info.srcX = (file.width - info.srcWidth) / 2;
+ info.srcY = (file.height - info.srcHeight) / 2;
+
+ info.trgWidth = width;
+ info.trgHeight = height;
+
+ return info;
+ },
+
+
+ /**
+ * Can be used to transform the file (for example, resize an image if necessary).
+ *
+ * The default implementation uses `resizeWidth` and `resizeHeight` (if provided) and resizes
+ * images according to those dimensions.
+ *
+ * Gets the `file` as the first parameter, and a `done()` function as the second, that needs
+ * to be invoked with the file when the transformation is done.
+ */
+ transformFile: function transformFile(file, done) {
+ if ((this.options.resizeWidth || this.options.resizeHeight) && file.type.match(/image.*/)) {
+ return this.resizeImage(file, this.options.resizeWidth, this.options.resizeHeight, this.options.resizeMethod, done);
+ } else {
+ return done(file);
+ }
+ },
+
+
+ /**
+ * A string that contains the template used for each dropped
+ * file. Change it to fulfill your needs but make sure to properly
+ * provide all elements.
+ *
+ * If you want to use an actual HTML element instead of providing a String
+ * as a config option, you could create a div with the id `tpl`,
+ * put the template inside it and provide the element like this:
+ *
+ * document
+ * .querySelector('#tpl')
+ * .innerHTML
+ *
+ */
+ previewTemplate: "
\n
\n
\n
\n
\n
\n
\n
\n
\n \n
\n
\n \n
\n
",
+
+ // END OPTIONS
+ // (Required by the dropzone documentation parser)
+
+
+ /*
+ Those functions register themselves to the events on init and handle all
+ the user interface specific stuff. Overwriting them won't break the upload
+ but can break the way it's displayed.
+ You can overwrite them if you don't like the default behavior. If you just
+ want to add an additional event handler, register it on the dropzone object
+ and don't overwrite those options.
+ */
+
+ // Those are self explanatory and simply concern the DragnDrop.
+ drop: function drop(e) {
+ return this.element.classList.remove("dz-drag-hover");
+ },
+ dragstart: function dragstart(e) {},
+ dragend: function dragend(e) {
+ return this.element.classList.remove("dz-drag-hover");
+ },
+ dragenter: function dragenter(e) {
+ return this.element.classList.add("dz-drag-hover");
+ },
+ dragover: function dragover(e) {
+ return this.element.classList.add("dz-drag-hover");
+ },
+ dragleave: function dragleave(e) {
+ return this.element.classList.remove("dz-drag-hover");
+ },
+ paste: function paste(e) {},
+
+
+ // Called whenever there are no files left in the dropzone anymore, and the
+ // dropzone should be displayed as if in the initial state.
+ reset: function reset() {
+ return this.element.classList.remove("dz-started");
+ },
+
+
+ // Called when a file is added to the queue
+ // Receives `file`
+ addedfile: function addedfile(file) {
+ var _this2 = this;
+
+ if (this.element === this.previewsContainer) {
+ this.element.classList.add("dz-started");
+ }
+
+ if (this.previewsContainer) {
+ file.previewElement = Dropzone.createElement(this.options.previewTemplate.trim());
+ file.previewTemplate = file.previewElement; // Backwards compatibility
+
+ this.previewsContainer.appendChild(file.previewElement);
+ for (var _iterator3 = file.previewElement.querySelectorAll("[data-dz-name]"), _isArray3 = true, _i3 = 0, _iterator3 = _isArray3 ? _iterator3 : _iterator3[Symbol.iterator]();;) {
+ var _ref3;
+
+ if (_isArray3) {
+ if (_i3 >= _iterator3.length) break;
+ _ref3 = _iterator3[_i3++];
+ } else {
+ _i3 = _iterator3.next();
+ if (_i3.done) break;
+ _ref3 = _i3.value;
+ }
+
+ var node = _ref3;
+
+ node.textContent = file.name;
+ }
+ for (var _iterator4 = file.previewElement.querySelectorAll("[data-dz-size]"), _isArray4 = true, _i4 = 0, _iterator4 = _isArray4 ? _iterator4 : _iterator4[Symbol.iterator]();;) {
+ if (_isArray4) {
+ if (_i4 >= _iterator4.length) break;
+ node = _iterator4[_i4++];
+ } else {
+ _i4 = _iterator4.next();
+ if (_i4.done) break;
+ node = _i4.value;
+ }
+
+ node.innerHTML = this.filesize(file.size);
+ }
+
+ if (this.options.addRemoveLinks) {
+ file._removeLink = Dropzone.createElement("" + this.options.dictRemoveFile + "");
+ file.previewElement.appendChild(file._removeLink);
+ }
+
+ var removeFileEvent = function removeFileEvent(e) {
e.preventDefault();
e.stopPropagation();
if (file.status === Dropzone.UPLOADING) {
- return Dropzone.confirm(_this.options.dictCancelUploadConfirmation, function() {
- return _this.removeFile(file);
+ return Dropzone.confirm(_this2.options.dictCancelUploadConfirmation, function () {
+ return _this2.removeFile(file);
});
} else {
- if (_this.options.dictRemoveFileConfirmation) {
- return Dropzone.confirm(_this.options.dictRemoveFileConfirmation, function() {
- return _this.removeFile(file);
+ if (_this2.options.dictRemoveFileConfirmation) {
+ return Dropzone.confirm(_this2.options.dictRemoveFileConfirmation, function () {
+ return _this2.removeFile(file);
});
} else {
- return _this.removeFile(file);
+ return _this2.removeFile(file);
}
}
};
- })(this);
- _ref2 = file.previewElement.querySelectorAll("[data-dz-remove]");
- _results = [];
- for (_k = 0, _len2 = _ref2.length; _k < _len2; _k++) {
- removeLink = _ref2[_k];
- _results.push(removeLink.addEventListener("click", removeFileEvent));
- }
- return _results;
- }
- },
- removedfile: function(file) {
- var _ref;
- if (file.previewElement) {
- if ((_ref = file.previewElement) != null) {
- _ref.parentNode.removeChild(file.previewElement);
- }
- }
- return this._updateMaxFilesReachedClass();
- },
- thumbnail: function(file, dataUrl) {
- var thumbnailElement, _i, _len, _ref;
- if (file.previewElement) {
- file.previewElement.classList.remove("dz-file-preview");
- _ref = file.previewElement.querySelectorAll("[data-dz-thumbnail]");
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
- thumbnailElement = _ref[_i];
- thumbnailElement.alt = file.name;
- thumbnailElement.src = dataUrl;
- }
- return setTimeout(((function(_this) {
- return function() {
- return file.previewElement.classList.add("dz-image-preview");
- };
- })(this)), 1);
- }
- },
- error: function(file, message) {
- var node, _i, _len, _ref, _results;
- if (file.previewElement) {
- file.previewElement.classList.add("dz-error");
- if (typeof message !== "String" && message.error) {
- message = message.error;
- }
- _ref = file.previewElement.querySelectorAll("[data-dz-errormessage]");
- _results = [];
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
- node = _ref[_i];
- _results.push(node.textContent = message);
- }
- return _results;
- }
- },
- errormultiple: noop,
- processing: function(file) {
- if (file.previewElement) {
- file.previewElement.classList.add("dz-processing");
- if (file._removeLink) {
- return file._removeLink.textContent = this.options.dictCancelUpload;
- }
- }
- },
- processingmultiple: noop,
- uploadprogress: function(file, progress, bytesSent) {
- var node, _i, _len, _ref, _results;
- if (file.previewElement) {
- _ref = file.previewElement.querySelectorAll("[data-dz-uploadprogress]");
- _results = [];
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
- node = _ref[_i];
- if (node.nodeName === 'PROGRESS') {
- _results.push(node.value = progress);
- } else {
- _results.push(node.style.width = "" + progress + "%");
+
+ for (var _iterator5 = file.previewElement.querySelectorAll("[data-dz-remove]"), _isArray5 = true, _i5 = 0, _iterator5 = _isArray5 ? _iterator5 : _iterator5[Symbol.iterator]();;) {
+ var _ref4;
+
+ if (_isArray5) {
+ if (_i5 >= _iterator5.length) break;
+ _ref4 = _iterator5[_i5++];
+ } else {
+ _i5 = _iterator5.next();
+ if (_i5.done) break;
+ _ref4 = _i5.value;
+ }
+
+ var removeLink = _ref4;
+
+ removeLink.addEventListener("click", removeFileEvent);
}
}
- return _results;
- }
- },
- totaluploadprogress: noop,
- sending: noop,
- sendingmultiple: noop,
- success: function(file) {
- if (file.previewElement) {
- return file.previewElement.classList.add("dz-success");
- }
- },
- successmultiple: noop,
- canceled: function(file) {
- return this.emit("error", file, "Upload canceled.");
- },
- canceledmultiple: noop,
- complete: function(file) {
- if (file._removeLink) {
- file._removeLink.textContent = this.options.dictRemoveFile;
- }
- if (file.previewElement) {
- return file.previewElement.classList.add("dz-complete");
- }
- },
- completemultiple: noop,
- maxfilesexceeded: noop,
- maxfilesreached: noop,
- queuecomplete: noop,
- previewTemplate: "
\n
\n
\n
\n
\n
\n
\n
\n
\n \n
\n
\n \n
\n
"
- };
+ },
- extend = function() {
- var key, object, objects, target, val, _i, _len;
- target = arguments[0], objects = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
- for (_i = 0, _len = objects.length; _i < _len; _i++) {
- object = objects[_i];
- for (key in object) {
- val = object[key];
+
+ // Called whenever a file is removed.
+ removedfile: function removedfile(file) {
+ if (file.previewElement != null && file.previewElement.parentNode != null) {
+ file.previewElement.parentNode.removeChild(file.previewElement);
+ }
+ return this._updateMaxFilesReachedClass();
+ },
+
+
+ // Called when a thumbnail has been generated
+ // Receives `file` and `dataUrl`
+ thumbnail: function thumbnail(file, dataUrl) {
+ if (file.previewElement) {
+ file.previewElement.classList.remove("dz-file-preview");
+ for (var _iterator6 = file.previewElement.querySelectorAll("[data-dz-thumbnail]"), _isArray6 = true, _i6 = 0, _iterator6 = _isArray6 ? _iterator6 : _iterator6[Symbol.iterator]();;) {
+ var _ref5;
+
+ if (_isArray6) {
+ if (_i6 >= _iterator6.length) break;
+ _ref5 = _iterator6[_i6++];
+ } else {
+ _i6 = _iterator6.next();
+ if (_i6.done) break;
+ _ref5 = _i6.value;
+ }
+
+ var thumbnailElement = _ref5;
+
+ thumbnailElement.alt = file.name;
+ thumbnailElement.src = dataUrl;
+ }
+
+ return setTimeout(function () {
+ return file.previewElement.classList.add("dz-image-preview");
+ }, 1);
+ }
+ },
+
+
+ // Called whenever an error occurs
+ // Receives `file` and `message`
+ error: function error(file, message) {
+ if (file.previewElement) {
+ file.previewElement.classList.add("dz-error");
+ if (typeof message !== "String" && message.error) {
+ message = message.error;
+ }
+ for (var _iterator7 = file.previewElement.querySelectorAll("[data-dz-errormessage]"), _isArray7 = true, _i7 = 0, _iterator7 = _isArray7 ? _iterator7 : _iterator7[Symbol.iterator]();;) {
+ var _ref6;
+
+ if (_isArray7) {
+ if (_i7 >= _iterator7.length) break;
+ _ref6 = _iterator7[_i7++];
+ } else {
+ _i7 = _iterator7.next();
+ if (_i7.done) break;
+ _ref6 = _i7.value;
+ }
+
+ var node = _ref6;
+
+ node.textContent = message;
+ }
+ }
+ },
+ errormultiple: function errormultiple() {},
+
+
+ // Called when a file gets processed. Since there is a cue, not all added
+ // files are processed immediately.
+ // Receives `file`
+ processing: function processing(file) {
+ if (file.previewElement) {
+ file.previewElement.classList.add("dz-processing");
+ if (file._removeLink) {
+ return file._removeLink.innerHTML = this.options.dictCancelUpload;
+ }
+ }
+ },
+ processingmultiple: function processingmultiple() {},
+
+
+ // Called whenever the upload progress gets updated.
+ // Receives `file`, `progress` (percentage 0-100) and `bytesSent`.
+ // To get the total number of bytes of the file, use `file.size`
+ uploadprogress: function uploadprogress(file, progress, bytesSent) {
+ if (file.previewElement) {
+ for (var _iterator8 = file.previewElement.querySelectorAll("[data-dz-uploadprogress]"), _isArray8 = true, _i8 = 0, _iterator8 = _isArray8 ? _iterator8 : _iterator8[Symbol.iterator]();;) {
+ var _ref7;
+
+ if (_isArray8) {
+ if (_i8 >= _iterator8.length) break;
+ _ref7 = _iterator8[_i8++];
+ } else {
+ _i8 = _iterator8.next();
+ if (_i8.done) break;
+ _ref7 = _i8.value;
+ }
+
+ var node = _ref7;
+
+ node.nodeName === 'PROGRESS' ? node.value = progress : node.style.width = progress + "%";
+ }
+ }
+ },
+
+
+ // Called whenever the total upload progress gets updated.
+ // Called with totalUploadProgress (0-100), totalBytes and totalBytesSent
+ totaluploadprogress: function totaluploadprogress() {},
+
+
+ // Called just before the file is sent. Gets the `xhr` object as second
+ // parameter, so you can modify it (for example to add a CSRF token) and a
+ // `formData` object to add additional information.
+ sending: function sending() {},
+ sendingmultiple: function sendingmultiple() {},
+
+
+ // When the complete upload is finished and successful
+ // Receives `file`
+ success: function success(file) {
+ if (file.previewElement) {
+ return file.previewElement.classList.add("dz-success");
+ }
+ },
+ successmultiple: function successmultiple() {},
+
+
+ // When the upload is canceled.
+ canceled: function canceled(file) {
+ return this.emit("error", file, this.options.dictUploadCanceled);
+ },
+ canceledmultiple: function canceledmultiple() {},
+
+
+ // When the upload is finished, either with success or an error.
+ // Receives `file`
+ complete: function complete(file) {
+ if (file._removeLink) {
+ file._removeLink.innerHTML = this.options.dictRemoveFile;
+ }
+ if (file.previewElement) {
+ return file.previewElement.classList.add("dz-complete");
+ }
+ },
+ completemultiple: function completemultiple() {},
+ maxfilesexceeded: function maxfilesexceeded() {},
+ maxfilesreached: function maxfilesreached() {},
+ queuecomplete: function queuecomplete() {},
+ addedfiles: function addedfiles() {}
+ };
+
+ this.prototype._thumbnailQueue = [];
+ this.prototype._processingThumbnail = false;
+ }
+
+ // global utility
+
+ }, {
+ key: "extend",
+ value: function extend(target) {
+ for (var _len2 = arguments.length, objects = Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {
+ objects[_key2 - 1] = arguments[_key2];
+ }
+
+ for (var _iterator9 = objects, _isArray9 = true, _i9 = 0, _iterator9 = _isArray9 ? _iterator9 : _iterator9[Symbol.iterator]();;) {
+ var _ref8;
+
+ if (_isArray9) {
+ if (_i9 >= _iterator9.length) break;
+ _ref8 = _iterator9[_i9++];
+ } else {
+ _i9 = _iterator9.next();
+ if (_i9.done) break;
+ _ref8 = _i9.value;
+ }
+
+ var object = _ref8;
+
+ for (var key in object) {
+ var val = object[key];
target[key] = val;
}
}
return target;
- };
+ }
+ }]);
- function Dropzone(element, options) {
- var elementOptions, fallback, _ref;
- this.element = element;
- this.version = Dropzone.version;
- this.defaultOptions.previewTemplate = this.defaultOptions.previewTemplate.replace(/\n*/g, "");
- this.clickableElements = [];
- this.listeners = [];
- this.files = [];
- if (typeof this.element === "string") {
- this.element = document.querySelector(this.element);
- }
- if (!(this.element && (this.element.nodeType != null))) {
- throw new Error("Invalid dropzone element.");
- }
- if (this.element.dropzone) {
- throw new Error("Dropzone already attached.");
- }
- Dropzone.instances.push(this);
- this.element.dropzone = this;
- elementOptions = (_ref = Dropzone.optionsForElement(this.element)) != null ? _ref : {};
- this.options = extend({}, this.defaultOptions, elementOptions, options != null ? options : {});
- if (this.options.forceFallback || !Dropzone.isBrowserSupported()) {
- return this.options.fallback.call(this);
- }
- if (this.options.url == null) {
- this.options.url = this.element.getAttribute("action");
- }
- if (!this.options.url) {
- throw new Error("No URL provided.");
- }
- if (this.options.acceptedFiles && this.options.acceptedMimeTypes) {
- throw new Error("You can't provide both 'acceptedFiles' and 'acceptedMimeTypes'. 'acceptedMimeTypes' is deprecated.");
- }
- if (this.options.acceptedMimeTypes) {
- this.options.acceptedFiles = this.options.acceptedMimeTypes;
- delete this.options.acceptedMimeTypes;
- }
- this.options.method = this.options.method.toUpperCase();
- if ((fallback = this.getExistingFallback()) && fallback.parentNode) {
- fallback.parentNode.removeChild(fallback);
- }
- if (this.options.previewsContainer !== false) {
- if (this.options.previewsContainer) {
- this.previewsContainer = Dropzone.getElement(this.options.previewsContainer, "previewsContainer");
- } else {
- this.previewsContainer = this.element;
- }
- }
- if (this.options.clickable) {
- if (this.options.clickable === true) {
- this.clickableElements = [this.element];
- } else {
- this.clickableElements = Dropzone.getElements(this.options.clickable, "clickable");
- }
- }
- this.init();
+ function Dropzone(el, options) {
+ _classCallCheck(this, Dropzone);
+
+ var _this = _possibleConstructorReturn(this, (Dropzone.__proto__ || Object.getPrototypeOf(Dropzone)).call(this));
+
+ var fallback = void 0,
+ left = void 0;
+ _this.element = el;
+ // For backwards compatibility since the version was in the prototype previously
+ _this.version = Dropzone.version;
+
+ _this.defaultOptions.previewTemplate = _this.defaultOptions.previewTemplate.replace(/\n*/g, "");
+
+ _this.clickableElements = [];
+ _this.listeners = [];
+ _this.files = []; // All files
+
+ if (typeof _this.element === "string") {
+ _this.element = document.querySelector(_this.element);
}
- Dropzone.prototype.getAcceptedFiles = function() {
- var file, _i, _len, _ref, _results;
- _ref = this.files;
- _results = [];
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
- file = _ref[_i];
- if (file.accepted) {
- _results.push(file);
- }
- }
- return _results;
- };
+ // Not checking if instance of HTMLElement or Element since IE9 is extremely weird.
+ if (!_this.element || _this.element.nodeType == null) {
+ throw new Error("Invalid dropzone element.");
+ }
- Dropzone.prototype.getRejectedFiles = function() {
- var file, _i, _len, _ref, _results;
- _ref = this.files;
- _results = [];
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
- file = _ref[_i];
- if (!file.accepted) {
- _results.push(file);
- }
- }
- return _results;
- };
+ if (_this.element.dropzone) {
+ throw new Error("Dropzone already attached.");
+ }
- Dropzone.prototype.getFilesWithStatus = function(status) {
- var file, _i, _len, _ref, _results;
- _ref = this.files;
- _results = [];
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
- file = _ref[_i];
- if (file.status === status) {
- _results.push(file);
- }
- }
- return _results;
- };
+ // Now add this dropzone to the instances.
+ Dropzone.instances.push(_this);
- Dropzone.prototype.getQueuedFiles = function() {
+ // Put the dropzone inside the element itself.
+ _this.element.dropzone = _this;
+
+ var elementOptions = (left = Dropzone.optionsForElement(_this.element)) != null ? left : {};
+
+ _this.options = Dropzone.extend({}, _this.defaultOptions, elementOptions, options != null ? options : {});
+
+ // If the browser failed, just call the fallback and leave
+ if (_this.options.forceFallback || !Dropzone.isBrowserSupported()) {
+ var _ret;
+
+ return _ret = _this.options.fallback.call(_this), _possibleConstructorReturn(_this, _ret);
+ }
+
+ // @options.url = @element.getAttribute "action" unless @options.url?
+ if (_this.options.url == null) {
+ _this.options.url = _this.element.getAttribute("action");
+ }
+
+ if (!_this.options.url) {
+ throw new Error("No URL provided.");
+ }
+
+ if (_this.options.acceptedFiles && _this.options.acceptedMimeTypes) {
+ throw new Error("You can't provide both 'acceptedFiles' and 'acceptedMimeTypes'. 'acceptedMimeTypes' is deprecated.");
+ }
+
+ if (_this.options.uploadMultiple && _this.options.chunking) {
+ throw new Error('You cannot set both: uploadMultiple and chunking.');
+ }
+
+ // Backwards compatibility
+ if (_this.options.acceptedMimeTypes) {
+ _this.options.acceptedFiles = _this.options.acceptedMimeTypes;
+ delete _this.options.acceptedMimeTypes;
+ }
+
+ // Backwards compatibility
+ if (_this.options.renameFilename != null) {
+ _this.options.renameFile = function (file) {
+ return _this.options.renameFilename.call(_this, file.name, file);
+ };
+ }
+
+ _this.options.method = _this.options.method.toUpperCase();
+
+ if ((fallback = _this.getExistingFallback()) && fallback.parentNode) {
+ // Remove the fallback
+ fallback.parentNode.removeChild(fallback);
+ }
+
+ // Display previews in the previewsContainer element or the Dropzone element unless explicitly set to false
+ if (_this.options.previewsContainer !== false) {
+ if (_this.options.previewsContainer) {
+ _this.previewsContainer = Dropzone.getElement(_this.options.previewsContainer, "previewsContainer");
+ } else {
+ _this.previewsContainer = _this.element;
+ }
+ }
+
+ if (_this.options.clickable) {
+ if (_this.options.clickable === true) {
+ _this.clickableElements = [_this.element];
+ } else {
+ _this.clickableElements = Dropzone.getElements(_this.options.clickable, "clickable");
+ }
+ }
+
+ _this.init();
+ return _this;
+ }
+
+ // Returns all files that have been accepted
+
+
+ _createClass(Dropzone, [{
+ key: "getAcceptedFiles",
+ value: function getAcceptedFiles() {
+ return this.files.filter(function (file) {
+ return file.accepted;
+ }).map(function (file) {
+ return file;
+ });
+ }
+
+ // Returns all files that have been rejected
+ // Not sure when that's going to be useful, but added for completeness.
+
+ }, {
+ key: "getRejectedFiles",
+ value: function getRejectedFiles() {
+ return this.files.filter(function (file) {
+ return !file.accepted;
+ }).map(function (file) {
+ return file;
+ });
+ }
+ }, {
+ key: "getFilesWithStatus",
+ value: function getFilesWithStatus(status) {
+ return this.files.filter(function (file) {
+ return file.status === status;
+ }).map(function (file) {
+ return file;
+ });
+ }
+
+ // Returns all files that are in the queue
+
+ }, {
+ key: "getQueuedFiles",
+ value: function getQueuedFiles() {
return this.getFilesWithStatus(Dropzone.QUEUED);
- };
-
- Dropzone.prototype.getUploadingFiles = function() {
+ }
+ }, {
+ key: "getUploadingFiles",
+ value: function getUploadingFiles() {
return this.getFilesWithStatus(Dropzone.UPLOADING);
- };
+ }
+ }, {
+ key: "getAddedFiles",
+ value: function getAddedFiles() {
+ return this.getFilesWithStatus(Dropzone.ADDED);
+ }
- Dropzone.prototype.getActiveFiles = function() {
- var file, _i, _len, _ref, _results;
- _ref = this.files;
- _results = [];
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
- file = _ref[_i];
- if (file.status === Dropzone.UPLOADING || file.status === Dropzone.QUEUED) {
- _results.push(file);
- }
- }
- return _results;
- };
+ // Files that are either queued or uploading
- Dropzone.prototype.init = function() {
- var eventName, noPropagation, setupHiddenFileInput, _i, _len, _ref, _ref1;
+ }, {
+ key: "getActiveFiles",
+ value: function getActiveFiles() {
+ return this.files.filter(function (file) {
+ return file.status === Dropzone.UPLOADING || file.status === Dropzone.QUEUED;
+ }).map(function (file) {
+ return file;
+ });
+ }
+
+ // The function that gets called when Dropzone is initialized. You
+ // can (and should) setup event listeners inside this function.
+
+ }, {
+ key: "init",
+ value: function init() {
+ var _this3 = this;
+
+ // In case it isn't set already
if (this.element.tagName === "form") {
this.element.setAttribute("enctype", "multipart/form-data");
}
+
if (this.element.classList.contains("dropzone") && !this.element.querySelector(".dz-message")) {
this.element.appendChild(Dropzone.createElement("
" + this.options.dictDefaultMessage + "
"));
}
+
if (this.clickableElements.length) {
- setupHiddenFileInput = (function(_this) {
- return function() {
- if (_this.hiddenFileInput) {
- document.body.removeChild(_this.hiddenFileInput);
- }
- _this.hiddenFileInput = document.createElement("input");
- _this.hiddenFileInput.setAttribute("type", "file");
- if ((_this.options.maxFiles == null) || _this.options.maxFiles > 1) {
- _this.hiddenFileInput.setAttribute("multiple", "multiple");
- }
- _this.hiddenFileInput.className = "dz-hidden-input";
- if (_this.options.acceptedFiles != null) {
- _this.hiddenFileInput.setAttribute("accept", _this.options.acceptedFiles);
- }
- if (_this.options.capture != null) {
- _this.hiddenFileInput.setAttribute("capture", _this.options.capture);
- }
- _this.hiddenFileInput.style.visibility = "hidden";
- _this.hiddenFileInput.style.position = "absolute";
- _this.hiddenFileInput.style.top = "0";
- _this.hiddenFileInput.style.left = "0";
- _this.hiddenFileInput.style.height = "0";
- _this.hiddenFileInput.style.width = "0";
- document.body.appendChild(_this.hiddenFileInput);
- return _this.hiddenFileInput.addEventListener("change", function() {
- var file, files, _i, _len;
- files = _this.hiddenFileInput.files;
- if (files.length) {
- for (_i = 0, _len = files.length; _i < _len; _i++) {
- file = files[_i];
- _this.addFile(file);
+ var setupHiddenFileInput = function setupHiddenFileInput() {
+ if (_this3.hiddenFileInput) {
+ _this3.hiddenFileInput.parentNode.removeChild(_this3.hiddenFileInput);
+ }
+ _this3.hiddenFileInput = document.createElement("input");
+ _this3.hiddenFileInput.setAttribute("type", "file");
+ if (_this3.options.maxFiles === null || _this3.options.maxFiles > 1) {
+ _this3.hiddenFileInput.setAttribute("multiple", "multiple");
+ }
+ _this3.hiddenFileInput.className = "dz-hidden-input";
+
+ if (_this3.options.acceptedFiles !== null) {
+ _this3.hiddenFileInput.setAttribute("accept", _this3.options.acceptedFiles);
+ }
+ if (_this3.options.capture !== null) {
+ _this3.hiddenFileInput.setAttribute("capture", _this3.options.capture);
+ }
+
+ // Not setting `display="none"` because some browsers don't accept clicks
+ // on elements that aren't displayed.
+ _this3.hiddenFileInput.style.visibility = "hidden";
+ _this3.hiddenFileInput.style.position = "absolute";
+ _this3.hiddenFileInput.style.top = "0";
+ _this3.hiddenFileInput.style.left = "0";
+ _this3.hiddenFileInput.style.height = "0";
+ _this3.hiddenFileInput.style.width = "0";
+ Dropzone.getElement(_this3.options.hiddenInputContainer, 'hiddenInputContainer').appendChild(_this3.hiddenFileInput);
+ return _this3.hiddenFileInput.addEventListener("change", function () {
+ var files = _this3.hiddenFileInput.files;
+
+ if (files.length) {
+ for (var _iterator10 = files, _isArray10 = true, _i10 = 0, _iterator10 = _isArray10 ? _iterator10 : _iterator10[Symbol.iterator]();;) {
+ var _ref9;
+
+ if (_isArray10) {
+ if (_i10 >= _iterator10.length) break;
+ _ref9 = _iterator10[_i10++];
+ } else {
+ _i10 = _iterator10.next();
+ if (_i10.done) break;
+ _ref9 = _i10.value;
}
+
+ var file = _ref9;
+
+ _this3.addFile(file);
}
- return setupHiddenFileInput();
- });
- };
- })(this);
+ }
+ _this3.emit("addedfiles", files);
+ return setupHiddenFileInput();
+ });
+ };
setupHiddenFileInput();
}
- this.URL = (_ref = window.URL) != null ? _ref : window.webkitURL;
- _ref1 = this.events;
- for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
- eventName = _ref1[_i];
+
+ this.URL = window.URL !== null ? window.URL : window.webkitURL;
+
+ // Setup all event listeners on the Dropzone object itself.
+ // They're not in @setupEventListeners() because they shouldn't be removed
+ // again when the dropzone gets disabled.
+ for (var _iterator11 = this.events, _isArray11 = true, _i11 = 0, _iterator11 = _isArray11 ? _iterator11 : _iterator11[Symbol.iterator]();;) {
+ var _ref10;
+
+ if (_isArray11) {
+ if (_i11 >= _iterator11.length) break;
+ _ref10 = _iterator11[_i11++];
+ } else {
+ _i11 = _iterator11.next();
+ if (_i11.done) break;
+ _ref10 = _i11.value;
+ }
+
+ var eventName = _ref10;
+
this.on(eventName, this.options[eventName]);
}
- this.on("uploadprogress", (function(_this) {
- return function() {
- return _this.updateTotalUploadProgress();
- };
- })(this));
- this.on("removedfile", (function(_this) {
- return function() {
- return _this.updateTotalUploadProgress();
- };
- })(this));
- this.on("canceled", (function(_this) {
- return function(file) {
- return _this.emit("complete", file);
- };
- })(this));
- this.on("complete", (function(_this) {
- return function(file) {
- if (_this.getUploadingFiles().length === 0 && _this.getQueuedFiles().length === 0) {
- return setTimeout((function() {
- return _this.emit("queuecomplete");
- }), 0);
- }
- };
- })(this));
- noPropagation = function(e) {
+
+ this.on("uploadprogress", function () {
+ return _this3.updateTotalUploadProgress();
+ });
+
+ this.on("removedfile", function () {
+ return _this3.updateTotalUploadProgress();
+ });
+
+ this.on("canceled", function (file) {
+ return _this3.emit("complete", file);
+ });
+
+ // Emit a `queuecomplete` event if all files finished uploading.
+ this.on("complete", function (file) {
+ if (_this3.getAddedFiles().length === 0 && _this3.getUploadingFiles().length === 0 && _this3.getQueuedFiles().length === 0) {
+ // This needs to be deferred so that `queuecomplete` really triggers after `complete`
+ return setTimeout(function () {
+ return _this3.emit("queuecomplete");
+ }, 0);
+ }
+ });
+
+ var noPropagation = function noPropagation(e) {
e.stopPropagation();
if (e.preventDefault) {
return e.preventDefault();
@@ -607,90 +1309,106 @@
return e.returnValue = false;
}
};
- this.listeners = [
- {
- element: this.element,
- events: {
- "dragstart": (function(_this) {
- return function(e) {
- return _this.emit("dragstart", e);
- };
- })(this),
- "dragenter": (function(_this) {
- return function(e) {
- noPropagation(e);
- return _this.emit("dragenter", e);
- };
- })(this),
- "dragover": (function(_this) {
- return function(e) {
- var efct;
- try {
- efct = e.dataTransfer.effectAllowed;
- } catch (_error) {}
- e.dataTransfer.dropEffect = 'move' === efct || 'linkMove' === efct ? 'move' : 'copy';
- noPropagation(e);
- return _this.emit("dragover", e);
- };
- })(this),
- "dragleave": (function(_this) {
- return function(e) {
- return _this.emit("dragleave", e);
- };
- })(this),
- "drop": (function(_this) {
- return function(e) {
- noPropagation(e);
- return _this.drop(e);
- };
- })(this),
- "dragend": (function(_this) {
- return function(e) {
- return _this.emit("dragend", e);
- };
- })(this)
- }
- }
- ];
- this.clickableElements.forEach((function(_this) {
- return function(clickableElement) {
- return _this.listeners.push({
- element: clickableElement,
- events: {
- "click": function(evt) {
- if ((clickableElement !== _this.element) || (evt.target === _this.element || Dropzone.elementInside(evt.target, _this.element.querySelector(".dz-message")))) {
- return _this.hiddenFileInput.click();
- }
- }
- }
- });
- };
- })(this));
- this.enable();
- return this.options.init.call(this);
- };
- Dropzone.prototype.destroy = function() {
- var _ref;
+ // Create the listeners
+ this.listeners = [{
+ element: this.element,
+ events: {
+ "dragstart": function dragstart(e) {
+ return _this3.emit("dragstart", e);
+ },
+ "dragenter": function dragenter(e) {
+ noPropagation(e);
+ return _this3.emit("dragenter", e);
+ },
+ "dragover": function dragover(e) {
+ // Makes it possible to drag files from chrome's download bar
+ // http://stackoverflow.com/questions/19526430/drag-and-drop-file-uploads-from-chrome-downloads-bar
+ // Try is required to prevent bug in Internet Explorer 11 (SCRIPT65535 exception)
+ var efct = void 0;
+ try {
+ efct = e.dataTransfer.effectAllowed;
+ } catch (error) {}
+ e.dataTransfer.dropEffect = 'move' === efct || 'linkMove' === efct ? 'move' : 'copy';
+
+ noPropagation(e);
+ return _this3.emit("dragover", e);
+ },
+ "dragleave": function dragleave(e) {
+ return _this3.emit("dragleave", e);
+ },
+ "drop": function drop(e) {
+ noPropagation(e);
+ return _this3.drop(e);
+ },
+ "dragend": function dragend(e) {
+ return _this3.emit("dragend", e);
+ }
+
+ // This is disabled right now, because the browsers don't implement it properly.
+ // "paste": (e) =>
+ // noPropagation e
+ // @paste e
+ } }];
+
+ this.clickableElements.forEach(function (clickableElement) {
+ return _this3.listeners.push({
+ element: clickableElement,
+ events: {
+ "click": function click(evt) {
+ // Only the actual dropzone or the message element should trigger file selection
+ if (clickableElement !== _this3.element || evt.target === _this3.element || Dropzone.elementInside(evt.target, _this3.element.querySelector(".dz-message"))) {
+ _this3.hiddenFileInput.click(); // Forward the click
+ }
+ return true;
+ }
+ }
+ });
+ });
+
+ this.enable();
+
+ return this.options.init.call(this);
+ }
+
+ // Not fully tested yet
+
+ }, {
+ key: "destroy",
+ value: function destroy() {
this.disable();
this.removeAllFiles(true);
- if ((_ref = this.hiddenFileInput) != null ? _ref.parentNode : void 0) {
+ if (this.hiddenFileInput != null ? this.hiddenFileInput.parentNode : undefined) {
this.hiddenFileInput.parentNode.removeChild(this.hiddenFileInput);
this.hiddenFileInput = null;
}
delete this.element.dropzone;
return Dropzone.instances.splice(Dropzone.instances.indexOf(this), 1);
- };
+ }
+ }, {
+ key: "updateTotalUploadProgress",
+ value: function updateTotalUploadProgress() {
+ var totalUploadProgress = void 0;
+ var totalBytesSent = 0;
+ var totalBytes = 0;
+
+ var activeFiles = this.getActiveFiles();
- Dropzone.prototype.updateTotalUploadProgress = function() {
- var activeFiles, file, totalBytes, totalBytesSent, totalUploadProgress, _i, _len, _ref;
- totalBytesSent = 0;
- totalBytes = 0;
- activeFiles = this.getActiveFiles();
if (activeFiles.length) {
- _ref = this.getActiveFiles();
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
- file = _ref[_i];
+ for (var _iterator12 = this.getActiveFiles(), _isArray12 = true, _i12 = 0, _iterator12 = _isArray12 ? _iterator12 : _iterator12[Symbol.iterator]();;) {
+ var _ref11;
+
+ if (_isArray12) {
+ if (_i12 >= _iterator12.length) break;
+ _ref11 = _iterator12[_i12++];
+ } else {
+ _i12 = _iterator12.next();
+ if (_i12.done) break;
+ _ref11 = _i12.value;
+ }
+
+ var file = _ref11;
+
totalBytesSent += file.upload.bytesSent;
totalBytes += file.upload.total;
}
@@ -698,139 +1416,200 @@
} else {
totalUploadProgress = 100;
}
- return this.emit("totaluploadprogress", totalUploadProgress, totalBytes, totalBytesSent);
- };
- Dropzone.prototype._getParamName = function(n) {
+ return this.emit("totaluploadprogress", totalUploadProgress, totalBytes, totalBytesSent);
+ }
+
+ // @options.paramName can be a function taking one parameter rather than a string.
+ // A parameter name for a file is obtained simply by calling this with an index number.
+
+ }, {
+ key: "_getParamName",
+ value: function _getParamName(n) {
if (typeof this.options.paramName === "function") {
return this.options.paramName(n);
} else {
return "" + this.options.paramName + (this.options.uploadMultiple ? "[" + n + "]" : "");
}
- };
+ }
- Dropzone.prototype.getFallbackForm = function() {
- var existingFallback, fields, fieldsString, form;
+ // If @options.renameFile is a function,
+ // the function will be used to rename the file.name before appending it to the formData
+
+ }, {
+ key: "_renameFile",
+ value: function _renameFile(file) {
+ if (typeof this.options.renameFile !== "function") {
+ return file.name;
+ }
+ return this.options.renameFile(file);
+ }
+
+ // Returns a form that can be used as fallback if the browser does not support DragnDrop
+ //
+ // If the dropzone is already a form, only the input field and button are returned. Otherwise a complete form element is provided.
+ // This code has to pass in IE7 :(
+
+ }, {
+ key: "getFallbackForm",
+ value: function getFallbackForm() {
+ var existingFallback = void 0,
+ form = void 0;
if (existingFallback = this.getExistingFallback()) {
return existingFallback;
}
- fieldsString = "
";
+
+ var fieldsString = "
";
if (this.options.dictFallbackText) {
fieldsString += "