diff --git a/.babelrc.js b/.babelrc.js deleted file mode 100644 index f8ee0cd15..000000000 --- a/.babelrc.js +++ /dev/null @@ -1,9 +0,0 @@ -module.exports = { - presets: [ - "@babel/preset-env" - ], - plugins: [ - '@wordpress/babel-plugin-import-jsx-pragma', - '@babel/plugin-transform-react-jsx', - ] -} \ No newline at end of file diff --git a/.distignore b/.distignore new file mode 100644 index 000000000..259d97f39 --- /dev/null +++ b/.distignore @@ -0,0 +1,47 @@ +# Directories +/.git/ +/.github/ +/.claude/ +/.phpunit.cache/ +/artifacts/ +/bin/ +/dist/ +/documentation/ +/node_modules/ +/tests/ +/vendor/ + +# Development configuration +.distignore +.editorconfig +.gitattributes +.gitignore +.nvmrc +.phpcs.xml.dist +.prettierignore +.prettierrc +.svnignore +.wp-env.json +.wp-env.override.json + +# Build tooling +babel.config.js +eslint.config.js +jest.config.js +playwright.config.js +webpack.config.js + +# Package management +composer.json +composer.lock +package.json +package-lock.json + +# Documentation (not needed in plugin distribution) +CHANGELOG.md +CONTRIBUTING.md +PUBLISHING.md +SECURITY.md + +# Test configuration +phpunit.xml.dist diff --git a/.editorconfig b/.editorconfig index 089d54616..99c33115f 100644 --- a/.editorconfig +++ b/.editorconfig @@ -14,7 +14,7 @@ insert_final_newline = true trim_trailing_whitespace = true indent_style = tab -[{*.yml,*.feature}] +[*.yml] indent_style = space indent_size = 2 diff --git a/.eslintignore b/.eslintignore deleted file mode 100644 index 50f443537..000000000 --- a/.eslintignore +++ /dev/null @@ -1,4 +0,0 @@ -*.build.js -node_modules -vendor -*.php diff --git a/.eslintrc.js b/.eslintrc.js deleted file mode 100644 index fe197efc2..000000000 --- a/.eslintrc.js +++ /dev/null @@ -1,38 +0,0 @@ -require( '@automattic/eslint-plugin-wpvip/init' ); - -module.exports = { - extends: [ 'plugin:@automattic/wpvip/recommended' ], - root: true, - env: { - jest: true, - }, - rules: { - "no-prototype-builtins": 0, - "no-eval": 0, - "complexity": 0, - "camelcase": 0, - "no-undef": 0, - "wpcalypso/import-docblock": 0, - "valid-jsdoc": 0, - "react/prop-types": 0, - "react/react-in-jsx-scope": 0, - "react-hooks/rules-of-hooks": 0, - "no-redeclare": 0, - "no-shadow": 0, - "no-nested-ternary": 0, - "no-var": 0, - "no-unused-vars": 0, - "no-useless-escape": 0, - "prefer-const": 0, - "no-global-assign": 0, - "no-constant-binary-expression": 0, - "valid-typeof": 0, - "eqeqeq": 0, - "radix": 0, - "no-eq-null": 0, - "array-callback-return": 0, - "no-unused-expressions": 0, - "no-alert": 0, - "no-lonely-if": 0, - } -}; diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 000000000..3b8daefd4 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,3 @@ +# The following teams will get auto-tagged for a review. +# See https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners +* @Automattic/vip-plugins diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 000000000..79a319e71 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,64 @@ +# Configuration for Dependabot version updates +# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file + +version: 2 +updates: + # Maintain dependencies for GitHub Actions + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + day: "monday" + groups: + actions: + patterns: ["*"] + labels: + - "dependencies" + commit-message: + prefix: "Actions" + include: "scope" + open-pull-requests-limit: 5 + + # Maintain dependencies for Composer + - package-ecosystem: "composer" + directory: "/" + schedule: + interval: "weekly" + day: "tuesday" + groups: + dev-dependencies: + patterns: + - "automattic/*" + - "dealerdirect/*" + - "php-parallel-lint/*" + - "phpcompatibility/*" + - "phpunit/*" + - "squizlabs/*" + - "yoast/*" + labels: + - "dependencies" + commit-message: + prefix: "Composer" + include: "scope" + open-pull-requests-limit: 5 + versioning-strategy: increase-if-necessary + + # Maintain dependencies for npm + - package-ecosystem: "npm" + directory: "/" + schedule: + interval: "weekly" + day: "wednesday" + groups: + dev-dependencies: + patterns: + - "@wordpress/*" + - "eslint*" + - "prettier*" + - "@types/*" + labels: + - "dependencies" + commit-message: + prefix: "npm" + include: "scope" + open-pull-requests-limit: 5 diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml new file mode 100644 index 000000000..c0f1bb238 --- /dev/null +++ b/.github/workflows/deploy.yml @@ -0,0 +1,57 @@ +name: Deploy to WordPress.org + +on: + release: + types: [released] + workflow_dispatch: + +# Workflow-level permissions set to none; jobs declare their own minimal permissions +permissions: {} + +jobs: + release: + name: Deploy to WordPress.org + runs-on: ubuntu-latest + + permissions: + contents: write # Required to upload release assets to the GitHub release + + steps: + - name: Checkout code + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + with: + persist-credentials: false + + - name: Set up Node.js + uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0 + with: + node-version: '20' + # Disabled to prevent cache poisoning in release workflows + package-manager-cache: false + + - name: Install dependencies + run: npm ci + + - name: Build assets + run: npm run build + + - name: Install SVN + run: | + sudo apt-get update + sudo apt-get install -y subversion + + - name: Deploy to WordPress.org + uses: 10up/action-wordpress-plugin-deploy@54bd289b8525fd23a5c365ec369185f2966529c2 # v2.3.0 + with: + generate-zip: true + env: + SLUG: edit-flow + SVN_USERNAME: ${{ secrets.SVN_USERNAME }} + SVN_PASSWORD: ${{ secrets.SVN_PASSWORD }} + + - name: Upload release asset + uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b # v2.5.0 + with: + files: ${{ github.workspace }}/${{ github.event.repository.name }}.zip + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/e2e-and-js-tests.yml b/.github/workflows/e2e-and-js-tests.yml index b05dfced8..ba3a1f175 100644 --- a/.github/workflows/e2e-and-js-tests.yml +++ b/.github/workflows/e2e-and-js-tests.yml @@ -1,42 +1,110 @@ name: E2E and JS tests -on: push +on: + pull_request: + push: + branches-ignore: + - develop + - main + +# Disable all permissions by default; grant minimal permissions per job +permissions: {} concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: - test: + build: + name: Build and Lint runs-on: ubuntu-latest - continue-on-error: false - - strategy: - fail-fast: true + permissions: + contents: read steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + with: + persist-credentials: false - name: Set up NodeJS 20 - uses: actions/setup-node@v4 + uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0 with: node-version: '20' cache: npm - - name: Build Edit Flow + - name: Install dependencies + run: npm ci + + - name: Build assets + run: npm run build + + - name: Verify built assets exist run: | - npm ci - npm run build + echo "Checking custom-status assets..." + test -f build/custom-status-block.js || (echo "Missing: build/custom-status-block.js" && exit 1) + test -f build/custom-status-block.css || (echo "Missing: build/custom-status-block.css" && exit 1) - - name: Install WordPress with wp-env - run: npm run wp-env start + echo "Checking calendar assets..." + test -f build/calendar-react.js || (echo "Missing: build/calendar-react.js" && exit 1) + test -f build/calendar-react.css || (echo "Missing: build/calendar-react.css" && exit 1) + + echo "All expected assets present!" + + - name: Report asset sizes + run: | + echo "### Asset Sizes" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "| File | Size |" >> $GITHUB_STEP_SUMMARY + echo "|------|------|" >> $GITHUB_STEP_SUMMARY + echo "| custom-status-block.js | $(du -h build/custom-status-block.js | cut -f1) |" >> $GITHUB_STEP_SUMMARY + echo "| calendar-react.js | $(du -h build/calendar-react.js | cut -f1) |" >> $GITHUB_STEP_SUMMARY - name: Run Lint JS run: npm run lint-js - - name: Run Jest tests - run: npm run test-jest + - name: Upload build artifacts + uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 + with: + name: build-artifacts + path: build/ + retention-days: 1 + + test: + name: E2E and Jest tests + # Pin to ubuntu-22.04 for Playwright compatibility + # ubuntu-latest (24.04) has library version mismatches with Playwright's WebKit dependencies + runs-on: ubuntu-22.04 + needs: build + permissions: + contents: read + + steps: + - name: Checkout code + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + with: + persist-credentials: false + + - name: Set up NodeJS 20 + uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0 + with: + node-version: '20' + cache: npm + + - name: Install dependencies + run: npm ci + + - name: Download build artifacts + uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0 + with: + name: build-artifacts + path: build/ + + - name: Install Playwright browsers and system dependencies + run: npx playwright install --with-deps chromium + + - name: Install WordPress with wp-env + run: npm run wp-env start - - name: Run E2E tests - run: npm run test-e2e + - name: Run tests + run: npm run test diff --git a/.github/workflows/php-tests.yml b/.github/workflows/integration.yml similarity index 59% rename from .github/workflows/php-tests.yml rename to .github/workflows/integration.yml index 0077d8758..574806719 100644 --- a/.github/workflows/php-tests.yml +++ b/.github/workflows/integration.yml @@ -1,6 +1,14 @@ -name: PHP Tests +name: Integration Tests -on: push +on: + pull_request: + push: + branches-ignore: + - develop + - main + +# Disable all permissions by default; grant minimal permissions per job +permissions: {} concurrency: group: ${{ github.workflow }}-${{ github.ref }} @@ -11,36 +19,37 @@ jobs: # Alias 'master' to 'latest' name: WP ${{ matrix.wp == 'master' && 'latest' || matrix.wp }} and PHP ${{ matrix.php }} runs-on: ubuntu-latest - continue-on-error: ${{ matrix.allowed_failure }} + permissions: + contents: read strategy: fail-fast: false matrix: include: # Check lowest supported WP version, with the lowest supported PHP. - - php: '8.0' - wp: '6.0' - allowed_failure: false - # Check latest WP with the highest supported PHP. + - php: '7.4' + wp: '6.4' + # Check latest WP with the latest PHP. - php: 'latest' wp: 'master' - allowed_failure: false steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + with: + persist-credentials: false - name: Install wordpress environment run: npm -g install @wordpress/env - name: Setup PHP ${{ matrix.php }} - uses: shivammathur/setup-php@v2 + uses: shivammathur/setup-php@44454db4f0199b8b9685a5d763dc37cbf79108e1 # 2.36.0 with: php-version: ${{ matrix.php }} tools: composer - name: Install Composer dependencies - uses: ramsey/composer-install@v3 + uses: ramsey/composer-install@3cf229dc2919194e9e36783941438d17239e8520 # 3.1.1 with: composer-options: --prefer-dist --no-progress @@ -49,11 +58,8 @@ jobs: env: WP_ENV_CORE: WordPress/WordPress#${{ matrix.wp }} - - name: Run PHPCS diff tests - run: bash bin/phpcs-diff.sh - - name: Run PHPUnit tests (single site) - run: composer integration + run: composer test:integration - name: Run PHPUnit tests (multisite) - run: composer integration-ms + run: composer test:integration-ms diff --git a/.github/workflows/php-lint.yml b/.github/workflows/php-lint.yml new file mode 100644 index 000000000..c609c23b5 --- /dev/null +++ b/.github/workflows/php-lint.yml @@ -0,0 +1,45 @@ +name: PHP Lint + +on: + pull_request: + push: + branches-ignore: + - develop + - main + +# Disable all permissions by default; grant minimal permissions per job +permissions: {} + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + lint: + name: PHP Syntax and Coding Standards + runs-on: ubuntu-latest + permissions: + contents: read + + steps: + - name: Checkout code + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + with: + persist-credentials: false + + - name: Setup PHP + uses: shivammathur/setup-php@44454db4f0199b8b9685a5d763dc37cbf79108e1 # 2.36.0 + with: + php-version: '8.2' + tools: composer, cs2pr + + - name: Install Composer dependencies + uses: ramsey/composer-install@3cf229dc2919194e9e36783941438d17239e8520 # 3.1.1 + with: + composer-options: --prefer-dist --no-progress + + - name: PHP syntax lint + run: composer lint-ci | cs2pr + + - name: PHP coding standards + run: composer cs -- --report=checkstyle | cs2pr diff --git a/.gitignore b/.gitignore index 3cf712282..250094d57 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,15 @@ -.svn -.DS_Store *.map node_modules wordpress vendor +composer.lock +build/ +dist/ +**/lib/dist/ # Test files -.phpunit.result.cache +.phpunit.cache/ artifacts/ + +# Local wp-env overrides +.wp-env.override.json diff --git a/.phpcs.xml.dist b/.phpcs.xml.dist new file mode 100644 index 000000000..52626fb14 --- /dev/null +++ b/.phpcs.xml.dist @@ -0,0 +1,282 @@ + + + Custom ruleset for Edit Flow plugin. + + + + + + . + + /node_modules/ + /vendor/ + /build/ + + common/php/screen-options\.php + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + 0 + + + + 0 + + + + 0 + + + + 0 + + + + + + + + + + + + + + + + + + + + /tests/ + + + + /tests/ + + + + /tests/ + + + /tests/ + + + /tests/ + + + /tests/ + + + + /tests/ + + + + /tests/ + + + /tests/ + + + + /tests/ + + + + /tests/ + + + /tests/ + + + + /tests/ + + + + /tests/ + + + + /tests/ + + + + /tests/ + + + + /tests/ + + + + /tests/ + + + + /tests/ + + + + /tests/ + + + + /tests/ + + + + /tests/ + + + + /tests/ + + + + /tests/ + + + + /tests/ + + + + /tests/ + + + + /tests/ + + + + /tests/ + + + + /tests/ + + + + /tests/ + + + + /tests/ + + + + /tests/ + + + + /tests/ + + + + edit_flow\.php + + + + common/php/screen-options\.php + + + + edit_flow\.php + + + + common/php/screen-options\.php + + + + edit_flow\.php + + + + modules/calendar/calendar\.php + modules/editorial-metadata/editorial-metadata\.php + modules/notifications/notifications\.php + modules/story-budget/story-budget\.php + + + + /tests/ + + + diff --git a/.svnignore b/.svnignore deleted file mode 100644 index 40d248be4..000000000 --- a/.svnignore +++ /dev/null @@ -1,15 +0,0 @@ -*.map -BLOCKS.md -CONTRIBUTING.md -composer.json -node_modules -package-lock.json -package.json -phpunit.xml -PUBLISHING.md -README.md -webpack.config.js -bin -documentation -tests -tools diff --git a/.wordpress-org/icon-256x256.png b/.wordpress-org/icon-256x256.png new file mode 100644 index 000000000..41f796bf6 Binary files /dev/null and b/.wordpress-org/icon-256x256.png differ diff --git a/screenshot-1.jpg b/.wordpress-org/screenshot-1.jpg similarity index 100% rename from screenshot-1.jpg rename to .wordpress-org/screenshot-1.jpg diff --git a/screenshot-2.jpg b/.wordpress-org/screenshot-2.jpg similarity index 100% rename from screenshot-2.jpg rename to .wordpress-org/screenshot-2.jpg diff --git a/screenshot-3.jpg b/.wordpress-org/screenshot-3.jpg similarity index 100% rename from screenshot-3.jpg rename to .wordpress-org/screenshot-3.jpg diff --git a/screenshot-4.jpg b/.wordpress-org/screenshot-4.jpg similarity index 100% rename from screenshot-4.jpg rename to .wordpress-org/screenshot-4.jpg diff --git a/screenshot-5.jpg b/.wordpress-org/screenshot-5.jpg similarity index 100% rename from screenshot-5.jpg rename to .wordpress-org/screenshot-5.jpg diff --git a/.wp-env.json b/.wp-env.json index 75c3e82e9..a8126439a 100644 --- a/.wp-env.json +++ b/.wp-env.json @@ -1,3 +1,20 @@ { - "plugins": [ "." ] + "plugins": [ + "." + ], + "phpVersion": "8.2", + "config": { + "WP_DEBUG": true, + "WP_DEBUG_LOG": true, + "SCRIPT_DEBUG": true + }, + "lifecycleScripts": { + "afterStart": "wp-env run cli wp plugin install query-monitor --activate" + }, + "env": { + "tests": { + "phpVersion": "8.4", + "core": "WordPress/WordPress#6.9" + } + } } diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 000000000..65ad5b27e --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,418 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [0.10.0] - 2026-01-02 + +This is a major update with significant bug fixes, new features, and modernised infrastructure. + +**PHP Compatibility:** Minimum PHP version has been lowered from 8.0 to 7.4 for broader compatibility. + +### Fixed + +* fix(story-budget): respect `ef_story_budget_taxonomy_used` filter in dropdown by @GaryJones in [#861](https://github.com/Automattic/Edit-Flow/pull/861) +* fix: prevent spurious "Leave site?" warning on new posts with custom statuses by @GaryJones in [#860](https://github.com/Automattic/Edit-Flow/pull/860) +* fix: scope module asset loading to relevant pages only by @GaryJones in [#858](https://github.com/Automattic/Edit-Flow/pull/858) +* fix: allow text selection in calendar overlay without triggering drag by @GaryJones in [#857](https://github.com/Automattic/Edit-Flow/pull/857) +* fix: update post date to current time when publishing from custom status by @GaryJones in [#856](https://github.com/Automattic/Edit-Flow/pull/856) +* fix: resolve calendar drag-and-drop not persisting post date changes by @GaryJones in [#854](https://github.com/Automattic/Edit-Flow/pull/854) +* fix: guard against null return from get_edit_post_link() and get_permalink() by @GaryJones in [#853](https://github.com/Automattic/Edit-Flow/pull/853) +* fix: prevent get_custom_statuses() from corrupting WordPress's term cache by @GaryJones in [#852](https://github.com/Automattic/Edit-Flow/pull/852) +* fix: add Private option to bulk edit status dropdown by @GaryJones in [#851](https://github.com/Automattic/Edit-Flow/pull/851) +* fix: resolve stale cache causing incorrect display in custom status Quick Edit by @GaryJones in [#849](https://github.com/Automattic/Edit-Flow/pull/849) +* fix: add type guard to prevent PHP warning in preview link filter by @GaryJones in [#834](https://github.com/Automattic/Edit-Flow/pull/834) + +### Added + +* feat(custom-status): add status migration tool and WP-CLI commands by @GaryJones in [#859](https://github.com/Automattic/Edit-Flow/pull/859) +* feat(notifications): add Post Author and Auto-subscribed badges by @GaryJones in [#847](https://github.com/Automattic/Edit-Flow/pull/847) +* feat(story-budget): improve UX with Screen Options and collapsible categories by @GaryJones in [#846](https://github.com/Automattic/Edit-Flow/pull/846) + +### Changed + +* style(story-budget): refresh print stylesheet for modern WordPress by @GaryJones in [#848](https://github.com/Automattic/Edit-Flow/pull/848) + +### Maintenance + +* chore: remove unused VIP feature flag setting and related code by @GaryJones in [#862](https://github.com/Automattic/Edit-Flow/pull/862) +* chore: rename workflow to match plugin standards by @GaryJones in [#850](https://github.com/Automattic/Edit-Flow/pull/850) +* chore: migrate build system from webpack to wp-scripts by @GaryJones in [#845](https://github.com/Automattic/Edit-Flow/pull/845) +* chore: simplify ESLint config after eslint-plugin-wpvip fix by @GaryJones in [#844](https://github.com/Automattic/Edit-Flow/pull/844) +* ci: standardise test matrix and update readme by @GaryJones in [#840](https://github.com/Automattic/Edit-Flow/pull/840) +* chore: migrate to ESLint 9 with flat config by @GaryJones in [#839](https://github.com/Automattic/Edit-Flow/pull/839) +* chore: migrate dependabot reviewers to CODEOWNERS by @GaryJones in [#836](https://github.com/Automattic/Edit-Flow/pull/836) +* ci: Improve CI infrastructure and expand PHP compatibility by @GaryJones in [#835](https://github.com/Automattic/Edit-Flow/pull/835) +* ci: pin E2E tests to Ubuntu 22.04 for Playwright compatibility by @GaryJones in [#833](https://github.com/Automattic/Edit-Flow/pull/833) + +## [0.9.9] - 2024-05-24 + +* Enhancements: bump lowest supported PHP version to 8.0 and lowest WordPress version to 6.0 ([#727](https://github.com/Automattic/Edit-Flow/pull/727)) +* Test fix: Update ESLint configuration and format JS files ([#723](https://github.com/Automattic/Edit-Flow/pull/723)) +* Enhancements: Move JS environment to node 20, upgrade packages ([#725](https://github.com/Automattic/Edit-Flow/pull/725)) + +## [0.9.8] - 2024-04-10 + +* Fix WP 5.9 deprecation notice with `who` in `WP_User_Query` ([#701](https://github.com/Automattic/Edit-Flow/pull/701)) +* Add PHP 8.2 fixes ([#700](https://github.com/Automattic/Edit-Flow/pull/700)) +* Bump @babel/traverse from 7.1.6 to 7.23.2 ([#714](https://github.com/Automattic/Edit-Flow/pull/714)) + +## [0.9.7] - 2022-08-26 + +* Bug fix: Allow scheduled posts to be shifted around on calendar ([#614](https://github.com/Automattic/Edit-Flow/pull/614)) +* Bug fix: Add back unpublish status, small css tweak for statuses ([#613](https://github.com/Automattic/Edit-Flow/pull/613)) +* Enhancements: Renaming some frontend calendar configuration variable ([#615](https://github.com/Automattic/Edit-Flow/pull/615)) +* Bug fix: Swap join() with implode() for PHP 8 compatibility ([#627](https://github.com/Automattic/Edit-Flow/pull/627)) +* Enhancements: Give each attribute in Edit Flow settings page a different id ([#650](https://github.com/Automattic/Edit-Flow/pull/650)) +* Bug fix: Fix test_story_budget_set_number_days_filter_invalid in PHP 8.0 ([#644](https://github.com/Automattic/Edit-Flow/pull/644)) +* Bug fix: Allow updating post slugs in Quick Edit and Classic Editor with a different status from published ([#648](https://github.com/Automattic/Edit-Flow/pull/648)) +* Bug fix: Fix jQuery warnings as WordPress upgraded it from 1.12.4-wp to 3.5.1 ([#649](https://github.com/Automattic/Edit-Flow/pull/649)) +* Enhancements: Remove redundant jQuery selector #the-list a.editinline ([#668](https://github.com/Automattic/Edit-Flow/pull/668)) +* Enhancements: Remove redundant jQuery selector #toggle_details ([#669](https://github.com/Automattic/Edit-Flow/pull/669)) +* Bug fix: Fixes non-variable being passed by reference ([#667](https://github.com/Automattic/Edit-Flow/pull/667)) + +## [0.9.6] - 2020-04-26 + +* Bug fix: Fix bug causing error on save button click for post after hovering over button ([#604](https://github.com/Automattic/Edit-Flow/pull/604)) +* Enhancements: Bring Gutenberg to Calendar filters ([#603](https://github.com/Automattic/Edit-Flow/pull/603)) +* Enhancements: Tweak styling on Calendar ([#605](https://github.com/Automattic/Edit-Flow/pull/605)) + +## [0.9.5] - 2020-04-08 + +* Bug fix: Fix bug preventing previewing posts authored by other users ([#597](https://github.com/Automattic/Edit-Flow/pull/597) -- props mallorydxw) +* Improvement: Status dropdowns are now be Edit Flow specific but filterable ([#595](https://github.com/Automattic/Edit-Flow/pull/595)) +* Improvement: Support i18n in Story Budget date picker ([#569](https://github.com/Automattic/Edit-Flow/pull/569)) +* Bug fix: Prevent multiple custom fields from being created ([#591](https://github.com/Automattic/Edit-Flow/pull/591)) +* Bug fix: Fix slug behavior ([#575](https://github.com/Automattic/Edit-Flow/pull/575)) + +## [0.9.4] - 2020-02-04 + +* Bug fix: Move 'Customize' link in metadata metabox to inside metabox ([#590](https://github.com/Automattic/Edit-Flow/pull/590) -- props jsit) +* Bug fix: Fix ef_custom_status_list filter on get_custom_statuses ([#587](https://github.com/Automattic/Edit-Flow/pull/587) -- props jsit) +* Bug fix: Keep save button text updated, without errors ([#585](https://github.com/Automattic/Edit-Flow/pull/585) -- props WPprodigy) +* Bug fix: Add ef_week_first_day as script data to prevent echoing script tags ([#582](https://github.com/Automattic/Edit-Flow/pull/582) -- props ryelle) +* Improvement: Deprecate ef_get_comments_plus ([#581](https://github.com/Automattic/Edit-Flow/pull/581) -- props WPprodigy) +* Improvement: Cleanup block editor compatibility logic ([#580](https://github.com/Automattic/Edit-Flow/pull/580) -- props WPprodigy) +* Improvement: Display custom statuses in post states ([#579](https://github.com/Automattic/Edit-Flow/pull/579) -- props WPprodigy) +* Improvement: Clean up dashboard-note logic ([#578](https://github.com/Automattic/Edit-Flow/pull/578) -- props WPprodigy) + +## [0.9.3] - 2019-12-18 + +* Bug fix: parse date time from numeric string instead of textual date ([#546](https://github.com/Automattic/Edit-Flow/pull/546) -- props batmoo, cojennin) +* Bug fix: ensure status friendly names are used in notifications ([#560](https://github.com/Automattic/Edit-Flow/pull/560) -- props batmoo, cojennin) +* Bug fix: fix WP Menu post title notice ([#552](https://github.com/Automattic/Edit-Flow/pull/552) -- props batmoo, cojennin) +* Updates to tests, build pipeline (props batmoo, dchymko, cojennin) + +## [0.9.2] - 2019-11-24 + +* Bug fix: Prevent issues with scheduling and trashing posts when using the block editor ([#556](https://github.com/Automattic/Edit-Flow/pull/556) -- props cojennin, davisshaver, batmoo) + +## [0.9.1] - 2019-11-04 + +* Bug fix: Prevent custom status from being reverted when using Gutenberg ([#521](https://github.com/Automattic/Edit-Flow/pull/521) -- props mikeyarce, batmoo) +* Bug fix: Don't break post previews when using custom statuses ([#515](https://github.com/Automattic/Edit-Flow/pull/515) -- props rebeccahum) +* Bug fix: Don't auto-subscribe the current user when notification settings are changed ([#540](https://github.com/Automattic/Edit-Flow/pull/540) -- props dchymko, jerclarke, mikeyarce) +* Bug fix: prevent fatals when editing posts on the frontend via certain plugins ([#538](https://github.com/Automattic/Edit-Flow/pull/538) -- props kjohnson, dchymko) +* Bug fix: Don't break classic editor when custom statuses are disabled ([#537](https://github.com/Automattic/Edit-Flow/pull/537) -- props batmoo, thesquaremedia) +* Bug fix: Prevent `count()` warning on PHP 7.2 ([#534](https://github.com/Automattic/Edit-Flow/pull/534) -- props batmoo, NeilWJames) +* Bug fix: Prevent multiple plugin entries on the plugins page ([#530](https://github.com/Automattic/Edit-Flow/pull/530) -- props batmoo, mboynes, joshbetz) +* Bug fix: jQuery compatibility issues ([#499](https://github.com/Automattic/Edit-Flow/pull/499) -- props jameslesliemiller) +* Dev: Fix Travis CI Tests (props dchymko) + +## [0.9] - 2018-01-10 + +* Feature: Block Editor compatibility for Custom Status module. Props rinatkhaziev. See BLOCKS.md for details. +* Feature: new filter `ef_calendar_item_html` for Calendar module that allows to print custom markup for each day. +* UI Improvement: start removing arbitrary colors and conform to WP Color guide. +* UI Improvement: Add [NO ACCESS] and [NO EMAIL] to the list of notified users. + +## [0.8.3] - 2018-06-14 + +* UI Improvement: Made primary buttons on Settings screen consistent with WordPress UI. Props cojennin. +* UI Improvement: Display who particularly was notified about an editorial comment. Props goodguyry, WPprodigy. +* Improvement: Updated Russian translation and documentation. Props achumakov. +* Improvement: Eliminate a few cases of raw SQL queries in favor of `date_query`. Props justnorris. +* Improvement: Cache calendar items for each user individually to prevent potential cache pollution. Props justnorris. +* Improvement: various i18n updates. +* Improvement: Move ef_story_budget_posts_query_args filter down to allow overriding the date query in Story Budget module. +* Improvement: Limit results in Calendar to 200 per page. +* Improvement: Don't generate rewrite rules for notepad as they're unused. +* Improvement: Support modifying HTML output of a Calendar day via ef_pre_calendar_single_date_item_html filter. Props cklosowski. +* Improvement: show custom post statuses in Calendar and Story Budget. Props mikeyarce. +* WordPress Coding Standards improvements and code cleanup. Props justnorris. +* Bug fix: Prevent user from removing "Draft" post status. +* Bug fix: Fix ef_pre_insert_editorial_comment filter. Props sudar. +* Bug fix: Fix PHP Warning: array_map(): Argument #2 should be an array. +* Bug fix: Always offset post times to UTC+0 for Calendars. Props justnorris. +* Bug fix: Use taxonomy when checking for term existence. Props shadyvb. +* Bug fix: Correctly handle screen options update for Story Budget columns. Props raduconst. +* Bug fix: EF_Calendar::get_beginning_of_week and EF_Calendar::get_ending_of_week should respect DST. Props FewKinG. +* Bug fix: Build home_url() previews with trailing slash. Props jeremyfelt. + +## [0.8.2] - 2016-09-16 + +* Improvement: Updated Spanish localization. Props moucho. +* Improvement: New Swedish localization. Props Warpsmith. +* Improvement: Japanese localization 100% on translate.wordpress.org. +* Improvement: Updated Brazilian Portuguese translation. Props arthurdapaz. +* Improvement: Internationalization improvements in settings and calendar. Props robertsky. +* Improvement: Updates Travis CI to support containerization, PHP 7 and HHVM. +* Bug fix: Fix PHP warning in class-module.php. Props jerclarke. +* Bug fix: Add label to Dashboard Notes so it displays as "Dashboard Notes" when exporting. +* Bug fix: Clean up PHP code to comply with PHP Strict Standards. +* Bug fix: Removed deprecated get_currentuserinfo. Props kraftbj. +* Bug fix: Adding $post param to preview_post_link filter. Props micahwave. +* Bug fix: Calendar current_user_can capability check corrected. Props keg. +* Bug fix: Clean up custom status timestamp fix and add unit tests. +* Bug fix: Fix error messaging for module settings pages. Props natebot. +* Bug fix: Add check on user-settings.php to prevent error. Props paulabbott. +* Bug fix: Add check for empty author when sending notification. Props petenelson. +* Bug fix: Remove PHP4 constructor from screen options. Props mjangda. + +## [0.8.1] - 2016-04-13 + +* New German localization. Props Circleview. +* New Spanish localization. Props Andrew Kurtis. +* Performance improvements for the calendar, custom statuses, and editorial metadata. +* Bug fix: Show "(no title)" on the calendar when a post doesn't have a title. +* Bug fix: Persist the future date position of a post on the calendar when a post is updated. + +## [0.8] - 2013-12-19 + +* New feature: Dashboard Notepad. +* New feature: Double-click to create a new post on the calendar. Props bbrooks, cojennin. +* Post subscriptions are now saved via AJAX. Props cojennin. +* Subscribe to a post's updates using a quick "Follow" link. +* Assign a date and time to editorial metadata's date field. Props cojennin. +* Modify which filters are used on the calendar and story budget. Props cojennin. +* Scheduled publication time is now included in relevant email notifications. Props mattoperry. +* Calendar and story budget module descriptions link to their respective pages. Props rgalindo05. +* New Russian localization. Props te-st.ru. +* Updated Japanese localization. Props naokomc. +* Updated Dutch localization. Props kardotim. +* Bug fix: User group selection no longer appears in network admin. +* Improved slug generation when changing title of Drafts. Props natebot. +* Bug fix: Permalink slugs are now editable after initial save. Props nickdaugherty. +* Bug fix: Permit calendar filters to be properly reset. +* Bug fix: Posts, pages, custom post types can now be previewed correctly. +* Bug fix: Fix Strict Standards PHP notice with add_caps_to_role(). Props azizur. +* Bug fix: PHP compatibility issue. Props ziz. +* Bug fix: Correct calendar encoding. Props willvanwazer. +* Bug fix: Check for $screen in filter_manage_posts_column. Props styledev. +* Bug fix: Correct Edit Flow icon size. Props Fstop. +* Improvement: Add editorial metadata to the Posts screen. Props drrobotnik. +* Improvement: Visual support for MP6. Props keoshi. +* Bug fix: Catch WP_Error returning with get_terms(). Props paulgibbs. +* Improvement: Better unit testing with PHPUnit. Props willvanwazer, mbijon. +* Bug fix: Correctly close out list item in editorial comments. Props jkovis. + +## [0.7.6] - 2013-01-30 + +* Bug fix for 3.4.2 compatibility. + +## [0.7.5] - 2013-01-29 + +* New Japanese localization. Props naokomc. +* New French localization. Props boris-hocde. +* Allow custom post statuses to be completely disabled for a post type. +* Better implementation of editable slugs hack. Props cojennin. +* Editorial metadata names can now be up to 200 characters. Props cojennin. +* Bug fix: Load modules on 'init' for proper translation. +* Bug fix: Pagination functional again when filtering to a post type. +* Bug fix: Pre-PHP 5.2.9 array_unique() compatibility. +* Bug fix: Respect the timezone when indicating which day is Today. +* Bug fix: Calendar should work for all post types. + +## [0.7.4] - 2012-11-21 + +* Added 'Scheduled' as one of the statuses you see in the 'Posts At A Glance' widget. +* Sort posts on the Manage Posts view by visible editorial metadata date fields. +* Modify email notifications with two filters. +* Bug fix: Proper support for unicode characters in custom status and editorial metadata descriptions. +* Bug fix: Show the proper last modified value on the story budget. Props danls. +* Bug fix: Make the jQuery UI theme more specific. Props danls. +* Bug fix: Use the proper singular label for a post type when generating notification text. +* Bug fix: Post slug now updates when the post has a custom status. +* Bug fix: When determining whether a user can change a post's status, check the 'edit_posts' cap. + +## [0.7.3] - 2012-07-03 + +* Bug fix: Support PHP 5.2.x by removing anonymous functions. +* Bug fix: Only update user's Story Budget saved filters when the Story Budget is being viewed. + +## [0.7.2] - 2012-07-03 + +* Users without the 'publish_posts' capability can now use and change custom statuses. Props Daniel Chesterton. +* Support for trashing posts from the calendar. Props Dan York. +* Updated codebase to use PHP5-style OOP references. +* Fixed some script and stylesheet references that had a double '//' in the URI path. +* New `edit_flow_supported_module_post_types_args` filter. + +## [0.7.1] - 2012-04-11 + +* Show the year on the calendar and story budget if it's not the current year. +* Allow users to save post subscriptions the first time they save the post. +* Changed the behavior of notifications for the user changing a status or leaving a comment. +* New Italian localization. Props Luca Patane. +* Bug fix: Auto-subscribe the post author to their posts by default. +* Bug fix: Only show authors in the user dropdown for the calendar and the story budget. +* Bug fix: Metaboxes are registered with proper priority. Props benbalter. +* Bug fix: If a user hasn't ever opened the calendar before, the date should default to today. +* Bug fix: Prevent editorial metadata filters from stomping on others' uses. +* Bug fix: Specify a max-width on `` dropdowns in the calendar and story budget so long values don't break formatting - -**0.7 (Jan. 9, 2012)** -* Entire plugin was rewritten into a modular architecture (e.g. each feature is broken into a module you can enable or disable). One point of the modular architecture is to make it much easier for others to contribute new features. For the end user, there’s a brand new settings page where you can manage your modules. Each module then registers a configuration view for module settings. Most have options to choose which post types you’d like it activated for, along with other configuration options. -* Calendar is far more functional. Content is viewed in a six week view by default, and number of weeks is configurable in screen options. Posts can be dragged and dropped between dates. Click on a post title to get the details about the post, including editorial metadata. -* Custom statuses can be drag and drop ordered with AJAX. All statuses (including core ‘draft’ and ‘pending’) can be edited or deleted. -* Editorial Metadata terms can be ordered with AJAX. Terms can be made “viewable” and then will be displayed on the manage posts view and calendar if enabled. -* Story Budget shows “viewable” editorial metadata and fixes a few bugs, including not showing posts in a subcategory of a parent category. -* Notifications/subscriptions are filtered so you can disable the auto-subscribing of authors or editorial commenters. -* Important note: If upgrading from pre-v0.6, please upgrade to v0.6.5 first to ensure all of your data remains intact. -* [Read the full release post](http://editflow.org/2012/01/09/edit-flow-v0-7-modular-architecture-monthly-calendar-and-sortable-statuses/) - -**0.6.5 (Sept. 19, 2011)** -* Bug fix: Workaround for a bug in core where the timestamp is set when a post is saved with a custom status. Instead, we update the timestamp on publish to current time if a custom post date hasn't been set. Thanks saomay for [help tracking the bug down](http://wordpress.org/support/topic/plugin-edit-flow-custom-statuses-create-timestamp-problem/). - -**0.6.4 (Jul. 22, 2011)** -* Display unpublished custom statuses inline with the post title, per WordPress standard UI -* New number type for editorial metadata, so you can have fields like "Word Count" -* Dropped the admin option for disabling custom statuses on posts. It didn't work, and this is handled by post_type_supports() -* Add a 'Clear' link to editorial metadata date fields to allow user to easily clear the input -* Bug fix: Proper support for bulk editing custom statuses -* Bug fix: Contributor saving a new post respects the default custom status, instead of reverting to 'draft' as the post status -* Bug fix: Better respect for user roles and capabilities in Story Budget -* Bug fix: Custom statuses in Quick Edit now work as you'd expect them -* Bug fix: Show all taxonomy terms (most likely categories) on the Story Budget, regardless of whether they include published content -* Bug fix: If there are no editorial metadata fields available, a message will display instead of leaving an empty post meta box - -**0.6.3 (Mar. 21, 2011)** -* Restored email notifications to old delivery method instead of queueing with WP cron because of reliability issues. -* Better approach to including files so Edit Flow works properly on Windows systems. -* Option to see all unpublished content on story budget and editorial calendar with a filter to include scheduled posts as unpublished content. - -**0.6.2 (Jan. 26, 2011)** -* Bug fix: Post Titles were broken in email notifications. (Thanks kfawcett and madguy000!) -* Bug fix: Bulk editing any post types would cause editorial metadata to occasionally be deleted. (Thanks meganknight!) - -**0.6.1 (Jan. 9, 2011)** -* Custom Post Type support for custom post statuses, editorial metadata, editorial comments, notifications, (Thanks to all who requested this!) -* Added search and filtering tools for user and usergroup lists -* Email notifications are now queued to improve performance and avoid issues with spam -* Posts in calendar now have a unique classname based on the status (Thanks [erikajurney](http://wordpress.org/support/profile/erikajurney)) -* The "Posts I'm Following" widget has a cleaner look -* Bug fix: Users without JavaScript no longer see the status dropdown -* Bug fix: Users with JavaScript no longer see the respond button for editorial comments -* Bug fix: Contributors should not have the ability to publish through Quick Edit -* Bug fix: Proper i18n support (Thanks Beto Frega and others) -* Bug fix: Editorial Comments issue in IE (Thanks [asecondwill](http://wordpress.org/support/profile/asecondwill) and James Skaggs) -* Bug fix: Always email admin feature was not working (Thanks [nicomollet](http://wordpress.org/support/profile/nicomollet)) -* Bug fix: Notifications for scheduled posts did not include links (Thanks [erikajurney](http://wordpress.org/support/profile/erikajurney)) - -**0.6 (Nov. 9, 2010)** -* New feature: Editorial Metadata. Previously, Edit Flow had 'due date', 'location' and 'description', as available editorial metadata. We've expanded this functionality to be completely customizable; admins can add any number of editorial metadata with the following types: checkbox, date, location, paragraph, text, or user dropdown. -* New feature: Story Budget. View all of your upcoming posts in a more traditional story budget view. Posts are grouped by category, and view can be filtered by post status, category, user, or limited to a date range. Hit the print button to take it on the go. -* Completely rewritten calendar view now saves filter state on a user by user basis. Also, highlights current day, and displays status and time for each post. -* Temporarily disabled QuickPitch widget until we rewrite it to support editorial metadata. -* Bug fix: Editorial comments should no longer show up in the stock Recent Comments widget or in the comments view in the WordPress Admin. The comment count number should also be correct. -* Bug fix: Duplicate custom post statuses and usergroups are handled in more sane ways (aka creating, editing, and deleting should work as expected) - -**0.5.3 (Oct. 6, 2010)** -* Fixes issue where default Custom Statuses and User Groups were returning even after being deleted - -**0.5.1 (Jul. 29, 2010)** -* Editorial calendar improvements: filter by category or author -* QuickPitch stories get default status instead of pitch status -* No email notifications for “Auto Draft” post status -* Backwards compatibility with WordPress 2.9.x - -**0.5 (Jul. 3, 2010)** -* Calendar view for visualizing and spec assignments at a glance -* Improvements for WordPress 3.0 compatibility - -**0.4** -* Users that edit a post automatically get subscribed to that post (only if they have the manage subscriptions capability) -* Edit Flow automatically hides editorial comments if the plugin is disabled -* Moved default custom status additions to upgrade function so they don't get added every time you activate -* Bug fix: remove editorial comments from comments feed - -**0.3.3 (Feb. 4, 2010)** -* Added tooltips with descriptions to the Status dropdown and Status Filter links. Thanks to [Gil Namur](http://lifeasahuman.com) for the great idea! -* Fixed the issue where subscribed users/usergroups were not receiving notifications - -**0.3.2 (Jan. 28, 2010)** -* Fixed fatal error if notifications were disabled - -**0.3.1** -* Small bug fixes - -**0.3** -* *Note:* Edit Flow now requires 2.9+ -* Notification emails on status change now have specific subject lines messages based on action taken -* Action links in comment notifications now take the user to the comment form; i.e. clicking reply link in the email will focus on the comment text box and reply to the message -* Usergroups! -* Assign users and usergroups that should be notified of post updates -* Removed notify by role option since it's redundant because of usergroups -* Added "Always notify admin option" -* Added option to hide the status dropdown on Post and Page edit pages (default set to show) -* Added option to globally disable QuickPitch widget -* Bug fix: Custom Status names cannot be longer than 20 chars -* Bug fix: Deleted users are removed as subscribers from posts -* Bug fix: Blank menu items should now be sorta hidden - -**0.2** -* Custom Statuses are now supported for pages -* Editorial Comments (with threading) -* Email Notifications (on post status change and editorial comment) -* Additional Post metadata -* Quick Pitch Dashboard widget -* Bug fix: sorting issue on Manage Posts page (Mad props to David Smith from Columbia U.) -* Other bug fixes -* Better localization support - -**0.1.5** -* Ability to assign custom statuses to posts +See [CHANGELOG.md](CHANGELOG.md) for the full changelog. diff --git a/babel.config.js b/babel.config.js new file mode 100644 index 000000000..ad71f404a --- /dev/null +++ b/babel.config.js @@ -0,0 +1,6 @@ +module.exports = { + presets: [ + '@babel/preset-env', + [ '@babel/preset-react', { runtime: 'automatic' } ], + ], +}; diff --git a/bin/phpcs-diff.sh b/bin/phpcs-diff.sh index c24bed151..b517af4a6 100755 --- a/bin/phpcs-diff.sh +++ b/bin/phpcs-diff.sh @@ -8,6 +8,6 @@ git remote set-branches --add origin master git fetch origin master git diff origin/master > $DIFF_FILE -$DIR/../vendor/bin/phpcs --extensions=php --standard=phpcs.xml.dist --report=json > $PHPCS_FILE || true +$DIR/../vendor/bin/phpcs --extensions=php --standard=.phpcs.xml.dist --report=json > $PHPCS_FILE || true $DIR/../vendor/bin/diffFilter --phpcs $DIFF_FILE $PHPCS_FILE 100 diff --git a/bin/prepare-svn-release.sh b/bin/prepare-svn-release.sh deleted file mode 100755 index ab65f4248..000000000 --- a/bin/prepare-svn-release.sh +++ /dev/null @@ -1,95 +0,0 @@ -#!/bin/bash - -if [ $# -eq 0 ]; then - echo 'Usage: `./deploy-to-svn.sh `' - exit 1 -fi - -EDIT_FLOW_GIT_DIR=$(dirname "$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" ) -EDIT_FLOW_SVN_DIR="/tmp/edit-flow" -TARGET=$1 - -cd $EDIT_FLOW_GIT_DIR - -# Make sure we don't have uncommitted changes. -if [[ -n $( git status -s --porcelain ) ]]; then - echo "Uncommitted changes found." - echo "Please deal with them and try again clean." - exit 1 -fi - -if [ "$1" != "HEAD" ]; then - - # Make sure we're trying to deploy something that's been tagged. Don't deploy non-tagged. - if [ -z $( git tag | grep "^$TARGET$" ) ]; then - echo "Tag $TARGET not found in git repository." - echo "Please try again with a valid tag." - exit 1 - fi -else - read -p "You are about to deploy a change from an unstable state 'HEAD'. This should only be done to update string typos for translators. Are you sure? [y/N]" -n 1 -r - if [[ $REPLY != "y" && $REPLY != "Y" ]] - then - exit 1 - fi -fi - -git checkout $TARGET - -# Prep a home to drop our new files in. Just make it in /tmp so we can start fresh each time. -rm -rf $EDIT_FLOW_SVN_DIR - -echo "Checking out SVN shallowly to $EDIT_FLOW_SVN_DIR" -svn -q checkout https://plugins.svn.wordpress.org/edit-flow/ --depth=empty $EDIT_FLOW_SVN_DIR -echo "Done!" - -cd $EDIT_FLOW_SVN_DIR - -echo "Checking out SVN trunk to $EDIT_FLOW_SVN_DIR/trunk" -svn -q up trunk -echo "Done!" - -echo "Checking out SVN tags shallowly to $EDIT_FLOW_SVN_DIR/tags" -svn -q up tags --depth=empty -echo "Done!" - -echo "Deleting everything in trunk except for .svn directories" -for file in $(find $EDIT_FLOW_SVN_DIR/trunk/* -not -path "*.svn*"); do - rm $file 2>/dev/null -done -echo "Done!" - -echo "Rsync'ing everything over from Git except for .git stuffs" -rsync -r --exclude='*.git*' $EDIT_FLOW_GIT_DIR/* $EDIT_FLOW_SVN_DIR/trunk -echo "Done!" - -echo "Purging paths included in .svnignore" -# check .svnignore -for file in $( cat "$EDIT_FLOW_GIT_DIR/.svnignore" 2>/dev/null ); do - rm -rf $EDIT_FLOW_SVN_DIR/trunk/$file -done -echo "Done!" - -# Instructions for next steps -echo "" -echo "================" -echo "Plugin release for $TARGET has been staged." -echo "" -echo "Please validate 'svn status' results before committing." -echo "" -echo "Some helpful commands:" -echo "" -echo "- goto dir" -echo "cd $EDIT_FLOW_SVN_DIR" -echo "- rm files:" -echo "svn st | grep ^\! | awk '{print \$2}' | xargs svn rm" -echo "- add files:" -echo "svn st | grep ^? | awk '{print \$2}' | xargs svn add" -echo "- review changes:" -echo "svn diff | colordiff | less -FRX" -echo "- tag the release" -echo "svn cp trunk tags/$TARGET" -echo "" -echo "Are there any new files that shouldn't be deployed?" -echo "Please add them to .svnignore in the GitHub repo." -echo "================" diff --git a/blocks/BLOCKS.md b/blocks/BLOCKS.md deleted file mode 100644 index ccadde955..000000000 --- a/blocks/BLOCKS.md +++ /dev/null @@ -1,61 +0,0 @@ -# Block Editor Compatibility - -This file describes steps to start developing Blocks for Edit Flow. -Currently, the following Edit Flow modules are compatible with Gutenberg Block Editor: - -* Custom Statuses - -### Setup - -*Note:* This document assumes you have a working knowledge of modern JavaScript and its tooling. Including npm, Webpack, and React. - -Prerequisites: `npm`. - -From the plugin's folder run: - -``` -npm i -``` - -This should leave you with everything you need for development, including a local copy of Webpack and webpack-cli. - -## Anatomy of an Edit Flow block. - -There are two parts for adding Block Editor compatibility to modules. - -#### PHP - -On the PHP side, we mostly just need to make sure the block assets are enqueued when they are needed. There is a [Block_Editor_Compatible](common/php/trait-block-editor-compatible.php) trait that gives access to helpful methods related to the block editor when used within modules. - -#### JavaScript - -##### Development - -To start the Webpack in watch mode: - -```npm run dev``` - -##### Build for production - -To generate optimized/minified production-ready files: - -```npm run build``` - -##### File Structure - -``` -blocks/ - # Source files: - src/ - module-slug/ - block.js # Gutenberg Block code for the module - editor.scss # Editor styles - style.scss # Front-end styles - # Build - dist/ - module-slug.build.js # Built block js - module-slug.editor.build.css # Built editor CSS - module-slug.style.build.css # Built front-end CSS -``` - -The files from `dist/` should be enqueued in the compat class for the module. diff --git a/blocks/dist/custom-status.build.js b/blocks/dist/custom-status.build.js deleted file mode 100644 index 1a26bb469..000000000 --- a/blocks/dist/custom-status.build.js +++ /dev/null @@ -1,2 +0,0 @@ -(()=>{"use strict";var t={n:e=>{var n=e&&e.__esModule?()=>e.default:()=>e;return t.d(n,{a:n}),n},d:(e,n)=>{for(var r in n)t.o(n,r)&&!t.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:n[r]})},o:(t,e)=>Object.prototype.hasOwnProperty.call(t,e)};const e=React;var n=t.n(e);function r(t,e){var n="undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(!n){if(Array.isArray(t)||(n=function(t,e){if(t){if("string"==typeof t)return o(t,e);var n=Object.prototype.toString.call(t).slice(8,-1);return"Object"===n&&t.constructor&&(n=t.constructor.name),"Map"===n||"Set"===n?Array.from(t):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?o(t,e):void 0}}(t))||e&&t&&"number"==typeof t.length){n&&(t=n);var r=0,a=function(){};return{s:a,n:function(){return r>=t.length?{done:!0}:{done:!1,value:t[r++]}},e:function(t){throw t},f:a}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var s,i=!0,u=!1;return{s:function(){n=n.call(t)},n:function(){var t=n.next();return i=t.done,t},e:function(t){u=!0,s=t},f:function(){try{i||null==n.return||n.return()}finally{if(u)throw s}}}}function o(t,e){(null==e||e>t.length)&&(e=t.length);for(var n=0,r=new Array(e);n*{flex-basis:45%}.edit-flow-extended-post-status .edit-flow-extended-post-status-note{flex-basis:100%}.edit-flow-extended-post-status-switch-to-draft{flex-basis:100%}.edit-flow-extended-post-status-publish>*{flex-basis:100%} - - -/*# sourceMappingURL=custom-status.editor.build.css.map*/ \ No newline at end of file diff --git a/blocks/dist/custom-status.style.build.css b/blocks/dist/custom-status.style.build.css deleted file mode 100644 index 2386bc5b6..000000000 --- a/blocks/dist/custom-status.style.build.css +++ /dev/null @@ -1,4 +0,0 @@ -.edit-flow-extended-post-status{flex-flow:row wrap}.edit-flow-extended-post-status>*{flex-basis:45%}.edit-flow-extended-post-status .edit-flow-extended-post-status-note{flex-basis:100%}.edit-flow-extended-post-status-switch-to-draft{flex-basis:100%}.edit-flow-extended-post-status-publish>*{flex-basis:100%} - - -/*# sourceMappingURL=custom-status.style.build.css.map*/ \ No newline at end of file diff --git a/blocks/src/blocks.js b/blocks/src/blocks.js deleted file mode 100644 index 00ea8bf85..000000000 --- a/blocks/src/blocks.js +++ /dev/null @@ -1,2 +0,0 @@ -// Custom Statuses -import './custom-status/block'; diff --git a/common/js/ef_date.js b/common/js/ef_date.js index 1029ad515..c62c4c077 100644 --- a/common/js/ef_date.js +++ b/common/js/ef_date.js @@ -1,31 +1,192 @@ -/* global document, jQuery, ef_week_first_day */ +/* global document, jQuery, ef_week_first_day, wp */ -jQuery( document ).ready( function() { - const dateTimePicks = jQuery( '.date-time-pick' ); +jQuery( document ).ready( function( $ ) { + /** + * Check if we're in the Gutenberg editor. + * + * @return {boolean} True if Gutenberg is available. + */ + function isGutenberg() { + return typeof wp !== 'undefined' && wp.data && wp.data.dispatch && wp.data.select; + } - dateTimePicks.each( function() { - const $dTP = jQuery( this ); + /** + * Check if Gutenberg post entity is ready for meta updates. + * + * @return {boolean} True if ready. + */ + function isGutenbergReady() { + if ( ! isGutenberg() ) { + return false; + } + try { + const postType = wp.data.select( 'core/editor' ).getCurrentPostType(); + return !! postType; + } catch ( e ) { + return false; + } + } - $dTP.datetimepicker( { + /** + * Update Gutenberg's data store with the meta value. + * This ensures that when the user saves, the REST API includes our updated meta. + * + * @param {string} metaKey The post meta key. + * @param {*} metaValue The value to save (will be converted to string). + */ + function updateGutenbergMeta( metaKey, metaValue ) { + if ( ! isGutenbergReady() ) { + return; + } + + const meta = {}; + // Convert to string since REST API expects string type. + meta[ metaKey ] = String( metaValue ); + + wp.data.dispatch( 'core/editor' ).editPost( { meta: meta } ); + } + + /** + * Update the hidden field with combined date and time values. + * The hidden field stores the value in 'Y-m-d H:i' format for PHP processing. + * Also updates Gutenberg's data store with the Unix timestamp. + * + * @param {jQuery} $dateInput The date input element. + * @param {boolean} updateGutenberg Whether to update Gutenberg store (default true). + */ + function updateHiddenField( $dateInput, updateGutenberg ) { + if ( typeof updateGutenberg === 'undefined' ) { + updateGutenberg = true; + } + + // Derive related element IDs from the date input ID. + // Date input: {key}_date, Time input: {key}_time, Hidden: {key}_hidden + const baseId = $dateInput.attr( 'id' ).replace( /_date$/, '' ); + const $timeInput = $( '#' + baseId + '_time' ); + const $hiddenInput = $( '#' + baseId + '_hidden' ); + + if ( ! $hiddenInput.length ) { + return; + } + + // Get the date value from the datepicker's altField mechanism or parse it. + let dateValue = $dateInput.datepicker( 'getDate' ); + if ( ! dateValue ) { + $hiddenInput.val( '' ); + if ( updateGutenberg ) { + updateGutenbergMeta( baseId, '' ); + } + return; + } + + // Format date as Y-m-d. + const year = dateValue.getFullYear(); + const month = String( dateValue.getMonth() + 1 ).padStart( 2, '0' ); + const day = String( dateValue.getDate() ).padStart( 2, '0' ); + const formattedDate = year + '-' + month + '-' + day; + + // Get time value (HH:mm format from HTML5 time input). + let timeValue = $timeInput.val() || '00:00'; + + // Combine into 'Y-m-d H:i' format for the hidden field. + $hiddenInput.val( formattedDate + ' ' + timeValue ); + + if ( updateGutenberg ) { + // Calculate Unix timestamp for Gutenberg. + const timeParts = timeValue.split( ':' ); + const hours = parseInt( timeParts[ 0 ], 10 ) || 0; + const minutes = parseInt( timeParts[ 1 ], 10 ) || 0; + + // Create a new Date object with the combined date and time. + const combinedDate = new Date( year, dateValue.getMonth(), dateValue.getDate(), hours, minutes, 0 ); + const timestamp = Math.floor( combinedDate.getTime() / 1000 ); + + // Update Gutenberg's data store with the Unix timestamp (as string). + updateGutenbergMeta( baseId, timestamp ); + } + } + + // Initialize jQuery UI datepicker on .date-pick elements. + const $datePicks = $( '.date-pick' ); + + $datePicks.each( function() { + const $datePicker = $( this ); + + $datePicker.datepicker( { dateFormat: 'M dd yy', firstDay: ef_week_first_day, - alwaysSetTime: false, - controlType: 'select', - altField: '#' + $dTP.prop( 'id' ) + '_hidden', - altFieldTimeOnly: false, - altFormat: 'yy-mm-dd', - altTimeFormat: 'HH:mm', + showButtonPanel: true, + onSelect: function() { + updateHiddenField( $datePicker, true ); + }, + } ); + + // Update hidden field when date input changes (e.g., manual input). + $datePicker.on( 'change', function() { + updateHiddenField( $datePicker, true ); } ); } ); - const datePicks = jQuery( '.date-pick' ); - datePicks.each( function() { - const $datePicker = jQuery( this ); + // Update hidden field when time input changes. + $( '.time-pick' ).on( 'change', function() { + const $timeInput = $( this ); + // Derive the date input from the time input ID. + const baseId = $timeInput.attr( 'id' ).replace( /_time$/, '' ); + const $dateInput = $( '#' + baseId + '_date' ); - $datePicker.datepicker( { - firstDay: ef_week_first_day, - altField: '#' + $datePicker.prop( 'id' ) + '_hidden', - altFormat: 'yy-mm-dd', - } ); + if ( $dateInput.length ) { + updateHiddenField( $dateInput, true ); + } } ); + + // Initialize hidden fields with current values on page load. + // Do NOT update Gutenberg here - just set up the hidden field for form submission. + $datePicks.each( function() { + const $datePicker = $( this ); + if ( $datePicker.val() ) { + updateHiddenField( $datePicker, false ); + } + } ); + + /** + * Sync all Editorial Metadata fields to Gutenberg. + * This handles text, paragraph, checkbox, user, number, and location fields. + */ + function setupMetaboxSync() { + const $metaBox = $( '#ef_editorial_meta_meta_box' ); + + if ( ! $metaBox.length || ! isGutenberg() ) { + return; + } + + // Text, paragraph, number, and location inputs. + $metaBox.find( 'input[type="text"]:not(.date-pick), textarea, select' ).on( 'change input', function() { + const $input = $( this ); + const name = $input.attr( 'name' ); + + // Skip hidden fields and fields without names. + if ( ! name || name.endsWith( '_hidden' ) ) { + return; + } + + updateGutenbergMeta( name, $input.val() ); + } ); + + // Checkbox inputs. + $metaBox.find( 'input[type="checkbox"]' ).on( 'change', function() { + const $input = $( this ); + const name = $input.attr( 'name' ); + + if ( ! name ) { + return; + } + + // Store as '1' or '' to match PHP behavior. + const value = $input.is( ':checked' ) ? '1' : ''; + updateGutenbergMeta( name, value ); + } ); + } + + // Set up metabox sync for Gutenberg. + setupMetaboxSync(); } ); diff --git a/common/js/jquery-ui-timepicker-addon.js b/common/js/jquery-ui-timepicker-addon.js deleted file mode 100644 index c680f5e12..000000000 --- a/common/js/jquery-ui-timepicker-addon.js +++ /dev/null @@ -1,1919 +0,0 @@ -/* - * jQuery timepicker addon - * By: Trent Richardson [http://trentrichardson.com] - * Version 1.2 - * Last Modified: 02/02/2013 - * - * Copyright 2013 Trent Richardson - * You may use this project under MIT or GPL licenses. - * http://trentrichardson.com/Impromptu/GPL-LICENSE.txt - * http://trentrichardson.com/Impromptu/MIT-LICENSE.txt - */ - -/*jslint evil: true, white: false, undef: false, nomen: false */ - -(function($) { - - /* - * Lets not redefine timepicker, Prevent "Uncaught RangeError: Maximum call stack size exceeded" - */ - $.ui.timepicker = $.ui.timepicker || {}; - if ($.ui.timepicker.version) { - return; - } - - /* - * Extend jQueryUI, get it started with our version number - */ - $.extend($.ui, { - timepicker: { - version: "1.2" - } - }); - - /* - * Timepicker manager. - * Use the singleton instance of this class, $.timepicker, to interact with the time picker. - * Settings for (groups of) time pickers are maintained in an instance object, - * allowing multiple different settings on the same page. - */ - var Timepicker = function() { - this.regional = []; // Available regional settings, indexed by language code - this.regional[''] = { // Default regional settings - currentText: 'Now', - closeText: 'Done', - amNames: ['AM', 'A'], - pmNames: ['PM', 'P'], - timeFormat: 'HH:mm', - timeSuffix: '', - timeOnlyTitle: 'Choose Time', - timeText: 'Time', - hourText: 'Hour', - minuteText: 'Minute', - secondText: 'Second', - millisecText: 'Millisecond', - timezoneText: 'Time Zone', - isRTL: false - }; - this._defaults = { // Global defaults for all the datetime picker instances - showButtonPanel: true, - timeOnly: false, - showHour: true, - showMinute: true, - showSecond: false, - showMillisec: false, - showTimezone: false, - showTime: true, - stepHour: 1, - stepMinute: 1, - stepSecond: 1, - stepMillisec: 1, - hour: 0, - minute: 0, - second: 0, - millisec: 0, - timezone: null, - useLocalTimezone: false, - defaultTimezone: "+0000", - hourMin: 0, - minuteMin: 0, - secondMin: 0, - millisecMin: 0, - hourMax: 23, - minuteMax: 59, - secondMax: 59, - millisecMax: 999, - minDateTime: null, - maxDateTime: null, - onSelect: null, - hourGrid: 0, - minuteGrid: 0, - secondGrid: 0, - millisecGrid: 0, - alwaysSetTime: true, - separator: ' ', - altFieldTimeOnly: true, - altTimeFormat: null, - altSeparator: null, - altTimeSuffix: null, - pickerTimeFormat: null, - pickerTimeSuffix: null, - showTimepicker: true, - timezoneIso8601: false, - timezoneList: null, - addSliderAccess: false, - sliderAccessArgs: null, - controlType: 'slider', - defaultValue: null, - parse: 'strict' - }; - $.extend(this._defaults, this.regional['']); - }; - - $.extend(Timepicker.prototype, { - $input: null, - $altInput: null, - $timeObj: null, - inst: null, - hour_slider: null, - minute_slider: null, - second_slider: null, - millisec_slider: null, - timezone_select: null, - hour: 0, - minute: 0, - second: 0, - millisec: 0, - timezone: null, - defaultTimezone: "+0000", - hourMinOriginal: null, - minuteMinOriginal: null, - secondMinOriginal: null, - millisecMinOriginal: null, - hourMaxOriginal: null, - minuteMaxOriginal: null, - secondMaxOriginal: null, - millisecMaxOriginal: null, - ampm: '', - formattedDate: '', - formattedTime: '', - formattedDateTime: '', - timezoneList: null, - units: ['hour','minute','second','millisec'], - control: null, - - /* - * Override the default settings for all instances of the time picker. - * @param settings object - the new settings to use as defaults (anonymous object) - * @return the manager object - */ - setDefaults: function(settings) { - extendRemove(this._defaults, settings || {}); - return this; - }, - - /* - * Create a new Timepicker instance - */ - _newInst: function($input, o) { - var tp_inst = new Timepicker(), - inlineSettings = {}, - fns = {}, - overrides, i; - - for (var attrName in this._defaults) { - if(this._defaults.hasOwnProperty(attrName)){ - var attrValue = $input.attr('time:' + attrName); - if (attrValue) { - try { - inlineSettings[attrName] = eval(attrValue); - } catch (err) { - inlineSettings[attrName] = attrValue; - } - } - } - } - overrides = { - beforeShow: function (input, dp_inst) { - if ($.isFunction(tp_inst._defaults.evnts.beforeShow)) { - return tp_inst._defaults.evnts.beforeShow.call($input[0], input, dp_inst, tp_inst); - } - }, - onChangeMonthYear: function (year, month, dp_inst) { - // Update the time as well : this prevents the time from disappearing from the $input field. - tp_inst._updateDateTime(dp_inst); - if ($.isFunction(tp_inst._defaults.evnts.onChangeMonthYear)) { - tp_inst._defaults.evnts.onChangeMonthYear.call($input[0], year, month, dp_inst, tp_inst); - } - }, - onClose: function (dateText, dp_inst) { - if (tp_inst.timeDefined === true && $input.val() !== '') { - tp_inst._updateDateTime(dp_inst); - } - if ($.isFunction(tp_inst._defaults.evnts.onClose)) { - tp_inst._defaults.evnts.onClose.call($input[0], dateText, dp_inst, tp_inst); - } - } - }; - for (i in overrides) { - if (overrides.hasOwnProperty(i)) { - fns[i] = o[i] || null; - } - } - tp_inst._defaults = $.extend({}, this._defaults, inlineSettings, o, overrides, { - evnts:fns, - timepicker: tp_inst // add timepicker as a property of datepicker: $.datepicker._get(dp_inst, 'timepicker'); - }); - tp_inst.amNames = $.map(tp_inst._defaults.amNames, function(val) { - return val.toUpperCase(); - }); - tp_inst.pmNames = $.map(tp_inst._defaults.pmNames, function(val) { - return val.toUpperCase(); - }); - - // controlType is string - key to our this._controls - if(typeof(tp_inst._defaults.controlType) === 'string'){ - if($.fn[tp_inst._defaults.controlType] === undefined){ - tp_inst._defaults.controlType = 'select'; - } - tp_inst.control = tp_inst._controls[tp_inst._defaults.controlType]; - } - // controlType is an object and must implement create, options, value methods - else{ - tp_inst.control = tp_inst._defaults.controlType; - } - - if (tp_inst._defaults.timezoneList === null) { - var timezoneList = ['-1200', '-1100', '-1000', '-0930', '-0900', '-0800', '-0700', '-0600', '-0500', '-0430', '-0400', '-0330', '-0300', '-0200', '-0100', '+0000', - '+0100', '+0200', '+0300', '+0330', '+0400', '+0430', '+0500', '+0530', '+0545', '+0600', '+0630', '+0700', '+0800', '+0845', '+0900', '+0930', - '+1000', '+1030', '+1100', '+1130', '+1200', '+1245', '+1300', '+1400']; - - if (tp_inst._defaults.timezoneIso8601) { - timezoneList = $.map(timezoneList, function(val) { - return val == '+0000' ? 'Z' : (val.substring(0, 3) + ':' + val.substring(3)); - }); - } - tp_inst._defaults.timezoneList = timezoneList; - } - - tp_inst.timezone = tp_inst._defaults.timezone; - tp_inst.hour = tp_inst._defaults.hour < tp_inst._defaults.hourMin? tp_inst._defaults.hourMin : - tp_inst._defaults.hour > tp_inst._defaults.hourMax? tp_inst._defaults.hourMax : tp_inst._defaults.hour; - tp_inst.minute = tp_inst._defaults.minute < tp_inst._defaults.minuteMin? tp_inst._defaults.minuteMin : - tp_inst._defaults.minute > tp_inst._defaults.minuteMax? tp_inst._defaults.minuteMax : tp_inst._defaults.minute; - tp_inst.second = tp_inst._defaults.second < tp_inst._defaults.secondMin? tp_inst._defaults.secondMin : - tp_inst._defaults.second > tp_inst._defaults.secondMax? tp_inst._defaults.secondMax : tp_inst._defaults.second; - tp_inst.millisec = tp_inst._defaults.millisec < tp_inst._defaults.millisecMin? tp_inst._defaults.millisecMin : - tp_inst._defaults.millisec > tp_inst._defaults.millisecMax? tp_inst._defaults.millisecMax : tp_inst._defaults.millisec; - tp_inst.ampm = ''; - tp_inst.$input = $input; - - if (o.altField) { - tp_inst.$altInput = $(o.altField).css({ - cursor: 'pointer' - }).on ( 'focus', function() { - $input.trigger("focus"); - }); - } - - if (tp_inst._defaults.minDate === 0 || tp_inst._defaults.minDateTime === 0) { - tp_inst._defaults.minDate = new Date(); - } - if (tp_inst._defaults.maxDate === 0 || tp_inst._defaults.maxDateTime === 0) { - tp_inst._defaults.maxDate = new Date(); - } - - // datepicker needs minDate/maxDate, timepicker needs minDateTime/maxDateTime.. - if (tp_inst._defaults.minDate !== undefined && tp_inst._defaults.minDate instanceof Date) { - tp_inst._defaults.minDateTime = new Date(tp_inst._defaults.minDate.getTime()); - } - if (tp_inst._defaults.minDateTime !== undefined && tp_inst._defaults.minDateTime instanceof Date) { - tp_inst._defaults.minDate = new Date(tp_inst._defaults.minDateTime.getTime()); - } - if (tp_inst._defaults.maxDate !== undefined && tp_inst._defaults.maxDate instanceof Date) { - tp_inst._defaults.maxDateTime = new Date(tp_inst._defaults.maxDate.getTime()); - } - if (tp_inst._defaults.maxDateTime !== undefined && tp_inst._defaults.maxDateTime instanceof Date) { - tp_inst._defaults.maxDate = new Date(tp_inst._defaults.maxDateTime.getTime()); - } - tp_inst.$input.on( 'focus', function() { - tp_inst._onFocus(); - }); - - return tp_inst; - }, - - /* - * add our sliders to the calendar - */ - _addTimePicker: function(dp_inst) { - var currDT = (this.$altInput && this._defaults.altFieldTimeOnly) ? this.$input.val() + ' ' + this.$altInput.val() : this.$input.val(); - - this.timeDefined = this._parseTime(currDT); - this._limitMinMaxDateTime(dp_inst, false); - this._injectTimePicker(); - }, - - /* - * parse the time string from input value or _setTime - */ - _parseTime: function(timeString, withDate) { - if (!this.inst) { - this.inst = $.datepicker._getInst(this.$input[0]); - } - - if (withDate || !this._defaults.timeOnly) { - var dp_dateFormat = $.datepicker._get(this.inst, 'dateFormat'); - try { - var parseRes = parseDateTimeInternal(dp_dateFormat, this._defaults.timeFormat, timeString, $.datepicker._getFormatConfig(this.inst), this._defaults); - if (!parseRes.timeObj) { - return false; - } - $.extend(this, parseRes.timeObj); - } catch (err) { - $.timepicker.log("Error parsing the date/time string: " + err + - "\ndate/time string = " + timeString + - "\ntimeFormat = " + this._defaults.timeFormat + - "\ndateFormat = " + dp_dateFormat); - return false; - } - return true; - } else { - var timeObj = $.datepicker.parseTime(this._defaults.timeFormat, timeString, this._defaults); - if (!timeObj) { - return false; - } - $.extend(this, timeObj); - return true; - } - }, - - /* - * generate and inject html for timepicker into ui datepicker - */ - _injectTimePicker: function() { - var $dp = this.inst.dpDiv, - o = this.inst.settings, - tp_inst = this, - litem = '', - uitem = '', - max = {}, - gridSize = {}, - size = null; - - // Prevent displaying twice - if ($dp.find("div.ui-timepicker-div").length === 0 && o.showTimepicker) { - var noDisplay = ' style="display:none;"', - html = '
' + '
' + o.timeText + '
' + - '
'; - - // Create the markup - for(var i=0,l=this.units.length; i' + o[litem +'Text'] + '' + - '
'; - - if (o['show'+uitem] && o[litem+'Grid'] > 0) { - html += '
'; - - if(litem == 'hour'){ - for (var h = o[litem+'Min']; h <= max[litem]; h += parseInt(o[litem+'Grid'], 10)) { - gridSize[litem]++; - var tmph = $.datepicker.formatTime(useAmpm(o.pickerTimeFormat || o.timeFormat)? 'hht':'HH', {hour:h}, o); - html += ''; - } - } - else{ - for (var m = o[litem+'Min']; m <= max[litem]; m += parseInt(o[litem+'Grid'], 10)) { - gridSize[litem]++; - html += ''; - } - } - - html += '
' + tmph + '' + ((m < 10) ? '0' : '') + m + '
'; - } - html += '
'; - } - - // Timezone - html += '
' + o.timezoneText + '
'; - html += '
'; - - // Create the elements from string - html += '
'; - var $tp = $(html); - - // if we only want time picker... - if (o.timeOnly === true) { - $tp.prepend('
' + '
' + o.timeOnlyTitle + '
' + '
'); - $dp.find('.ui-datepicker-header, .ui-datepicker-calendar').hide(); - } - - // add sliders, adjust grids, add events - for(var i=0,l=tp_inst.units.length; i 0) { - size = 100 * gridSize[litem] * o[litem+'Grid'] / (max[litem] - o[litem+'Min']); - $tp.find('.ui_tpicker_'+litem+' table').css({ - width: size + "%", - marginLeft: o.isRTL? '0' : ((size / (-2 * gridSize[litem])) + "%"), - marginRight: o.isRTL? ((size / (-2 * gridSize[litem])) + "%") : '0', - borderCollapse: 'collapse' - }).find("td").on( 'click', function(e){ - var $t = $(this), - h = $t.html(), - n = parseInt(h.replace(/[^0-9]/g),10), - ap = h.replace(/[^apm]/ig), - f = $t.data('for'); // loses scope, so we use data-for - - if(f == 'hour'){ - if(ap.indexOf('p') !== -1 && n < 12){ - n += 12; - } - else{ - if(ap.indexOf('a') !== -1 && n === 12){ - n = 0; - } - } - } - - tp_inst.control.value(tp_inst, tp_inst[f+'_slider'], litem, n); - - tp_inst._onTimeChange(); - tp_inst._onSelectHandler(); - }) - .css({ - cursor: 'pointer', - width: (100 / gridSize[litem]) + '%', - textAlign: 'center', - overflow: 'hidden' - }); - } // end if grid > 0 - } // end for loop - - // Add timezone options - this.timezone_select = $tp.find('.ui_tpicker_timezone').append('').find("select"); - $.fn.append.apply(this.timezone_select, - $.map(o.timezoneList, function(val, idx) { - return $("