diff --git a/.circleci/config.yml b/.circleci/config.yml new file mode 100644 index 00000000000..9ab1bf3469d --- /dev/null +++ b/.circleci/config.yml @@ -0,0 +1,81 @@ +version: 2 + +jobs: + backend: + docker: + - image: circleci/python:3.6.4 + steps: + - checkout + - restore_cache: + keys: + - pip-packages-v1-{{ .Branch }} + - pip-packages-v1- + - run: pipenv install -e .[testing] + - save_cache: + paths: + - ~/.local/ + key: pip-package-v1-{{ .Branch }} + - run: pipenv run flake8 wagtail + - run: pipenv run isort --check-only --diff --recursive wagtail + # Filter out known false positives, while preserving normal output and error codes. + # See https://github.com/motet-a/jinjalint/issues/18. + # And https://circleci.com/docs/2.0/configuration-reference/#default-shell-options. + - run: + shell: /bin/bash -e + command: pipenv run jinjalint --parse-only wagtail | grep -v 'welcome_page.html:6:70' | tee /dev/tty | wc -l | grep -q '0' + - run: DATABASE_NAME=wagtail.db pipenv run python -u runtests.py + + frontend: + docker: + - image: circleci/node:8.11.3 + steps: + - checkout + - restore_cache: + keys: + - node-v1-{{ .Branch }}-{{ checksum "package-lock.json" }} + - node-v1-{{ .Branch }}- + - node-v1- + - run: npm install --no-save + - save_cache: + paths: + - ~/project/node_modules/ + key: node-v1-{{ .Branch }}-{{ checksum "package-lock.json" }} + - run: npm run lint:js + - run: npm run lint:css + - run: npm run test:unit:coverage -- --runInBand + - run: npm rebuild node-sass + - run: npm run dist + - run: bash <(curl -s https://codecov.io/bash) -F frontend + + nightly-build: + docker: + - image: circleci/python:3.7.3 + steps: + - checkout + - run: cd ~ && wget https://nodejs.org/dist/v8.7.0/node-v8.7.0-linux-x64.tar.gz + - run: cd /usr/local/ && sudo tar --strip-components 1 -xzf ~/node-v8.7.0-linux-x64.tar.gz + - run: pip install --user wheel boto3 + - run: npm install + - run: npm run dist + - run: PYTHONPATH=. python scripts/nightly/get_version.py > __init__.py + - run: mv __init__.py wagtail/__init__.py + - run: python setup.py bdist_wheel + - run: python scripts/nightly/upload.py + +workflows: + version: 2 + test: + jobs: + - backend + - frontend + + nightly: + jobs: + - nightly-build + triggers: + - schedule: + cron: "0 0 * * *" + filters: + branches: + only: + - master diff --git a/.circleci/trigger-nightly-build.sh b/.circleci/trigger-nightly-build.sh new file mode 100755 index 00000000000..3e2381cb4c2 --- /dev/null +++ b/.circleci/trigger-nightly-build.sh @@ -0,0 +1,9 @@ +#!/bin/bash +# Triggers a nightly build for the latest commit on master +# Use this for testing changes to the nightly release process +# Call with the CIRCLE_API_USER_TOKEN set to your Personal API key +# You can find this under User Settings on Circle CI + +curl -u ${CIRCLE_API_USER_TOKEN}: \ + -d build_parameters[CIRCLE_JOB]=nightly-build \ + https://circleci.com/api/v1.1/project/github/wagtail/wagtail/tree/master diff --git a/.coveragerc b/.coveragerc index 5713778546d..e2e7969b81c 100644 --- a/.coveragerc +++ b/.coveragerc @@ -6,6 +6,7 @@ source = wagtail omit = */migrations/* + docs/conf.py [report] diff --git a/.eslintignore b/.eslintignore index cfadd5e8be6..87b4c4a9521 100644 --- a/.eslintignore +++ b/.eslintignore @@ -6,28 +6,13 @@ coverage/ gulp/ **/vendor/ gulpfile.js -client/src/cli wagtail/admin/static wagtail/documents/static wagtail/images/static wagtail/embeds/static +wagtail/search/static wagtail/snippets/static wagtail/users/static wagtail/admin/templates/wagtailadmin/edit_handlers/inline_panel.js wagtail/contrib/search_promotions/templates/wagtailsearchpromotions/includes/searchpromotions_formset.js wagtail/users/templates/wagtailusers/groups/includes/page_permissions_formset.js -wagtail/snippets/templates/wagtailsnippets/chooser/chosen.js -wagtail/images/templates/wagtailimages/chooser/image_chosen.js -wagtail/images/templates/wagtailimages/chooser/chooser.js -wagtail/search/templates/wagtailsearch/queries/chooser/chooser.js -wagtail/images/templates/wagtailimages/chooser/select_format.js -wagtail/embeds/templates/wagtailembeds/chooser/embed_chosen.js -wagtail/embeds/templates/wagtailembeds/chooser/chooser.js -wagtail/documents/templates/wagtaildocs/chooser/chooser.js -wagtail/documents/templates/wagtaildocs/chooser/document_chosen.js -wagtail/admin/templates/wagtailadmin/page_privacy/set_privacy.js -wagtail/admin/templates/wagtailadmin/chooser/external_link_chosen.js -wagtail/admin/templates/wagtailadmin/chooser/external_link.js -wagtail/admin/templates/wagtailadmin/chooser/email_link.js -wagtail/admin/templates/wagtailadmin/chooser/browse.js -wagtail/admin/templates/wagtailadmin/page_privacy/set_privacy_done.js diff --git a/.eslintrc b/.eslintrc index 8034dc2c22e..f26ed0f8d28 100644 --- a/.eslintrc +++ b/.eslintrc @@ -11,5 +11,9 @@ "config": "client/webpack/prod.config.js" } } + }, + + "rules": { + "no-underscore-dangle": ["error", { "allow": ["__REDUX_DEVTOOLS_EXTENSION__"] }] } } diff --git a/CONTRIBUTING.md b/.github/CONTRIBUTING.md similarity index 100% rename from CONTRIBUTING.md rename to .github/CONTRIBUTING.md diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE/BUG_REPORT.md similarity index 62% rename from .github/ISSUE_TEMPLATE.md rename to .github/ISSUE_TEMPLATE/BUG_REPORT.md index 3e0d7496188..fb0a0a6399d 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE/BUG_REPORT.md @@ -1,12 +1,20 @@ +--- +name: "🐞 Bug Report" +about: Create a report to help us improve +title: '' +labels: 'type:Bug' +assignees: '' + +--- + Found a bug? Please fill out the sections below. 👍 ### Issue Summary A summary of the issue. -### Steps to Reproduce -It's essential that you provide enough information for someone else to replicate the problem you're seeing. Simply describing something that's broken on your current project is not enough! +### Steps to Reproduce 1. (for example) Start a new project with `wagtail start myproject` 2. Edit models.py as follows... @@ -14,9 +22,12 @@ It's essential that you provide enough information for someone else to replicate Any other relevant information. For example, why do you consider this a bug and what did you expect to happen instead? +* I have confirmed that this issue can be reproduced as described on a fresh Wagtail project: (yes / no) + + ### Technical details * Python version: Run `python --version`. * Django version: Look in your requirements.txt, or run `pip show django | grep Version`. -* Wagtail version: Hover over the Wagtail bird in the admin, or run `pip show wagtail | grep Version:`. +* Wagtail version: Look at the bottom of the Settings menu in the Wagtail admin, or run `pip show wagtail | grep Version:`. * Browser version: You can use http://www.whatsmybrowser.org/ to find this out. diff --git a/.github/ISSUE_TEMPLATE/FEATURE_REQUEST.md b/.github/ISSUE_TEMPLATE/FEATURE_REQUEST.md new file mode 100644 index 00000000000..260f6a11dd1 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/FEATURE_REQUEST.md @@ -0,0 +1,42 @@ +--- +name: "🚀 Feature request" +about: Suggest an idea for improving Wagtail +title: '' +labels: 'type:Enhancement' +assignees: '' + +--- + +### Is your proposal related to a problem? + + + +(Write your answer here.) + +### Describe the solution you'd like + + + +(Describe your proposed solution here.) + +### Describe alternatives you've considered + + + +(Write your answer here.) + +### Additional context + + + +(Write your answer here.) diff --git a/.github/ISSUE_TEMPLATE/QUESTION.md b/.github/ISSUE_TEMPLATE/QUESTION.md new file mode 100644 index 00000000000..2a67eb3dab0 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/QUESTION.md @@ -0,0 +1,16 @@ +--- +name: "⛔ Question" +about: Please use StackOverflow or Slack for support +title: '' +labels: '' +assignees: '' + +--- + +Please do not use GitHub for asking questions. Instead, if you have a general question about Wagtail or about building a site with Wagtail we encourage you to post on our Slack workspace instead of this issue tracker: https://github.com/wagtail/wagtail/wiki/Slack. The maintainers and other community members can provide help and answer your questions there. + +Please keep in mind that many of Wagtail's core and expert developers prefer to handle support queries through [Stack Overflow](https://stackoverflow.com/questions/tagged/wagtail), since the non-realtime format encourages more structured and fully-formed questions. Asking questions on Stack Overflow requires more up-front effort (see Stack Overflow's advice on how to ask a good question), but you may well find you get a better response as a result. + +If you've discovered a bug or would like to propose a change please use one of the other issue templates. + +Thanks! diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index d6fffb30206..f291ac1fffa 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -5,4 +5,5 @@ Before submitting, please review the contributor guidelines \ No newline at end of file diff --git a/.github/wagtail-screenshot-with-browser.png b/.github/wagtail-screenshot-with-browser.png new file mode 100644 index 00000000000..f646fe16747 Binary files /dev/null and b/.github/wagtail-screenshot-with-browser.png differ diff --git a/.github/wagtail.svg b/.github/wagtail.svg new file mode 100644 index 00000000000..84b04b9b6cc --- /dev/null +++ b/.github/wagtail.svg @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.gitignore b/.gitignore index 4aeb88bed39..6879e6fe99e 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,8 @@ npm-debug.log* *.idea/ /*.egg/ +/.cache/ +/.pytest_cache/ ### JetBrains .idea/ @@ -21,3 +23,6 @@ npm-debug.log* *.iws coverage/ client/node_modules + +### vscode +.vscode diff --git a/docs/readthedocs.yml b/.readthedocs.yml similarity index 66% rename from docs/readthedocs.yml rename to .readthedocs.yml index ec774c7203e..893e91364f7 100644 --- a/docs/readthedocs.yml +++ b/.readthedocs.yml @@ -1,3 +1,4 @@ python: version: 3.5 pip_install: true +requirements_file: null diff --git a/.squash.yml b/.squash.yml new file mode 100644 index 00000000000..9a0721594fa --- /dev/null +++ b/.squash.yml @@ -0,0 +1,23 @@ +deployments: + default: + dockerimage: python:3.7.4-stretch + build_steps: + - apt-get update && apt-get install -y libssl-dev libpq-dev git build-essential libfontconfig1 libfontconfig1-dev curl + - RUN bash -c "curl -sL https://deb.nodesource.com/setup_8.x | bash -" + - apt install -y nodejs + - pip install setuptools pip --upgrade --force-reinstall + - cd /code + post_build_steps: + - npm install --no-save + - npm run dist + - pip install /code + - mkdir /myproject + - cd /myproject + - wagtail start mysite + - cd /myproject/mysite + - python manage.py migrate + - echo "from django.contrib.auth import get_user_model; User = get_user_model(); User.objects.create_superuser('admin', 'admin@example.com', 'changeme')" | python manage.py shell + launch_steps: + - cd /myproject/mysite + - python manage.py runserver 0.0.0.0:80 + run_options: -v ~/code:/code diff --git a/.stylelintrc.yaml b/.stylelintrc.yaml index 4c048515159..d379ab91eb2 100644 --- a/.stylelintrc.yaml +++ b/.stylelintrc.yaml @@ -1,78 +1,5 @@ ignoreFiles: - node_modules -plugins: - - stylelint-scss -# See https://github.com/stylelint/stylelint/blob/master/docs/user-guide/rules.md -rules: - block-closing-brace-newline-after: - - always - - ignoreAtRules: - # Ignore @if … @else in SCSS. - - if - - else - block-no-empty: true - block-opening-brace-space-before: always - color-hex-case: lower - color-hex-length: short - color-named: never - color-no-invalid-hex: true - comment-no-empty: true - declaration-bang-space-after: never - declaration-bang-space-before: always - declaration-block-no-duplicate-properties: true - declaration-block-no-redundant-longhand-properties: true - declaration-block-single-line-max-declarations: 1 - declaration-block-trailing-semicolon: always - declaration-colon-space-after: always - declaration-colon-space-before: never - declaration-property-value-blacklist: - - /^border/: [none] - - severity: error - declaration-no-important: true - font-family-no-duplicate-names: true - function-calc-no-unspaced-operator: true - function-comma-space-after: always - function-linear-gradient-no-nonstandard-direction: true - function-parentheses-space-inside: never - function-url-quotes: always - indentation: - - 4 - - severity: warning - length-zero-no-unit: true - max-nesting-depth: 3 - media-feature-name-no-unknown: true - no-empty-source: true - no-eol-whitespace: true - no-extra-semicolons: true - no-missing-end-of-source-newline: true - number-no-trailing-zeros: true - number-leading-zero: always - property-case: lower - property-no-unknown: true - rule-empty-line-before: - - always - - except: - - after-single-line-comment - - first-nested - scss/at-import-no-partial-leading-underscore: true - scss/at-import-partial-extension-blacklist: - - scss - scss/at-else-empty-line-before: never - selector-no-qualifying-type: - - true - - ignore: - - attribute - - class - selector-list-comma-newline-after: always - selector-max-id: 0 - selector-pseudo-element-no-unknown: true - selector-type-no-unknown: true - scss/at-rule-no-unknown: true - scss/media-feature-value-dollar-variable: always - scss/selector-no-redundant-nesting-selector: true - string-no-newline: true - string-quotes: single - unit-no-unknown: true - unit-case: lower - value-no-vendor-prefix: true - property-no-vendor-prefix: true + - build/**/* +extends: + - '@wagtail/stylelint-config-wagtail' diff --git a/.travis.yml b/.travis.yml index bf15973c5d2..365f738826f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,71 +1,77 @@ language: python cache: pip -dist: trusty +dist: xenial -# Use container-based infrastructure -sudo: false - -# Install JDK9 for Elasticsearch 5 addons: - apt: - packages: - - oracle-java9-installer - - oracle-java9-set-default + postgresql: "9.6" matrix: include: - - env: TOXENV=py34-dj111-postgres-noelasticsearch - python: 3.4 - - env: TOXENV=py34-dj111-sqlite-noelasticsearch - python: 3.4 - - env: TOXENV=py34-dj20-mysql-noelasticsearch - python: 3.4 - - env: TOXENV=py35-dj111-postgres-noelasticsearch - python: 3.5 - - env: TOXENV=py35-dj111-mysql-noelasticsearch - python: 3.5 - - env: TOXENV=py35-dj111-postgres-elasticsearch2 INSTALL_ELASTICSEARCH2=yes - python: 3.5 - sudo: true - env: TOXENV=py35-dj20-sqlite-noelasticsearch python: 3.5 - - env: TOXENV=py36-dj111-sqlite-noelasticsearch - python: 3.6 - - env: TOXENV=py36-dj111-postgres-noelasticsearch - python: 3.6 - - env: TOXENV=py36-dj111-mysql-noelasticsearch - python: 3.6 + - env: TOXENV=py35-dj21-mysql-noelasticsearch + python: 3.5 - env: TOXENV=py36-dj20-postgres-noelasticsearch python: 3.6 - - env: TOXENV=py36-dj111-postgres-elasticsearch2 INSTALL_ELASTICSEARCH2=yes + - env: TOXENV=py36-dj21-postgres-noelasticsearch python: 3.6 - sudo: true + - env: TOXENV=py37-dj21-postgres-noelasticsearch + python: 3.7 + - env: TOXENV=py37-dj22-sqlite-noelasticsearch + python: 3.7 + - env: TOXENV=py37-dj22-mysql-noelasticsearch + python: 3.7 + - env: TOXENV=py37-dj22-postgres-noelasticsearch + python: 3.7 + - env: TOXENV=py37-dj22stable-postgres-noelasticsearch + python: 3.7 + - env: TOXENV=py37-djmaster-postgres-noelasticsearch + python: 3.7 + - env: TOXENV=py38-dj22-postgres-noelasticsearch + python: 3.8 - env: TOXENV=py36-dj20-sqlite-elasticsearch2 INSTALL_ELASTICSEARCH2=yes python: 3.6 - sudo: true - - env: TOXENV=py36-dj111-postgres-elasticsearch5 INSTALL_ELASTICSEARCH5=yes + - env: TOXENV=py36-dj21-sqlite-elasticsearch2 INSTALL_ELASTICSEARCH2=yes + python: 3.6 + - env: TOXENV=py36-dj21-postgres-elasticsearch5 INSTALL_ELASTICSEARCH5=yes + python: 3.6 + - env: TOXENV=py36-dj20-postgres-elasticsearch6 INSTALL_ELASTICSEARCH6=yes python: 3.6 - sudo: true - - env: TOXENV=py36-dj20-postgres-elasticsearch5 INSTALL_ELASTICSEARCH5=yes + - env: TOXENV=py36-dj21-postgres-elasticsearch6 INSTALL_ELASTICSEARCH6=yes python: 3.6 - sudo: true + - env: TOXENV=py37-dj22-postgres-elasticsearch6 INSTALL_ELASTICSEARCH6=yes + python: 3.7 + - env: TOXENV=py37-dj22-postgres-elasticsearch7 INSTALL_ELASTICSEARCH7=yes + python: 3.7 + - env: TOXENV=py38-dj22-postgres-elasticsearch7 INSTALL_ELASTICSEARCH7=yes + python: 3.8 allow_failures: # Ignore failures on Elasticsearch tests because ES on Travis is intermittently flaky - - env: TOXENV=py35-dj111-postgres-elasticsearch2 INSTALL_ELASTICSEARCH2=yes - - env: TOXENV=py36-dj111-postgres-elasticsearch2 INSTALL_ELASTICSEARCH2=yes - env: TOXENV=py36-dj20-sqlite-elasticsearch2 INSTALL_ELASTICSEARCH2=yes - - env: TOXENV=py36-dj111-postgres-elasticsearch5 INSTALL_ELASTICSEARCH5=yes - - env: TOXENV=py36-dj20-postgres-elasticsearch5 INSTALL_ELASTICSEARCH5=yes + - env: TOXENV=py36-dj21-sqlite-elasticsearch2 INSTALL_ELASTICSEARCH2=yes + - env: TOXENV=py36-dj21-postgres-elasticsearch5 INSTALL_ELASTICSEARCH5=yes + - env: TOXENV=py36-dj20-postgres-elasticsearch6 INSTALL_ELASTICSEARCH6=yes + - env: TOXENV=py36-dj21-postgres-elasticsearch6 INSTALL_ELASTICSEARCH6=yes + - env: TOXENV=py37-dj22-postgres-elasticsearch6 INSTALL_ELASTICSEARCH6=yes + - env: TOXENV=py37-dj22-postgres-elasticsearch7 INSTALL_ELASTICSEARCH7=yes + - env: TOXENV=py38-dj22-postgres-elasticsearch7 INSTALL_ELASTICSEARCH7=yes + # allow failures against Django 2.2.x stable branch + - env: TOXENV=py37-dj22stable-postgres-noelasticsearch + # allow failures against Django master + - env: TOXENV=py37-djmaster-postgres-noelasticsearch # Services services: - elasticsearch + - mysql # Package installation install: - pip install tox codecov - 'if [[ -n "$INSTALL_ELASTICSEARCH2" ]]; then ./scripts/travis/install_elasticsearch2.sh; fi' - 'if [[ -n "$INSTALL_ELASTICSEARCH5" ]]; then ./scripts/travis/install_elasticsearch5.sh; fi' + - 'if [[ -n "$INSTALL_ELASTICSEARCH6" ]]; then ./scripts/travis/install_elasticsearch6.sh; fi' + - 'if [[ -n "$INSTALL_ELASTICSEARCH7" ]]; then ./scripts/travis/install_elasticsearch7.sh; fi' # Pre-test configuration before_script: @@ -78,7 +84,7 @@ script: tox after_success: - - codecov + - codecov -F backend # Who to notify about build results notifications: diff --git a/.tx/config b/.tx/config index c609ef4c8b3..6bb20bb546e 100644 --- a/.tx/config +++ b/.tx/config @@ -1,5 +1,6 @@ [main] host = https://www.transifex.com +lang_map = zh_CN:zh_Hans, zh-Hant:zh_Hant [wagtail.wagtailadmin] file_filter = wagtail/admin/locale//LC_MESSAGES/django.po @@ -96,3 +97,4 @@ file_filter = wagtail/contrib/table_block/locale//LC_MESSAGES/django.po source_file = wagtail/contrib/table_block/locale/en/LC_MESSAGES/django.po source_lang = en type = PO + diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 57b2c501fd2..e1f6d6c5ee6 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -1,6 +1,439 @@ Changelog ========= +2.7.2 (14.04.2020) +~~~~~~~~~~~~~~~~~~ + + * Fix: CVE-2020-11001 - prevent XSS attack via page revision comparison view (Vlad Gerasimenko, Matt Westcott) + + +2.7.1 (08.01.2020) +~~~~~~~~~~~~~~~~~~ + + * Fix: Management command startup checks under `ManifestStaticFilesStorage` no longer fail if `collectstatic` has not been run first (Alex Tomkins) + + +2.7 LTS (06.11.2019) +~~~~~~~~~~~~~~~~~~~~ + + * Improved StreamField design (Bertrand Bordage) + * Added WebP image support (frmdstryr, Karl Hobley, Matt Westcott) + * Added Elasticsearch 7 support (pySilver) + * Added Python 3.8 support (John Carter, Matt Westcott) + * Added `construct_page_listing_buttons` hook (Michael van Tellingen) + * Added more detailed documentation and troubleshooting for installing OpenCV for feature detection (Daniele Procida) + * Added Table Block caption for accessibility (Rahmi Pruitt) + * Move and refactor upgrade notification JS (Jonny Scholes) + * Add ability to insert internal anchor links/links with fragment identifiers in Draftail (rich text) fields (Iman Syed) + * Remove need for Elasticsearch `update_all_types` workaround, upgrade minimum release to 6.4.0 or above (Jonathan Liuti) + * Add ability for users to change their own name via the account settings page (Kevin Howbrook) + * Add ability to insert telephone numbers as links in Draftail (rich text) fields (Mikael Engström and Liam Brenner) + * Increase delay before search in the snippet chooser, to prevent redundant search request round trips (Robert Rollins) + * Add `WAGTAIL_EMAIL_MANAGEMENT_ENABLED` setting to determine whether users can change their email address (Janne Alatalo) + * Recognise Soundcloud artist URLs as embeddable (Kiril Staikov) + * Add `WAGTAILDOCS_SERVE_METHOD` setting to determine how document downloads will be linked to and served (Tobias McNulty, Matt Westcott) + * Add `WAGTAIL_MODERATION_ENABLED` setting to enable / disable the 'Submit for Moderation' option (Jacob Topp-Mugglestone) + * Added settings to customise pagination page size for the Images admin area (Brian Whitton) + * Added ARIA role to TableBlock output (Matt Westcott) + * Added cache-busting query parameters to static files within the Wagtail admin (Matt Westcott) + * Allow `register_page_action_menu_item` and `construct_page_action_menu` hooks to override the default menu action (Rahmi Pruitt, Matt Westcott) + * `WAGTAILIMAGES_MAX_IMAGE_PIXELS` limit now takes the number of animation frames into account (Karl Hobley) + * Fix: Added line breaks to long filenames on multiple image / document uploader (Kevin Howbrook) + * Fix: Added https support for Scribd oEmbed provider (Rodrigo) + * Fix: Changed StreamField group labels color so labels are visible (Catherine Farman) + * Fix: Prevented images with a very wide aspect ratio from being displayed distorted in the rich text editor (Iman Syed) + * Fix: Prevent exception when deleting a model with a protected One-to-one relationship (Neal Todd) + * Fix: Added labels to snippet bulk edit checkboxes for screen reader users (Martey Dodoo) + * Fix: Middleware responses during page preview are now properly returned to the user (Matt Westcott) + * Fix: Default text of page links in rich text uses the public page title rather than the admin display title (Andy Chosak) + * Fix: Specific page permission checks are now enforced when viewing a page revision (Andy Chosak) + * Fix: `pageurl` and `slugurl` tags no longer fail when `request.site` is `None` (Samir Shah) + * Fix: Output form media on add/edit image forms with custom models (Matt Westcott) + * Fix: Output form media on add/edit document forms with custom models (Sergey Fedoseev) + * Fix: Layout for the clear checkbox in default FileField widget (Mikalai Radchuk) + * Fix: Remove ASCII conversion from Postgres search backend, to support stemming in non-Latin alphabets (Pavel Denisov) + * Fix: Prevent tab labels on page edit view from being cut off on very narrow screens (Kevin Howbrook) + * Fix: Very long words in page listings are now broken where necessary (Kevin Howbrook) + * Fix: Language chosen in user preferences no longer persists on subsequent requests (Bojan Mihelac) + * Fix: Prevent new block IDs from being assigned on repeated calls to `StreamBlock.get_prep_value` (Colin Klein) + * Fix: Prevent broken images in notification emails when static files are hosted on a remote domain (Eduard Luca) + * Fix: Replace styleguide example avatar with default image to avoid issues when custom user model is used (Matt Westcott) + * Fix: `DraftailRichTextArea` is no longer treated as a hidden field by Django's form logic (Sergey Fedoseev) + * Fix: Replace format() placeholders in translatable strings with % formatting (Matt Westcott) + * Fix: Altering Django REST Framework's `DEFAULT_AUTHENTICATION_CLASSES` setting no longer breaks the page explorer menu and admin API (Matt Westcott) + * Fix: Regression - missing label for external link URL field in link chooser (Stefani Castellanos) + + +2.6.3 (22.10.2019) +~~~~~~~~~~~~~~~~~~ + + * Fix: Altering Django REST Framework's `DEFAULT_AUTHENTICATION_CLASSES` setting no longer breaks the page explorer menu and admin API (Matt Westcott) + + +2.6.2 (19.09.2019) +~~~~~~~~~~~~~~~~~~ + + * Fix: Prevent search indexing failures on Postgres 9.4 and Django >= 2.2.1 (Matt Westcott) + + +2.6.1 (05.08.2019) +~~~~~~~~~~~~~~~~~~ + + * Fix: Prevent Javascript errors caused by unescaped quote characters in translation strings (Matt Westcott) + + +2.6 (01.08.2019) +~~~~~~~~~~~~~~~~ + + * Removed support for Python 3.4 + * Added support for `short_description` for field labels in modeladmin's `InspectView` (Wesley van Lee) + * Rearranged SCSS folder structure to the client folder and split them approximately according to ITCSS. (Naomi Morduch Toubman, Jonny Scholes, Janneke Janssen, Hugo van den Berg) + * Added support for specifying cell alignment on TableBlock (Samuel Mendes) + * Added more informative error when a non-image object is passed to the `image` template tag (Deniz Dogan) + * Added more ARIA landmarks across the admin interface and welcome page for screen reader users to navigate the CMS more easily (Beth Menzies) + * Added ButtonHelper examples in the modelAdmin primer page within documentation (Kalob Taulien) + * Multiple clarifications, grammar and typo fixes throughout documentation (Dan Swain) + * Use correct URL in API example in documentation (Michael Bunsen) + * Move datetime widget initialiser JS into the widget's form media instead of page editor media (Matt Westcott) + * Add form field prefixes for input forms in chooser modals (Matt Westcott) + * Increase font-size across the whole admin (Beth Menzies, Katie Locke) + * Improved text color contrast across the whole admin (Beth Menzies, Katie Locke) + * Added consistent focus outline styles across the whole admin (Thibaud Colas) + * Removed version number from the logo link’s title. The version can now be found under the Settings menu (Thibaud Colas) + * Added "don't delete" option to confirmation screen when deleting images, documents and modeladmin models (Kevin Howbrook) + * Added `branding_title` template block for the admin title prefix (Dillen Meijboom) + * Add image dimensions in image gallery and image choosers for screen reader users (Helen Chapman) + * Added support for custom search handler classes to modeladmin's IndexView, and added a class that uses the default Wagtail search backend for searching (Seb Brown, Andy Babic) + * Improved heading structure for screen reader users navigating the CMS admin (Beth Menzies, Helen Chapman) + * Updated group edit view to expose the Permission object for each checkbox (George Hickman) + * Improve performance of Pages for Moderation panel (Fidel Ramos) + * Add more contextual information for screen readers in the explorer menu’s links (Helen Chapman) + * Added `process_child_object` and `exclude_fields` arguments to ``Page.copy()`` to make it easier for third-party apps to customise copy behavior (Karl Hobley) + * Added `Page.with_content_json()`, allowing revision content loading behaviour to be customised on a per-model basis (Karl Hobley) + * Improved screen-reader labels for action links in page listing (Helen Chapman, Katie Locke) + * Added screen-reader labels for table headings in page listing (Helen Chapman, Katie Locke) + * Added screen reader labels for page privacy toggle, edit lock, status tag in page explorer & edit views (Helen Chapman, Katie Locke) + * Added screen-reader labels for dashboard summary cards (Helen Chapman, Katie Locke) + * Added screen-reader labels for privacy toggle of collections (Helen Chapman, Katie Locke) + * Added `construct_settings_menu` hook (Jordan Bauer, Quadric) + * Fixed compatibility of date / time choosers with wagtail-react-streamfield (Mike Hearn) + * Performance optimization of several admin functions, including breadcrumbs, home and index pages (Fidel Ramos) + * Fix: ModelAdmin no longer fails when filtering over a foreign key relation (Jason Dilworth, Matt Westcott) + * Fix: The Wagtail version number is now visible within the Settings menu (Kevin Howbrook) + * Fix: Scaling images now rounds values to an integer so that images render without errors (Adrian Brunyate) + * Fix: Revised test decorator to ensure TestPageEditHandlers test cases run correctly (Alex Tomkins) + * Fix: Wagtail bird animation in admin now ends correctly on all browsers (Deniz Dogan) + * Fix: Explorer menu no longer shows sibling pages for which the user does not have access (Mike Hearn) + * Fix: Fixed occurences of invalid HTML across the CMS admin (Thibaud Colas) + * Fix: Admin HTML now includes the correct `dir` attribute for the active language (Andreas Bernacca) + * Fix: Fix type error when using `--chunk_size` argument on `./manage.py update_index` (Seb Brown) + * Fix: Avoid rendering entire form in EditHandler's `repr` method (Alex Tomkins) + * Fix: Add empty alt attributes to HTML output of Embedly and oEmbed embed finders (Andreas Bernacca) + * Fix: Add empty alt attributes to all images in the CMS admin (Andreas Bernacca) + * Fix: Make URL generator preview image alt translateable (Thibaud Colas) + * Fix: Clear pending AJAX request if error occurs on page chooser (Matt Westcott) + * Fix: Prevent text from overlapping in focal point editing UI (Beth Menzies) + * Fix: Screen readers now announce "Dashboard" for the main nav’s logo link instead of Wagtail’s version number (Thibaud Colas) + * Fix: Screen readers now treat page-level action dropdowns as navigation instead of menus (Helen Chapman) + * Fix: Make icon font implementation more screen-reader-friendly (Thibaud Colas) + * Fix: Remove duplicate labels in image gallery and image choosers for screen reader users (Helen Chapman) + * Fix: Restore custom "Date" icon for scheduled publishing panel in Edit page’s Settings tab (Helen Chapman) + * Fix: Added missing form media to user edit form template (Matt Westcott) + * Fix: Add a label to the modals’ “close” button for screen reader users (Helen Chapman, Katie Locke) + * Fix: Ensure the 'add child page' button displays when focused (Helen Chapman, Katie Locke) + * Fix: Remove tab order customisations in CMS admin (Jordan Bauer) + * Fix: Add labels to permission checkboxes for screen reader users (Helen Chapman, Katie Locke) + * Fix: Page.copy() no longer copies child objects when the accesssor name is included in `exclude_fields_in_copy` (Karl Hobley) + * Fix: Move focus to the pages explorer menu when open (Helen Chapman) + * Fix: Clicking the privacy toggle while the page is still loading no longer loads the wrong data in the page (Helen Chapman) + * Fix: Added missing `is_stored_locally` method to `AbstractDocument` (jonny5532) + * Fix: Query model no longer removes punctuation as part of string normalisation (William Blackie) + * Fix: Make login test helper work with user models with non-default username fields (Andrew Miller) + * Fix: Delay dirty form check to prevent "unsaved changes" warning from being wrongly triggered (Thibaud Colas) + + +2.5.2 (01.08.2019) +~~~~~~~~~~~~~~~~~~ + + * Fix: Delay dirty form check to prevent "unsaved changes" warning from being wrongly triggered (Thibaud Colas) + + +2.5.1 (07.05.2019) +~~~~~~~~~~~~~~~~~~ + + * Fix: Prevent crash when comparing StructBlocks in revision history (Adrian Turjak, Matt Westcott) + + +2.5 (24.04.2019) +~~~~~~~~~~~~~~~~ + + * Django 2.2 support (Matt Westcott, Andy Babic) + * Added support for customising EditHandler-based forms on a per-request basis (Bertrand Bordage) + * Added more informative error message when `|richtext` filter is applied to a non-string value (mukesh5) + * Automatic search indexing can now be disabled on a per-model basis via the `search_auto_update` attribute (Karl Hobley) + * Improved diffing of StreamFields when comparing page revisions (Karl Hobley) + * Highlight broken links to pages and missing documents in rich text (Brady Moe) + * Preserve links when copy-pasting rich text content from Wagtail to other tools (Thibaud Colas) + * Rich text to contentstate conversion now prioritises more specific rules, to accommodate `

` and `
` elements with attributes (Matt Westcott) + * Added limit image upload size by number of pixels (Thomas Elliott) + * Added `manage.py wagtail_update_index` alias to avoid clashes with `update_index` commands from other packages (Matt Westcott) + * Renamed `target_model` argument on `PageChooserBlock` to `page_type` (Loic Teixeira) + * `edit_handler` and `panels` can now be defined on a `ModelAdmin` definition (Thomas Kremmel) + * Add Learn Wagtail to third-party tutorials in documentation (Matt Westcott) + * Add a Django setting `TAG_LIMIT` to limit number of tags that can be added to any taggit model (Mani) + * Added instructions on how to generate urls for `ModelAdmin` to documentation (LB (Ben Johnston), Andy Babic) + * Added option to specify a fallback URL on `{% pageurl %}` (Arthur Holzner) + * Add support for more rich text formats, disabled by default: `blockquote`, `superscript`, `subscript`, `strikethrough`, `code` (Md Arifin Ibne Matin) + * Added `max_count_per_parent` option on page models to limit the number of pages of a given type that can be created under one parent page (Wesley van Lee) + * `StreamField` field blocks now accept a `validators` argument (Tom Usher) + * Added edit / delete buttons to snippet index and "don't delete" option to confirmation screen, for consistency with pages (Kevin Howbrook) + * Added support for Markdown shortcuts for inline formatting in rich text editor, e.g. `**` for bold, `_` for italic, etc. (Thibaud Colas) + * Added name attributes to all built-in page action menu items (LB (Ben Johnston)) + * Added validation on the filter string to the Jinja2 image template tag (Jonny Scholes) + * Changed the pages reordering UI toggle to make it easier to find (Katie Locke, Thibaud Colas) + * Added support for rich text link rewrite handlers for `external` and `email` links (Md Arifin Ibne Matin) + * Clarify installation instructions in documentation, especially regarding virtual environments. (Naomi Morduch Toubman) + * Fix: Set `SERVER_PORT` to 443 in `Page.dummy_request()` for HTTPS sites (Sergey Fedoseev) + * Fix: Include port number in `Host` header of `Page.dummy_request()` (Sergey Fedoseev) + * Fix: Validation error messages in `InlinePanel` no longer count towards `max_num` when disabling the 'add' button (Todd Dembrey, Thibaud Colas) + * Fix: Rich text to contentstate conversion now ignores stray closing tags (frmdstryr) + * Fix: Escape backslashes in `postgres_search` queries (Hammy Goonan) + * Fix: Parent page link in page chooser search results no longer navigates away (Asanka Lihiniyagoda, Sævar Öfjörð Magnússon) + * Fix: `routablepageurl` tag now correctly omits domain part when multiple sites exist at the same root (Gassan Gousseinov) + * Fix: Added missing collection column specifier on document listing template (Sergey Fedoseev) + * Fix: Page Copy will now also copy ParentalManyToMany field relations (LB (Ben Johnston)) + * Fix: Admin HTML header now includes correct language code (Matt Westcott) + * Fix: Unclear error message when saving image after focal point edit (Hugo van den Berg) + * Fix: `send_mail` now correctly uses the `html_message` kwarg for HTML messages (Tiago Requeijo) + * Fix: Page copying no longer allowed if page model has reached its `max_count` (Andy Babic) + * Fix: Don't show page type on page chooser button when multiple types are allowed (Thijs Kramer) + * Fix: Make sure page chooser search results correspond to the latest search by canceling previous requests (Esper Kuijs) + * Fix: Inform user when moving a page from one parent to another where there is an already existing page with the same slug (Casper Timmers) + * Fix: User add/edit forms now support form widgets with JS/CSS media (Damian Grinwis) + * Fix: Rich text processing now preserves non-breaking spaces instead of converting them to normal spaces (Wesley van Lee) + * Fix: Prevent autocomplete dropdowns from appearing over date choosers on Chrome (Kevin Howbrook) + * Fix: Prevent crash when logging HTTP errors from Cloudflare (Kevin Howbrook) + * Fix: Prevent rich text editor crash when filtering copy-pasted content and the last block is to be removed, e.g. unsupported image (Thibaud Colas) + * Fix: Removing rich text links / documents now also works when the text selection is backwards (Thibaud Colas) + * Fix: Prevent the rich text editor from crashing when copy-paste filtering removes all of its content (Thibaud Colas) + * Fix: Page chooser now respects custom `get_admin_display_title` methods on parent page and breadcrumb (Haydn Greatnews) + * Fix: Added consistent whitespace around sortable table headings (Matt Westcott) + * Fix: Moved locale names for Chinese (Simplified) and Chinese (Traditional) to `zh_Hans` and `zh_Hant` (Matt Westcott) + * Fix: Increase max length on `Embed.thumbnail_url` to 255 characters (Kevin Howbrook) + + +2.4 (19.12.2018) +~~~~~~~~~~~~~~~~ + + * Added support for Python 3.7 (Matt Westcott) + * Added `max_count` option on page models to limit the number of pages of a particular type that can be created (Dan Braghis) + * Document and image choosers now show the document / image's collection (Alejandro Garza, Janneke Janssen) + * Added new "Welcome to your Wagtail site" Starter Page when using wagtail start command (Timothy Allen, Scott Cranfill) + * Added ability to run individual tests through tox (Benjamin Bach) + * Collection listings are now ordered by name (Seb Brown) + * Added `file_hash` field to documents (Karl Hobley, Dan Braghis) + * Added last login to the user overview (Noah B Johnson) + * Changed design of image editing page (Janneke Janssen, Ben Enright) + * Added Slovak character map for JavaScript slug generation (Andy Chosak) + * Make documentation links on welcome page work for prereleases (Matt Westcott) + * Allow overridden `copy()` methods in `Page` subclasses to be called from the page copy view (Robert Rollins) + * Users without a preferred language set on their profile now use language selected by Django's `LocaleMiddleware` (Benjamin Bach) + * Added hooks to customise the actions menu on the page create/edit views (Matt Westcott) + * Cleanup: Use `functools.partial()` instead of `django.utils.functional.curry()` (Sergey Fedoseev) + * Squashed migrations for wagtailimages (Karl Hobley) + * Added `before_move_page` and `after_move_page` hooks (Maylon Pedroso) + * Bulk deletion button for snippets is now hidden until items are selected (Karl Hobley) + * Fix: Query objects returned from `PageQuerySet.type_q` can now be merged with `|` (Brady Moe) + * Fix: Add `rel="noopener noreferrer"` to target blank links (Anselm Bradford) + * Fix: Additional fields on custom document models now show on the multiple document upload view (Robert Rollins, Sergey Fedoseev) + * Fix: Help text is partially hidden when using a combination of BooleanField and FieldPanel in page model (Dzianis Sheka) + * Fix: Allow custom logos of any height in the admin menu (Meteor0id) + * Fix: Allow nav menu to take up all available space instead of scrolling (Meteor0id) + * Fix: Redirects now return 404 when destination is unspecified or a page with no site (Hillary Jeffrey) + * Fix: Refactor all breakpoint definitions, removing style overlaps (Janneke Janssen) + * Fix: Updated draftjs_exporter to 2.1.5 to fix bug in handling adjacent entities (Thibaud Colas) + * Fix: Page titles consisting only of stopwords now generate a non-empty default slug (Andy Chosak, Janneke Janssen) + * Fix: Sitemap generator now allows passing a sitemap instance in the URL configuration (Mitchel Cabuloy, Dan Braghis) + + +2.3 LTS (23.10.2018) +~~~~~~~~~~~~~~~~~~~~ + + * Added support for Django 2.1 (Ryan Verner, Matt Westcott) + * Improved colour contrast (Coen van der Kamp, Naomi Morduch Toubman, Naa Marteki Reed, Edd Baldry, Ben Enright) + * Added 'scale' image filter (Oliver Wilkerson) + * Added meta tag to prevent search engines from indexing admin pages (Karl Hobley) + * EmbedBlock now validates against recognised embed providers on save (Bertrand Bordage) + * Made cache control headers on Wagtail admin consistent with Django admin (Tomasz Knapik) + * Notification emails now include an "Auto-Submitted: auto-generated" header (Dan Braghis) + * Image chooser panels now show alt text as title (Samir Shah) + * Added `download_url` field to images in the API (Michael Harrison) + * Dummy requests for preview now preserve the HTTP Authorization header (Ben Dickinson) + * Fix: Respect next param on login (Loic Teixeira) + * Fix: InlinePanel now handles relations that specify a related_query_name (Aram Dulyan) + * Fix: before_delete_page / after_delete_page hooks now run within the same database transaction as the page deletion (Tomasz Knapik) + * Fix: Snippet chooser modal no longer fails on snippet models with UUID primary keys (Sævar Öfjörð Magnússon) + * Fix: Restored localisation in date/time pickers (David Moore, Thibaud Colas) + * Fix: Tag input field no longer treats 'б' on Russian keyboards as a comma (Michael Borisov) + * Fix: Disabled autocomplete dropdowns on date/time chooser fields (Janneke Janssen) + * Fix: Split up `wagtail.admin.forms` to make it less prone to circular imports (Matt Westcott) + * Fix: Disable linking to root page in rich text, making the page non-functional (Matt Westcott) + * Fix: Pages should be editable and save-able even if there are broken page or document links in rich text (Matt Westcott) + * Fix: Avoid redundant round-trips of JSON StreamField data on save, improving performance and preventing consistency issues on fixture loading (Andy Chosak, Matt Westcott) + * Fix: Users are not logged out when changing their own password through the Users area (Matt Westcott) + + +2.2.2 (29.08.2018) +~~~~~~~~~~~~~~~~~~ + + * Fix: Seek to the beginning of image files when uploading, to restore compatibility with django-storages Google Cloud and Azure backends (Mikalai Radchuk) + * Fix: Respect next param on login (Loic Teixeira) + + +2.2.1 (13.08.2018) +~~~~~~~~~~~~~~~~~~ + + * Fix: Pin Beautiful Soup to 4.6.0 due to further regressions in formatting empty elements (Matt Westcott) + * Fix: Prevent AppRegistryNotReady error when wagtail.contrib.sitemaps is in INSTALLED_APPS (Matt Westcott) + + +2.2 (10.08.2018) +~~~~~~~~~~~~~~~~ + + * Added faceted search using the `.facet()` method (Karl Hobley) + * Added page type filtering and ordering to the Wagtail admin page search (Karl Hobley) + * Added another valid AudioBoom oEmbed pattern (Bertrand Bordage) + * Added `annotate_score` support to PostgreSQL search backend (Bertrand Bordage) + * Pillow's image optimisation is now applied when saving PNG images (Dmitry Vasilev) + * JS / CSS media files can now be associated with Draftail feature definitions (Matt Westcott) + * The `{% slugurl %}` template tag is now site-aware (Samir Shah) + * Added `file_size` field to documents (Karl Hobley) + * Added `file_hash` field to images (Karl Hobley) + * Update documentation (configuring Django for Wagtail) to contain all current settings options (Matt Westcott, LB (Ben Johnston)) + * Added `defer` flag to `PageQuerySet.specific` (Karl Hobley) + * Snippets can now be deleted from the listing view (LB (Ben Johnston)) + * Increased max length of redirect URL field to 255 (Michael Harrison) + * Added documentation for new JS/CSS media files association with Draftail feature definitions (Ed Henderson) + * Added accessible colour contrast guidelines to the style guide (Catherine Farman) + * Admin modal views no longer rely on Javascript `eval()`, for better CSP compliance (Matt Westcott) + * Update editor guide for embeds and documents in rich text (Kevin Howbrook) + * Improved performance of sitemap generation (Michael van Tellingen, Bertrand Bordage) + * Added an internal API for autocomplete (Karl Hobley, Bertrand Bordage) + * Fix: Handle all exceptions from `Image.get_file_size` (Andrew Plummer) + * Fix: Fix display of breadcrumbs in ModelAdmin (LB (Ben Johnston)) + * Fix: Remove duplicate border radius of avatars (Benjamin Thurm) + * Fix: Site.get_site_root_paths() preferring other sites over the default when some sites share the same root_page (Andy Babic) + * Fix: Pages with missing model definitions no longer crash the API (Abdulmalik Abdulwahab) + * Fix: Rich text image chooser no longer skips format selection after a validation error (Matt Westcott) + * Fix: Null characters in URLs no longer crash the redirect middleware on PostgreSQL (Andrew Crewdson, Matt Westcott) + * Fix: Permission checks no longer prevent a non-live page from being unscheduled (Abdulmalik Abdulwahab) + * Fix: Copy-paste between Draftail editors now preserves all formatting/content (Thibaud Colas) + * Fix: Fix alignment of checkboxes and radio buttons on Firefox (Matt Westcott) + + +2.1.3 (13.08.2018) +~~~~~~~~~~~~~~~~~~ + + * Fix: Pin Beautiful Soup to 4.6.0 due to further regressions in formatting empty elements (Matt Westcott) + + +2.1.2 (06.08.2018) +~~~~~~~~~~~~~~~~~~ + + * Fix: Bundle the l18n package to avoid installation issues on systems with a non-Unicode locale (Matt Westcott) + * Fix: Mark Beautiful Soup 4.6.1 as incompatible due to bug in formatting empty elements (Matt Westcott) + + +2.1.1 (04.07.2018) +~~~~~~~~~~~~~~~~~~ + + * Fix: Site.get_site_root_paths() preferring other sites over the default when some sites share the same root_page (Andy Babic) + * Fix: Rich text image chooser no longer skips format selection after a validation error (Matt Westcott) + * Fix: Null characters in URLs no longer crash the redirect middleware on PostgreSQL (Matt Westcott) + + +2.1 (22.05.2018) +~~~~~~~~~~~~~~~~ + + * Add `HelpPanel` to add HTML within an edit form (Keving Chung) + * Added direct profile picture upload to account preferences (Daniel Chimeno, Pierre Geier, Matt Westcott) + * Added API endpoint for finding pages by HTML path (Karl Hobley) + * Added time zone setting to account preferences (David Moore) + * Added Elasticsearch 6 support (Karl Hobley) + * Persist tab hash in URL to allow direct navigation to tabs in the admin interface (Ben Weatherman) + * Animate the chevron icon when opening sub-menus in the admin (Carlo Ascani) + * Look through the target link and target page slug (in addition to the old slug) when searching for redirects in the admin (Michael Harrison) + * Remove support for IE6 to IE9 from project template (Samir Shah) + * Remove outdated X-UA-Compatible meta from admin template (Thibaud Colas) + * Add JavaScript source maps in production build for packaged Wagtail (Thibaud Colas) + * Removed `assert` statements from Wagtail API (Kim Chee Leong) + * Update `jquery-datetimepicker` dependency to make Wagtail more CSP-friendly (`unsafe-eval`) (Pomax) + * Added error notification when running the `wagtail` command on Python <3.4 (Matt Westcott) + * `update_index` management command now accepts a `--chunk_size` option to determine the number of items to load at once (Dave Bell) + * Added hook `register_account_menu_item` to add new account preference items (Michael van Tellingen) + * Added change email functionality from the account settings (Alejandro Garza, Alexs Mathilda) + * Add request parameter to edit handlers (Rajeev J Sebastian) + * ImageChooser now sets a default title based on filename (Coen van der Kamp) + * Added error handling to the Draftail editor (Thibaud Colas) + * Add new `wagtail_icon` template tag to facilitate making admin icons accessible (Sander Tuit) + * Set `ALLOWED_HOSTS` in the project template to allow any host in development (Tom Dyson) + * Expose reusable client-side code to build Draftail extensions (Thibaud Colas) + * Added `WAGTAILFRONTENDCACHE_LANGUAGES` setting to specify the languages whose URLs are to be purged when using `i18n_patterns` (PyMan Claudio Marinozzi) + * Added `extra_footer_actions` template blocks for customising the add/edit page views (Arthur Holzner) + * Fix: Status button on 'edit page' now links to the correct URL when live and draft slug differ (LB (Ben Johnston)) + * Fix: Image title text in the gallery and in the chooser now wraps for long filenames (LB (Ben Johnston), Luiz Boaretto) + * Fix: Move image editor action buttons to the bottom of the form on mobile (Julian Gallo) + * Fix: StreamField icons are now correctly sorted into groups on the 'append' menu (Tim Heap) + * Fix: Draftail now supports features specified via the `WAGTAILADMIN_RICH_TEXT_EDITORS` setting (Todd Dembrey) + * Fix: Password reset form no longer indicates whether the email is recognised, as per standard Django behaviour (Bertrand Bordage) + * Fix: `UserAttributeSimilarityValidator` is now correctly enforced on user creation / editing forms (Tim Heap) + * Fix: Focal area removal not working in IE11 and MS Edge (Thibaud Colas) + * Fix: Rewrite password change feedback message to be more user-friendly (Casper Timmers) + * Fix: Correct dropdown arrow styling in Firefox, IE11 (Janneke Janssen, Alexs Mathilda) + * Fix: Password reset no indicates specific validation errors on certain password restrictions (Lucas Moeskops) + * Fix: Confirmation page on page deletion now respects custom `get_admin_display_title` methods (Kim Chee Leong) + * Fix: Adding external link with selected text now includes text in link chooser (Tony Yates, Thibaud Colas, Alexs Mathilda) + * Fix: Editing setting object with no site configured no longer crashes (Harm Zeinstra) + * Fix: Creating a new object with inlines while mandatory fields are empty no longer crashes (Bertrand Bordage) + * Fix: Localization of image and apps verbose names + * Fix: Draftail editor no longer crashes after deleting image/embed using DEL key (Thibaud Colas) + * Fix: Breadcrumb navigation now respects custom `get_admin_display_title` methods (Arthur Holzner, Wietze Helmantel, Matt Westcott) + * Fix: Inconsistent order of heading features when adding h1, h5 or h6 as default feature for Hallo RichText editor (Loic Teixeira) + * Fix: Add invalid password reset link error message (Coen van der Kamp) + * Fix: Bypass select/prefetch related optimisation on `update_index` for `ParentalManyToManyField` to fix crash (Tim Kamanin) + * Fix: 'Add user' is now rendered as a button due to the use of quotes within translations (Benoît Vogel) + * Fix: Menu icon no longer overlaps with title in Modeladmin on mobile (Coen van der Kamp) + * Fix: Background color overflow within the Wagtail documentation (Sergey Fedoseev) + * Fix: Page count on homepage summary panel now takes account of user permissions (Andy Chosak) + * Fix: Explorer view now prevents navigating outside of the common ancestor of the user's permissions (Andy Chosak) + * Fix: Generate URL for the current site when multiple sites share the same root page (Codie Roelf) + * Fix: Restored ability to use non-model fields with FieldPanel (Matt Westcott, LB (Ben Johnston)) + * Fix: Stop revision comparison view from crashing when non-model FieldPanels are in use (LB (Ben Johnston)) + * Fix: Ordering in the page explorer now respects custom `get_admin_display_title` methods when sorting <100 pages (Matt Westcott) + * Fix: Use index-specific Elasticsearch endpoints for bulk insertion, for compatibility with providers that lock down the root endpoint (Karl Hobley) + * Fix: Fix usage URL on the document edit page (Jérôme Lebleu) + + +2.0.2 (13.08.2018) +~~~~~~~~~~~~~~~~~~ + + * Fix: Restored ability to use non-model fields with FieldPanel (Matt Westcott, LB (Ben Johnston)) + * Fix: Fix usage URL on the document edit page (Jérôme Lebleu) + * Fix: Pin Beautiful Soup to 4.6.0 due to further regressions in formatting empty elements (Matt Westcott) + + +2.0.1 (04.04.2018) +~~~~~~~~~~~~~~~~~~ + + * Added error notification when running the `wagtail` command on Python <3.4 (Matt Westcott) + * Added error handling to the Draftail editor (Thibaud Colas) + * Fix: Draftail now supports features specified via the `WAGTAILADMIN_RICH_TEXT_EDITORS` setting (Todd Dembrey) + * Fix: Password reset form no longer indicates whether the email is recognised, as per standard Django behaviour (Bertrand Bordage) + * Fix: `UserAttributeSimilarityValidator` is now correctly enforced on user creation / editing forms (Tim Heap) + * Fix: Editing setting object with no site configured no longer crashes (Harm Zeinstra) + * Fix: Creating a new object with inlines while mandatory fields are empty no longer crashes (Bertrand Bordage) + + 2.0 (28.02.2018) ~~~~~~~~~~~~~~~~ @@ -79,6 +512,28 @@ Changelog * Fix: Prevent style leak of Wagtail panel icons in widgets using ``h2`` elements (THibaud Colas) +1.13.4 (13.08.2018) +~~~~~~~~~~~~~~~~~~~ + + * Fix: Pin Beautiful Soup to 4.6.0 due to further regressions in formatting empty elements (Matt Westcott) + + +1.13.3 (13.08.2018) +~~~~~~~~~~~~~~~~~~~ + + * Fix: Pin django-taggit to <0.23 to restore Django 1.8 compatibility (Matt Westcott) + * Fix: Mark Beautiful Soup 4.6.1 as incompatible due to bug in formatting empty elements (Matt Westcott) + + +1.13.2 (04.07.2018) +~~~~~~~~~~~~~~~~~~~ + + * Fix: Fix support of `ATOMIC_REBUILD` for projects with Elasticsearch client >=1.7.0 (Mikalai Radchuk) + * Fix: Logging an indexing failure on an object with a non-ASCII representation no longer crashes on Python 2 (Aram Dulyan) + * Fix: Rich text image chooser no longer skips format selection after a validation error (Matt Westcott) + * Fix: Null characters in URLs no longer crash the redirect middleware on PostgreSQL (Matt Westcott) + + 1.13.1 (17.11.2017) ~~~~~~~~~~~~~~~~~~~ @@ -91,8 +546,8 @@ Changelog * Fix: Prevented intermittent failures on Postgres search backend when a field is defined as both a `SearchField` and a `FilterField` (Matt Westcott) -1.13 (16.10.2017) -~~~~~~~~~~~~~~~~~ +1.13 LTS (16.10.2017) +~~~~~~~~~~~~~~~~~~~~~ * Front-end cache invalidator now supports purging URLs as a batch (Karl Hobley) * Custom document model is now documented (Emily Horsman) @@ -123,6 +578,28 @@ Changelog * Fix: API listing views no longer fail when no site records are defined (Karl Hobley) +1.12.6 (13.08.2018) +~~~~~~~~~~~~~~~~~~~ + + * Fix: Pin Beautiful Soup to 4.6.0 due to further regressions in formatting empty elements (Matt Westcott) + + +1.12.5 (13.08.2018) +~~~~~~~~~~~~~~~~~~~ + + * Fix: Pin django-taggit to <0.23 to restore Django 1.8 compatibility (Matt Westcott) + * Fix: Mark Beautiful Soup 4.6.1 as incompatible due to bug in formatting empty elements (Matt Westcott) + + +1.12.4 (04.07.2018) +~~~~~~~~~~~~~~~~~~~ + + * Fix: Fix support of `ATOMIC_REBUILD` for projects with Elasticsearch client >=1.7.0 (Mikalai Radchuk) + * Fix: Logging an indexing failure on an object with a non-ASCII representation no longer crashes on Python 2 (Aram Dulyan) + * Fix: Rich text image chooser no longer skips format selection after a validation error (Matt Westcott) + * Fix: Null characters in URLs no longer crash the redirect middleware on PostgreSQL (Matt Westcott) + + 1.12.3 (17.11.2017) ~~~~~~~~~~~~~~~~~~~ diff --git a/CONTRIBUTORS.rst b/CONTRIBUTORS.rst index a90db2ce2d8..cbd4635f26d 100644 --- a/CONTRIBUTORS.rst +++ b/CONTRIBUTORS.rst @@ -4,17 +4,29 @@ Core team * Matthew Westcott (Torchbox) * Karl Hobley (Torchbox) * Tom Dyson (Torchbox) -* Mikalai Radchuk (Torchbox) -* Thibaud Colas (Springload) +* Thibaud Colas (Torchbox) * Janneke Janssen (Lukkien) * Mike Dingjan (Lab Digital) -* Rob Moorman (Moor Interactive) * Bertrand Bordage (NoriPyt) -* Emily Horsman (Little Weaver) * Loïc Teixeira (Springload) * Andy Chosak (consumerfinance.gov) * Will Barton (consumerfinance.gov) * LB Johnston +* Coen van der Kamp (Four Digits) +* Codie Roelf (Praekelt) +* Lisa Adams (Praekelt) +* Naomi Morduch Toubman +* Kalob Taulien +* Jonny Scholes (Neon Jungle) +* Andy Babic (Torchbox) +* Dan Braghis (Torchbox) + +Core team alumni +================ + +* Josh Barr +* Tim Heap +* Mikalai Radchuk Contributors ============ @@ -40,7 +52,6 @@ Contributors * Tom Talbot * Jeffrey Hearn * Robert Clark -* Tim Heap * Nathan Brizendine * Gordon Pendleton * John-Scott Atlakson @@ -83,7 +94,6 @@ Contributors * Alex Gleason * Ryan Pineo * Petr Vacha -* Josh Barr * Sævar Öfjörð Magnússon * Ashia Zawaduk * Denis Voskvitsov @@ -123,12 +133,12 @@ Contributors * Nicolas Kuttler * Juha Kujala * Eirik Krogstad +* Rob Moorman * Matthijs Melissen * Jonas Lergell * Danielle Madeley * Roel Bruggink * Yannick Chabbert -* Andy Babic * Tomas Olander * Andrew Tork Baker * Vincent Audebert @@ -146,7 +156,6 @@ Contributors * Stephen Rice * Behzad Nategh * Yann Fouillat (Gagaro) -* Jonny Scholev * Richard McMillan * Johannes Spielmann * Franklin Kingma @@ -246,12 +255,13 @@ Contributors * Lucas Moeskops * Rob van der Linde * Paul Kamp -* dwasyl +* David Wasylciw * Eugene Morozov * Levi Adler * Edwar Baron * Tomasz Knapik * Venelin Stoykov +* Emily Horsman * jcronyn * Ben Sturmfels * Anselm Bradford @@ -269,55 +279,197 @@ Contributors * Bruno Alla * Christopher Bledsoe (The Motley Fool) * Florent Osmont +* J Rob Gant * Mary Kate Fain * Dário Marcelino +* Dave Bell +* Ben Weatherman +* Carlo Ascani +* Julian Gallo * Dan Dietz +* Michael Harrison +* Todd Dembrey +* Sebastian Brestin +* Casper Timmers +* Kevin Chung +* Kim Chee Leong +* Dan Swain +* Alexs Mathilda +* Tony Yates +* Pomax +* Arthur Holzner +* Alejandro Garza +* Rajeev J Sebastian +* Sander Tuit +* Tim Kamanin +* Sergey Fedoseev +* Harm Zeinstra +* David Moore +* Pierre Geier +* Jérôme Lebleu +* Victor Miti +* Andrew Plummer +* Dmitry Vasilev +* Benjamin Thurm +* Ed Henderson +* Strother Scott +* Daniele Procida +* Catherine Farman +* Abdulmalik Abdulwahab +* Andrew Crewdson +* Aram Dulyan +* Kevin Howbrook +* Ryan Verner +* Oliver Wilkerson +* Matthew Schinckel +* Michael Borisov +* Dan Braghis +* Ben Dickinson +* Meteor0id +* Naa Marteki Reed +* Jorge Barata +* Brady Moe +* Yi Huang +* Stas Rudakou +* Abdulaziz Alfuhigi +* Dzianis Sheka +* Scott Cranfill +* gmmoraes +* Justin Focus +* Fedor Selitsky +* Seb Brown +* Noah B Johnson +* Hillary Jeffrey +* Nick Travis +* Maylon Pedroso +* Thijs Walcarius +* mukesh5 +* frmdstryr +* Aidarbek Suleimenov +* Matthew Linares +* Asanka Lihiniyagoda +* David Beitey +* Paul Vetch +* Vladimir Knobel +* Matt Collins +* Thomas Elliott +* damianosSemmle +* Evan Winter +* Neil Lyons +* Gassan Gousseinov +* Thomas Kremmel +* patta42 +* Esper Kuijs +* Damian Grinwis +* Wesley van Lee +* Md Arifin Ibne Matin +* Tom Usher +* Haydn Greatnews +* Katie Locke +* Cassidy Brooke +* dthompson86 +* Jason Dilworth +* Deniz Dogan +* Po-Chuan Hsieh +* scil +* Mike Hearn +* Samuel Mendes +* Adam Eikman +* Andreas Bernacca +* Alex Tomkins +* Beth Menzies +* Michael Bunsen +* Dillen Meijboom +* George Hickman +* Eric Dyken +* Jordan Bauer +* Fidel Ramos +* Quadric +* jonny5532 +* William Blackie +* Andrew Miller +* Rodrigo +* Iman Syed +* John Carter +* Jonathan Liuti +* Rahmi Pruitt +* Sanyam Khurana +* Pavel Denisov +* Mikael Engström +* Zac Connelly +* Sarath Kumar Somana +* Dani Hodovic +* Janne Alatalo +* Colin Klein +* Eduard Luca +* Kiril Staikov +* Saptak Sengupta +* Dawid Bugajewski +* Dawn Wages +* Jacob Topp-Mugglestone +* Brian Whitton +* Tim White +* Mike Janger +* Prithvi MK +* pySilver +* a-mere-peasant +* David T Thompson +* kailwallin +* ryanomor +* Thijs Baaijen +* Stefani Castellanos +* Vlad Gerasimenko Translators =========== -* Afrikaans: Jaco du Plessis -* Arabic: alfuhigi, Roger Allen, Ahmad Kiswani, Mohamed Mayla +* Afrikaans: Jaco du Plessis, Jared Osborn +* Arabic: Abdulaziz Alfuhigi, Roger Allen, Khaled Arnaout, Mohammed Abdul Gadir, Ahmad Kiswani, Mohamed Mayla, Ultraify Media +* Armenian: Vachagan * Basque: Unai Zalakain +* Belarusian: Stas Rudakou, Tatsiana Tsygan * Bulgarian: Lyuboslav Petrov +* Burmese: ime11 * Catalan: Antoni Aloy, David Llop, Roger Pons -* Chinese: hanfeng, Lihan Li, Leway Colin, Orangle Liu -* Chinese (China): hanfeng, Daniel Hwang, Jian Li, Listeng Teng, Feng Wang, Fred Zeng, Joey Zhao, Vincent Zhao, zhushajun -* Chinese (Taiwan): gogobook, Lihan Li, Jp Shieh -* Croatian (Croatia): Luka Matijević -* Czech: Ales Dvorak, Martin Galda, Sophy O, Ivan Pomykacz, Jiri Stepanek, Marek Turnovec, Stanislav Vasko -* Danish: Asger Sørensen +* Chinese: hanfeng, Lihan Li, Leway Colin, Orangle Liu, shengsheng gz +* Chinese (Simplified): Ed, hanfeng, Yi Huang, Daniel Hwang, Jian Li, Aosp T, Listeng Teng, Feng Wang, whuim, Fred Zeng, Joey Zhao, Vincent Zhao, zhushajun +* Chinese (Traditional): c o, gogobook, Lihan Li, Jp Shieh, Yeh Yen-Ke +* Croatian (Croatia): Ivica Dosen, Luka Matijević +* Czech: Ales Dvorak, Martin Galda, IT Management, Eva Mikesova, Mořeplavec, Sophy O, Martina Oleksakova, Ivan Pomykacz, Jiri Stepanek, Marek Turnovec, Mirek Zvolský +* Danish: Mads Kronborg, MRostgaard, Asger Sørensen * Dutch: benny_AT_it_digin.com, Bram, Brecht Dervaux, Huib Keemink, Thijs Kramer, Samuel Leeuwenburg, mahulst, Rob Moorman, Michael van Tellingen, Arne Turpyn -* Dutch (Netherlands): Bram, Kees Hink, Franklin Kingma, Maarten Kling, Thijs Kramer +* Dutch (Netherlands): Bram, Kees Hink, Coen van der Kamp, Franklin Kingma, Maarten Kling, Thijs Kramer, Meteor0id * Finnish: Eetu Häivälä, Niklas Jerva, Aarni Koskela, Rauli Laine, Glen Somerville, Juha Yrjölä -* French: Adrien, Timothy Allen, Sebastien Andrivet, Bertrand Bordage, André Bouatchidzé, Aurélien Debord, Romain Dorgueil, Tom Dyson, Antonin Enfrun, Axel Haustant, Léo, Pierre Marfoure, nahuel, Dominique Peretti, Loïc Teixeira, Benoît Vogel +* French: Adrien, Timothy Allen, Sebastien Andrivet, Bertrand Bordage, André Bouatchidzé, Aurélien Debord, Romain Dorgueil, Tom Dyson, Antonin Enfrun, Axel Haustant, Léo, Pierre Marfoure, nahuel, Sophy O, Dominique Peretti, fpoulain, Loïc Teixeira, Benoît Vogel * Galician: fooflare * Georgian: André Bouatchidzé -* German: Ettore Atalan, Patrick Craston, Henrik Kröger, Tammo van Lessen, Martin Löhle, Wasilis Mandratzis-Walz, Daniel Manser, m0rph3u5, Max Pfeiffer, Moritz Pfeiffer, Herbert Poul, Karl Sander, Tobias Schmidt, Johannes Spielmann, Raphael Stolt, Jannis Vajen, Vorlif, Matthew Westcott +* German: Ettore Atalan, Patrick Craston, Peter Dreuw, Johannes Fleck, Henrik Kröger, Tammo van Lessen, Martin Löhle, Wasilis Mandratzis-Walz, Daniel Manser, Matthias Martin, m0rph3u5, Max Pfeiffer, Moritz Pfeiffer, Herbert Poul, Karl Sander, Tobias Schmidt, Johannes Spielmann, Raphael Stolt, Benjamin Thurm, Norman Uekermann, Jannis Vajen, Vorlif, Matthew Westcott * Greek: Jim Dal, George Giannoulopoulos, Yiannis Inglessis, Wasilis Mandratzis-Walz, Nick Mavrakis, NeotheOne, Serafeim Papastefanos -* Hebrew (Israel): Lior Abazon, bjesus, Yossi Lalum, Oleg Sverdlov -* Hungarian: Laszlo Molnar, Kornél Novák Mergulhão +* Hebrew (Israel): Lior Abazon, bjesus, Yossi Lalum, Adi Ron, Oleg Sverdlov +* Hungarian: Istvan Farkas, Laszlo Molnar, Kornél Novák Mergulhão, BN, Aron Santa * Icelandic (Iceland): Arnar Tumi Þorsteinsson, Kjartan Sverrisson, Sævar Öfjörð Magnússon -* Indonesian (Indonesia): Sutrisno Efendi, Geek Pantura, Ronggo Radityo -* Italian: Edd Baldry, Claudio Bantaloukas, Gian-Maria Daffre, Giacomo Ghizzani, Carlo Miron, Alessio Di Stasio, Andrea Tagliazucchi -* Japanese: Sangmin Ahn, Shu Ishida, Daigo Shitara, Shimizu Taku +* Indonesian (Indonesia): atmosuwiryo, Sutrisno Efendi, Dzikri Hakim, Geek Pantura, Ronggo Radityo, M. Febrian Ramadhana +* Italian: Sandro Badalamenti, Edd Baldry, Claudio Bantaloukas, Guglielmo Celata, Gian-Maria Daffre, Giacomo Ghizzani, LB (Ben Johnston), Carlo Miron, Alessio Di Stasio, Andrea Tagliazucchi +* Japanese: Sangmin Ahn, Shuhei Hirota, Shu Ishida, Yudai Kobayashi, Tri Minh, Hideaki Oguchi, Tomo Mizoe, Safu9, Daigo Shitara, Shimizu Taku, umepon0626, Takuya Yamamoto * Korean: Kyungil Choi, Jihan Chung * Latvian: Reinis Rozenbergs, Maris Serzans * Lithuanian: Matas Dailyda -* Mongolian: Delgermurun Purevkhuu -* Norwegian Bokmål: Eirik Krogstad, Robin Skahjem-Eriksen +* Mongolian: Myagmarjav Enkhbileg, Delgermurun Purevkhuu +* Norwegian Bokmål: Eirik Krogstad, Robin Skahjem-Eriksen, Stein Strindhaug * Persian: Mohammad reza Jelveh, Mohammad Hossein Mojtahedi, Py Zenberg -* Polish: Konrad Lalik, Mateusz, Miłosz Miśkiewicz, Bartek Sielicki, utek, Grzegorz Wasilewski, Bartosz Wiśniewski +* Polish: Konrad Lalik, Miron Levitsky, Mateusz, Miłosz Miśkiewicz, Bartek Sielicki, utek, Grzegorz Wasilewski, Bartosz Wiśniewski * Portuguese (Brazil): Claudemiro Alves Feitosa Neto, Bruno Bertoldi, Luiz Boaretto, Gladson Brito, Thiago Cangussu, Gilson Filho, Joao Garcia, João Luiz Lorencetti, Marcio Mazza, Douglas Miranda, Guilherme Nabanete * Portuguese (Portugal): Gladson Brito, Thiago Cangussu, Tiago Henriques, Jose Lourenco, Nuno Matos, Douglas Miranda, Manuela Silva * Romanian: Dan Braghis -* Russian: ajk, Andrey Avdey, Daniil, gsstver, Sergey Khalymon, Sergey Komarov, Arseni M, Eugene MechanisM, Rustam Mirzaev, Mikalai Radchuk, Alexandr Romantsov, Nikita Viktorovich, Vassiliy Vorobyov +* Russian: ajk, Andrey Avdey, Daniil, Mikhail Gerasimov, gsstver, Sergey Khalymon, Sergey Komarov, Miron Levitskiy, Arseni M, Eugene MechanisM, Rustam Mirzaev, Alexander Penshin, Mikalai Radchuk, Alexandr Romantsov, Nikita Tonkoshkur, Tatsiana Tsygan, Nikita Viktorovich, Vassiliy Vorobyov * Slovak (Slovakia): Stevo Backor, dellax, Martin Janšto, Jozef Karabelly -* Slovenian: Mitja Pagon +* Slovenian: Mitja Pagon, Matej Stavanja * Spanish: Mauricio Baeza, Daniel Chimeno, fonso, fooflare, José Luis, Joaquín Tita, Unai Zalakain -* Swedish: Andreas Bergström, Jim Brouzoulis, Alexander Holmbäck, André Karlsson, Jon Karlsson, Ludwig Kjellström, Thomas Kunambi, Andreas Lans, Hannes Lohmander -* Turkish: Zafer Cengiz, Cihad Gündoǧdu, Ragıp Ünal +* Swedish: Philip Andersen, Andreas Bergström, Jim Brouzoulis, Alexander Holmbäck, André Karlsson, Jon Karlsson, Ludwig Kjellström, Thomas Kunambi, Andreas Lans, Hannes Lohmander +* Tetum: Alessandro, Joanico Barros, Peter Coward, Mariano de Deus, Onorio de Jesus Afonso, Mario Alves Pinto +* Thai: Amawalee Combe, Jon Combe, Walaksawan Vervoort +* Turkish: Umut Bektaş, Zafer Cengiz, Cihad Gündoǧdu, Ahmet Sarıcan, Ragıp Ünal * Turkish (Turkey): Saadettin Yasir Akel, Cihad Gündoǧdu, José Luis, Ragıp Ünal -* Ukrainian: Viktor Shytiuk, Mykola Zamkovoi -* Vietnamese: Luan Nguyen, Nguyễn Hồng Quân +* Ukrainian: Mikolai Incognito, Sergiy Shkodenko, Viktor Shytiuk, Zoriana Zaiats, Mykola Zamkovoi +* Vietnamese: Hồng Quân Nguyễn, Luan Nguyen * Welsh: Adam Hughes diff --git a/LICENSE b/LICENSE index c3d098f01f6..78f552b3d55 100644 --- a/LICENSE +++ b/LICENSE @@ -4,21 +4,21 @@ All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. - 3. Neither the name of Torchbox nor the names of its contributors may be used - to endorse or promote products derived from this software without - specific prior written permission. +* Neither the name of Torchbox nor the names of its contributors may be used + to endorse or promote products derived from this software without + specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON diff --git a/MANIFEST.in b/MANIFEST.in index ddd18ce9c80..5d7681b9c83 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,4 +1,4 @@ -include LICENSE *.rst *.txt +include LICENSE *.rst *.txt *.md graft wagtail prune wagtail/wagtailadmin/static_src global-exclude __pycache__ diff --git a/Makefile b/Makefile index 827bbb85c86..4ddce6ebe25 100644 --- a/Makefile +++ b/Makefile @@ -13,11 +13,14 @@ clean-pyc: develop: clean-pyc pip install -e .[testing,docs] - npm install && npm run build + npm install --no-save && npm run build lint: flake8 wagtail isort --check-only --diff --recursive wagtail + # Filter out known false positives, while preserving normal output and error codes. + # See https://github.com/motet-a/jinjalint/issues/18. + jinjalint --parse-only wagtail | grep -v 'welcome_page.html:6:70' | tee /dev/tty | wc -l | grep -q '0' npm run lint:css --silent npm run lint:js --silent diff --git a/README.md b/README.md new file mode 100644 index 00000000000..b5939088b3b --- /dev/null +++ b/README.md @@ -0,0 +1,117 @@ +

+ Wagtail +
+
+

+ +Wagtail is an open source content management system built on Django, with a strong community and commercial support. It's focused on user experience, and offers precise control for designers and developers. + +![Wagtail screenshot](https://cdn.jsdelivr.net/gh/wagtail/wagtail@master/.github/wagtail-screenshot-with-browser.png) + +### Features + +* A fast, attractive interface for authors +* Complete control over front-end design and structure +* Scales to millions of pages and thousands of editors +* Fast out of the box, cache-friendly when you need it +* Content API for 'headless' sites with de-coupled front-end +* Runs on a Raspberry Pi or a multi-datacenter cloud platform +* StreamField encourages flexible content without compromising structure +* Powerful, integrated search, using Elasticsearch or PostgreSQL +* Excellent support for images and embedded content +* Multi-site and multi-language ready +* Embraces and extends Django + +Find out more at [wagtail.io](https://wagtail.io/). + +### Getting started + +Wagtail works with [Python 3](https://www.python.org/downloads/), on any platform. + +To get started with Wagtail, run the following in a virtual environment: + +``` bash +pip install wagtail +wagtail start mysite +cd mysite +pip install -r requirements.txt +python manage.py migrate +python manage.py createsuperuser +python manage.py runserver +``` + +For detailed installation and setup docs, see [docs.wagtail.io](http://docs.wagtail.io/). + +### Who’s using it? + +Wagtail is used by NASA, Google, Oxfam, the NHS, Mozilla, MIT, the Red Cross, Salesforce, NBC, BMW, and the US and UK governments. Add your own Wagtail site to [madewithwagtail.org](http://madewithwagtail.org). + +### Documentation + +[docs.wagtail.io](http://docs.wagtail.io/) is the full reference for Wagtail, and includes guides for developers, designers and editors, alongside release notes and our roadmap. + +### Compatibility + +Wagtail supports: + +* Django 2.0.x, 2.1.x and 2.2.x +* Python 3.5, 3.6, 3.7 and 3.8 +* PostgreSQL, MySQL and SQLite as database backends + +Previous versions of Wagtail (1.13 and earlier) additionally supported Python 2.7 and Django 1.x. + +--- + +### Community Support + +There is an active community of Wagtail users and developers responding to questions on [Stack Overflow](http://stackoverflow.com/questions/tagged/wagtail). When posting questions, please read Stack Overflow's advice on [how to ask questions](http://stackoverflow.com/help/how-to-ask) and remember to tag your question "wagtail". + +For topics and discussions that do not fit Stack Overflow's question and answer format, we have a [Slack workspace](https://github.com/wagtail/wagtail/wiki/Slack) and a [Wagtail Support mailing list](https://groups.google.com/forum/#!forum/wagtail). Please respect the time and effort of volunteers by not asking the same question in multiple places. + +We maintain a curated list of third party packages, articles and other resources at [Awesome Wagtail](https://github.com/springload/awesome-wagtail). + +### Commercial Support + +Wagtail is sponsored by [Torchbox](https://torchbox.com/). If you need help implementing or hosting Wagtail, please contact us: hello@torchbox.com. See also [madewithwagtail.org/developers/](https://madewithwagtail.org/developers/) for expert Wagtail developers around the world. + +### Security + +We take the security of Wagtail, and related packages we maintain, seriously. If you have found a security issue with any of our projects please email us at [security@wagtail.io](mailto:security@wagtail.io) so we can work together to find and patch the issue. We appreciate responsible disclosure with any security related issues, so please contact us first before creating a Github issue. + +If you want to send an encrypted email (optional), the public key ID for security@wagtail.io is 0x6ba1e1a86e0f8ce8, and this public key is available from most commonly-used keyservers. + +### Release schedule + +Feature releases of Wagtail are released every three months. Selected releases are designated as Long Term Support (LTS) releases, and will receive maintenance updates for an extended period to address any security and data-loss related issues. For dates of past and upcoming releases and support periods, see [Release Schedule](https://github.com/wagtail/wagtail/wiki/Release-schedule). + +#### Nightly releases + +To try out the latest features before a release, we also create builds from master every night. You can find instructions on how to install the latest nightly release at https://releases.wagtail.io/nightly/index.html + +### Contributing + +If you're a Python or Django developer, fork the repo and get stuck in! We run a separate group for developers of Wagtail itself at https://groups.google.com/forum/#!forum/wagtail-developers (please note that this is not for support requests). + +You might like to start by reviewing the [contributing guidelines](http://docs.wagtail.io/en/latest/contributing/index.html) and checking issues with the [good first issue](https://github.com/wagtail/wagtail/labels/good%20first%20issue) label. + +We also welcome translations for Wagtail's interface. Translation work should be submitted through [Transifex](https://www.transifex.com/projects/p/wagtail/). + +### License +[BSD](https://github.com/wagtail/wagtail/blob/master/LICENSE) + +### Thanks + +We thank the following organisations for their services used in Wagtail's development: + +[![Browserstack](https://cdn.jsdelivr.net/gh/wagtail/wagtail@master/.github/browserstack-logo.svg)](https://www.browserstack.com/)
+[BrowserStack](https://www.browserstack.com/) provides the project with free access to their live web-based browser testing tool, and automated Selenium cloud testing. + +[![squash.io](https://cdn.jsdelivr.net/gh/wagtail/wagtail@master/.github/squash-logo.svg)](https://www.squash.io/)
+[Squash](https://www.squash.io/) provides the project with free test environments for reviewing pull requests. + + +[![Build Status](https://api.travis-ci.org/wagtail/wagtail.svg?branch=master)](https://travis-ci.org/wagtail/wagtail) +[![License](https://img.shields.io/badge/license-BSD-blue.svg)](https://opensource.org/licenses/BSD-3-Clause) +[![Version](https://img.shields.io/pypi/v/wagtail.svg)](https://pypi.python.org/pypi/wagtail/) +[![Coverage](http://codecov.io/github/wagtail/wagtail/coverage.svg?branch=master)](http://codecov.io/github/wagtail/wagtail?branch=master) +[![Slack](https://wagtail-slack.now.sh/badge.svg)](https://wagtail-slack.now.sh) diff --git a/README.rst b/README.rst deleted file mode 100644 index fb641aa9796..00000000000 --- a/README.rst +++ /dev/null @@ -1,91 +0,0 @@ -.. image:: https://api.travis-ci.org/wagtail/wagtail.svg?branch=master - :target: https://travis-ci.org/wagtail/wagtail -.. image:: https://img.shields.io/pypi/l/wagtail.svg - :target: https://pypi.python.org/pypi/wagtail/ -.. image:: https://img.shields.io/pypi/v/wagtail.svg - :target: https://pypi.python.org/pypi/wagtail/ -.. image:: http://codecov.io/github/wagtail/wagtail/coverage.svg?branch=master - :target: http://codecov.io/github/wagtail/wagtail?branch=master - - -Wagtail CMS -=========== - -Wagtail is a content management system built on Django. It's focused on user experience, -and offers precise control for designers and developers. - -.. image:: http://i.imgur.com/hSVerKq.jpg - :width: 728 px - -Features -~~~~~~~~ - -* A fast, attractive interface for authors and editors -* Complete control over design with standard Django templates -* Configure content types through standard Django models -* Fast out of the box. Cache-friendly if you need it -* Tightly integrated search -* Strong document and image management -* Wide support for embedded content -* Straightforward integration with existing Django apps -* Simple, configurable permissions -* Workflow support -* An extensible `form builder `_ -* Multi-site and multi-language support -* Excellent `test coverage `_ - -Find out more at `wagtail.io `_. - -Getting started -~~~~~~~~~~~~~~~ - -.. code-block:: sh - - pip install wagtail - wagtail start mysite - cd mysite - python manage.py migrate - python manage.py createsuperuser - python manage.py runserver - -then sign in at http://127.0.0.1:8000/admin/ - -For detailed installation and setup docs, see `docs.wagtail.io `_. - -Who's using it? -~~~~~~~~~~~~~~~ -`madewithwagtail.org `_ lists some of the public Wagtail sites we know about; please `add your own `_. - -Documentation -~~~~~~~~~~~~~ -`docs.wagtail.io `_ is the full reference for Wagtail, and includes guides for developers, designers and editors, alongside release notes and our roadmap. - -Community Support -~~~~~~~~~~~~~~~~~ -There is an active community of Wagtail users and developers responding to questions on `Stack Overflow `_. When posting questions, please read Stack Overflow's advice on `how to ask questions `_ and remember to tag your question with "wagtail". - -For topics and discussions that do not fit Stack Overflow's question-and-answer format, there is also a `Wagtail Support mailing list `_ and a `Slack workspace `_. - -Commercial Support -~~~~~~~~~~~~~~~~~~ -Wagtail is sponsored by `Torchbox `_. If you need help implementing or hosting Wagtail, please contact us: hello@torchbox.com. - -Thanks -~~~~~~ -We thank `BrowserStack `_, who provide the project with free access to their live web-based browser testing tool, and automated Selenium cloud testing. - -.. image:: https://cdn.rawgit.com/wagtail/wagtail/master/.github/browserstack-logo.svg - :target: https://www.browserstack.com/ - :width: 219 px - -Compatibility -~~~~~~~~~~~~~ -Wagtail supports Django 1.11.x and 2.0 on Python 3.4, 3.5 and 3.6. Supported database backends are PostgreSQL, MySQL and SQLite. - -Contributing -~~~~~~~~~~~~ -If you're a Python or Django developer, fork the repo and get stuck in! We run a separate group for developers of Wagtail itself at https://groups.google.com/forum/#!forum/wagtail-developers (please note that this is not for support requests). - -You might like to start by reviewing the `contributing guidelines `_ and checking issues with the `good first issue `_ label. - -We also welcome translations for Wagtail's interface. Translation work should be submitted through `Transifex `_. diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 00000000000..4f2b6694cc2 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,4 @@ +# Security +We take the security of Wagtail, and related packages we maintain, seriously. If you have found a security issue with any of our projects please email us at security@wagtail.io so we can work together to find and patch the issue. We appreciate responsible disclosure with any security related issues, so please contact us first before creating a Github issue. + +If you want to send an encrypted email (optional), the public key ID for security@wagtail.io is 0x6ba1e1a86e0f8ce8, and this public key is available from most commonly-used keyservers. diff --git a/SPONSORS.md b/SPONSORS.md new file mode 100644 index 00000000000..026bb0af5db --- /dev/null +++ b/SPONSORS.md @@ -0,0 +1,17 @@ +# Sponsors + +The following organisations and individuals supported the [Wagtail's First Hatch](https://www.kickstarter.com/projects/noripyt/wagtails-first-hatch) crowdfunding campaign: + +- [Springload](https://springload.nz/) +- [NetFM](https://netfm.org/) +- [Ambient Innovation](https://ambient-innovation.com/) +- [Shenberger Technology](http://shenbergertech.com/) +- [Type/Code](https://typecode.com/) +- [SharperTool](http://sharpertool.com/) +- [Overcast Software](https://www.overcast.io/) +- [Octave](https://octave.nz/) +- [Taywa](https://www.taywa.ch/) +- [Rock Kitchen Harris](https://www.rkh.co.uk/) +- [The Motley Fool](http://www.fool.com/) +- [R Strother Scott](https://twitter.com/rstrotherscott) +- [Beyond Media](http://beyond.works/) diff --git a/circle.yml b/circle.yml deleted file mode 100644 index 0f1d97e8c3c..00000000000 --- a/circle.yml +++ /dev/null @@ -1,19 +0,0 @@ -machine: - python: - version: 3.6.1 - node: - version: 8.9.3 - -dependencies: - pre: - - pip install -e .[testing] - -test: - override: - - flake8 wagtail - - isort --check-only --diff --recursive wagtail - - npm run lint:js - - npm run lint:css - - python -u runtests.py - - npm run test:unit:coverage -- --runInBand - - npm run dist diff --git a/client/package-lock.json b/client/package-lock.json deleted file mode 100644 index a8f129b9b59..00000000000 --- a/client/package-lock.json +++ /dev/null @@ -1,613 +0,0 @@ -{ - "name": "wagtail-client", - "version": "0.1.0", - "lockfileVersion": 1, - "requires": true, - "dependencies": { - "mustache": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/mustache/-/mustache-2.2.1.tgz", - "integrity": "sha1-LEDKIcJ49TFQaCvPkJDkGjM5uHY=" - }, - "yargs": { - "version": "4.7.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-4.7.1.tgz", - "integrity": "sha1-5gQyZYozh/8mnAKOrN5KUS5Djf8=", - "requires": { - "camelcase": "3.0.0", - "cliui": "3.2.0", - "decamelize": "1.2.0", - "lodash.assign": "4.0.9", - "os-locale": "1.4.0", - "pkg-conf": "1.1.3", - "read-pkg-up": "1.0.1", - "require-main-filename": "1.0.1", - "set-blocking": "1.0.0", - "string-width": "1.0.1", - "window-size": "0.2.0", - "y18n": "3.2.1", - "yargs-parser": "2.4.0" - }, - "dependencies": { - "camelcase": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", - "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=" - }, - "cliui": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", - "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", - "requires": { - "string-width": "1.0.1", - "strip-ansi": "3.0.1", - "wrap-ansi": "2.0.0" - }, - "dependencies": { - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "requires": { - "ansi-regex": "2.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.0.0.tgz", - "integrity": "sha1-xQYbbg74qBd15Q9dZhUb9r83EQc=" - } - } - }, - "wrap-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.0.0.tgz", - "integrity": "sha1-fTD4+HP5pbvDpk2ryNF34HGuQm8=", - "requires": { - "string-width": "1.0.1" - } - } - } - }, - "decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" - }, - "lodash.assign": { - "version": "4.0.9", - "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.0.9.tgz", - "integrity": "sha1-Cgcx2TWQ3dm6RYn61lqvbuCSF+M=", - "requires": { - "lodash.keys": "4.0.7", - "lodash.rest": "4.0.3" - }, - "dependencies": { - "lodash.keys": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-4.0.7.tgz", - "integrity": "sha1-MOGzvZjlTWoGEZkYEmhba8R8tjs=" - }, - "lodash.rest": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/lodash.rest/-/lodash.rest-4.0.3.tgz", - "integrity": "sha1-TBwyxAAoCHJQ+r9w1C4BUVSPSMU=" - } - } - }, - "os-locale": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", - "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", - "requires": { - "lcid": "1.0.0" - }, - "dependencies": { - "lcid": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", - "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", - "requires": { - "invert-kv": "1.0.0" - }, - "dependencies": { - "invert-kv": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", - "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=" - } - } - } - } - }, - "pkg-conf": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/pkg-conf/-/pkg-conf-1.1.3.tgz", - "integrity": "sha1-N45W1v0T6Iv7b0ol33qD+qvduls=", - "requires": { - "find-up": "1.1.2", - "load-json-file": "1.1.0", - "object-assign": "4.1.0", - "symbol": "0.2.3" - }, - "dependencies": { - "find-up": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", - "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", - "requires": { - "path-exists": "2.1.0", - "pinkie-promise": "2.0.1" - }, - "dependencies": { - "path-exists": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", - "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", - "requires": { - "pinkie-promise": "2.0.1" - } - }, - "pinkie-promise": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", - "requires": { - "pinkie": "2.0.4" - }, - "dependencies": { - "pinkie": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=" - } - } - } - } - }, - "load-json-file": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", - "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", - "requires": { - "graceful-fs": "4.1.4", - "parse-json": "2.2.0", - "pify": "2.3.0", - "pinkie-promise": "2.0.1", - "strip-bom": "2.0.0" - }, - "dependencies": { - "graceful-fs": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.4.tgz", - "integrity": "sha1-7widKIDwM7ARgjzlyPrnmNp3Xb0=" - }, - "parse-json": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", - "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", - "requires": { - "error-ex": "1.3.0" - }, - "dependencies": { - "error-ex": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.0.tgz", - "integrity": "sha1-5ntD8+gsluo6WE/+4Ln8MyXYAtk=", - "requires": { - "is-arrayish": "0.2.1" - }, - "dependencies": { - "is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=" - } - } - } - } - }, - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" - }, - "pinkie-promise": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", - "requires": { - "pinkie": "2.0.4" - }, - "dependencies": { - "pinkie": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=" - } - } - }, - "strip-bom": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", - "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", - "requires": { - "is-utf8": "0.2.1" - }, - "dependencies": { - "is-utf8": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", - "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=" - } - } - } - } - }, - "object-assign": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.0.tgz", - "integrity": "sha1-ejs9DpgGPUP0wD8uiubNUahog6A=" - }, - "symbol": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/symbol/-/symbol-0.2.3.tgz", - "integrity": "sha1-O5hzuKkB5Hxu/iFSajrDcu8ou8c=" - } - } - }, - "read-pkg-up": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", - "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", - "requires": { - "find-up": "1.1.2", - "read-pkg": "1.1.0" - }, - "dependencies": { - "find-up": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", - "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", - "requires": { - "path-exists": "2.1.0", - "pinkie-promise": "2.0.1" - }, - "dependencies": { - "path-exists": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", - "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", - "requires": { - "pinkie-promise": "2.0.1" - } - }, - "pinkie-promise": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", - "requires": { - "pinkie": "2.0.4" - }, - "dependencies": { - "pinkie": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=" - } - } - } - } - }, - "read-pkg": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", - "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", - "requires": { - "load-json-file": "1.1.0", - "normalize-package-data": "2.3.5", - "path-type": "1.1.0" - }, - "dependencies": { - "load-json-file": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", - "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", - "requires": { - "graceful-fs": "4.1.4", - "parse-json": "2.2.0", - "pify": "2.3.0", - "pinkie-promise": "2.0.1", - "strip-bom": "2.0.0" - }, - "dependencies": { - "graceful-fs": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.4.tgz", - "integrity": "sha1-7widKIDwM7ARgjzlyPrnmNp3Xb0=" - }, - "parse-json": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", - "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", - "requires": { - "error-ex": "1.3.0" - }, - "dependencies": { - "error-ex": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.0.tgz", - "integrity": "sha1-5ntD8+gsluo6WE/+4Ln8MyXYAtk=", - "requires": { - "is-arrayish": "0.2.1" - }, - "dependencies": { - "is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=" - } - } - } - } - }, - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" - }, - "pinkie-promise": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", - "requires": { - "pinkie": "2.0.4" - }, - "dependencies": { - "pinkie": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=" - } - } - }, - "strip-bom": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", - "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", - "requires": { - "is-utf8": "0.2.1" - }, - "dependencies": { - "is-utf8": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", - "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=" - } - } - } - } - }, - "normalize-package-data": { - "version": "2.3.5", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.3.5.tgz", - "integrity": "sha1-jZJPFClg4Xd+f/4XBUNjHMfLAt8=", - "requires": { - "hosted-git-info": "2.1.5", - "is-builtin-module": "1.0.0", - "semver": "5.1.0", - "validate-npm-package-license": "3.0.1" - }, - "dependencies": { - "hosted-git-info": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.1.5.tgz", - "integrity": "sha1-C6gdkNouJas0ozLm7HeTbhWYEYs=" - }, - "is-builtin-module": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", - "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", - "requires": { - "builtin-modules": "1.1.1" - }, - "dependencies": { - "builtin-modules": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", - "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=" - } - } - }, - "semver": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.1.0.tgz", - "integrity": "sha1-hfLPhVBGXE3wAM99hvawVBBqueU=" - }, - "validate-npm-package-license": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz", - "integrity": "sha1-KAS6vnEq0zeUWaz74kdGqywwP7w=", - "requires": { - "spdx-correct": "1.0.2", - "spdx-expression-parse": "1.0.2" - }, - "dependencies": { - "spdx-correct": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-1.0.2.tgz", - "integrity": "sha1-SzBz2TP/UfORLwOsVRlJikFQ20A=", - "requires": { - "spdx-license-ids": "1.2.1" - }, - "dependencies": { - "spdx-license-ids": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-1.2.1.tgz", - "integrity": "sha1-0H6hek0v2TUfnZTi/5zsdBgP6PM=" - } - } - }, - "spdx-expression-parse": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-1.0.2.tgz", - "integrity": "sha1-1SsUtelnB3FECvIlvLVjEirEUvY=", - "requires": { - "spdx-exceptions": "1.0.4", - "spdx-license-ids": "1.2.1" - }, - "dependencies": { - "spdx-exceptions": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-1.0.4.tgz", - "integrity": "sha1-IguEI5EZrpBFqJLbgag/TOFvgP0=" - }, - "spdx-license-ids": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-1.2.1.tgz", - "integrity": "sha1-0H6hek0v2TUfnZTi/5zsdBgP6PM=" - } - } - } - } - } - } - }, - "path-type": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", - "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", - "requires": { - "graceful-fs": "4.1.4", - "pify": "2.3.0", - "pinkie-promise": "2.0.1" - }, - "dependencies": { - "graceful-fs": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.4.tgz", - "integrity": "sha1-7widKIDwM7ARgjzlyPrnmNp3Xb0=" - }, - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" - }, - "pinkie-promise": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", - "requires": { - "pinkie": "2.0.4" - }, - "dependencies": { - "pinkie": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=" - } - } - } - } - } - } - } - } - }, - "require-main-filename": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", - "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=" - }, - "set-blocking": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-1.0.0.tgz", - "integrity": "sha1-zV5dk4BI3xrJLf6S4fFq3WVvXsU=" - }, - "string-width": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.1.tgz", - "integrity": "sha1-ySEptvHX9SrPmvQkom44ZKBc6wo=", - "requires": { - "code-point-at": "1.0.0", - "is-fullwidth-code-point": "1.0.0", - "strip-ansi": "3.0.1" - }, - "dependencies": { - "code-point-at": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.0.0.tgz", - "integrity": "sha1-9psZLT99keOC5Lcb3bd4eGGasMY=", - "requires": { - "number-is-nan": "1.0.0" - }, - "dependencies": { - "number-is-nan": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.0.tgz", - "integrity": "sha1-wCD1KcUoKt/dIz2R1LGBw9aG3Es=" - } - } - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "requires": { - "number-is-nan": "1.0.0" - }, - "dependencies": { - "number-is-nan": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.0.tgz", - "integrity": "sha1-wCD1KcUoKt/dIz2R1LGBw9aG3Es=" - } - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "requires": { - "ansi-regex": "2.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.0.0.tgz", - "integrity": "sha1-xQYbbg74qBd15Q9dZhUb9r83EQc=" - } - } - } - } - }, - "window-size": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.2.0.tgz", - "integrity": "sha1-tDFbtCFKPXBY6+7okuE/ok2YsHU=" - }, - "y18n": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", - "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=" - }, - "yargs-parser": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-2.4.0.tgz", - "integrity": "sha1-HzZ9ycbPpWYLaXEjDzsnf8Xjrco=", - "requires": { - "camelcase": "2.1.1", - "lodash.assign": "4.0.9" - }, - "dependencies": { - "camelcase": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", - "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=" - } - } - } - } - } - } -} diff --git a/client/package.json b/client/package.json index c946623bac7..fe15f6b18ed 100644 --- a/client/package.json +++ b/client/package.json @@ -6,16 +6,10 @@ "license": "BSD-3-Clause", "author": "Wagtail", "main": "src/index.js", - "bin": { - "wagtail": "./src/cli/index.js" - }, "files": [ "src/index.js" ], "devDependencies": {}, - "dependencies": { - "mustache": "^2.2.1", - "yargs": "^4.2.0" - }, + "dependencies": {}, "scripts": {} } diff --git a/client/scss/_components.scss b/client/scss/_components.scss deleted file mode 100644 index 0e34b1b87a2..00000000000 --- a/client/scss/_components.scss +++ /dev/null @@ -1,4 +0,0 @@ -@import '../src/components/Transition/Transition'; -@import '../src/components/LoadingSpinner/LoadingSpinner'; -@import '../src/components/PublicationStatus/PublicationStatus'; -@import '../src/components/Explorer/Explorer'; diff --git a/client/scss/_settings.scss b/client/scss/_settings.scss new file mode 100644 index 00000000000..18a8986c127 --- /dev/null +++ b/client/scss/_settings.scss @@ -0,0 +1,2 @@ +@import 'settings/variables'; +@import 'settings/variables.icons'; diff --git a/client/scss/_tools.breakpoints.scss b/client/scss/_tools.breakpoints.scss deleted file mode 100644 index 4c9e72f3d7b..00000000000 --- a/client/scss/_tools.breakpoints.scss +++ /dev/null @@ -1,14 +0,0 @@ -$breakpoint-small: $breakpoint-mobile - 0.0625em; -$breakpoint-medium: $breakpoint-mobile; - -@mixin small { - @media only screen and (max-width: $breakpoint-small) { - @content; - } -} - -@mixin medium { - @media only screen and (min-width: $breakpoint-medium) { - @content; - } -} diff --git a/client/scss/_tools.scss b/client/scss/_tools.scss new file mode 100644 index 00000000000..3fa1ccd6d8a --- /dev/null +++ b/client/scss/_tools.scss @@ -0,0 +1,10 @@ +/* TOOLS +These are functions and mixins. +No CSS should be produced by these files. +*/ + +@import 'tools/functions.breakpoints'; +@import 'tools/mixins.breakpoints'; +@import 'tools/mixins.fonts'; +@import 'tools/mixins.general'; +@import 'tools/mixins.grid'; diff --git a/client/scss/components/_breadcrumb.scss b/client/scss/components/_breadcrumb.scss new file mode 100644 index 00000000000..41f97e7321a --- /dev/null +++ b/client/scss/components/_breadcrumb.scss @@ -0,0 +1,108 @@ +.breadcrumb { + @include unlist(); + @include clearfix(); + overflow: hidden; + padding-top: 1.4em; + font-size: 0.85em; + + li { + display: block; + float: left; + padding: 0.5em 1.3em; + position: relative; + text-decoration: none; + color: $color-white; + white-space: nowrap; + line-height: 1.5em; + + a, + span { + color: $color-white; + display: block; + max-width: 12em; + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; + line-height: 1.6em; + padding-right: 1em; + + &:after { + right: 0; + // z-index: 5; + position: absolute; + font-family: wagtail; + content: map-get($icons, 'arrow-right'); + padding-left: 20px; + font-size: 2em; + color: $color-teal-darker; + line-height: 0.9em; + } + } + + &:hover { + background: $color-teal-dark; + + a { + color: $color-white; + } + } + + &:hover:after { + border-left-color: $color-teal-dark; + } + + &.home { + a { + // stylelint-disable max-nesting-depth + padding-right: 0; + text-align: center; + width: 3em; + font-size: 1em; + text-overflow: clip; + + &:before { + font-size: 1.15rem; + line-height: 0.85em; + padding-top: 0.1em; + } + + &:after { + right: -0.3em; + } + } + } + } + + header & li { + &:before { + border-left: 1em solid $color-white; + position: absolute; + left: 0; + top: 0; + } + } + + &.single { + li a { + white-space: nowrap; + text-overflow: inherit; + max-width: 100%; + } + } + + @include media-breakpoint-up(sm) { + padding-top: 0; + background: $color-teal-darker; + margin-left: -($desktop-nice-padding); + margin-right: -($desktop-nice-padding); + + li { + a, + span { + &:after { + color: $color-teal; + } + } + } + } +} diff --git a/client/scss/components/_button.scss b/client/scss/components/_button.scss new file mode 100644 index 00000000000..66a9f6978e2 --- /dev/null +++ b/client/scss/components/_button.scss @@ -0,0 +1,528 @@ +// Core button style +// Note that these styles include methods to render buttons the same x-browser, described here: +// http: //cbjdigital.com/blog/2010/08/bulletproof_css_input_button_heights +// input[type=submit], +// input[type=reset], +// input[type=button], +.button { + border-radius: 3px; + font-family: Open Sans,Arial,sans-serif; + width: auto; + height: 2.4em; + padding: 0 1em; + font-size: 0.9em; + font-weight: normal; + vertical-align: middle; + display: inline-block; + background-color: $color-button; + border: 1px solid $color-button; + color: $color-white; + text-decoration: none; + text-transform: uppercase; + white-space: nowrap; + position: relative; + overflow: hidden; + box-sizing: border-box; + -webkit-font-smoothing: auto; + // stylelint-disable-next-line property-no-vendor-prefix + -moz-appearance: none; + + &:hover { + color: $color-teal; + } + + + &.yes { + background-color: $color-button-yes; + border: 1px solid $color-button-yes; + + &.button-secondary { + border: 1px solid $color-button-yes; + color: $color-button-yes; + background-color: transparent; + } + + &:hover { + color: $color-white; + border-color: transparent; + background-color: $color-button-yes-hover; + } + + &.button-nobg:hover { + color: $color-button-yes; + background-color: transparent; + } + } + + &.warning { + background-color: $color-button-warning; + border: 1px solid $color-button-warning; + + &.button-secondary { + border: 1px solid $color-button-warning; + color: $color-button-warning; + background-color: transparent; + } + + &:hover { + color: $color-white; + border-color: transparent; + background-color: $color-button-warning-hover; + } + + &.button-nobg:hover { + color: $color-button-warning; + background-color: transparent; + } + } + + + &.no, + &.serious { + background-color: $color-button-no; + border: 1px solid $color-button-no; + + &.button-secondary { + border: 1px solid $color-button-no; + color: $color-button-no; + background-color: transparent; + } + + &:hover { + color: $color-white; + border-color: transparent; + background-color: $color-button-no-hover; + } + + &.button-nobg:hover { + color: $color-button-no; + background-color: transparent; + } + } + + &.button-nobg { + border: 0; + background-color: transparent; + } + + &.bicolor { + border: 0; + padding-left: 3.5em; + + &:before { + font-size: 1rem; + position: absolute; + left: 0; + top: 0; + width: 2em; + line-height: 1.85em; + height: 100%; + text-align: center; + background-color: rgba(0, 0, 0, 0.2); + display: block; + border-top-left-radius: inherit; + border-bottom-left-radius: inherit; + } + } + + &.button-small.bicolor { + padding-left: 3.5em; + + &:before { + width: 2em; + font-size: 0.9rem; + line-height: 1.65em; + } + } + + + // + input[type=submit], + // + input[type=reset], + // + input[type=button], + + .button { + // + button { + margin-left: 1em; + } + + // A completely unstyled button + &.unbutton { + border-radius: 0; + width: auto; + height: auto; + padding: 0; + font-size: inherit; + font-weight: normal; + vertical-align: middle; + display: inline; + background-color: transparent; + border: 0; + color: inherit; + text-decoration: none; + text-transform: uppercase; + white-space: nowrap; + position: relative; + overflow: hidden; + box-sizing: border-box; + -webkit-font-smoothing: auto; + // stylelint-disable-next-line property-no-vendor-prefix + -moz-appearance: none; + } + + &:hover { + background-color: $color-button-hover; + color: $color-white; + border-color: transparent; + + &.hover-no { + background-color: $color-button-no; + } + } + + &.button-longrunning { + span { + @include transition(all 0.3s ease); + transform: scale(0.9); + display: inline-block; + height: 0.9em; + position: relative; + opacity: 0; + width: 0; + visibility: hidden; + text-align: center; + padding-right: 0; + } + + em { + font-style: normal; + } + + &.button-longrunning-active span { + transform: scale(1); + visibility: visible; + width: 1em; + opacity: 0.8; + padding-right: 0.5em; + } + + .icon-spinner:after { + text-align: center; + position: absolute; + left: 0; + margin: 0; + line-height: 1em; + display: inline-block; + font-size: 1em; + } + } + + &:disabled, + &[disabled], + &.disabled { + background-color: $color-grey-3; + border-color: $color-grey-3; + color: $color-grey-2; + cursor: default; + } + + &.button-secondary:disabled, + &.button-secondary[disabled], + &.button-secondary.disabled { + background-color: $color-white; + border-color: $color-grey-3; + color: $color-grey-3; + } + + &.button-nostroke { + border: 0; + } + + @include media-breakpoint-up(sm) { + font-size: 0.95em; + padding: 0 1.4em; + height: 3em; + + &.icon.text-replace { + width: 2.2rem; + height: 2.2rem; + + &:before { + line-height: 2.1em; + } + } + + &.button-small { + &.icon.text-replace { + height: 1.8rem; + width: 1.8rem; + + // stylelint-disable-next-line max-nesting-depth + &:before { + line-height: 1.7em; + } + } + } + + &.bicolor { + padding-left: 3.7em; + + &:before { + width: 2em; + line-height: 2.2em; + font-size: 1.1rem; + } + } + + &.button-small.bicolor { + // line-height: 2.2em; + padding-left: 3em; + + &:before { + width: 1.8em; + line-height: 1.65em; + } + } + } +} + + +.button-small { + padding: 0 0.8em; + height: 2em; + font-size: 0.95em; +} + +.button-secondary { + color: $color-button; + background-color: transparent; +} + +// Buttons which are only an icon +.button.icon.text-replace { + font-size: 0; // unavoidable duplication of setting in icons.scss + width: 1.8rem; + height: 1.8rem; + + &:before { + line-height: 1.7em; + } +} + +.button-neutral { + color: $color-grey-2; + + &:hover { + color: $color-teal; + } +} + +.yes { + background-color: $color-button-yes; + border: 1px solid $color-button-yes; + + &.button-secondary { + border: 1px solid $color-button-yes; + color: $color-button-yes; + background-color: transparent; + } + + &:hover { + color: $color-white; + border-color: transparent; + background-color: $color-button-yes-hover; + } + + &.button-nobg:hover { + color: $color-button-yes; + background-color: transparent; + } +} + +.no, +.serious { + background-color: $color-button-no; + border: 1px solid $color-button-no; + + &.button-secondary { + border: 1px solid $color-button-no; + color: $color-button-no; + background-color: transparent; + } + + &:hover { + color: $color-white; + border-color: transparent; + background-color: $color-button-no-hover; + } + + &.button-nobg:hover { + color: $color-button-no; + background-color: transparent; + } +} + +.button-nobg { + border: 0; + background-color: transparent; +} + +.bicolor { + border: 0; + padding-left: 3.5em; + + &:before { + font-size: 1rem; + position: absolute; + left: 0; + top: 0; + width: 2em; + line-height: 1.85em; + height: 100%; + text-align: center; + background-color: rgba(0, 0, 0, 0.2); + display: block; + } +} + +.button-small.bicolor { + padding-left: 3.5em; + + &:before { + width: 2em; + font-size: 0.8rem; + line-height: 1.65em; + } +} + + +a.button { + line-height: 2.4em; + height: auto; + + &.button-small { + line-height: 1.85em; + } + + @include media-breakpoint-up(sm) { + line-height: 2.9em; + } +} + +// Special styles to counteract Firefox's completely unwarranted assumptions about button styles +input[type=submit], +input[type=reset], +input[type=button], +button { + padding: 0 1em; + + @include media-breakpoint-up(sm) { + &.button-small { + height: 2em; + } + } +} + +.button-group { + @include clearfix; + + input[type=submit], + input[type=reset], + input[type=button], + .button, + button { + border-radius: 0; + float: left; + margin-right: 1px; + margin-left: 0; + + &:only-child { + border-radius: 3px; + } + + &:first-child { + border-radius: 3px 0 0 3px; + } + + &:last-child { + border-radius: 0 3px 3px 0; + margin-right: 0; + } + } + + &.button-group-square { + &, + input[type=submit], + input[type=reset], + input[type=button], + .button, + button { + border-radius: 0; + } + } +} + + +.multiple { + padding: 0; + max-width: 1024px - 50px; + overflow: hidden; + + > li { + @include row(); + border-radius: 2px; + position: relative; + overflow: hidden; + background-color: $color-white; + padding: 1em 10em 1em 1.5em; // 10em padding leaves room for controls + margin-bottom: 1em; + border: 1px solid lighten($color-grey-4, 3%); // really trying to avoid creating more greys, but this one is better than grey 4 or 5 + } + + &.moving { + position: relative; + } + + li.moving { + position: absolute; + width: 100%; + } + + fieldset { + padding-top: 0; + padding-bottom: 0; + } + + // Object controls + .controls { + position: absolute; + z-index: 1; + right: 1em; + top: 1em; + color: $color-white; + + li { + float: left; + margin-right: 1px; + + &:last-child { + margin-right: 0; + } + } + + .disabled { + display: none; + visibility: hidden; + } + } + +} + +// wrapper around add button for mutliple objects +.add { + font-weight: 700; + cursor: pointer; + margin-top: 0; + margin-bottom: 0; + padding-top: 1em; + padding-bottom: 2em; + clear: both; +} diff --git a/client/scss/components/_chooser.scss b/client/scss/components/_chooser.scss new file mode 100644 index 00000000000..907ea9f3d0b --- /dev/null +++ b/client/scss/components/_chooser.scss @@ -0,0 +1,143 @@ +/* +TODO this chooser style has been made more generic based on two identical +methods for choosing pages and images that were previously included in their +own less files in each app directory (and since deleted). It would be best if +an admin 'theme' provided all the design for a UI in a single place, but +should that be a series of overrides to the css provided from an app? If so, +perhaps those two previous less files should be re-instated and then +overriden here? hmm. +*/ + +.chooser { + // We show the 'chosen' state... + @include clearfix(); + + input[type=text] { + float: left; + width: 50%; + margin-right: 1em; + } + + .chosen { + display: block; + } + + .unchosen, + .chosen { + position: relative; + + &:before { + vertical-align: middle; + font-family: wagtail; + content: ''; + // position: relative + display: inline-block; + // float: left; + color: $color-grey-3; + line-height: 1em; + font-size: 2.5em; + margin-right: 0.3em; + } + } + + .unchosen { + display: none; + } + + .actions { + @include clearfix; + overflow: hidden; + + li { + float: left; + margin: 0.3em; + } + } + + // ...unless the .page-chooser has the 'blank' class set + &.blank { + .chosen { display: none; } + + .unchosen { display: block; } + } +} + +// standard way of doing a chooser where the chosen object's title is overlaid +.page-chooser, +.snippet-chooser, +.document-chooser { + .chosen { + .title { + color: $color-grey-1; + // display: block; + padding-left: 1em; + display: inline-block; + } + + .actions { + clear: both; + padding-top: 0.6em; + } + } +} + +.page-chooser { + .unchosen, + .chosen { + &:before { + content: map-get($icons, 'doc-empty-inverse'); + } + } +} + +.snippet-chooser { + .unchosen, + .chosen { + &:before { + content: map-get($icons, 'snippet'); + } + } +} + +.document-chooser { + .unchosen, + .chosen { + &:before { + content: map-get($icons, 'doc-full-inverse'); + } + } +} + +.image-chooser { + .unchosen, + .chosen { + &:before { + content: map-get($icons, 'image'); + } + } + + .chosen { + padding-left: $thumbnail-width; + + &:before { + content: ''; + } + + .preview-image { + float: left; + margin-left: -($thumbnail-width); + margin-right: 1em; + max-width: $thumbnail-width; + + // Resize standard Wagtail thumbnail size (165x165) to 130 for space-saving purposes. + // We could request a 130x130 rendition, but that's just unnecessary and burdens installations + // where images are store off-site with higher rendering times. + img { + max-width: $thumbnail-width; + max-height: $thumbnail-width; + height: auto; + width: auto; + } + } + } +} diff --git a/wagtail/admin/static_src/wagtailadmin/scss/components/_dropdowns.scss b/client/scss/components/_dropdown.legacy.scss similarity index 56% rename from wagtail/admin/static_src/wagtailadmin/scss/components/_dropdowns.scss rename to client/scss/components/_dropdown.legacy.scss index 39cb4015807..bc43f6a04e1 100644 --- a/wagtail/admin/static_src/wagtailadmin/scss/components/_dropdowns.scss +++ b/client/scss/components/_dropdown.legacy.scss @@ -227,189 +227,3 @@ .dropdown ul { @include transition(opacity 0.2s linear); } - - -// ============================================================================= -// Listing view smaller dropdowns -// ============================================================================= - -// .c-dropdown { -// } -.o-icon { - display: inline-block; - vertical-align: middle; - line-height: 1; - margin-top: -0.25rem; -} - -.c-dropdown__button { - display: inline-block; - box-sizing: border-box; - padding-left: 0.5rem; - padding-right: 0.25rem; - // Make this the same as the other buttons - line-height: 1.85; - border: solid 1px transparent; - border-radius: 2px; - font-size: 0.95em; - cursor: pointer; - -webkit-font-smoothing: subpixel-antialiased; - user-select: none; -} - -.c-dropdown__toggle { - display: inline-block; -} - -.c-dropdown__menu.c-dropdown__menu { - margin-top: 0.75rem; - padding: 0.75rem 1rem; - min-width: 8rem; - text-transform: none; - position: absolute; - z-index: 1; - animation: dropdownIn 0.1s ease-out backwards; - list-style: none; -} - -.c-dropdown__item { - margin-bottom: 0.375rem; - - &:hover { - .c-dropdown__indicator { - opacity: 0.6; - } - } -} - - - -.c-dropdown__item:last-child { - margin-bottom: 0; -} - -.c-dropdown__divider { - border-color: #555; - border-style: dotted; - margin-top: 12px; - margin-bottom: 12px; -} - -// ============================================================================= -// Arrows -// ============================================================================= -.u-arrow:before { - content: ''; - border: solid 0.35rem transparent; - display: block; - position: absolute; -} - -.u-arrow--tl:before { - bottom: 100%; - left: 1rem; -} - -// ============================================================================= -// Default dropdown theme -// ============================================================================= - -// .t-default { - -// } -.t-default .u-btn-current { - border-color: rgba(0, 0, 0, 0.15); - color: #43b1b0; -} - -.t-default .u-btn-current:hover { - background: #43b1b0; - color: #fff; - border-color: #43b1b0; -} - -.t-default .u-btn-current:active { - background: #333; - color: #fff; - border-color: #333; -} - -.t-inverted .u-btn-current { - border-color: rgba(0, 0, 0, 0.25); - color: #fff; -} - -.t-inverted .u-btn-current:hover { - background-color: $color-teal-darker; - border-color: $color-teal-darker; -} - -.t-inverted .u-btn-current:active { - border-color: rgba(0, 0, 0, 0.25); - background: #333; - color: #fff; -} - - -// ============================================================================= -// Dark theme -// ============================================================================= -.t-dark .u-link { - color: #fff; -} - -.t-dark .u-link:hover { - color: #aaa; -} - -.t-dark .u-background { - background: #333; -} - -.t-dark .u-arrow:before { - border-bottom-color: #333; -} - -@keyframes dropdownIn { - 0% { - opacity: 0; - } - - 100% { - opacity: 1; - } -} - -// ============================================================================= -// Light theme -// ============================================================================= -.t-light .u-link { - color: #333; -} - -.t-light .u-link:hover { - color: #aaa; -} - -.t-light .u-background { - background: #fff; - border-color: #ccc; -} - -.t-light .u-arrow:before { - border-bottom-color: #fff; -} - -// ============================================================================= -// States -// ============================================================================= -.u-toggle { - display: none; -} - -.is-open .u-toggle { - display: block; -} - - - diff --git a/client/scss/components/_dropdown.scss b/client/scss/components/_dropdown.scss new file mode 100644 index 00000000000..93b8065d39c --- /dev/null +++ b/client/scss/components/_dropdown.scss @@ -0,0 +1,66 @@ +// ============================================================================= +// Listing view smaller dropdowns +// ============================================================================= + +// .c-dropdown { +// } +.c-dropdown__button { + display: inline-block; + box-sizing: border-box; + padding-left: 0.5rem; + padding-right: 0.25rem; + // Make this the same as the other buttons + line-height: 1.85; + border: solid 1px transparent; + border-radius: 2px; + font-size: 0.95em; + cursor: pointer; + -webkit-font-smoothing: subpixel-antialiased; + user-select: none; +} + +.c-dropdown__toggle { + display: inline-block; +} + +.c-dropdown__menu.c-dropdown__menu { + margin-top: 0.75rem; + padding: 0.75rem 1rem; + min-width: 8rem; + text-transform: none; + position: absolute; + z-index: 1; + animation: dropdownIn 0.1s ease-out backwards; + list-style: none; +} + +.c-dropdown__item { + margin-bottom: 0.375rem; + + &:hover { + .c-dropdown__indicator { + opacity: 0.6; + } + } +} + +.c-dropdown__item:last-child { + margin-bottom: 0; +} + +.c-dropdown__divider { + border-color: #555; + border-style: dotted; + margin-top: 12px; + margin-bottom: 12px; +} + +@keyframes dropdownIn { + 0% { + opacity: 0; + } + + 100% { + opacity: 1; + } +} diff --git a/client/scss/components/_footer.scss b/client/scss/components/_footer.scss new file mode 100644 index 00000000000..6d8ae3ea75a --- /dev/null +++ b/client/scss/components/_footer.scss @@ -0,0 +1,76 @@ +footer { + @include transition(bottom 0.5s ease 1s); + @include row(); + border-radius: 3px 3px 0 0; + box-shadow: 0 0 2px rgba(255, 255, 255, 0.5); + background: $color-grey-1; + position: fixed; + bottom: 0; + padding: 0.5em; + width: 90%; + margin: 0 5%; + color: $color-white; + + ul { + @include unlist(); + } + + li { + float: left; + } + + .actions { + width: 250px; + margin-right: $grid-gutter-width / 2; + } + + .preview .dropdown { + width: 250px; + } + + .meta { + float: right; + text-align: right; + padding: 7px $grid-gutter-width / 2; + font-size: 0.85em; + + p { + margin: 0; + margin-right: $grid-gutter-width; + white-space: nowrap; + } + + a { + color: inherit; + + &:hover { + color: $color-link; + } + } + } + + @include media-breakpoint-down(xs) { + .actions, + .preview, + .preview .dropdown { + width: 100%; + } + + .meta { + p { + white-space: normal; + width: 100%; + } + + .avatar { + left: auto; + } + } + } + + @include media-breakpoint-up(sm) { + margin-left: $desktop-nice-padding; + margin-right: $desktop-nice-padding; + width: calc(100% - #{$menu-width} - #{2 * $desktop-nice-padding}); + } +} diff --git a/client/scss/components/_forms.scss b/client/scss/components/_forms.scss new file mode 100644 index 00000000000..81e0e8b64b8 --- /dev/null +++ b/client/scss/components/_forms.scss @@ -0,0 +1,420 @@ +// These are the generic stylings for forms of any type. +// If you're styling something specific to the page editing interface, +// it probably ought to go in layouts/page-editor.scss + +// TODO: mixin, +// These these styles are currently in elements +// but the ones for the class should be here +// +// label, +// .label { +// text-transform: none; +// font-weight: bold; +// color: $color-grey-1; +// font-size: 1.1em; +// display: block; +// padding: 0 0 0.8em; +// margin: 0; +// line-height: 1.3em; +// +// .checkbox &, +// .radio & { +// display: inline; +// } +// } +.plain-checkbox-label { + // cancel heavy / floated label styles, for labels that should appear inline against checkboxes + + float: none; + color: inherit; + font-weight: inherit; + font-size: inherit; +} + +// TODO: mixin, +// These these styles are currently in elements +// but the ones for the classes should be here +// +// input, +// textarea, +// select, +// .halloeditor, +// .tagit { +// appearance: none; +// box-sizing: border-box; +// border-radius: 6px; +// width: 100%; +// font-family: Open Sans,Arial,sans-serif; +// border: 1px solid $color-input-border; +// padding: 0.9em 1.2em; +// background-color: $color-fieldset-hover; +// color: $color-text-input; +// font-size: 1.2em; +// font-weight: 300; +// +// &:hover { +// background-color: $color-white; +// } +// +// &:focus { +// background-color: $color-input-focus; +// border-color: $color-input-focus-border; +// } +// +// &:disabled, +// &[disabled], +// &:disabled:hover, +// &[disabled]:hover { +// background-color: inherit; +// cursor: default; +// color: $color-grey-4; +// } +// } + +// Reset the arrow on ``s in IE10+. +select::-ms-expand { + display: none; +} + +.file_field { + .input { + label { + float: none; + display: inline; + padding: 0; + } + + input[type=checkbox] { + margin-top: 5px; + } + + a { + &:after { + content: ' '; + display: block; + } + } + } +} + + +// radio and check boxes +input[type=radio], +input[type=checkbox] { + border-radius: 0; + cursor: pointer; + border: 0; +} + +input[type=radio] { + height: 12px; + width: auto; + position: relative; + margin-right: 27px; +} + +input[type=radio]:before { + border-radius: 100%; + font-family: wagtail; + font-style: normal; + text-align: center; + position: absolute; + top: -5px; + left: -2px; + cursor: pointer; + display: block; + content: map-get($icons, 'radio-full'); + width: 1em; + height: 1em; + line-height: 1.1em; + padding: 4px; + background-color: $color-white; + color: $color-grey-4; + border: 1px solid $color-grey-4; +} + +input[type=radio]:checked:before { + content: map-get($icons, 'radio-full'); + color: $color-teal; +} + +input[type=checkbox] { + height: 12px; + width: auto; + position: relative; + margin-right: 27px; +} + +input[type=checkbox]:before { + font-family: wagtail; + font-style: normal; + text-align: center; + position: absolute; + top: -5px; + cursor: pointer; + display: block; + content: map-get($icons, 'tick'); + line-height: 20px; + width: 20px; + height: 20px; + background-color: $color-white; + border: 1px solid $color-grey-4; + color: $color-white; +} + +input[type=checkbox]:checked:before { + color: $color-teal; +} + + +// Special styles to counteract Firefox's completely unwarranted assumptions about button styles +input[type=submit], +input[type=reset], +input[type=button], +button { + padding: 0 1em; + + @include media-breakpoint-up(sm) { + &.button-small { + height: 2em; + } + } +} + +// Transitions +fieldset, +input, +textarea, +select { + @include transition(background-color 0.2s ease); +} diff --git a/client/scss/elements/_typography.scss b/client/scss/elements/_typography.scss new file mode 100644 index 00000000000..ba4574f0ed1 --- /dev/null +++ b/client/scss/elements/_typography.scss @@ -0,0 +1,93 @@ +@include webfont(Open Sans, opensans-light, 300, normal); +@include webfont(Open Sans, opensans-regular, 400, normal); +@include webfont(Open Sans, opensans-semibold, 600, normal); +@include webfont(Open Sans, opensans-bold, 700, normal); +@include webfont(Roboto Slab, robotoslab-regular, 400, normal); +@include webfont(Roboto Slab, robotoslab-bold, 700, normal); + +body { + -webkit-font-smoothing: antialiased; // Do not remove! + font-family: Open Sans, Arial, sans-serif; + font-size: 85%; + line-height: 1.5em; + color: $color-text-base; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + font-weight: normal; +} + +h1 { + line-height: 1.3em; + font-size: 1.5em; + text-transform: uppercase; + color: $color-grey-1; + font-weight: 600; + + span { + text-transform: none; + font-weight: 300; + } +} + +h2 { + text-transform: uppercase; + font-size: 1.3em; + font-family: Open Sans; + font-weight: 600; + color: $color-grey-2; +} + +p { + margin-top: 0; +} + +a { + // @include transition(color 0.2s ease, background-color 0.2s ease); + color: $color-link; + text-decoration: none; + + &:hover { + color: $color-link-hover; + } +} + +code { + box-shadow: inset 0 0 4px 0 rgba(0, 0, 0, 0.2); + background-color: $color-fieldset-hover; + padding: 2px 5px; +} + +kbd { + border-radius: 3px; + font-family: Open Sans, Arial, sans-serif; + border: 1px solid $color-grey-2; + border-color: rgba(0, 0, 0, 0.2); + padding: 0.3em 0.5em; +} + +dl, +dt, +dd { + padding: 0; + margin: 0; +} + +dl { + margin-top: 1em; +} + +dt { + color: $color-grey-2; + text-transform: uppercase; + font-size: 0.9em; +} + +dd { + margin-bottom: 1em; +} diff --git a/client/scss/generic/_generic.scss b/client/scss/generic/_generic.scss new file mode 100644 index 00000000000..441a18b24a4 --- /dev/null +++ b/client/scss/generic/_generic.scss @@ -0,0 +1 @@ +// generic styles go in this folder. diff --git a/client/scss/objects/_avatar.scss b/client/scss/objects/_avatar.scss new file mode 100644 index 00000000000..760ac1890af --- /dev/null +++ b/client/scss/objects/_avatar.scss @@ -0,0 +1,35 @@ +// user avatars +.avatar { + border-radius: 100%; + position: relative; + display: inline-block; + vertical-align: middle; + text-align: center; + overflow: hidden; + width: 50px; + height: 50px; + + img { + position: absolute; + z-index: 2; + top: 0; + left: 0; + right: 0; + border: 0; + } + + &.small { + vertical-align: middle; + margin: 0 0.5em; + width: 25px; + height: 25px; + } + + &.square { + border-radius: 0; + + &:before { + border-radius: 0; + } + } +} diff --git a/client/scss/_objects.scss b/client/scss/objects/_objects.scss similarity index 51% rename from client/scss/_objects.scss rename to client/scss/objects/_objects.scss index c62ae707d9b..b1ff5f7e583 100644 --- a/client/scss/_objects.scss +++ b/client/scss/objects/_objects.scss @@ -5,3 +5,12 @@ vertical-align: middle; line-height: 1.5; } + + +// For dropdowns +.o-icon { + display: inline-block; + vertical-align: middle; + line-height: 1; + margin-top: -0.25rem; +} diff --git a/client/scss/overrides/_pages.homepage.scss b/client/scss/overrides/_pages.homepage.scss new file mode 100644 index 00000000000..f903223a8fa --- /dev/null +++ b/client/scss/overrides/_pages.homepage.scss @@ -0,0 +1,3 @@ +.homepage h1 { + text-transform: none; +} diff --git a/client/scss/overrides/_pages.page-explorer.scss b/client/scss/overrides/_pages.page-explorer.scss new file mode 100644 index 00000000000..6579e27f4a5 --- /dev/null +++ b/client/scss/overrides/_pages.page-explorer.scss @@ -0,0 +1,3 @@ +.page-explorer h2 { + text-transform: none; +} diff --git a/client/scss/overrides/_utilities.dropdowns.scss b/client/scss/overrides/_utilities.dropdowns.scss new file mode 100644 index 00000000000..cae0b9628f4 --- /dev/null +++ b/client/scss/overrides/_utilities.dropdowns.scss @@ -0,0 +1,105 @@ +// ============================================================================= +// Arrows +// ============================================================================= +.u-arrow:before { + content: ''; + border: solid 0.35rem transparent; + display: block; + position: absolute; +} + +.u-arrow--tl:before { + bottom: 100%; + left: 1rem; +} + +// ============================================================================= +// Default dropdown theme +// ============================================================================= + +// .t-default { + +// } +.t-default .u-btn-current { + border-color: rgba(0, 0, 0, 0.15); + color: $color-teal; +} + +.t-default .u-btn-current:hover { + background: $color-teal; + color: #fff; + border-color: $color-teal; +} + +.t-default .u-btn-current:active { + background: #333; + color: #fff; + border-color: #333; +} + +.t-inverted .u-btn-current { + border-color: rgba(0, 0, 0, 0.35); + color: #fff; +} + +.t-inverted .u-btn-current:hover { + background-color: $color-teal-darker; + border-color: rgba(0, 0, 0, 0.35); +} + +.t-inverted .u-btn-current:active { + border-color: rgba(0, 0, 0, 0.35); + background: #333; + color: #fff; +} + + +// ============================================================================= +// Dark theme +// ============================================================================= +.t-dark .u-link { + color: #fff; +} + +.t-dark .u-link:hover { + color: #aaa; +} + +.t-dark .u-background { + background: #333; +} + +.t-dark .u-arrow:before { + border-bottom-color: #333; +} + +// ============================================================================= +// Light theme +// ============================================================================= +.t-light .u-link { + color: #333; +} + +.t-light .u-link:hover { + color: #aaa; +} + +.t-light .u-background { + background: #fff; + border-color: #ccc; +} + +.t-light .u-arrow:before { + border-bottom-color: #fff; +} + +// ============================================================================= +// States +// ============================================================================= +.u-toggle { + display: none; +} + +.is-open .u-toggle { + display: block; +} diff --git a/client/scss/overrides/_utilities.focus.scss b/client/scss/overrides/_utilities.focus.scss new file mode 100644 index 00000000000..e53f1aaf69a --- /dev/null +++ b/client/scss/overrides/_utilities.focus.scss @@ -0,0 +1,11 @@ +// stylelint-disable declaration-no-important +// Set global focus outline styles so they are consistent across the UI, +// without individual components having to explicitly define focus styles. +// Using !important because we want to enforce only one style is used across the UI. +.focus-outline-on *:focus { + outline: $focus-outline-width solid $color-focus-outline !important; +} + +.focus-outline-off *:focus { + outline: none !important; +} diff --git a/client/scss/_utilities.scss b/client/scss/overrides/_utilities.hidden.scss similarity index 51% rename from client/scss/_utilities.scss rename to client/scss/overrides/_utilities.hidden.scss index fb0bfbf4595..b2b697b0e36 100644 --- a/client/scss/_utilities.scss +++ b/client/scss/overrides/_utilities.hidden.scss @@ -3,38 +3,38 @@ display: none !important; } -.u-hidden\@medium { - @include medium { +.u-hidden\@sm { + @include media-breakpoint-up(sm) { display: none !important; } } -.u-hidden\@small { - @include small { +.u-hidden\@xs { + @include media-breakpoint-down(xs) { display: none !important; } } -.u-inline\@medium { - @include medium { +.u-inline\@sm { + @include media-breakpoint-up(sm) { display: inline !important; } } -.u-inline\@small { - @include small { +.u-inline\@xs { + @include media-breakpoint-down(xs) { display: inline !important; } } -.u-block\@medium { - @include medium { +.u-block\@sm { + @include media-breakpoint-up(sm) { display: block !important; } } -.u-block\@small { - @include small { +.u-block\@xs { + @include media-breakpoint-down(xs) { display: block !important; } } diff --git a/client/scss/overrides/_utilities.legacy.scss b/client/scss/overrides/_utilities.legacy.scss new file mode 100644 index 00000000000..9719d97cf0e --- /dev/null +++ b/client/scss/overrides/_utilities.legacy.scss @@ -0,0 +1,55 @@ +.clearfix { + @include clearfix(); +} + +.nice-padding { + padding-left: $mobile-nice-padding; + padding-right: $mobile-nice-padding; + + @include media-breakpoint-up(sm) { + padding-left: $desktop-nice-padding; + padding-right: $desktop-nice-padding; + } +} + +@include media-breakpoint-up(sm) { + .divider-before { + border-left: 1px solid $color-grey-4; + } + + .divider-after { + border-right: 1px solid $color-grey-4; + } + +} + +body.reordering { + overflow: visible; +} + +// Show a transparency grid in background +.show-transparency { + background: url('#{$images-root}transparency.svg'); +} + +// make a block-level element inline +.inline { + display: inline; +} + +.inline-block { + display: inline-block; +} + +.block { + display: block; +} + +.unlist { + @include unlist(); +} + +// utility class to allow things to be scrollable if their contents can't wrap more nicely +.overflow { + overflow: auto; +} diff --git a/client/scss/overrides/_utilities.text.legacy.scss b/client/scss/overrides/_utilities.text.legacy.scss new file mode 100644 index 00000000000..84e7d3602c9 --- /dev/null +++ b/client/scss/overrides/_utilities.text.legacy.scss @@ -0,0 +1,3 @@ +.unbold { + font-weight: normal; +} diff --git a/client/scss/overrides/_utilities.text.scss b/client/scss/overrides/_utilities.text.scss new file mode 100644 index 00000000000..9f97d0099a2 --- /dev/null +++ b/client/scss/overrides/_utilities.text.scss @@ -0,0 +1,11 @@ +.u-text-transform-uppercase { + text-transform: uppercase; +} + +.u-text-weight-normal { + font-weight: normal; +} + +.u-para { + margin-bottom: 1rem; +} diff --git a/client/scss/overrides/_utilities.visuallyhidden.scss b/client/scss/overrides/_utilities.visuallyhidden.scss new file mode 100644 index 00000000000..41166b92a50 --- /dev/null +++ b/client/scss/overrides/_utilities.visuallyhidden.scss @@ -0,0 +1,7 @@ +.visuallyvisible { + @include visuallyvisible; +} + +.visuallyhidden { + @include visuallyhidden; +} diff --git a/wagtail/admin/static_src/wagtailadmin/scss/components/_datetimepicker.scss b/client/scss/overrides/_vendor.datetimepicker.scss similarity index 96% rename from wagtail/admin/static_src/wagtailadmin/scss/components/_datetimepicker.scss rename to client/scss/overrides/_vendor.datetimepicker.scss index cbf22cb8126..10f6eeeeda7 100644 --- a/wagtail/admin/static_src/wagtailadmin/scss/components/_datetimepicker.scss +++ b/client/scss/overrides/_vendor.datetimepicker.scss @@ -84,7 +84,7 @@ float: left; &:before { - content: 'z'; + content: map-get($icons, 'arrow-left'); } } @@ -93,7 +93,7 @@ margin-left: 5px; &:before { - content: 'W'; + content: map-get($icons, 'home'); } } @@ -101,7 +101,7 @@ float: right; &:before { - content: 'n'; + content: map-get($icons, 'arrow-right'); } } @@ -127,11 +127,11 @@ } .xdsoft_prev:before { - content: 'e'; + content: map-get($icons, 'arrow-up'); } .xdsoft_next:before { - content: 'q'; + content: map-get($icons, 'arrow-down'); } .xdsoft_time_box { diff --git a/client/scss/overrides/_vendor.tagit.scss b/client/scss/overrides/_vendor.tagit.scss new file mode 100644 index 00000000000..88138fa230b --- /dev/null +++ b/client/scss/overrides/_vendor.tagit.scss @@ -0,0 +1,43 @@ +// taggit tagging +.tagit { + padding: 0.6em 1.2em; + + .tagit-choice { + border: 0; + } +} + +// Additional specificity (.admin_tag_widget ) required to override tagit stylesheets, +// which get added after the core CSS, and otherweise trump our styles. +.admin_tag_widget ul.tagit input[type='text'] { + padding: 0.2em 0.5em; +} + +// Additional specificity (.admin_tag_widget ) required to override tagit stylesheets, +// which get added after the core CSS, and otherweise trump our styles. +.admin_tag_widget ul.tagit li.tagit-choice-editable { + padding: 0 23px 0 0; +} + +.ui-front { // provided by jqueryui but not high enough an index + z-index: 1000; +} + +.tagit-close { + .ui-icon-close { + margin-left: 1em; + text-indent: 0; + background: none; + } + + .ui-icon-close:before { + font-family: wagtail; + display: block; + color: $color-grey-3; + content: map-get($icons, 'cross'); + } + + .ui-icon-close:hover:before { + color: $color-red; + } +} diff --git a/client/scss/settings/_variables.icons.scss b/client/scss/settings/_variables.icons.scss new file mode 100644 index 00000000000..8acf36debbd --- /dev/null +++ b/client/scss/settings/_variables.icons.scss @@ -0,0 +1,89 @@ +$icons: ( + 'arrow-down-big': '\e030', + 'arrow-down': '\e01a', + 'arrow-left': '\e022', + 'arrow-right': '\e017', + 'arrow-up-big': '\e02f', + 'arrow-up': '\e010', + 'arrows-up-down': '\e016', + 'bin': '\e038', + 'bold': '\e026', + 'chain-broken': '\e047', + 'code': '\e001', + 'cog': '\e020', + 'cogs': '\e00c', + 'collapse-down': '\e03f', + 'collapse-up': '\e03e', + 'cross': '\e012', + 'date': '\e045', + 'doc-empty-inverse': '\e00d', + 'doc-empty': '\e00e', + 'doc-full-inverse': '\e01b', + 'doc-full': '\e018', + 'download': '\e044', + 'edit': '\e00f', + 'folder-inverse': '\e014', + 'folder-open-1': '\e013', + 'folder-open-inverse': '\e01f', + 'folder': '\e01c', + 'form': '\e00b', + 'grip': '\e03b', + 'group': '\e031', + 'help': '\e041', + // help-inverse directly renders the corresponding character. + 'help-inverse': '?', + 'home': '\e035', + // horizontalrule is not rendered as an icon font – it uses a unicode dash character rendered with a fallback font. + 'horizontalrule': '\2014', + 'image': '\e019', + 'italic': '\e027', + 'link': '\e02c', + 'list-ol': '\e029', + 'list-ul': '\e028', + 'locked': '\e009', + 'logout': '\e049', + 'mail': '\e015', + 'media': '\e032', + 'no-view': '\e006', + 'openquote': '\e000', + 'order-down': '\e036', + 'order-up': '\e037', + 'order': '\e034', + 'password': '\e033', + 'pick': '\e03d', + 'pilcrow': '\e002', + 'placeholder': '\e003', + 'plus-inverse': '\e024', + 'plus': '\e01d', + 'radio-empty': '\e02e', + 'radio-full': '\e02d', + 'redirect': '\e03c', + 'repeat': '\e02b', + 'search': '\e011', + 'site': '\e007', + 'snippet': '\e025', + 'spinner': '\e03a', + 'strikethrough': '\e04a', + 'subscript': '\e04c', + 'success': '\e043', + 'superscript': '\e04b', + 'table': '\e048', + 'tag': '\e01e', + 'tick-inverse': '\e023', + 'tick': '\e021', + 'time': '\e008', + 'title': '\e046', + 'undo': '\e02a', + 'unlocked': '\e00a', + 'user': '\e004', + 'view': '\e005', + 'wagtail-inverse': '\e040', + 'wagtail': '\e039', + 'warning': '\e042', +); + +$icons-after: ( + 'arrow-down-after': map-get($icons, 'arrow-down'), + 'arrow-right-after': map-get($icons, 'arrow-right'), + 'arrow-up-after': map-get($icons, 'arrow-up'), +); diff --git a/client/scss/settings/_variables.scss b/client/scss/settings/_variables.scss new file mode 100644 index 00000000000..7c55f7029ff --- /dev/null +++ b/client/scss/settings/_variables.scss @@ -0,0 +1,120 @@ +// paths + +// We can't use absolute paths here, because those are dependent on Django's +// STATIC_URL setting. Instead, relative paths from the final location of the +// compiled CSS files are used. +// */ + +$static-root: '../../'; +$images-root: $static-root + 'wagtailadmin/images/'; +$font-root: '../../wagtailadmin/fonts/'; + +// grid settings +$grid-columns: 12; +$grid-gutter-width: 3%; +$grid-max-width: 1200px; +$grid-content-indent: 0.7; + +$mobile-nice-padding: 20px; +$desktop-nice-padding: 50px; + +// screen breakpoints +$breakpoints: ( + xs: 0, + sm: 50em, // 800px + md: 56.25em, // 900px + lg: 75em, // 1200px + xl: 100em, // 1440px +); + +// colours +$color-teal: #007d7e; +$color-teal-darker: darken(adjust-hue($color-teal, 1), 4); +$color-teal-dark: darken(adjust-hue($color-teal, 1), 7); + +$color-blue: #71b2d4; +$color-red: #cd3238; +$color-red-dark: #b4191f; +$color-orange: #e9b04d; +$color-orange-dark: #bb5b03; +$color-green: #189370; +$color-green-dark: #157b57; +$color-salmon: #f37e77; +$color-salmon-light: #fcf2f2; +$color-white: #fff; +$color-black: #000; + +// darker to lighter +$color-grey-1: darken($color-white, 80); +$color-grey-2: darken($color-white, 70); +$color-grey-3: darken($color-white, 15); +$color-grey-4: darken($color-white, 10); +$color-grey-5: darken($color-white, 2); + +$color-menu-text: darken($color-white, 20); + +$color-thead-bg: $color-grey-5; +$color-header-bg: $color-teal; + +$color-fieldset-hover: $color-grey-5; +$color-input-border: $color-grey-4; +$color-input-focus: lighten(desaturate($color-teal, 40), 72); +$color-input-focus-border: lighten(saturate($color-teal, 12), 10); +$color-input-error-bg: lighten(saturate($color-red, 28), 45); + +$color-button: $color-teal; +$color-button-hover: $color-teal-darker; +$color-button-yes: $color-green-dark; +$color-button-yes-hover: darken($color-button-yes, 8%); +$color-button-no: $color-red-dark; +$color-button-no-hover: darken($color-button-no, 20%); +$color-button-warning: $color-orange-dark; +$color-button-warning-hover: darken($color-button-warning, 20%); + +$color-link: $color-teal-darker; +$color-link-hover: $color-teal-dark; + +// The focus outline color is defined without reusing a named color variable +// because it shouldn’t be reused for anything else in the UI. +$color-focus-outline: #ffbf47; + +$color-text-base: darken($color-white, 85); +$color-text-input: darken($color-white, 90); + +// Color states +$color-state-live: #59b524; +$color-state-draft: #808080; +$color-state-absent: #ff8f11; +$color-state-live-draft: #43b1b0; + +// Fonts +$font-sans: Open Sans, Arial, sans-serif; +$font-serif: Roboto Slab, Georgia, serif; + +// misc sizing +$thumbnail-width: 130px; +$menu-width: 200px; +$menu-width-max: 320px; +$mobile-nav-indent: 50px; + +$focus-outline-width: 3px; + +$nav-wrapper-inner-z-index: 26; +$draftail-editor-z-index: $nav-wrapper-inner-z-index + 1; + +// Nav +$nav-grey-1: darken($color-white, 80); +$nav-grey-2: darken($color-white, 60); +$nav-item-hover-bg: rgba(100, 100, 100, 0.15); +$nav-item-active-bg: darken($color-white, 90); +$submenu-bg: darken($color-white, 85); +$footer-account: $nav-item-active-bg; +$footer-submenu: $submenu-bg; + +// Nav search +$nav-search-color: darken($color-white, 20); +$nav-search-border: darken($color-white, 40); +$nav-search-bg: $nav-grey-1; +$nav-search-hover-bg: $nav-item-hover-bg; +$nav-search-focus-color: $color-white; +$nav-search-focus-bg: $nav-item-hover-bg; diff --git a/client/scss/styles.scss b/client/scss/styles.scss index c79065e9e07..e65d405bd3a 100644 --- a/client/scss/styles.scss +++ b/client/scss/styles.scss @@ -1,8 +1,157 @@ -// ============================================================================= -// Wagtail CMS main stylesheet -// ============================================================================= - -@import 'tools.breakpoints'; -@import 'objects'; -@import 'components'; -@import 'utilities'; +/* ============================================================================= +/* Wagtail CMS main stylesheet +/* ============================================================================= + +REFERENCE + + * We organize our styles based on a combination of ITCSS and + the Sass 7-1 pattern. + * Classes should be written using BEM, which we modify to include a prefix. + * Every BEM block should have its own file. + +┌────────────┬────────────────────────┬──────────────┬────────┐ +│ Folder │ Contents │ ITCSS level │ Prefix │ +├────────────┼────────────────────────┼──────────────┼────────┤ +│ settings │ variables, maps, fonts │ 1 Settings │ │ +│ tools │ mixins, functions │ 2 Tools │ │ +│ generic │ resets │ 3 Generic │ │ +│ elements │ elements, no classes │ 4 Elements │ │ +│ objects │ classes │ 5 Objects │ o- │ +│ │ layout │ │ │ +│ components │ classes │ 6 Components │ c- │ +│ │ BEM blocks │ │ │ +│ overrides │ classes │ 7 Trumps │ u- │ +│ │ overrides, utilities │ │ │ +└────────────┴────────────────────────┴──────────────┴────────┘ + +SCSS: https://sass-lang.com/guide +ITCSS: https://www.creativebloq.com/web-design/manage-large-css-projects-itcss-101517528 +Sass 7-1 pattern: https://gist.github.com/rveitch/84cea9650092119527bc +BEM: http://getbem.com/ + + +OTHER PREFIXES + +┌────────┬─────────┐ +│ Prefix │ Purpose │ +├────────┼─────────┤ +│ t- │ theme │ +│ is- │ state │ +└────────┴─────────┘ + +==============================================================================*/ + + +/* SETTINGS +These are variables, maps, and fonts. +* No CSS should be produced by these files +*/ + +@import 'settings'; + + +/* TOOLS +These are functions and mixins. +* No CSS should be produced by these files. +*/ + +@import 'tools'; + + +/* GENERIC +This is for resets and other rules that affect large collections of bare elements. +* Changes to them should be very rare. +*/ + +// @import 'generic/generic'; + + +/* ELEMENTS +These are base styles for bare HTML elements. +* Changes to them should be very rare. +*/ + +@import 'elements/elements'; +@import 'elements/typography'; +@import 'elements/forms'; + + +/* OBJECTS +These are classes related to layout, known as 'objects' in ITCSS or OOCSS. +* This is for grids, wrappers, and other non-consmetic layout utilities. +* These classes are prefixed with `.o-`. +*/ + +@import 'objects/objects'; +@import 'objects/avatar'; + + +/* COMPONENTS +These are classes for components. +* These classes (unless legacy) are prefixed with `.c-`. +* React component styles live in the same folders as their React components, + which is the preferred pattern over housing them in the scss folder. +*/ + +@import '../src/components/Transition/Transition'; +@import '../src/components/LoadingSpinner/LoadingSpinner'; +@import '../src/components/PublicationStatus/PublicationStatus'; +@import '../src/components/Explorer/Explorer'; + +// Legacy +@import 'components/icons'; +@import 'components/tabs'; +@import 'components/dropdown'; +@import 'components/dropdown.legacy'; +@import 'components/help-block'; +@import 'components/modals'; +@import 'components/forms'; +@import 'components/button'; +@import 'components/chooser'; +@import 'components/tag'; +@import 'components/listing'; +@import 'components/messages'; +@import 'components/messages.capability'; +@import 'components/messages.status'; +@import 'components/header'; +@import 'components/progressbar'; +@import 'components/main-nav'; +@import 'components/indicator'; +@import 'components/tooltips'; +@import 'components/logo'; +@import 'components/grid.legacy'; +@import 'components/breadcrumb'; +@import 'components/footer'; +@import 'components/loading-mask'; +@import 'components/media-placeholder'; +@import 'components/human-readable-date'; +@import 'components/link.legacy'; +@import 'components/privacy-indicator'; +@import 'components/status-tag'; + + +/* OVERRIDES +These are classes that provide overrides. +* Higher specificity is allowed here because these are overrides and imported last. +*/ + +// VENDOR: overrides of vendor styles. +@import 'overrides/vendor.datetimepicker'; +@import 'overrides/vendor.tagit'; + + +// UTILITIES: classes that do one simple thing. +@import 'overrides/utilities.hidden'; +@import 'overrides/utilities.text'; +@import 'overrides/utilities.dropdowns'; +@import 'overrides/utilities.focus'; +@import 'overrides/utilities.visuallyhidden'; + +// Legacy utilities +@import 'overrides/utilities.text.legacy'; +@import 'overrides/utilities.legacy'; + + +// PAGES: page-specific overrides +@import 'overrides/pages.homepage'; +@import 'overrides/pages.page-explorer'; diff --git a/client/scss/tools/_functions.breakpoints.scss b/client/scss/tools/_functions.breakpoints.scss new file mode 100644 index 00000000000..c53b99898ce --- /dev/null +++ b/client/scss/tools/_functions.breakpoints.scss @@ -0,0 +1,33 @@ +// Based upon the fine work and thoughts from Bootstrap v4. +// +// Copyright 2011-2018 The Bootstrap Authors +// Copyright 2011-2018 Twitter, Inc. +// Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + +// Name of the next breakpoint, or null for the last breakpoint. +// +// >> breakpoint-next(sm) +// md +@function breakpoint-next($name) { + $breakpoint-names: map-keys($breakpoints); + $n: index($breakpoint-names, $name); + @return if($n < length($breakpoint-names), nth($breakpoint-names, $n + 1), null); +} + +// Minimum breakpoint width. Null for the smallest (first) breakpoint. +// +// >> breakpoint-min(sm) +// 50em +@function breakpoint-min($name) { + $min: map-get($breakpoints, $name); + @return if($min != 0, $min, null); +} + +// Maximum breakpoint width. Null for the largest (last) breakpoint. +// +// >> breakpoint-max(sm) +// 56.1875em +@function breakpoint-max($name) { + $next: breakpoint-next($name); + @return if($next, breakpoint-min($next) - 0.0625em, null); +} diff --git a/client/scss/tools/_mixins.breakpoints.scss b/client/scss/tools/_mixins.breakpoints.scss new file mode 100644 index 00000000000..28bd6fac88f --- /dev/null +++ b/client/scss/tools/_mixins.breakpoints.scss @@ -0,0 +1,32 @@ +// Based upon the fine work and thoughts from Bootstrap v4. +// +// Copyright 2011-2018 The Bootstrap Authors +// Copyright 2011-2018 Twitter, Inc. +// Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + + +// Media of at least the minimum breakpoint width. No query for the smallest breakpoint. +// Makes the @content apply to the given breakpoint and wider. +@mixin media-breakpoint-up($name) { + $min: breakpoint-min($name); + @if $min { + @media screen and (min-width: $min) { + @content; + } + } @else { + @content; + } +} + +// Media of at most the maximum breakpoint width. No query for the largest breakpoint. +// Makes the @content apply to the given breakpoint and narrower. +@mixin media-breakpoint-down($name) { + $max: breakpoint-max($name); + @if $max { + @media screen and (max-width: $max) { + @content; + } + } @else { + @content; + } +} diff --git a/client/scss/tools/_mixins.fonts.scss b/client/scss/tools/_mixins.fonts.scss new file mode 100644 index 00000000000..877d1054bda --- /dev/null +++ b/client/scss/tools/_mixins.fonts.scss @@ -0,0 +1,26 @@ +/* +NB: Due to Wagtail's browser support the following @font-face formats are required: +- WOFF for modern browsers +- WOFF2 For super-modern browsers + +This example is all we need now: + +@font-face { + font-family: 'MyWebFont'; + src: url('myfont.woff2') format('woff2'), + url('myfont.woff') format('woff'); +} + +See https://css-tricks.com/snippets/css/using-font-face/ for more information. + +*/ + +@mixin webfont($fontname, $filestub, $weight, $style:normal) { + @font-face { + font-family: '#{$fontname}'; + src: url('#{$font-root}#{$filestub}.woff2') format('woff2'), + url('#{$font-root}#{$filestub}.woff') format('woff'); + font-weight: $weight; + font-style: $style; + } +} diff --git a/wagtail/admin/static_src/wagtailadmin/scss/_mixins.scss b/client/scss/tools/_mixins.general.scss similarity index 83% rename from wagtail/admin/static_src/wagtailadmin/scss/_mixins.scss rename to client/scss/tools/_mixins.general.scss index 583ac739327..1b826f489da 100644 --- a/wagtail/admin/static_src/wagtailadmin/scss/_mixins.scss +++ b/client/scss/tools/_mixins.general.scss @@ -1,9 +1,6 @@ // ============================================================================= // Mixins // ============================================================================= - -@import '../../../../../client/scss/tools.breakpoints'; - // Please note that the mixins partial shouldn't include any classes. This is so // it can be included in any file without accidentally producing output @@ -110,17 +107,6 @@ } -@mixin webfont($fontname, $filestub, $weight, $style:normal) { - @font-face { - font-family: '#{$fontname}'; - src: url('#{$font-root}#{$filestub}.woff2') format('woff2'), - url('#{$font-root}#{$filestub}.woff') format('woff'), - url('#{$font-root}#{$filestub}.ttf') format('truetype'); - font-weight: $weight; - font-style: $style; - } -} - // Applies given rules on hover, except for touch screens. // Relies on feature detection to add a no-touch class on the html element. @mixin hover { @@ -128,3 +114,9 @@ @content; } } + +// Where included, show the focus outline within focusable items instead of around them. +// This is useful when focusable items are tightly packed and there is no space in-between. +@mixin show-focus-outline-inside { + outline-offset: -1 * $focus-outline-width; +} diff --git a/wagtail/admin/static_src/wagtailadmin/scss/_grid.scss b/client/scss/tools/_mixins.grid.scss similarity index 96% rename from wagtail/admin/static_src/wagtailadmin/scss/_grid.scss rename to client/scss/tools/_mixins.grid.scss index 660e112a668..0b6ae790a85 100644 --- a/wagtail/admin/static_src/wagtailadmin/scss/_grid.scss +++ b/client/scss/tools/_mixins.grid.scss @@ -56,7 +56,7 @@ $padding: $grid-gutter-width * 0.5; padding-left: $mobile-nice-padding; padding-right: $mobile-nice-padding; - @include medium { + @include media-breakpoint-up(sm) { padding-left: $desktop-nice-padding; padding-right: $desktop-nice-padding; } @@ -66,7 +66,7 @@ $padding: $grid-gutter-width * 0.5; margin-left: $mobile-nice-padding; margin-right: $mobile-nice-padding; - @include medium { + @include media-breakpoint-up(sm) { margin-left: $desktop-nice-padding; margin-right: $desktop-nice-padding; } diff --git a/client/src/cli/component.js b/client/src/cli/component.js deleted file mode 100644 index 39997bbab7a..00000000000 --- a/client/src/cli/component.js +++ /dev/null @@ -1,90 +0,0 @@ -var path = require('path'); -var fs = require('fs'); -var Mustache = require('mustache'); - -var TEMPLATES = path.join(__dirname, '..', '..', 'template'); - -var files = [ -{ - name: 'component.js', - template: 'component.mst', - suffix: '.js', -}, -{ - name: 'style.scss', - template: 'style.mst' -}, -{ - name: 'README.md', - template: 'README.mst' -}, -{ - name: 'component.test.js', - template: 'component.test.mst', - suffix: '.test.js', -} -]; - - -// ============================================================================= -// Helper methods -// ============================================================================= - -function slugify(text) { - return text.toString().split(/(?=[A-Z])/).join('-').toLowerCase().trim() - .replace(/\s+/g, '-') // Replace spaces with - - .replace(/&/g, '-and-') // Replace & with 'and' - .replace(/[^\w\-]+/g, '') // Remove all non-word chars - .replace(/\-\-+/g, '-'); // Replace multiple - with single - -} - - -function write(name, data) { - fs.writeFile(name, data, function(err) { - if (err) { - return console.log('[ error ] ' + err); - } - console.log('[ created ] ' + name); - }); -} - - -// ============================================================================= -// Write files! -// ============================================================================= -function run(argv) { - var name = argv.name[0].toUpperCase() + argv.name.substring(1); - var slug = slugify(name); - var directory = path.join(argv.dir, slug); - - if (!fs.existsSync(directory)) { - fs.mkdirSync(directory); - } else { - console.warn('[ error ] ' + directory + ' already exists'); - return; - } - - files.forEach(function(file) { - var fileName = file.suffix ? name + file.suffix : file.name; - var template = fs.readFileSync(path.join(TEMPLATES, file.template), 'utf8'); - var newPath = path.join(directory, fileName); - var context = { - name: name, - slug: slug - }; - - write(newPath, Mustache.render(template, context)); - }); -} - - -function build(cli) { - return cli - .option('dir', { - default: process.env.PWD - }); -} - - -exports.handler = run; -exports.builder = build; diff --git a/client/src/cli/index.js b/client/src/cli/index.js deleted file mode 100755 index ac39b3e8d8f..00000000000 --- a/client/src/cli/index.js +++ /dev/null @@ -1,15 +0,0 @@ -#!/usr/bin/env node -var cli = require('yargs'); - -cli - .usage('Usage: $0 [options]') - .help('help'); - -cli - .command( - 'component ', - 'scaffold out a wagtail component', - require('./component')); - -cli - .argv; diff --git a/client/src/components/Button/Button.js b/client/src/components/Button/Button.js index 932755d079e..ec994244856 100644 --- a/client/src/components/Button/Button.js +++ b/client/src/components/Button/Button.js @@ -38,6 +38,7 @@ const Button = ({ target, preventDefault, onClick, + dialogTrigger, }) => { const hasText = children !== null; const iconName = isLoading ? 'spinner' : icon; @@ -54,6 +55,7 @@ const Button = ({ rel={target === '_blank' ? 'noopener noreferrer' : null} href={href} target={target} + aria-haspopup={dialogTrigger ? 'dialog' : null} > {hasText ? children : accessibleElt} @@ -73,6 +75,7 @@ Button.propTypes = { onClick: PropTypes.func, isLoading: PropTypes.bool, preventDefault: PropTypes.bool, + dialogTrigger: PropTypes.bool, }; Button.defaultProps = { @@ -85,6 +88,7 @@ Button.defaultProps = { onClick: null, isLoading: false, preventDefault: true, + dialogTrigger: false, }; export default Button; diff --git a/client/src/components/Button/Button.test.js b/client/src/components/Button/Button.test.js index eb69fe977fc..611b2d2ab43 100644 --- a/client/src/components/Button/Button.test.js +++ b/client/src/components/Button/Button.test.js @@ -20,12 +20,16 @@ describe('Button', () => { expect(shallow( + )} + + + + {/* At first we propose reloading the editor. If it still crashes, reload the whole page. */} + {reloads < MAX_EDITOR_RELOADS ? ( + + ) : ( + + )} + + +
+
+
+ {STRINGS.EDITOR_CRASH} + + {showContent && ( + ', result) @@ -285,9 +309,9 @@ def test_render_form_content(self): event = EventPage(title='Abergavenny sheepdog trials') form = EventPageForm(instance=event) - tabbed_interface = self.event_page_tabbed_interface.bind_to_instance( + tabbed_interface = self.event_page_tabbed_interface.bind_to( instance=event, - form=form + form=form, ) result = tabbed_interface.render_form_content() @@ -300,13 +324,17 @@ def test_render_form_content(self): class TestObjectList(TestCase): def setUp(self): + self.request = RequestFactory().get('/') + user = AnonymousUser() # technically, Anonymous users cannot access the admin + self.request.user = user # a custom ObjectList for EventPage self.event_page_object_list = ObjectList([ FieldPanel('title', widget=forms.Textarea), FieldPanel('date_from'), FieldPanel('date_to'), InlinePanel('speakers', label="Speakers"), - ], heading='Event details', classname="shiny").bind_to_model(EventPage) + ], heading='Event details', classname="shiny").bind_to( + model=EventPage, request=self.request) def test_get_form_class(self): EventPageForm = self.event_page_object_list.get_form_class() @@ -323,9 +351,9 @@ def test_render(self): event = EventPage(title='Abergavenny sheepdog trials') form = EventPageForm(instance=event) - object_list = self.event_page_object_list.bind_to_instance( + object_list = self.event_page_object_list.bind_to( instance=event, - form=form + form=form, ) result = object_list.render() @@ -333,8 +361,8 @@ def test_render(self): # result should contain ObjectList furniture self.assertIn('