├── modules
└── yoocccreadingtime
│ ├── elements
│ └── yoocccreadingtimeelement
│ │ ├── assets
│ │ ├── css
│ │ │ └── cccreadingtime.css
│ │ └── js
│ │ │ └── cccreadingtime.js
│ │ ├── images
│ │ ├── iconSmall.svg
│ │ └── icon.svg
│ │ ├── templates
│ │ ├── content.php
│ │ └── template.php
│ │ └── element.json
│ └── bootstrap.php
├── vendor
├── yootheme
│ └── starter-utils
│ │ ├── README.md
│ │ ├── src
│ │ ├── stubs
│ │ │ ├── module
│ │ │ │ ├── assets
│ │ │ │ │ ├── css
│ │ │ │ │ │ └── custom.css
│ │ │ │ │ ├── js
│ │ │ │ │ │ └── custom.js
│ │ │ │ │ └── less
│ │ │ │ │ │ └── my-component.less
│ │ │ │ ├── languages
│ │ │ │ │ └── de_DE.json
│ │ │ │ ├── src
│ │ │ │ │ ├── MyTypeProvider.php
│ │ │ │ │ ├── SourceListener.php
│ │ │ │ │ ├── TranslationListener.php
│ │ │ │ │ ├── StyleListener.php
│ │ │ │ │ ├── AssetsListener.php
│ │ │ │ │ ├── Type
│ │ │ │ │ │ ├── MyType.php
│ │ │ │ │ │ └── MyQueryType.php
│ │ │ │ │ └── SettingsListener.php
│ │ │ │ ├── config
│ │ │ │ │ ├── customizer.json
│ │ │ │ │ └── styler.json
│ │ │ │ └── bootstrap.php
│ │ │ ├── single-element
│ │ │ │ ├── images
│ │ │ │ │ ├── iconSmall.svg
│ │ │ │ │ └── icon.svg
│ │ │ │ ├── templates
│ │ │ │ │ ├── content.php
│ │ │ │ │ └── template.php
│ │ │ │ └── element.json
│ │ │ ├── multiple-element
│ │ │ │ ├── images
│ │ │ │ │ ├── iconSmall.svg
│ │ │ │ │ └── icon.svg
│ │ │ │ ├── templates
│ │ │ │ │ ├── content.php
│ │ │ │ │ └── template.php
│ │ │ │ └── element.json
│ │ │ ├── multiple-element_item
│ │ │ │ ├── element.php
│ │ │ │ ├── templates
│ │ │ │ │ ├── content.php
│ │ │ │ │ └── template.php
│ │ │ │ └── element.json
│ │ │ └── plugin
│ │ │ │ ├── .env
│ │ │ │ ├── build
│ │ │ │ ├── joomla
│ │ │ │ │ ├── plugin.stub
│ │ │ │ │ └── plugin.xml
│ │ │ │ └── wordpress
│ │ │ │ │ └── plugin.stub
│ │ │ │ └── Taskfile.yml
│ │ ├── StringHelper.php
│ │ ├── CreateWordpressUpdateCommand.php
│ │ ├── CreatePluginCommand.php
│ │ ├── CreateElementCommand.php
│ │ ├── CreateJoomlaUpdateCommand.php
│ │ ├── TaskHelper.php
│ │ └── CreateModuleCommand.php
│ │ ├── phpstan.neon
│ │ ├── LICENSE.md
│ │ ├── Taskfile.yml
│ │ ├── composer.json
│ │ └── CHANGELOG.md
├── composer
│ ├── autoload_namespaces.php
│ ├── autoload_psr4.php
│ ├── autoload_classmap.php
│ ├── platform_check.php
│ ├── LICENSE
│ ├── installed.php
│ ├── autoload_static.php
│ ├── autoload_real.php
│ ├── installed.json
│ ├── InstalledVersions.php
│ └── ClassLoader.php
└── autoload.php
├── dist
├── yoocccreadingtime-j-0.0.1.zip
├── yoocccreadingtime-wp-0.0.1.zip
├── update.json
└── update.xml
├── .env
├── yoocccreadingtime.php
├── composer.json
├── yoocccreadingtime.xml
├── composer.lock
├── Taskfile.yml
└── README.md
/modules/yoocccreadingtime/elements/yoocccreadingtimeelement/assets/css/cccreadingtime.css:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/vendor/yootheme/starter-utils/README.md:
--------------------------------------------------------------------------------
1 | # starter-utils
2 |
3 | YOOtheme Pro - Starter Utilities
4 |
--------------------------------------------------------------------------------
/vendor/yootheme/starter-utils/src/stubs/module/assets/css/custom.css:
--------------------------------------------------------------------------------
1 | * {
2 | color: red !important;
3 | }
4 |
--------------------------------------------------------------------------------
/dist/yoocccreadingtime-j-0.0.1.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/coolcat-creations/yoocccreadingtime/main/dist/yoocccreadingtime-j-0.0.1.zip
--------------------------------------------------------------------------------
/dist/yoocccreadingtime-wp-0.0.1.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/coolcat-creations/yoocccreadingtime/main/dist/yoocccreadingtime-wp-0.0.1.zip
--------------------------------------------------------------------------------
/vendor/yootheme/starter-utils/src/stubs/module/assets/js/custom.js:
--------------------------------------------------------------------------------
1 | document.body.insertAdjacentHTML('afterbegin', '
Script file
');
2 |
--------------------------------------------------------------------------------
/dist/update.json:
--------------------------------------------------------------------------------
1 | {
2 | "slug": "yoocccreadingtime",
3 | "version": "0.0.1",
4 | "package": "https:\/\/www.example.com\/downloads\/yoocccreadingtime-wp-0.0.1.zip"
5 | }
--------------------------------------------------------------------------------
/vendor/yootheme/starter-utils/phpstan.neon:
--------------------------------------------------------------------------------
1 | parameters:
2 | level: 5
3 |
4 | paths:
5 | - src
6 |
7 | excludePaths:
8 | analyseAndScan:
9 | - src/stubs/*
10 |
--------------------------------------------------------------------------------
/vendor/composer/autoload_namespaces.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/modules/yoocccreadingtime/elements/yoocccreadingtimeelement/images/iconSmall.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/vendor/yootheme/starter-utils/src/stubs/multiple-element/images/iconSmall.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/vendor/yootheme/starter-utils/src/stubs/multiple-element/images/icon.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/vendor/yootheme/starter-utils/src/stubs/single-element/images/icon.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/modules/yoocccreadingtime/elements/yoocccreadingtimeelement/images/icon.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/vendor/composer/autoload_psr4.php:
--------------------------------------------------------------------------------
1 | array($vendorDir . '/yootheme/starter-utils/src'),
10 | );
11 |
--------------------------------------------------------------------------------
/vendor/composer/autoload_classmap.php:
--------------------------------------------------------------------------------
1 | $vendorDir . '/composer/InstalledVersions.php',
10 | );
11 |
--------------------------------------------------------------------------------
/vendor/yootheme/starter-utils/src/stubs/module/src/MyTypeProvider.php:
--------------------------------------------------------------------------------
1 | "The data for id: {$id}"];
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/vendor/yootheme/starter-utils/src/stubs/multiple-element_item/element.php:
--------------------------------------------------------------------------------
1 | [
5 | 'render' => function ($node) {
6 | // Don't render element if content fields are empty
7 | return $node->props['title'] || $node->props['content'] || $node->props['image'];
8 | },
9 | ],
10 | ];
11 |
--------------------------------------------------------------------------------
/vendor/yootheme/starter-utils/src/StringHelper.php:
--------------------------------------------------------------------------------
1 | $replace[$matches[1]] ?? $matches[0];
10 |
11 | return preg_replace_callback('/{{\s*(\w+?)\s*}}/', $callback, $str);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/vendor/yootheme/starter-utils/src/stubs/single-element/templates/content.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
= $props['title'] ?>
6 |
7 |
8 |
9 |
= $props['content'] ?>
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/modules/yoocccreadingtime/elements/yoocccreadingtimeelement/templates/content.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
= $props['title'] ?>
6 |
7 |
8 |
9 |
= $props['content'] ?>
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/vendor/yootheme/starter-utils/src/stubs/module/src/SourceListener.php:
--------------------------------------------------------------------------------
1 | objectType('MyType', MyType::config());
15 | $source->queryType(MyQueryType::config());
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/vendor/yootheme/starter-utils/src/stubs/module/src/TranslationListener.php:
--------------------------------------------------------------------------------
1 | addResource(Path::get("../languages/{$config('locale.code')}.json"));
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/vendor/yootheme/starter-utils/src/stubs/module/src/StyleListener.php:
--------------------------------------------------------------------------------
1 | *"
11 | }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/vendor/yootheme/starter-utils/src/stubs/multiple-element/templates/content.php:
--------------------------------------------------------------------------------
1 | 1): ?>
2 |
3 |
4 | -
5 |
6 | = $builder->render($child, ['element' => $props]) ?>
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | = $builder->render($children[0], ['element' => $props]) ?>
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/vendor/yootheme/starter-utils/src/stubs/multiple-element_item/templates/content.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | <= $element['title_element'] ?>>= $props['title'] ?>= $element['title_element'] ?>>
7 |
8 |
9 |
10 | = $props['content'] ?>
11 |
12 |
13 |
14 | = $element['link_text'] ?>
15 |
16 |
--------------------------------------------------------------------------------
/vendor/yootheme/starter-utils/src/stubs/multiple-element/templates/template.php:
--------------------------------------------------------------------------------
1 | el('div', [
5 | 'class' => ['example-element'],
6 | ]);
7 |
8 | // Grid
9 | $grid = $this->el('ul', [
10 | 'class' => ['uk-child-width-1-{grid_columns}'],
11 | 'uk-grid' => true,
12 | ]);
13 | ?>
14 |
15 | = $el($props, $attrs) ?>
16 |
17 | = $grid($props) ?>
18 |
19 | = $builder->render($child, ['element' => $props]) ?>
20 |
21 | = $grid->end() ?>
22 |
23 | = $el->end() ?>
24 |
--------------------------------------------------------------------------------
/vendor/yootheme/starter-utils/src/stubs/plugin/.env:
--------------------------------------------------------------------------------
1 | TITLE='{{TITLE}}'
2 | NAME='{{NAME}}'
3 | VERSION='0.0.1'
4 | DESCRIPTION='{{DESCRIPTION}}'
5 | DATE='{{now | date "2006-01-02"}}'
6 | COPYRIGHT='Copyright (C)'
7 | LICENSE='GNU General Public License'
8 | AUTHOR='{{AUTHOR}}'
9 | AUTHOREMAIL='{{AUTHOREMAIL}}'
10 | AUTHORURL='{{AUTHORURL}}'
11 |
12 | # Update server
13 | UPDATEURI='{{UPDATEURI}}'
14 |
15 | # Package information
16 | TYPE='plugin'
17 | STABILITY='stable'
18 | DOWNLOADURL='https://www.example.com/downloads'
19 | PHPMINIMUM='7.4'
20 | JOOMLAMINIMUM='(5\.[01]|4\.[01234]|3\.10)\.'
21 | WORDPRESSMINIMUM='6.2'
22 |
--------------------------------------------------------------------------------
/vendor/yootheme/starter-utils/src/stubs/single-element/templates/template.php:
--------------------------------------------------------------------------------
1 | el('div', [
4 | 'class' => '',
5 | ]);
6 |
7 | // Title
8 | $title = $this->el('h1', [
9 | 'class' => ['el-title'],
10 | ]);
11 |
12 | // Content
13 | $content = $this->el('div', [
14 | 'class' => ['el-content'],
15 | ]);
16 | ?>
17 |
18 | = $el($props, $attrs) ?>
19 |
20 |
21 | = $title($props, $props['title']) ?>
22 |
23 |
24 |
25 | = $content($props, $props['content']) ?>
26 |
27 |
28 | = $el->end() ?>
29 |
--------------------------------------------------------------------------------
/vendor/yootheme/starter-utils/src/stubs/module/bootstrap.php:
--------------------------------------------------------------------------------
1 | [
12 | // add theme config ...
13 | ],
14 |
15 | 'config' => [
16 | // add styler config ...
17 | ],
18 |
19 | 'events' => [
20 | // add event handlers ...
21 | ],
22 |
23 | 'extend' => [
24 | // extend container services ...
25 |
26 | Builder::class => function (Builder $builder) {
27 | $builder->addTypePath(Path::get('./elements/*/element.json'));
28 | },
29 | ],
30 | ];
31 |
--------------------------------------------------------------------------------
/modules/yoocccreadingtime/bootstrap.php:
--------------------------------------------------------------------------------
1 | [
12 | // add theme config ...
13 | ],
14 |
15 | 'config' => [
16 | // add styler config ...
17 | ],
18 |
19 | 'events' => [
20 | // add event handlers ...
21 | ],
22 |
23 | 'extend' => [
24 | // extend container services ...
25 |
26 | Builder::class => function (Builder $builder) {
27 | $builder->addTypePath(Path::get('./elements/*/element.json'));
28 | },
29 | ],
30 | ];
31 |
--------------------------------------------------------------------------------
/.env:
--------------------------------------------------------------------------------
1 | TITLE='YOO CCC Reading Time'
2 | NAME='yoocccreadingtime'
3 | VERSION='0.0.1'
4 | DESCRIPTION='YOOtheme Pro Element to display the reading time of a block or specific content'
5 | DATE='{{now | date "2006-01-02"}}'
6 | COPYRIGHT='Copyright (C)'
7 | LICENSE='GNU General Public License'
8 | AUTHOR='Elisa Sophia Foltyn'
9 | AUTHOREMAIL='contact@coolcat-creations.com'
10 | AUTHORURL='https://coolcat-creations.com'
11 |
12 | # Update server
13 | UPDATEURI='https://coolcat-campus.com/updates'
14 |
15 | # Package information
16 | TYPE='plugin'
17 | STABILITY='stable'
18 | DOWNLOADURL='https://www.example.com/downloads'
19 | PHPMINIMUM='7.4'
20 | JOOMLAMINIMUM='(5\.[01]|4\.[01234]|3\.10)\.'
21 | WORDPRESSMINIMUM='6.2'
22 |
--------------------------------------------------------------------------------
/modules/yoocccreadingtime/elements/yoocccreadingtimeelement/assets/js/cccreadingtime.js:
--------------------------------------------------------------------------------
1 | document.addEventListener("DOMContentLoaded", function() {
2 | var container = document.querySelectorAll('.uk-section ');
3 |
4 |
5 | const readingTimeSummary = document.querySelector("#readingtime");
6 | const avgWordsPerMin = 250;
7 |
8 | function totalWords(container) {
9 | var total = 0;
10 | for (var i = 0; i < container.length; i++) {
11 | total += container[i].innerText.split(' ').length;
12 | }
13 | return total;
14 | }
15 |
16 | function setReadingTime() {
17 | let count = totalWords(container);
18 |
19 | let time = Math.ceil(count / avgWordsPerMin);
20 | readingTimeSummary.innerText = time;
21 | }
22 |
23 | setReadingTime();
24 |
25 | });
26 |
27 |
--------------------------------------------------------------------------------
/yoocccreadingtime.php:
--------------------------------------------------------------------------------
1 | load(__DIR__ . '/modules/*/bootstrap.php');
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/vendor/yootheme/starter-utils/src/stubs/module/src/AssetsListener.php:
--------------------------------------------------------------------------------
1 | set('style:my-css', ['href' => Path::get('../assets/css/custom.css')]);
14 |
15 | // Inline style
16 | $metadata->set('style:my-inline-css', 'body {color: blue}');
17 |
18 | // Script file
19 | $metadata->set('script:my-js', [
20 | 'src' => Path::get('../assets/js/custom.js'),
21 | 'defer' => true,
22 | ]);
23 |
24 | // Inline script
25 | $metadata->set('script:my-inline-js', 'var custom = 123;');
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/vendor/yootheme/starter-utils/src/stubs/plugin/build/joomla/plugin.stub:
--------------------------------------------------------------------------------
1 | load(__DIR__ . '/modules/*/bootstrap.php');
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/vendor/autoload.php:
--------------------------------------------------------------------------------
1 |
2 |
3 | {{TITLE}}
4 | {{VERSION}}
5 | {{DESCRIPTION}}
6 | {{DATE}}
7 | {{COPYRIGHT}}
8 | {{LICENSE}}
9 | {{AUTHOR}}
10 | {{AUTHOREMAIL}}
11 | {{AUTHORURL}}
12 |
13 | {{PLUGIN}}.php
14 | modules
15 |
16 |
17 |
18 | {{UPDATEURI}}/update.xml
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/vendor/yootheme/starter-utils/src/stubs/module/src/Type/MyType.php:
--------------------------------------------------------------------------------
1 | [
11 | 'my_field' => [
12 | 'type' => 'String',
13 | 'metadata' => [
14 | 'label' => 'My Field',
15 | ],
16 | 'extensions' => [
17 | 'call' => __CLASS__ . '::resolve',
18 | ],
19 | ],
20 | ],
21 |
22 | 'metadata' => [
23 | 'type' => true,
24 | 'label' => 'My Type',
25 | ],
26 | ];
27 | }
28 |
29 | public static function resolve($obj, $args, $context, $info)
30 | {
31 | // Query the data …
32 | return $obj->my_field;
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/vendor/yootheme/starter-utils/src/stubs/module/src/SettingsListener.php:
--------------------------------------------------------------------------------
1 | set('customizer.panels.my-panel', [
14 | 'title' => 'My Panel',
15 | 'width' => 400,
16 | 'fields' => [
17 | 'option_b' => [
18 | 'label' => 'Option B',
19 | 'description' => 'A description text.',
20 | ],
21 | ],
22 | ]);
23 | $config->set('customizer.sections.settings.fields.settings.items.my-panel', 'My Panel');
24 |
25 | // Add section using a JSON config file
26 | $config->addFile('customizer', Path::get('../config/customizer.json'));
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "yootheme/starter-plugin",
3 | "description": "YOOtheme Pro - Starter Plugin",
4 | "license": "MIT",
5 | "type": "project",
6 | "keywords": [
7 | "joomla",
8 | "wordpress",
9 | "yootheme"
10 | ],
11 | "require": {
12 | "php": "^8.0"
13 | },
14 | "require-dev": {
15 | "yootheme/starter-utils": "^1.0"
16 | },
17 | "scripts": {
18 | "run:task": "YOOtheme\\Starter\\TaskHelper::run",
19 | "create:plugin": "YOOtheme\\Starter\\CreatePluginCommand",
20 | "create:element": "YOOtheme\\Starter\\CreateElementCommand",
21 | "create:module": "YOOtheme\\Starter\\CreateModuleCommand",
22 | "create:joomlaUpdate": "YOOtheme\\Starter\\CreateJoomlaUpdateCommand",
23 | "create:wordpressUpdate": "YOOtheme\\Starter\\CreateWordpressUpdateCommand",
24 | "post-create-project-cmd": "@composer create:plugin"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/yoocccreadingtime.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | YOO CCC Reading Time
4 | 0.0.1
5 | YOOtheme Pro Element to display the reading time of a block or specific content
6 | 2024-09-14
7 | Copyright (C)
8 | GNU General Public License
9 | Elisa Sophia Foltyn
10 | contact@coolcat-creations.com
11 | https://coolcat-creations.com
12 |
13 | yoocccreadingtime.php
14 | modules
15 |
16 |
17 |
18 | https://coolcat-campus.com/updates/update.xml
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/vendor/composer/platform_check.php:
--------------------------------------------------------------------------------
1 | = 80000)) {
8 | $issues[] = 'Your Composer dependencies require a PHP version ">= 8.0.0". You are running ' . PHP_VERSION . '.';
9 | }
10 |
11 | if ($issues) {
12 | if (!headers_sent()) {
13 | header('HTTP/1.1 500 Internal Server Error');
14 | }
15 | if (!ini_get('display_errors')) {
16 | if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
17 | fwrite(STDERR, 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . implode(PHP_EOL, $issues) . PHP_EOL.PHP_EOL);
18 | } elseif (!headers_sent()) {
19 | echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL;
20 | }
21 | }
22 | trigger_error(
23 | 'Composer detected issues in your platform: ' . implode(' ', $issues),
24 | E_USER_ERROR
25 | );
26 | }
27 |
--------------------------------------------------------------------------------
/dist/update.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | yoocccreadingtime
5 | YOOtheme Pro Element to display the reading time of a block or specific content
6 | yoocccreadingtime
7 | plugin
8 | 0.0.1
9 |
10 | https://www.example.com/downloads/yoocccreadingtime-j-0.0.1.zip
11 |
12 | stable
13 | e1f32d2ebd5cbea7672939737c2eec9878f801d0b996f1169557c60972ddaeb4
14 | d36075faa21f1108f0c1749f29635979e8fcd3076bda2e99ad4792c58e0696c26af39c2d697b94ed707bd7133a3ec2e6
15 | efc56c0474a85ebad8ba423deffd9247e3cba010bfd24cc711ba7422ff0f6c171307e123853c6f455cf875655db5630233d80a7a53ef96ea4f92430a2e63d6c8
16 | Elisa Sophia Foltyn
17 | https://coolcat-creations.com
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/vendor/composer/LICENSE:
--------------------------------------------------------------------------------
1 |
2 | Copyright (c) Nils Adermann, Jordi Boggiano
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy
5 | of this software and associated documentation files (the "Software"), to deal
6 | in the Software without restriction, including without limitation the rights
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the Software is furnished
9 | to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in all
12 | copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | THE SOFTWARE.
21 |
22 |
--------------------------------------------------------------------------------
/vendor/yootheme/starter-utils/LICENSE.md:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) YOOtheme GmbH
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/vendor/composer/installed.php:
--------------------------------------------------------------------------------
1 | array(
3 | 'name' => 'yootheme/starter-plugin',
4 | 'pretty_version' => '1.0.2',
5 | 'version' => '1.0.2.0',
6 | 'reference' => null,
7 | 'type' => 'project',
8 | 'install_path' => __DIR__ . '/../../',
9 | 'aliases' => array(),
10 | 'dev' => true,
11 | ),
12 | 'versions' => array(
13 | 'yootheme/starter-plugin' => array(
14 | 'pretty_version' => '1.0.2',
15 | 'version' => '1.0.2.0',
16 | 'reference' => null,
17 | 'type' => 'project',
18 | 'install_path' => __DIR__ . '/../../',
19 | 'aliases' => array(),
20 | 'dev_requirement' => false,
21 | ),
22 | 'yootheme/starter-utils' => array(
23 | 'pretty_version' => '1.0.4',
24 | 'version' => '1.0.4.0',
25 | 'reference' => '7d2385d398fa3a7af8164dcda25a31e69cd298d5',
26 | 'type' => 'library',
27 | 'install_path' => __DIR__ . '/../yootheme/starter-utils',
28 | 'aliases' => array(),
29 | 'dev_requirement' => true,
30 | ),
31 | ),
32 | );
33 |
--------------------------------------------------------------------------------
/vendor/yootheme/starter-utils/Taskfile.yml:
--------------------------------------------------------------------------------
1 | version: '3'
2 |
3 | env:
4 | ROOT_DIR: '{{.ROOT_DIR}}'
5 |
6 | tasks:
7 | copy:
8 | dir: '{{.ROOT_DIR}}'
9 | env:
10 | TASK_CWD: '{{.cwd}}'
11 | cmds:
12 | - composer run:task -q -- copy {{q .src}} {{q .dest}} {{if .ignore}}{{q .ignore}}{{end}}
13 | requires:
14 | vars: [src, dest]
15 | internal: true
16 |
17 | remove:
18 | dir: '{{.ROOT_DIR}}'
19 | env:
20 | TASK_CWD: '{{.cwd}}'
21 | cmds:
22 | - composer run:task -q -- remove {{q .src}} {{if .ignore}}{{q .ignore}}{{end}}
23 | requires:
24 | vars: [src]
25 | internal: true
26 |
27 | placeholder:
28 | dir: '{{.ROOT_DIR}}'
29 | env:
30 | TASK_CWD: '{{.cwd}}'
31 | cmds:
32 | - composer run:task -q -- placeholder {{q .src}} {{q (toRawJson .replace)}} {{if .ignore}}{{q .ignore}}{{end}}
33 | requires:
34 | vars: [src, replace]
35 | internal: true
36 |
37 | zip:
38 | dir: '{{.ROOT_DIR}}'
39 | env:
40 | TASK_CWD: '{{.cwd}}'
41 | cmds:
42 | - composer run:task -q -- zip {{q .src}} {{q .dest}} {{if .ignore}}{{q .ignore}}{{end}}
43 | requires:
44 | vars: [src, dest]
45 | internal: true
46 |
--------------------------------------------------------------------------------
/vendor/yootheme/starter-utils/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "yootheme/starter-utils",
3 | "description": "YOOtheme Pro - Starter Utilities",
4 | "license": "MIT",
5 | "keywords": [
6 | "joomla",
7 | "wordpress",
8 | "yootheme"
9 | ],
10 | "homepage": "https://yootheme.com",
11 | "support": {
12 | "issues": "https://github.com/yootheme/starter-utils/issues",
13 | "source": "https://github.com/yootheme/starter-utils"
14 | },
15 | "require": {
16 | "php": "^8.0"
17 | },
18 | "require-dev": {
19 | "composer/composer": "^2.7",
20 | "phpstan/phpstan": "^1.11"
21 | },
22 | "autoload": {
23 | "psr-4": {
24 | "YOOtheme\\Starter\\": "src"
25 | }
26 | },
27 | "scripts": {
28 | "phpstan": "phpstan analyse -c phpstan.neon",
29 | "run:task": "YOOtheme\\Starter\\TaskHelper::run",
30 | "create:plugin": "YOOtheme\\Starter\\CreatePluginCommand",
31 | "create:element": "YOOtheme\\Starter\\CreateElementCommand",
32 | "create:module": "YOOtheme\\Starter\\CreateModuleCommand",
33 | "create:joomlaUpdate": "YOOtheme\\Starter\\CreateJoomlaUpdateCommand"
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/vendor/composer/autoload_static.php:
--------------------------------------------------------------------------------
1 |
11 | array (
12 | 'YOOtheme\\Starter\\' => 17,
13 | ),
14 | );
15 |
16 | public static $prefixDirsPsr4 = array (
17 | 'YOOtheme\\Starter\\' =>
18 | array (
19 | 0 => __DIR__ . '/..' . '/yootheme/starter-utils/src',
20 | ),
21 | );
22 |
23 | public static $classMap = array (
24 | 'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
25 | );
26 |
27 | public static function getInitializer(ClassLoader $loader)
28 | {
29 | return \Closure::bind(function () use ($loader) {
30 | $loader->prefixLengthsPsr4 = ComposerStaticInitb954339d110cc4773e95741258d341ad::$prefixLengthsPsr4;
31 | $loader->prefixDirsPsr4 = ComposerStaticInitb954339d110cc4773e95741258d341ad::$prefixDirsPsr4;
32 | $loader->classMap = ComposerStaticInitb954339d110cc4773e95741258d341ad::$classMap;
33 |
34 | }, null, ClassLoader::class);
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/vendor/yootheme/starter-utils/src/stubs/plugin/build/wordpress/plugin.stub:
--------------------------------------------------------------------------------
1 | load(__DIR__ . '/modules/*/bootstrap.php');
29 | });
30 |
31 | add_filter('update_plugins_{{UPDATEHOST}}', function($update, $plugin_data, $plugin_file, $locales) {
32 | if ($plugin_file == plugin_basename(__FILE__)) {
33 | $request = wp_remote_get($plugin_data['UpdateURI']);
34 | $request_body = wp_remote_retrieve_body( $request );
35 | $update = json_decode( $request_body, true );
36 | }
37 |
38 | return $update;
39 | },10, 4);
40 |
--------------------------------------------------------------------------------
/vendor/composer/autoload_real.php:
--------------------------------------------------------------------------------
1 | register(true);
35 |
36 | return $loader;
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/vendor/yootheme/starter-utils/src/stubs/module/src/Type/MyQueryType.php:
--------------------------------------------------------------------------------
1 | [
11 | 'custom_my_type' => [
12 | 'type' => 'MyType',
13 |
14 | 'args' => [
15 | 'id' => [
16 | 'type' => 'String',
17 | ],
18 | ],
19 |
20 | 'metadata' => [
21 | 'label' => 'Custom MyType',
22 | 'group' => 'Custom',
23 |
24 | 'fields' => [
25 | 'id' => [
26 | 'label' => 'Type ID',
27 | 'description' => 'Input a type ID.',
28 | ],
29 | ],
30 | ],
31 |
32 | 'extensions' => [
33 | 'call' => __CLASS__ . '::resolve',
34 | ],
35 | ],
36 | ],
37 | ];
38 | }
39 |
40 | public static function resolve($item, $args, $context, $info)
41 | {
42 | return MyTypeProvider::get($args['id']);
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/modules/yoocccreadingtime/elements/yoocccreadingtimeelement/templates/template.php:
--------------------------------------------------------------------------------
1 | el('div', [
4 | 'class' => '',
5 | ]);
6 |
7 | // Content
8 | $content = $this->el('div', [
9 | 'class' => ['el-content'],
10 | ]);
11 | ?>
12 |
13 |
14 | = $el($props, $attrs) ?>
15 |
16 | min.
17 |
18 | = $el->end() ?>
19 |
20 |
31 |
32 |
33 |
34 |
57 |
--------------------------------------------------------------------------------
/vendor/yootheme/starter-utils/src/CreateWordpressUpdateCommand.php:
--------------------------------------------------------------------------------
1 | writeln('Could not find Wordpress package in dist folder.');
22 |
23 | return Command::FAILURE;
24 | }
25 |
26 | $metadata = parse_ini_file(getcwd() . '/.env');
27 |
28 | $update = [
29 | 'slug' => $metadata['NAME'],
30 | 'version' => $metadata['VERSION'],
31 | 'package' => "{$metadata['DOWNLOADURL']}/{$metadata['NAME']}-wp-{$metadata['VERSION']}.zip",
32 | ];
33 |
34 | $fs = new Filesystem();
35 | $fs->dumpFile(
36 | Path::join(getcwd(), 'dist', 'update.json'),
37 | json_encode($update, JSON_PRETTY_PRINT),
38 | );
39 |
40 | return Command::SUCCESS;
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/vendor/yootheme/starter-utils/src/stubs/multiple-element_item/templates/template.php:
--------------------------------------------------------------------------------
1 | el('div', [
12 | 'class' => ['el-item uk-panel'],
13 | ]);
14 |
15 | // Title
16 | $title = $this->el($element['title_element'], [
17 | 'class' => ['el-title'],
18 | ]);
19 |
20 | // Content
21 | $content = $this->el('div', [
22 | 'class' => ['el-content uk-panel'],
23 | ]);
24 |
25 | $image = $this->el('image', [
26 | 'class' => ['el-image'],
27 | 'src' => $props['image'],
28 | 'alt' => $props['image_alt'],
29 | 'loading' => $element['image_loading'] ? false : null,
30 | 'width' => $element['image_width'],
31 | 'height' => $element['image_height'],
32 | 'focal_point' => $props['image_focal_point'],
33 | 'thumbnail' => true,
34 | ]);
35 |
36 | // Link
37 | $link = $this->el('a', [
38 | 'class' => ['el-link uk-button uk-button-default'],
39 | 'href' => $props['link'],
40 | 'uk-scroll' => str_contains((string) $props['link'], '#'),
41 | ]);
42 | ?>
43 |
44 | = $el($element, $attrs) ?>
45 |
46 |
47 | = $image($element, $props['image']) ?>
48 |
49 |
50 |
51 | = $title($element, $props['title']) ?>
52 |
53 |
54 |
55 | = $content($element, $props['content']) ?>
56 |
57 |
58 |
59 | = $link($element, $element['link_text']) ?>
60 |
61 |
62 | = $el->end() ?>
63 |
--------------------------------------------------------------------------------
/vendor/composer/installed.json:
--------------------------------------------------------------------------------
1 | {
2 | "packages": [
3 | {
4 | "name": "yootheme/starter-utils",
5 | "version": "1.0.4",
6 | "version_normalized": "1.0.4.0",
7 | "source": {
8 | "type": "git",
9 | "url": "https://github.com/yootheme/starter-utils.git",
10 | "reference": "7d2385d398fa3a7af8164dcda25a31e69cd298d5"
11 | },
12 | "dist": {
13 | "type": "zip",
14 | "url": "https://api.github.com/repos/yootheme/starter-utils/zipball/7d2385d398fa3a7af8164dcda25a31e69cd298d5",
15 | "reference": "7d2385d398fa3a7af8164dcda25a31e69cd298d5",
16 | "shasum": ""
17 | },
18 | "require": {
19 | "php": "^8.0"
20 | },
21 | "require-dev": {
22 | "composer/composer": "^2.7",
23 | "phpstan/phpstan": "^1.11"
24 | },
25 | "time": "2024-09-03T16:47:27+00:00",
26 | "type": "library",
27 | "installation-source": "dist",
28 | "autoload": {
29 | "psr-4": {
30 | "YOOtheme\\Starter\\": "src"
31 | }
32 | },
33 | "notification-url": "https://packagist.org/downloads/",
34 | "license": [
35 | "MIT"
36 | ],
37 | "description": "YOOtheme Pro - Starter Utilities",
38 | "homepage": "https://yootheme.com",
39 | "keywords": [
40 | "joomla",
41 | "wordpress",
42 | "yootheme"
43 | ],
44 | "support": {
45 | "issues": "https://github.com/yootheme/starter-utils/issues",
46 | "source": "https://github.com/yootheme/starter-utils"
47 | },
48 | "install-path": "../yootheme/starter-utils"
49 | }
50 | ],
51 | "dev": true,
52 | "dev-package-names": [
53 | "yootheme/starter-utils"
54 | ]
55 | }
56 |
--------------------------------------------------------------------------------
/composer.lock:
--------------------------------------------------------------------------------
1 | {
2 | "_readme": [
3 | "This file locks the dependencies of your project to a known state",
4 | "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
5 | "This file is @generated automatically"
6 | ],
7 | "content-hash": "b954339d110cc4773e95741258d341ad",
8 | "packages": [],
9 | "packages-dev": [
10 | {
11 | "name": "yootheme/starter-utils",
12 | "version": "1.0.4",
13 | "source": {
14 | "type": "git",
15 | "url": "https://github.com/yootheme/starter-utils.git",
16 | "reference": "7d2385d398fa3a7af8164dcda25a31e69cd298d5"
17 | },
18 | "dist": {
19 | "type": "zip",
20 | "url": "https://api.github.com/repos/yootheme/starter-utils/zipball/7d2385d398fa3a7af8164dcda25a31e69cd298d5",
21 | "reference": "7d2385d398fa3a7af8164dcda25a31e69cd298d5",
22 | "shasum": ""
23 | },
24 | "require": {
25 | "php": "^8.0"
26 | },
27 | "require-dev": {
28 | "composer/composer": "^2.7",
29 | "phpstan/phpstan": "^1.11"
30 | },
31 | "type": "library",
32 | "autoload": {
33 | "psr-4": {
34 | "YOOtheme\\Starter\\": "src"
35 | }
36 | },
37 | "notification-url": "https://packagist.org/downloads/",
38 | "license": [
39 | "MIT"
40 | ],
41 | "description": "YOOtheme Pro - Starter Utilities",
42 | "homepage": "https://yootheme.com",
43 | "keywords": [
44 | "joomla",
45 | "wordpress",
46 | "yootheme"
47 | ],
48 | "support": {
49 | "issues": "https://github.com/yootheme/starter-utils/issues",
50 | "source": "https://github.com/yootheme/starter-utils"
51 | },
52 | "time": "2024-09-03T16:47:27+00:00"
53 | }
54 | ],
55 | "aliases": [],
56 | "minimum-stability": "stable",
57 | "stability-flags": [],
58 | "prefer-stable": false,
59 | "prefer-lowest": false,
60 | "platform": {
61 | "php": "^8.0"
62 | },
63 | "platform-dev": [],
64 | "plugin-api-version": "2.6.0"
65 | }
66 |
--------------------------------------------------------------------------------
/vendor/yootheme/starter-utils/src/stubs/multiple-element_item/element.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "{{ NAME }}_item",
3 | "title": "Item",
4 | "width": 500,
5 | "templates": {
6 | "render": "./templates/template.php",
7 | "content": "./templates/content.php"
8 | },
9 | "placeholder": {
10 | "props": {
11 | "title": "Title",
12 | "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.",
13 | "image": ""
14 | }
15 | },
16 | "fields": {
17 | "title": {
18 | "label": "Title",
19 | "source": true
20 | },
21 | "content": {
22 | "label": "Content",
23 | "type": "editor",
24 | "source": true
25 | },
26 | "image": {
27 | "label": "Image",
28 | "type": "image",
29 | "source": true
30 | },
31 | "image_alt": {
32 | "label": "Image Alt",
33 | "enable": "image",
34 | "source": true
35 | },
36 | "link": {
37 | "label": "Link",
38 | "type": "link",
39 | "description": "Enter or pick a link, an image or a video file.",
40 | "attrs": {
41 | "placeholder": "http://"
42 | },
43 | "source": true
44 | },
45 | "image_focal_point": {
46 | "label": "Focal Point",
47 | "description": "Set a focal point to adjust the image focus when cropping.",
48 | "type": "select",
49 | "options": {
50 | "Top Left": "top-left",
51 | "Top Center": "top-center",
52 | "Top Right": "top-right",
53 | "Center Left": "center-left",
54 | "Center Center": "",
55 | "Bottom Left": "bottom-left",
56 | "Bottom Center": "bottom-center",
57 | "Bottom Right": "bottom-right"
58 | },
59 | "source": true,
60 | "enable": "image"
61 | },
62 | "status": "${builder.statusItem}",
63 | "source": "${builder.source}"
64 | },
65 | "fieldset": {
66 | "default": {
67 | "type": "tabs",
68 | "fields": [
69 | {
70 | "title": "Content",
71 | "fields": ["title", "content", "image", "image_alt", "link"]
72 | },
73 | {
74 | "title": "Settings",
75 | "fields": [
76 | {
77 | "label": "Image",
78 | "type": "group",
79 | "fields": ["image_focal_point"]
80 | }
81 | ]
82 | },
83 | "${builder.advancedItem}"
84 | ]
85 | }
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/vendor/yootheme/starter-utils/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ## [1.0.4](https://github.com/yootheme/starter-utils/compare/1.0.3...1.0.4) (2024-09-03)
2 |
3 |
4 | ### Bug Fixes
5 |
6 | * lowercase node names and duplicates in update.xml ([508f4e6](https://github.com/yootheme/starter-utils/commit/508f4e6705805da068c7031429e8cc33b0a341f8))
7 |
8 |
9 | ### Features
10 |
11 | * add wordpress update command ([8d23351](https://github.com/yootheme/starter-utils/commit/8d2335124a54df97d0ec90e94d72f8f737d5de5f))
12 | * build task creates plugin update files ([b1014a5](https://github.com/yootheme/starter-utils/commit/b1014a5681cf0f624f5dda0fc4e5e5a179749228))
13 |
14 |
15 |
16 | ## [1.0.3](https://github.com/yootheme/starter-utils/compare/1.0.2...1.0.3) (2024-08-30)
17 |
18 |
19 | ### Bug Fixes
20 |
21 | * generating file hashes ([3b17e76](https://github.com/yootheme/starter-utils/commit/3b17e764910fdbf5a02c12ba39115f86f5b8e084))
22 |
23 |
24 |
25 | ## [1.0.2](https://github.com/yootheme/starter-utils/compare/1.0.1...1.0.2) (2024-08-30)
26 |
27 |
28 | ### Features
29 |
30 | * add create update xml command ([fc013f7](https://github.com/yootheme/starter-utils/commit/fc013f77241f144755ef46d40c0bf61ab1fea2df))
31 |
32 |
33 |
34 | # [1.0.0](https://github.com/yootheme/starter-utils/compare/497aa24b246fb9f0f867768094e8945dd55590e8...1.0.0) (2024-08-20)
35 |
36 | ### Bug Fixes
37 |
38 | - element path ([c1cf045](https://github.com/yootheme/starter-utils/commit/c1cf045e5f60a317feb1b4d3b9589c9eac260481))
39 | - php include replacements ([d75d321](https://github.com/yootheme/starter-utils/commit/d75d3213f0bcd156a8a1588bc3a4f91f173e7779))
40 | - syntax error ([20a410f](https://github.com/yootheme/starter-utils/commit/20a410f7609fdb3fd81f08d56bccdaa1fd205f64))
41 |
42 | ### Features
43 |
44 | - add create module command ([f2b34a3](https://github.com/yootheme/starter-utils/commit/f2b34a355a5fd47f101d617a04d7fb4e37aed3e0))
45 | - add create plugin command ([4e39933](https://github.com/yootheme/starter-utils/commit/4e3993354f200b6ea418a6068f3bb43f7c4bbebc))
46 | - add create:element command ([497aa24](https://github.com/yootheme/starter-utils/commit/497aa24b246fb9f0f867768094e8945dd55590e8))
47 | - add custom LESS example in create module command ([553640d](https://github.com/yootheme/starter-utils/commit/553640d47b573e74bdab7dd387d287a94eb08979))
48 | - add custom source example in create module command ([5de877d](https://github.com/yootheme/starter-utils/commit/5de877d1f238843b3b388ed6d75e9563a2d030f9))
49 | - add multiple-items element to create element command ([e39ffda](https://github.com/yootheme/starter-utils/commit/e39ffdab7cf0e8b30ff62100e8ae89c85e188187))
50 | - add remove task ([7445b43](https://github.com/yootheme/starter-utils/commit/7445b4387f9bbe43c889de4443d9842e7e566e96))
51 | - add task helpers ([46431d5](https://github.com/yootheme/starter-utils/commit/46431d5ec78c64c96076d3da110a39807b98674e))
52 | - ask for module namespace in createModuleCommand ([bcc9b97](https://github.com/yootheme/starter-utils/commit/bcc9b97105141b9eb22289883c64d2445766469d))
53 | - test minimum composer version ([5b638a8](https://github.com/yootheme/starter-utils/commit/5b638a8d7166b9c3296da002e6f4b04f5ec57337))
54 |
--------------------------------------------------------------------------------
/vendor/yootheme/starter-utils/src/CreatePluginCommand.php:
--------------------------------------------------------------------------------
1 | addArgument('name', InputArgument::OPTIONAL, default: basename(getcwd()));
28 | }
29 |
30 | protected function execute(InputInterface $input, OutputInterface $output): int
31 | {
32 | $fs = new Filesystem();
33 | $cwd = getcwd();
34 |
35 | $name = strtr($input->getArgument('name'), ['-' => '_', ' ' => '_']);
36 |
37 | $fn = [$this->getHelper('question'), 'ask'];
38 | $ask = $this->partial($fn, $input, $output);
39 | $finder = (new Finder())
40 | ->in("{$this->stubs}/plugin")
41 | ->ignoreDotFiles(false);
42 |
43 | $filemap = [
44 | '/env' => '/.env',
45 | '/plugin.xml' => "/{$name}.xml",
46 | '/plugin.stub' => "/{$name}.php",
47 | ];
48 |
49 | $variables = [
50 | 'NAME' => $name,
51 | 'PLUGIN' => $name,
52 | 'PLUGIN_CLASS' => 'plgSystem' . ucfirst(strtr($name, ['-' => '', '_' => ''])),
53 | 'TITLE' => $ask(new Question('Enter plugin title: ', $name)),
54 | ];
55 |
56 | $questions = $variables + [
57 | 'DESCRIPTION' => $ask(new Question('Enter plugin description: ', '')),
58 | 'AUTHOR' => $ask(new Question('Enter author name: ', '')),
59 | 'AUTHOREMAIL' => $ask(new Question('Enter author email: ', '')),
60 | 'AUTHORURL' => $ask(new Question('Enter author url: ', '')),
61 | 'UPDATEURI' => $ask(new Question('Enter update server url: ', '')),
62 | ];
63 |
64 | $variables['UPDATEHOST'] = parse_url($questions['UPDATEURI'], PHP_URL_HOST);
65 |
66 | foreach ($finder->files() as $file) {
67 | $fs->dumpFile(
68 | strtr("{$cwd}/{$file->getRelativePathname()}", $filemap),
69 | Str::placeholder(
70 | $file->getContents(),
71 | in_array($file->getBasename(), ['Taskfile.yml', '.env'])
72 | ? $questions
73 | : $variables,
74 | ),
75 | );
76 | }
77 |
78 | $output->writeln("Plugin '{$name}' created successfully.");
79 |
80 | return Command::SUCCESS;
81 | }
82 |
83 | protected function partial(callable $func, ...$args): callable
84 | {
85 | return fn(...$rest) => $func(...$args, ...$rest);
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/vendor/yootheme/starter-utils/src/CreateElementCommand.php:
--------------------------------------------------------------------------------
1 | addArgument('name', InputArgument::REQUIRED);
26 | $this->addArgument('module', InputArgument::OPTIONAL);
27 | }
28 |
29 | protected function execute(InputInterface $input, OutputInterface $output): int
30 | {
31 | $fs = new Filesystem();
32 | $cwd = getcwd();
33 |
34 | $fn = [$this->getHelper('question'), 'ask'];
35 | $ask = $this->partial($fn, $input, $output);
36 |
37 | $name = $input->getArgument('name');
38 | if ($module = $input->getArgument('module')) {
39 | $module = "modules/$module";
40 | } else {
41 | if ($modules = glob(Path::join($cwd, 'modules', '*'), GLOB_ONLYDIR)) {
42 | $module = $ask(
43 | new ChoiceQuestion(
44 | 'Select module: (defaults to first)',
45 | array_map(fn($module) => basename($module), $modules),
46 | 0,
47 | ),
48 | );
49 | } else {
50 | throw new \RuntimeException(
51 | 'Create a module first with command `composer create:module`',
52 | );
53 | }
54 |
55 | $module = "modules/$module";
56 | }
57 |
58 | $finders = [
59 | $name => (new Finder())->in("{$this->stubs}/single-element"),
60 | ];
61 |
62 | if ($ask(new ConfirmationQuestion('Create multiple items element? [y/N] ', false))) {
63 | $finders = [
64 | $name => (new Finder())->in("{$this->stubs}/multiple-element"),
65 | "{$name}_item" => (new Finder())->in("{$this->stubs}/multiple-element_item"),
66 | ];
67 | }
68 |
69 | $variables = [
70 | 'NAME' => $name,
71 | 'TITLE' => $ask(new Question('Enter element title: ', $name)),
72 | ];
73 |
74 | foreach ($finders as $name => $finder) {
75 | $path = Path::join($cwd, $module, 'elements', $name);
76 |
77 | if (file_exists($path)) {
78 | throw new \RuntimeException("Element '{$path}' already exists");
79 | }
80 |
81 | foreach ($finder->files() as $file) {
82 | $fs->dumpFile(
83 | "{$path}/{$file->getRelativePathname()}",
84 | Str::placeholder($file->getContents(), $variables),
85 | );
86 | }
87 | }
88 |
89 | $output->writeln('Element created successfully.');
90 |
91 | return Command::SUCCESS;
92 | }
93 |
94 | protected function partial(callable $func, ...$args): callable
95 | {
96 | return fn(...$rest) => $func(...$args, ...$rest);
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/vendor/yootheme/starter-utils/src/CreateJoomlaUpdateCommand.php:
--------------------------------------------------------------------------------
1 | writeln('Could not find Joomla package in dist folder.');
22 |
23 | return Command::FAILURE;
24 | }
25 |
26 | $metadata = $this->getMetadata($files);
27 |
28 | $xml = dom_import_simplexml($this->toXML($metadata))->ownerDocument;
29 | $xml->formatOutput = true;
30 |
31 | $fs = new Filesystem();
32 | $fs->dumpFile(Path::join(getcwd(), 'dist', 'update.xml'), $xml->saveXML());
33 |
34 | return Command::SUCCESS;
35 | }
36 |
37 | protected function getMetadata($files)
38 | {
39 | $metadata = parse_ini_file(getcwd() . '/.env');
40 |
41 | $file = array_values(
42 | array_filter($files, function ($file) use ($metadata) {
43 | return preg_match("/-j-{$metadata['VERSION']}/", $file);
44 | }),
45 | )[0];
46 |
47 | $metadata['SHA256'] = hash_file('sha256', $file);
48 | $metadata['SHA384'] = hash_file('sha384', $file);
49 | $metadata['SHA512'] = hash_file('sha512', $file);
50 |
51 | return $metadata;
52 | }
53 |
54 | protected function toXML($metadata)
55 | {
56 | $xml = new \SimpleXMLElement('');
57 |
58 | $xmlUpdate = $xml->addChild('update');
59 |
60 | $keys = [
61 | 'NAME',
62 | 'DESCRIPTION',
63 | 'ELEMENT',
64 | 'TYPE',
65 | 'VERSION',
66 | 'DOWNLOADURL',
67 | 'STABILITY',
68 | 'SHA256',
69 | 'SHA384',
70 | 'SHA512',
71 | 'MAINTAINER',
72 | 'MAINTAINERURL',
73 | 'JOOMLAMINIMUM',
74 | 'PHP_MINIMUM',
75 | ];
76 |
77 | foreach ($keys as $key) {
78 | if ('ELEMENT' == $key) {
79 | $xmlUpdate->addChild('element', $metadata['NAME']);
80 | } elseif ('DOWNLOADURL' == $key) {
81 | $downloads = $xmlUpdate->addChild('downloads');
82 | $download = $downloads->addChild(
83 | 'downloadurl',
84 | htmlentities(
85 | "{$metadata['DOWNLOADURL']}/{$metadata['NAME']}-j-{$metadata['VERSION']}.zip",
86 | ),
87 | );
88 | $download->addAttribute('type', 'full');
89 | $download->addAttribute('format', 'zip');
90 | } elseif ('MAINTAINER' == $key) {
91 | $xmlUpdate->addChild('maintainer', $metadata['AUTHOR']);
92 | $xmlUpdate->addChild('maintainerurl', $metadata['AUTHORURL']);
93 | } elseif ('JOOMLAMINIMUM' == $key) {
94 | $xmlChild = $xmlUpdate->addChild('targetplatform');
95 | $xmlChild->addAttribute('name', 'joomla');
96 | $xmlChild->addAttribute('version', $metadata['JOOMLAMINIMUM']);
97 | } elseif (!is_null($value = $metadata[$key] ?? null)) {
98 | $xmlUpdate->addChild(strtolower($key), $value);
99 | }
100 | }
101 |
102 | return $xml;
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/vendor/yootheme/starter-utils/src/stubs/module/assets/less/my-component.less:
--------------------------------------------------------------------------------
1 | // Name: My Component
2 | // Description: This is my custom component
3 | //
4 | // Component: `my-component`
5 | //
6 | // Sub-objects: `my-component-title`
7 | // `my-component-card`
8 | //
9 | // ========================================================================
10 |
11 |
12 | // Variables
13 | // ========================================================================
14 |
15 | @my-component-title-margin: 40px;
16 |
17 | @my-component-title-color: #ddd;
18 |
19 | @my-component-title-font-family: @global-primary-font-family;
20 | @my-component-title-font-weight: @global-primary-font-weight;
21 | @my-component-title-text-transform: @global-primary-text-transform;
22 | @my-component-title-letter-spacing: @global-primary-letter-spacing;
23 | @my-component-title-font-style: @global-primary-font-style;
24 |
25 | @my-component-title-text-shadow: none;
26 |
27 | @my-component-card-background: @global-primary-background;
28 |
29 | @my-component-card-box-shadow: none;
30 |
31 | @my-component-card-border-mode: ~'';
32 | @my-component-card-border-width: 0;
33 | @my-component-card-border: transparent;
34 | @my-component-card-border-radius: 0;
35 |
36 | @internal-my-component-card-gradient: ~'';
37 |
38 |
39 | /* ========================================================================
40 | Component: My Component
41 | ========================================================================== */
42 |
43 | .my-component-title {
44 | margin-top: @my-component-title-margin;
45 | .hook-my-component-title();
46 | }
47 |
48 | .my-component-card {
49 | background-color: @my-component-card-background;
50 | .hook-my-component-card();
51 | }
52 |
53 | //
54 | // Following properties will only be set if they differ from their default value
55 | //
56 |
57 | // Color
58 | .hook-my-component-title() when not (@my-component-title-color = transparent) {
59 | color: @my-component-title-color;
60 | }
61 |
62 | // Typography
63 | .hook-my-component-title() when not (@my-component-title-font-family = inherit) {
64 | font-family: @my-component-title-font-family;
65 | }
66 |
67 | .hook-my-component-title() when not (@my-component-title-font-weight = inherit) {
68 | font-weight: @my-component-title-font-weight;
69 | }
70 |
71 | .hook-my-component-title() when not (@my-component-title-text-transform = inherit) {
72 | text-transform: @my-component-title-text-transform;
73 | }
74 |
75 | .hook-my-component-title() when not (@my-component-title-letter-spacing = inherit) {
76 | letter-spacing: @my-component-title-letter-spacing;
77 | }
78 |
79 | .hook-my-component-title() when not (@my-component-title-font-style = inherit) {
80 | font-style: @my-component-title-font-style;
81 | }
82 |
83 | // Shadows
84 | .hook-my-component-title() when not (@my-component-title-text-shadow = none) {
85 | text-shadow: @my-component-title-text-shadow;
86 | }
87 |
88 | .hook-my-component-card() when not (@my-component-card-box-shadow = none) {
89 | box-shadow: @my-component-card-box-shadow;
90 | }
91 |
92 | // Border
93 | .hook-my-component-card() when not (@my-component-card-border-width = 0) {
94 | border@{my-component-card-border-mode}: @my-component-card-border-width solid @my-component-card-border;
95 | }
96 |
97 | .hook-my-component-card() when not (@my-component-card-border-radius = 0) {
98 | border-radius: @my-component-card-border-radius;
99 | }
100 |
101 | // Background Gradient
102 | // Mind that variables prefixed with `internal` will not show up in the style customizer.
103 |
104 | .hook-my-component-card() when not (@internal-my-component-card-gradient = ~'') {
105 | background-image: @internal-my-component-card-gradient;
106 | }
107 |
--------------------------------------------------------------------------------
/Taskfile.yml:
--------------------------------------------------------------------------------
1 | version: '3'
2 |
3 | includes:
4 | utils: vendor/yootheme/starter-utils
5 |
6 | dotenv: ['.env']
7 |
8 | tasks:
9 | build:
10 | deps:
11 | - for: [joomla, wordpress]
12 | task: build-{{.ITEM}}
13 |
14 | build-joomla:
15 | cmds:
16 | - task: utils:copy
17 | vars:
18 | cwd: build/joomla
19 | src: '**'
20 | ignore: update.xml
21 | dest: dist/joomla
22 |
23 | - task: copy-module-joomla
24 |
25 | - task: placeholder-joomla
26 |
27 | - task: utils:zip
28 | vars:
29 | cwd: dist/joomla
30 | src: '**'
31 | dest: dist/{{.NAME}}-j-{{.VERSION}}.zip
32 |
33 | - task: joomlaUpdate
34 |
35 | - defer:
36 | task: clear-dist-joomla
37 |
38 | build-wordpress:
39 | cmds:
40 | - task: utils:copy
41 | vars:
42 | cwd: build/wordpress
43 | src: '*.php'
44 | dest: dist/wordpress/{{.NAME}}
45 |
46 | - task: copy-module-wordpress
47 |
48 | - task: placeholder-wordpress
49 |
50 | - task: utils:zip
51 | vars:
52 | cwd: dist/wordpress
53 | src: '**'
54 | dest: dist/{{.NAME}}-wp-{{.VERSION}}.zip
55 |
56 | - task: wordpressUpdate
57 |
58 | - defer:
59 | task: clear-dist-wordpress
60 |
61 | copy-module-joomla:
62 | internal: true
63 | cmds:
64 | - task: utils:copy
65 | vars:
66 | src: modules/**
67 | dest: dist/joomla
68 | ignore: modules/*wordpress*/**
69 |
70 | copy-module-wordpress:
71 | internal: true
72 | cmds:
73 | - task: utils:copy
74 | vars:
75 | src: modules/**
76 | dest: dist/wordpress
77 | ignore: modules/*joomla*/**
78 |
79 | placeholder-joomla:
80 | internal: true
81 | cmds:
82 | - task: utils:placeholder
83 | vars:
84 | src: 'dist/joomla/**/*.xml'
85 | replace:
86 | ref: >
87 | dict
88 | "AUTHOR" "{{.AUTHOR}}"
89 | "AUTHOREMAIL" "{{.AUTHOREMAIL}}"
90 | "AUTHORURL" "{{.AUTHORURL}}"
91 | "COPYRIGHT" "{{.COPYRIGHT}}"
92 | "DATE" "{{.DATE}}"
93 | "DESCRIPTION" "{{.DESCRIPTION}}"
94 | "LICENSE" "{{.LICENSE}}"
95 | "NAME" "{{.NAME}}"
96 | "VERSION" "{{.VERSION}}"
97 | "UPDATEURI" "{{.UPDATEURI}}"
98 |
99 | placeholder-wordpress:
100 | internal: true
101 | cmds:
102 | - task: utils:placeholder
103 | vars:
104 | src: dist/wordpress/{{.NAME}}/{{.NAME}}.php
105 | replace:
106 | ref: >
107 | dict
108 | "AUTHOR" "{{.AUTHOR}}"
109 | "AUTHOREMAIL" "{{.AUTHOREMAIL}}"
110 | "AUTHORURL" "{{.AUTHORURL}}"
111 | "COPYRIGHT" "{{.COPYRIGHT}}"
112 | "DATE" "{{.DATE}}"
113 | "DESCRIPTION" "{{.DESCRIPTION}}"
114 | "LICENSE" "{{.LICENSE}}"
115 | "NAME" "{{.NAME}}"
116 | "VERSION" "{{.VERSION}}"
117 | "PHPMINIMUM" "{{.PHPMINIMUM}}"
118 | "WORDPRESSMINIMUM" "{{.WORDPRESSMINIMUM}}"
119 | "UPDATEURI" "{{.UPDATEURI}}"
120 | "UPDATEHOST" "{{.UPDATEHOST}}"
121 |
122 | joomlaUpdate:
123 | cmds:
124 | - composer create:joomlaUpdate
125 |
126 | wordpressUpdate:
127 | cmds:
128 | - composer create:wordpressUpdate
129 |
130 | clear-dist-joomla:
131 | internal: true
132 | cmds:
133 | - task: utils:remove
134 | vars:
135 | src: dist/joomla
136 |
137 | clear-dist-wordpress:
138 | internal: true
139 | cmds:
140 | - task: utils:remove
141 | vars:
142 | src: dist/wordpress
143 |
144 | setup-joomla:
145 | cmds:
146 | - task: utils:copy
147 | vars:
148 | cwd: build/joomla
149 | src: '**'
150 | ignore: update.xml
151 | dest: dist/joomla
152 |
153 | - task: placeholder-joomla
154 |
155 | - task: utils:copy
156 | vars:
157 | cwd: dist/joomla
158 | src: '**'
159 | dest: ./
160 |
161 | - defer:
162 | task: clear-dist-joomla
163 |
164 | setup-wordpress:
165 | cmds:
166 | - task: utils:copy
167 | vars:
168 | cwd: build/wordpress
169 | src: '*.php'
170 | dest: dist/wordpress
171 |
172 | - task: placeholder-wordpress
173 |
174 | - task: utils:copy
175 | vars:
176 | cwd: dist/wordpress
177 | src: '**'
178 | dest: ./
179 |
180 | - defer:
181 | task: clear-dist-wordpress
182 |
--------------------------------------------------------------------------------
/vendor/yootheme/starter-utils/src/stubs/single-element/element.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "{{ NAME }}",
3 | "title": "{{ TITLE }}",
4 | "icon": "${url:images/icon.svg}",
5 | "iconSmall": "${url:images/iconSmall.svg}",
6 | "element": true,
7 | "width": 500,
8 | "defaults": {},
9 | "templates": {
10 | "render": "./templates/template.php",
11 | "content": "./templates/content.php"
12 | },
13 | "placeholder": {
14 | "props": {
15 | "title": "",
16 | "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat."
17 | }
18 | },
19 | "fields": {
20 | "title": {
21 | "label": "Title",
22 | "source": true
23 | },
24 | "content": {
25 | "label": "Content",
26 | "type": "editor",
27 | "source": true
28 | },
29 | "position": "${builder.position}",
30 | "position_left": "${builder.position_left}",
31 | "position_right": "${builder.position_right}",
32 | "position_top": "${builder.position_top}",
33 | "position_bottom": "${builder.position_bottom}",
34 | "position_z_index": "${builder.position_z_index}",
35 | "margin": "${builder.margin}",
36 | "margin_remove_top": "${builder.margin_remove_top}",
37 | "margin_remove_bottom": "${builder.margin_remove_bottom}",
38 | "maxwidth": "${builder.maxwidth}",
39 | "maxwidth_breakpoint": "${builder.maxwidth_breakpoint}",
40 | "block_align": "${builder.block_align}",
41 | "block_align_breakpoint": "${builder.block_align_breakpoint}",
42 | "block_align_fallback": "${builder.block_align_fallback}",
43 | "text_align": "${builder.text_align_justify}",
44 | "text_align_breakpoint": "${builder.text_align_breakpoint}",
45 | "text_align_fallback": "${builder.text_align_justify_fallback}",
46 | "animation": "${builder.animation}",
47 | "_parallax_button": "${builder._parallax_button}",
48 | "visibility": "${builder.visibility}",
49 | "name": "${builder.name}",
50 | "status": "${builder.status}",
51 | "id": "${builder.id}",
52 | "class": "${builder.cls}",
53 | "attributes": "${builder.attrs}",
54 | "css": {
55 | "label": "CSS",
56 | "description": "Enter your own custom CSS. The following selectors will be prefixed automatically for this element: .el-element, .el-item, .el-title, .el-content, .el-image, .el-link",
57 | "type": "editor",
58 | "editor": "code",
59 | "mode": "css",
60 | "attrs": {
61 | "debounce": 500
62 | }
63 | }
64 | },
65 | "fieldset": {
66 | "default": {
67 | "type": "tabs",
68 | "fields": [
69 | {
70 | "title": "Content",
71 | "fields": ["title", "content"]
72 | },
73 | {
74 | "title": "Settings",
75 | "fields": [
76 | {
77 | "label": "General",
78 | "type": "group",
79 | "fields": [
80 | "position",
81 | "position_left",
82 | "position_right",
83 | "position_top",
84 | "position_bottom",
85 | "position_z_index",
86 | "margin",
87 | "margin_remove_top",
88 | "margin_remove_bottom",
89 | "maxwidth",
90 | "maxwidth_breakpoint",
91 | "block_align",
92 | "block_align_breakpoint",
93 | "block_align_fallback",
94 | "text_align",
95 | "text_align_breakpoint",
96 | "text_align_fallback",
97 | "animation",
98 | "_parallax_button",
99 | "visibility"
100 | ]
101 | }
102 | ]
103 | },
104 | "${builder.advanced}"
105 | ]
106 | }
107 | }
108 | }
109 |
--------------------------------------------------------------------------------
/vendor/yootheme/starter-utils/src/stubs/plugin/Taskfile.yml:
--------------------------------------------------------------------------------
1 | version: '3'
2 |
3 | includes:
4 | utils: vendor/yootheme/starter-utils
5 |
6 | dotenv: ['.env']
7 |
8 | tasks:
9 | build:
10 | deps:
11 | - for: [joomla, wordpress]
12 | task: build-{{.ITEM}}
13 |
14 | build-joomla:
15 | cmds:
16 | - task: utils:copy
17 | vars:
18 | cwd: build/joomla
19 | src: '**'
20 | ignore: update.xml
21 | dest: dist/joomla
22 |
23 | - task: copy-module-joomla
24 |
25 | - task: placeholder-joomla
26 |
27 | - task: utils:zip
28 | vars:
29 | cwd: dist/joomla
30 | src: '**'
31 | dest: dist/{{.NAME}}-j-{{.VERSION}}.zip
32 |
33 | - task: joomlaUpdate
34 |
35 | - defer:
36 | task: clear-dist-joomla
37 |
38 | build-wordpress:
39 | cmds:
40 | - task: utils:copy
41 | vars:
42 | cwd: build/wordpress
43 | src: '*.php'
44 | dest: dist/wordpress/{{.NAME}}
45 |
46 | - task: copy-module-wordpress
47 |
48 | - task: placeholder-wordpress
49 |
50 | - task: utils:zip
51 | vars:
52 | cwd: dist/wordpress
53 | src: '**'
54 | dest: dist/{{.NAME}}-wp-{{.VERSION}}.zip
55 |
56 | - task: wordpressUpdate
57 |
58 | - defer:
59 | task: clear-dist-wordpress
60 |
61 | copy-module-joomla:
62 | internal: true
63 | cmds:
64 | - task: utils:copy
65 | vars:
66 | src: modules/**
67 | dest: dist/joomla
68 | ignore: modules/*wordpress*/**
69 |
70 | copy-module-wordpress:
71 | internal: true
72 | cmds:
73 | - task: utils:copy
74 | vars:
75 | src: modules/**
76 | dest: dist/wordpress
77 | ignore: modules/*joomla*/**
78 |
79 | placeholder-joomla:
80 | internal: true
81 | cmds:
82 | - task: utils:placeholder
83 | vars:
84 | src: 'dist/joomla/**/*.xml'
85 | replace:
86 | ref: >
87 | dict
88 | "AUTHOR" "{{.AUTHOR}}"
89 | "AUTHOREMAIL" "{{.AUTHOREMAIL}}"
90 | "AUTHORURL" "{{.AUTHORURL}}"
91 | "COPYRIGHT" "{{.COPYRIGHT}}"
92 | "DATE" "{{.DATE}}"
93 | "DESCRIPTION" "{{.DESCRIPTION}}"
94 | "LICENSE" "{{.LICENSE}}"
95 | "NAME" "{{.NAME}}"
96 | "VERSION" "{{.VERSION}}"
97 | "UPDATEURI" "{{.UPDATEURI}}"
98 |
99 | placeholder-wordpress:
100 | internal: true
101 | cmds:
102 | - task: utils:placeholder
103 | vars:
104 | src: dist/wordpress/{{.NAME}}/{{.NAME}}.php
105 | replace:
106 | ref: >
107 | dict
108 | "AUTHOR" "{{.AUTHOR}}"
109 | "AUTHOREMAIL" "{{.AUTHOREMAIL}}"
110 | "AUTHORURL" "{{.AUTHORURL}}"
111 | "COPYRIGHT" "{{.COPYRIGHT}}"
112 | "DATE" "{{.DATE}}"
113 | "DESCRIPTION" "{{.DESCRIPTION}}"
114 | "LICENSE" "{{.LICENSE}}"
115 | "NAME" "{{.NAME}}"
116 | "VERSION" "{{.VERSION}}"
117 | "PHPMINIMUM" "{{.PHPMINIMUM}}"
118 | "WORDPRESSMINIMUM" "{{.WORDPRESSMINIMUM}}"
119 | "UPDATEURI" "{{.UPDATEURI}}"
120 | "UPDATEHOST" "{{.UPDATEHOST}}"
121 |
122 | joomlaUpdate:
123 | cmds:
124 | - composer create:joomlaUpdate
125 |
126 | wordpressUpdate:
127 | cmds:
128 | - composer create:wordpressUpdate
129 |
130 | clear-dist-joomla:
131 | internal: true
132 | cmds:
133 | - task: utils:remove
134 | vars:
135 | src: dist/joomla
136 |
137 | clear-dist-wordpress:
138 | internal: true
139 | cmds:
140 | - task: utils:remove
141 | vars:
142 | src: dist/wordpress
143 |
144 | setup-joomla:
145 | cmds:
146 | - task: utils:copy
147 | vars:
148 | cwd: build/joomla
149 | src: '**'
150 | ignore: update.xml
151 | dest: dist/joomla
152 |
153 | - task: placeholder-joomla
154 |
155 | - task: utils:copy
156 | vars:
157 | cwd: dist/joomla
158 | src: '**'
159 | dest: ./
160 |
161 | - defer:
162 | task: clear-dist-joomla
163 |
164 | setup-wordpress:
165 | cmds:
166 | - task: utils:copy
167 | vars:
168 | cwd: build/wordpress
169 | src: '*.php'
170 | dest: dist/wordpress
171 |
172 | - task: placeholder-wordpress
173 |
174 | - task: utils:copy
175 | vars:
176 | cwd: dist/wordpress
177 | src: '**'
178 | dest: ./
179 |
180 | - defer:
181 | task: clear-dist-wordpress
182 |
--------------------------------------------------------------------------------
/vendor/yootheme/starter-utils/src/TaskHelper.php:
--------------------------------------------------------------------------------
1 | dir = $env['ROOT_DIR'] ?? '';
28 | $this->cwd = $env['TASK_CWD'] ?? '';
29 | }
30 |
31 | public function copy(string $src, string $dest, string $ignore = ''): void
32 | {
33 | $fs = new Filesystem();
34 | $files = self::glob($this->cwd, $src, $ignore);
35 | $count = count($files->files());
36 |
37 | foreach ($files as $file) {
38 | $to = self::resolvePath($dest, $file->getRelativePathname());
39 | $fs->copy($file->getPathname(), $to, true);
40 | }
41 |
42 | echo "Copied {$count} file" . ($count !== 1 ? 's' : '') . " to '{$dest}'\n";
43 | }
44 |
45 | public function remove(string $src, string $ignore = ''): void
46 | {
47 | $fs = new Filesystem();
48 | $files = self::glob($this->cwd, $src, $ignore);
49 | $count = [0, 0]; // [files, directories]
50 |
51 | foreach ([...$files->files(), ...$files->directories()] as $file) {
52 | $count[intval($file->isDir())]++;
53 | $fs->remove($file->getPathname());
54 | }
55 |
56 | echo "Removed {$count[0]} file" .
57 | ($count[0] !== 1 ? 's' : '') .
58 | ", {$count[1]} director" .
59 | ($count[1] === 1 ? 'y' : 'ies') .
60 | "\n";
61 | }
62 |
63 | public function placeholder(string $src, string $replace, string $ignore = ''): void
64 | {
65 | $fs = new Filesystem();
66 | $files = self::glob($this->cwd, $src, $ignore);
67 |
68 | foreach ($files->files() as $file) {
69 | $fs->dumpFile(
70 | $file->getPathname(),
71 | Str::placeholder($file->getContents(), json_decode($replace, true)),
72 | );
73 | }
74 | }
75 |
76 | public function zip(string $src, string $dest, string $ignore = ''): void
77 | {
78 | $zip = new ZipArchive();
79 | $files = self::glob($this->cwd, $src, $ignore);
80 | $count = count($files->files());
81 |
82 | if (!$zip->open($dest, ZipArchive::CREATE | ZipArchive::OVERWRITE)) {
83 | throw new \RuntimeException("Failed to create archive '{$dest}'");
84 | }
85 |
86 | foreach ($files as $file) {
87 | $name = $file->getRelativePathname();
88 | $zip->addFile($file->getPathname(), $name);
89 | $zip->setCompressionName($name, ZipArchive::CM_DEFLATE, 9);
90 | }
91 |
92 | $zip->close();
93 |
94 | echo "Created '{$dest}' ({$count} file" . ($count !== 1 ? 's' : '') . ")\n";
95 | }
96 |
97 | public static function run(Event $event): void
98 | {
99 | $args = $event->getArguments();
100 | $task = array_shift($args);
101 |
102 | if (!method_exists(self::class, $task)) {
103 | throw new \RuntimeException("Task '$task' not found");
104 | }
105 |
106 | call_user_func_array([new self($_SERVER), $task], $args);
107 | }
108 |
109 | protected static function glob(string $path, string $src, string $ignore = ''): Finder
110 | {
111 | $finder = Finder::create()->in(self::resolvePath($path));
112 |
113 | foreach (array_filter(explode(' ', $src)) as $glob) {
114 | $finder->path(self::toRegex($glob));
115 | }
116 |
117 | foreach (array_filter(explode(' ', $ignore)) as $glob) {
118 | $finder->notPath(self::toRegex($glob));
119 | }
120 |
121 | return $finder;
122 | }
123 |
124 | protected static function toRegex(string $path): string
125 | {
126 | $path = Path::canonicalize("/{$path}");
127 | $regex = Glob::toRegex($path, false);
128 |
129 | return str_replace('#^/', '#^', $regex);
130 | }
131 |
132 | protected static function resolvePath(string ...$paths): string
133 | {
134 | $parts = [];
135 |
136 | foreach (array_reverse([getcwd(), ...$paths]) as $path) {
137 | array_unshift($parts, $path);
138 |
139 | if (Path::isAbsolute($path)) {
140 | break;
141 | }
142 | }
143 |
144 | return ($result = Path::join(...$parts)) !== '/' ? rtrim($result, '/') : $result;
145 | }
146 | }
147 |
--------------------------------------------------------------------------------
/modules/yoocccreadingtime/elements/yoocccreadingtimeelement/element.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "yoocccreadingtimeelement",
3 | "title": "Reading Time",
4 | "group": "COOLCAT creations",
5 | "icon": "${url:images/icon.svg}",
6 | "iconSmall": "${url:images/iconSmall.svg}",
7 | "element": true,
8 | "width": 500,
9 | "defaults": {
10 | "type": "css"
11 | },
12 | "templates": {
13 | "render": "./templates/template.php",
14 | "content": "./templates/content.php"
15 | },
16 | "placeholder": {
17 | "props": {
18 | "title": "",
19 | "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat."
20 | }
21 | },
22 | "fields": {
23 | "type": {
24 | "label": "Type",
25 | "description": "How should the reading time be calculated?",
26 | "type": "select",
27 | "options": {
28 | "CSS Selector": "css",
29 | "Content": "content"
30 | },
31 | "source": true
32 | },
33 | "cssselector": {
34 | "label": "CSS Selector",
35 | "description": "Enter a CSS selector to target the element you want to display the reading time for. For example: .el-content",
36 | "show": "type =='css'",
37 | "source": true
38 | },
39 | "content": {
40 | "label": "Content",
41 | "type": "editor",
42 | "show": "type =='content'",
43 | "source": true
44 | },
45 | "position": "${builder.position}",
46 | "position_left": "${builder.position_left}",
47 | "position_right": "${builder.position_right}",
48 | "position_top": "${builder.position_top}",
49 | "position_bottom": "${builder.position_bottom}",
50 | "position_z_index": "${builder.position_z_index}",
51 | "margin": "${builder.margin}",
52 | "margin_remove_top": "${builder.margin_remove_top}",
53 | "margin_remove_bottom": "${builder.margin_remove_bottom}",
54 | "maxwidth": "${builder.maxwidth}",
55 | "maxwidth_breakpoint": "${builder.maxwidth_breakpoint}",
56 | "block_align": "${builder.block_align}",
57 | "block_align_breakpoint": "${builder.block_align_breakpoint}",
58 | "block_align_fallback": "${builder.block_align_fallback}",
59 | "text_align": "${builder.text_align_justify}",
60 | "text_align_breakpoint": "${builder.text_align_breakpoint}",
61 | "text_align_fallback": "${builder.text_align_justify_fallback}",
62 | "animation": "${builder.animation}",
63 | "_parallax_button": "${builder._parallax_button}",
64 | "visibility": "${builder.visibility}",
65 | "name": "${builder.name}",
66 | "status": "${builder.status}",
67 | "source": "${builder.source}",
68 | "id": "${builder.id}",
69 | "class": "${builder.cls}",
70 | "attributes": "${builder.attrs}",
71 | "css": {
72 | "label": "CSS",
73 | "description": "Enter your own custom CSS. The following selectors will be prefixed automatically for this element: .el-element, .el-item, .el-title, .el-content, .el-image, .el-link",
74 | "type": "editor",
75 | "editor": "code",
76 | "mode": "css",
77 | "attrs": {
78 | "debounce": 500
79 | }
80 | }
81 | },
82 | "fieldset": {
83 | "default": {
84 | "type": "tabs",
85 | "fields": [
86 | {
87 | "title": "Content",
88 | "fields": ["type", "cssselector", "content"]
89 | },
90 | {
91 | "title": "Settings",
92 | "fields": [
93 | {
94 | "label": "General",
95 | "type": "group",
96 | "fields": [
97 | "position",
98 | "position_left",
99 | "position_right",
100 | "position_top",
101 | "position_bottom",
102 | "position_z_index",
103 | "margin",
104 | "margin_remove_top",
105 | "margin_remove_bottom",
106 | "maxwidth",
107 | "maxwidth_breakpoint",
108 | "block_align",
109 | "block_align_breakpoint",
110 | "block_align_fallback",
111 | "text_align",
112 | "text_align_breakpoint",
113 | "text_align_fallback",
114 | "animation",
115 | "_parallax_button",
116 | "visibility"
117 | ]
118 | }
119 | ]
120 | },
121 | "${builder.advanced}"
122 | ]
123 | }
124 | }
125 | }
126 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Starter Plugin
2 |
3 | The YOOtheme starter kit provides a minimal and simple starting point for building your next [YOOtheme Pro](https://yootheme.com) extension. Easily create a module for YOOtheme Pro to extend its functionalities. For example, add setting panels to the customizer, elements to the page builder or load needed asset files into the site. Once the module is customized based on your application's needs, automatically build a Joomla plugin and WordPress plugin to distribute it to your customer project.
4 |
5 | ## Requirements
6 |
7 | Install [Composer v2.5+](https://getcomposer.org/download/), which is used to install PHP packages.
8 |
9 | Also, use Node and npm to install [Task](https://taskfile.dev/), which is needed to run build tasks.
10 |
11 | ```bash
12 | npm install -g @go-task/cli
13 | ```
14 |
15 | ## Create a new plugin
16 |
17 | To create a new plugin run the following command in the plugins folder of WordPress `wp-content/plugins` or Joomla `plugins/system` depending on your preferred development environment. Replace `PLUGIN_NAME` with the name of your plugin, for example `myplugin`.
18 |
19 | ```bash
20 | composer create-project yootheme/starter-plugin PLUGIN_NAME
21 | ```
22 |
23 | You will be asked for additional plugin information which will be used in the plugin metadata.
24 |
25 | - **Enter plugin title:** The plugin title, for example `My Plugin`
26 | - **Enter plugin description:** The plugin description
27 | - **Enter author name:** The author Name
28 | - **Enter author email:** The author email
29 | - **Enter author url:** The author URL
30 | - **Enter update server url:** The URL to the update server file
31 |
32 | This will create a new `myplugin` directory with required plugin files.
33 |
34 | ```
35 | .
36 | ├── build # Plugin blueprint files
37 | │ ├── joomla
38 | │ ├── myplugin.php # Joomla plugin
39 | | ├── myplugin.xml # Joomla plugin metadata
40 | │ ├── wordpress
41 | │ ├── myplugin.php # WordPress plugin
42 | ├── .env # Metadata
43 | ├── vendor # Development dependencies
44 | ├── LICENSE.md
45 | ├── README.md
46 | └── Taskfile.yml # Tasks
47 | ```
48 |
49 | ## Set up the plugin
50 |
51 | Open your new plugin folder in the terminal and use one of the following task to copy the necessary plugin files from the `build` folder to the plugin root folder.
52 |
53 | ```bash
54 | task setup-wordpress
55 | task setup-joomla
56 | ```
57 |
58 | Now the plugin can be discoverd and installed in WordPress or Joomla.
59 |
60 | ## Create a new module
61 |
62 | To create a new module run the following command and replace `MODULE_NAME` with the name of your module, for example `my-module`.
63 |
64 | ```bash
65 | composer create:module MODULE_NAME
66 | ```
67 |
68 | You will be asked further questions to configure the module.
69 |
70 | - **Enter module namespace:** Enter a PHP namespace, for example `MyPlugin\MyModule`
71 | - **Add asset files example? [y/N]** Press Enter for _No_.
72 | - **Add settings example? [y/N]** Press Enter for _No_.
73 | - **Add custom LESS example? [y/N]** Press Enter for _No_.
74 | - **Add custom source example? [y/N]** Press Enter for _No_.
75 | - **Add translation files example? [y/N]** Press Enter for _No_.
76 |
77 | Read the [Modules documentation](https://yootheme.com/support/yootheme-pro/joomla/developers-modules) to learn more about the created files and code examples.
78 |
79 | **Note:** Add `wordpress` or `joomla` to the name for system-specific modules, for example `my-module-wordpress` or `my-module-joomla`. The build tasks will only copy the relevant modules into the WordPress and Joomla zip archives.
80 |
81 | ## Create a new element
82 |
83 | To create a new element run the following command and replace `ELEMENT_NAME` with the name of your element, for example `my-element`. If there are multiple modules, choose a module of the provided list.
84 |
85 | ```bash
86 | composer create:element ELEMENT_NAME
87 | ```
88 |
89 | Optionally define the module where the element should be created.
90 |
91 | ```bash
92 | composer create:element ELEMENT_NAME MODULE_NAME
93 | ```
94 |
95 | You will be asked further questions to configure the element.
96 |
97 | - **Enter element title:** The element title, for example `My Element`
98 | - **Create multiple items element? [y/N]** Press Enter for _No_.
99 |
100 | Read the [Elements documentation](https://yootheme.com/support/yootheme-pro/joomla/developers-modules) to learn more about the created files and code examples.
101 |
102 | ## Build distribution files
103 |
104 | To create an installable zip archive of the plugin for WordPress and Joomla, run the following task. The created zip files are located in the `dist` folder.
105 |
106 | ```bash
107 | task build
108 | ```
109 |
110 | Alternatively, create the archives individually.
111 |
112 | ```bash
113 | task build-wordpress
114 | task build-joomla
115 | ```
116 |
117 | ## Publishing and versioning
118 |
119 | To raise the version number of your plugin or change metadata like the plugin title or description, open the `.env` and edit the options.
120 |
121 | ```yaml
122 | TITLE='My Plugin'
123 | NAME='myplugin'
124 | VERSION='0.0.1'
125 | DESCRIPTION='Lorem ipsum'
126 | DATE='{{ now | date "2006-01-02" }}'
127 | COPYRIGHT='Copyright (C)'
128 | LICENSE='GNU General Public License'
129 | AUTHOR='My Company'
130 | AUTHOREMAIL='me@example.com'
131 | AUTHORURL='example.com'
132 | ```
133 |
134 | After that, re-run the [setup task](#user-content-set-up-the-plugin) to update the plugin for your develop environment meaning WordPress or Joomla and run the [build task](#user-content-build-distribution-files) to create the distribution files.
135 |
136 | ## Update Server
137 |
138 | Running the [build task](#user-content-build-distribution-files) will also create update server files for Joomla `dist/update.xml` and WordPress `dist/update.json`.
139 |
140 | Upload these files to the configured `Update Server URL` to inform about a new version and provide one-click updates for the plugin.
141 |
142 | The package information is also stored in the `.env` configuration.
143 |
144 | ```yaml
145 | # Update server
146 | UPDATEURI='https://www.example.com/updates'
147 |
148 | # Package information
149 | TYPE='plugin'
150 | STABILITY='stable'
151 | DOWNLOADURL=https://www.example.com/downloads
152 | PHPMINIMUM='7.4'
153 | JOOMLAMINIMUM='(5\.[01]|4\.[01234]|3\.10)\.'
154 | WORDPRESSMINIMUM='6.2'
155 | ```
156 |
157 | ## Updating commands and tasks
158 |
159 | The command and task scripts have their own [starter-utils](https://github.com/yootheme/starter-utils) Github repository. To update the package to the latest version run `composer update` from time to time.
160 |
161 | ## Github
162 |
163 | To make your plugin a Git repository use `git init -b main` and follow the steps under [Adding a local repository to GitHub using Git](https://docs.github.com/en/migrations/importing-source-code/using-the-command-line-to-import-source-code/adding-locally-hosted-code-to-github#adding-a-local-repository-to-github-using-git).
164 |
165 | ## License
166 |
167 | [MIT](https://opensource.org/licenses/MIT)
168 |
--------------------------------------------------------------------------------
/vendor/yootheme/starter-utils/src/stubs/multiple-element/element.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "{{ NAME }}",
3 | "title": "{{ TITLE }}",
4 | "icon": "${url:images/icon.svg}",
5 | "iconSmall": "${url:images/iconSmall.svg}",
6 | "element": true,
7 | "container": true,
8 | "width": 500,
9 | "defaults": {
10 | "show_title": true,
11 | "show_content": true,
12 | "show_image": true,
13 | "show_link": true,
14 | "grid_columns": "3",
15 | "title_element": "h3",
16 | "link_text": "Read more"
17 | },
18 | "templates": {
19 | "render": "./templates/template.php",
20 | "content": "./templates/content.php"
21 | },
22 | "placeholder": {
23 | "children": [
24 | { "type": "example_item", "props": {} },
25 | { "type": "example_item", "props": {} },
26 | { "type": "example_item", "props": {} }
27 | ]
28 | },
29 | "fields": {
30 | "content": {
31 | "label": "Items",
32 | "type": "content-items",
33 | "item": "{{ NAME }}_item",
34 | "media": {
35 | "type": "image",
36 | "item": { "title": "title", "image": "src" }
37 | }
38 | },
39 | "show_title": {
40 | "label": "Display",
41 | "type": "checkbox",
42 | "text": "Show the title"
43 | },
44 | "show_content": {
45 | "type": "checkbox",
46 | "text": "Show the content"
47 | },
48 | "show_image": {
49 | "type": "checkbox",
50 | "text": "Show the image"
51 | },
52 | "show_link": {
53 | "description": "Show or hide content fields without the need to delete the content itself.",
54 | "type": "checkbox",
55 | "text": "Show the link"
56 | },
57 | "grid_columns": {
58 | "label": "Columns",
59 | "description": "Set the number of grid columns.",
60 | "type": "select",
61 | "options": {
62 | "1 Column": "1",
63 | "2 Columns": "2",
64 | "3 Columns": "3",
65 | "4 Columns": "4",
66 | "5 Columns": "5",
67 | "6 Columns": "6"
68 | }
69 | },
70 | "title_element": {
71 | "label": "HTML Element",
72 | "description": "Choose one of the HTML elements to fit your semantic structure.",
73 | "type": "select",
74 | "options": {
75 | "h1": "h1",
76 | "h2": "h2",
77 | "h3": "h3",
78 | "h4": "h4",
79 | "h5": "h5",
80 | "h6": "h6",
81 | "div": "div"
82 | },
83 | "enable": "show_title"
84 | },
85 | "image_width": {
86 | "attrs": {
87 | "placeholder": "auto"
88 | },
89 | "enable": "show_image"
90 | },
91 | "image_height": {
92 | "attrs": {
93 | "placeholder": "auto"
94 | },
95 | "enable": "show_image"
96 | },
97 | "image_loading": {
98 | "label": "Loading",
99 | "description": "By default, images are loaded lazy. Enable eager loading for images in the initial viewport.",
100 | "type": "checkbox",
101 | "text": "Load image eagerly",
102 | "enable": "show_image"
103 | },
104 | "link_text": {
105 | "label": "Text",
106 | "description": "Enter the text for the link.",
107 | "enable": "show_link"
108 | },
109 | "position": "${builder.position}",
110 | "position_left": "${builder.position_left}",
111 | "position_right": "${builder.position_right}",
112 | "position_top": "${builder.position_top}",
113 | "position_bottom": "${builder.position_bottom}",
114 | "position_z_index": "${builder.position_z_index}",
115 | "margin": "${builder.margin}",
116 | "margin_remove_top": "${builder.margin_remove_top}",
117 | "margin_remove_bottom": "${builder.margin_remove_bottom}",
118 | "maxwidth": "${builder.maxwidth}",
119 | "maxwidth_breakpoint": "${builder.maxwidth_breakpoint}",
120 | "block_align": "${builder.block_align}",
121 | "block_align_breakpoint": "${builder.block_align_breakpoint}",
122 | "block_align_fallback": "${builder.block_align_fallback}",
123 | "text_align": "${builder.text_align_justify}",
124 | "text_align_breakpoint": "${builder.text_align_breakpoint}",
125 | "text_align_fallback": "${builder.text_align_justify_fallback}",
126 | "item_animation": "${builder.animation}",
127 | "_parallax_button": "${builder._parallax_button}",
128 | "visibility": "${builder.visibility}",
129 | "name": "${builder.name}",
130 | "status": "${builder.status}",
131 | "id": "${builder.id}",
132 | "class": "${builder.cls}",
133 | "attributes": "${builder.attrs}",
134 | "css": {
135 | "label": "CSS",
136 | "description": "Enter your own custom CSS. The following selectors will be prefixed automatically for this element: .el-element, .el-item, .el-title, .el-content, .el-image, .el-link",
137 | "type": "editor",
138 | "editor": "code",
139 | "mode": "css",
140 | "attrs": {
141 | "debounce": 500
142 | }
143 | }
144 | },
145 | "fieldset": {
146 | "default": {
147 | "type": "tabs",
148 | "fields": [
149 | {
150 | "title": "Content",
151 | "fields": ["content", "show_title", "show_content", "show_image", "show_link"]
152 | },
153 | {
154 | "title": "Settings",
155 | "fields": [
156 | {
157 | "label": "Grid",
158 | "type": "group",
159 | "divider": true,
160 | "fields": ["grid_columns"]
161 | },
162 | {
163 | "label": "Title",
164 | "type": "group",
165 | "divider": true,
166 | "fields": ["title_element"]
167 | },
168 | {
169 | "label": "Image",
170 | "type": "group",
171 | "divider": true,
172 | "fields": [
173 | {
174 | "label": "Width/Height",
175 | "description": "Setting just one value preserves the original proportions. The image will be resized and cropped automatically, and where possible, high resolution images will be auto-generated.",
176 | "type": "grid",
177 | "width": "1-2",
178 | "fields": ["image_width", "image_height"]
179 | },
180 | "image_loading"
181 | ]
182 | },
183 | {
184 | "label": "Link",
185 | "type": "group",
186 | "divider": true,
187 | "fields": ["link_text"]
188 | },
189 | {
190 | "label": "General",
191 | "type": "group",
192 | "fields": [
193 | "position",
194 | "position_left",
195 | "position_right",
196 | "position_top",
197 | "position_bottom",
198 | "position_z_index",
199 | "margin",
200 | "margin_remove_top",
201 | "margin_remove_bottom",
202 | "maxwidth",
203 | "maxwidth_breakpoint",
204 | "block_align",
205 | "block_align_breakpoint",
206 | "block_align_fallback",
207 | "text_align",
208 | "text_align_breakpoint",
209 | "text_align_fallback",
210 | "item_animation",
211 | "_parallax_button",
212 | "visibility"
213 | ]
214 | }
215 | ]
216 | },
217 | "${builder.advanced}"
218 | ]
219 | }
220 | }
221 | }
222 |
--------------------------------------------------------------------------------
/vendor/yootheme/starter-utils/src/CreateModuleCommand.php:
--------------------------------------------------------------------------------
1 | addArgument('name', InputArgument::REQUIRED);
24 | }
25 |
26 | protected function execute(InputInterface $input, OutputInterface $output): int
27 | {
28 | $fs = new Filesystem();
29 | $cwd = getcwd();
30 |
31 | $name = $input->getArgument('name');
32 | $path = Path::join($cwd, 'modules', $name);
33 |
34 | if (file_exists($path)) {
35 | throw new \RuntimeException("Module '{$path}' already exists");
36 | }
37 |
38 | $fn = [$this->getHelper('question'), 'ask'];
39 | $ask = $this->partial($fn, $input, $output);
40 |
41 | $namespace = new Question('Enter module namespace: ');
42 | $namespace->setNormalizer(fn($value) => $value ?? '');
43 | $namespace->setValidator(function ($value) {
44 | if ('' === trim($value)) {
45 | throw new \Exception('The namespace cannot be empty');
46 | }
47 |
48 | if (str_contains($value, '/')) {
49 | throw new \Exception('The namespace is invalid');
50 | }
51 |
52 | return $value;
53 | });
54 | $namespace->setMaxAttempts(10);
55 | $namespace = $ask($namespace);
56 |
57 | $assets = $ask(new ConfirmationQuestion('Add assets files example? [y/N] ', false));
58 | $settings = $ask(new ConfirmationQuestion('Add settings example? [y/N] ', false));
59 | $less = $ask(new ConfirmationQuestion('Add custom LESS example? [y/N] ', false));
60 | $source = $ask(new ConfirmationQuestion('Add custom source example? [y/N] ', false));
61 | $translator = $ask(
62 | new ConfirmationQuestion('Add translation files example? [y/N] ', false),
63 | );
64 |
65 | $finders = [
66 | 'module' => (new Finder())
67 | ->name('bootstrap.php')
68 | ->in("{$this->stubs}/module"),
69 | ];
70 |
71 | if ($assets) {
72 | $finders['assets'] = (new Finder())
73 | ->name(['AssetsListener.php', 'custom.js', 'custom.css'])
74 | ->in("{$this->stubs}/module");
75 | }
76 |
77 | if ($settings) {
78 | $finders['settings'] = (new Finder())
79 | ->name(['SettingsListener.php', 'customizer.json'])
80 | ->in("{$this->stubs}/module");
81 | }
82 |
83 | if ($less) {
84 | $finders['less'] = (new Finder())
85 | ->name(['StyleListener.php', 'my-component.less', 'styler.json'])
86 | ->in("{$this->stubs}/module");
87 | }
88 |
89 | if ($source) {
90 | $finders['source'] = (new Finder())
91 | ->name([
92 | 'SourceListener.php',
93 | 'MyTypeProvider.php',
94 | 'MyQueryType.php',
95 | 'MyType.php',
96 | ])
97 | ->in("{$this->stubs}/module");
98 | }
99 |
100 | if ($translator) {
101 | $finders['translator'] = (new Finder())
102 | ->name(['TranslationListener.php', 'en_GB.json'])
103 | ->in("{$this->stubs}/module");
104 | }
105 |
106 | foreach ($finders as $name => $finder) {
107 | foreach ($finder->files() as $file) {
108 | $fs->dumpFile("{$path}/{$file->getRelativePathname()}", $file->getContents());
109 | }
110 | }
111 |
112 | // namespace
113 | $this->replaceInFile(
114 | "{$path}/bootstrap.php",
115 | ['#// namespace#'],
116 | ["namespace {$namespace};"],
117 | );
118 |
119 | if ($assets) {
120 | // add AssetsListener
121 | $find = ['#// includes#', '#// add event handlers ...#'];
122 | $replace = [
123 | "\${0}\ninclude_once __DIR__ . '/src/AssetsListener.php';",
124 | "\${0}\n\n 'theme.head' => [
125 | AssetsListener::class => 'initHead',
126 | ],",
127 | ];
128 |
129 | $this->replaceInFile("{$path}/bootstrap.php", $find, $replace);
130 |
131 | // namespace
132 | $this->replaceInFile(
133 | "{$path}/src/AssetsListener.php",
134 | ['#// namespace#'],
135 | ["namespace {$namespace};"],
136 | );
137 | }
138 |
139 | if ($settings) {
140 | // add SettingsListener
141 | $find = ['#// includes#', '#// add event handlers ...#'];
142 | $replace = [
143 | "\${0}\ninclude_once __DIR__ . '/src/SettingsListener.php';",
144 | "\${0}\n\n 'customizer.init' => [
145 | SettingsListener::class => 'initCustomizer',
146 | ],",
147 | ];
148 |
149 | $this->replaceInFile("{$path}/bootstrap.php", $find, $replace);
150 |
151 | // namespace
152 | $this->replaceInFile(
153 | "{$path}/src/SettingsListener.php",
154 | ['#// namespace#'],
155 | ["namespace {$namespace};"],
156 | );
157 | }
158 |
159 | if ($less) {
160 | // add custom LESS
161 | $find = [
162 | '#use YOOtheme\\\\Path;#',
163 | '#// includes#',
164 | '#// add theme config ...#',
165 | '#// add styler config ...#',
166 | '#// add event handlers ...#',
167 | ];
168 | $replace = [
169 | "\${0}\nuse YOOtheme\Theme\Styler\StylerConfig;",
170 | "\${0}\ninclude_once __DIR__ . '/src/StyleListener.php';",
171 | "\${0}\n\n 'styles' => [
172 | 'components' => [
173 | 'my-component' => Path::get('./assets/less/my-component.less'),
174 | ],
175 | ],",
176 | "StylerConfig::class => __DIR__ . '/config/styler.json',",
177 | "\${0}\n\n StylerConfig::class => [
178 | StyleListener::class => 'config'
179 | ],",
180 | ];
181 |
182 | $this->replaceInFile("{$path}/bootstrap.php", $find, $replace);
183 |
184 | // namespace
185 | $this->replaceInFile(
186 | "{$path}/src/StyleListener.php",
187 | ['#// namespace#'],
188 | ["namespace {$namespace};"],
189 | );
190 | }
191 |
192 | if ($source) {
193 | $find = ['#// includes#', '#// add event handlers ...#'];
194 | $replace = [
195 | "\${0}\ninclude_once __DIR__ . '/src/SourceListener.php';\ninclude_once __DIR__ . '/src/MyTypeProvider.php';\ninclude_once __DIR__ . '/src/Type/MyType.php';\ninclude_once __DIR__ . '/src/Type/MyQueryType.php';",
196 | "\${0}\n\n 'source.init' => [
197 | SourceListener::class => ['initSource']
198 | ],",
199 | ];
200 |
201 | $this->replaceInFile("{$path}/bootstrap.php", $find, $replace);
202 |
203 | // namespace
204 | foreach (
205 | [
206 | 'SourceListener.php',
207 | 'MyTypeProvider.php',
208 | 'Type/MyType.php',
209 | 'Type/MyQueryType.php',
210 | ]
211 | as $file
212 | ) {
213 | $this->replaceInFile(
214 | "{$path}/src/{$file}",
215 | ['#// namespace#'],
216 | ["namespace {$namespace};"],
217 | );
218 | }
219 | }
220 |
221 | if ($translator) {
222 | // add TranslationListener
223 | $find = ['#// includes#', '#// add event handlers ...#'];
224 | $replace = [
225 | "\${0}\ninclude_once __DIR__ . '/src/TranslationListener.php';",
226 | "\${0}\n\n 'customizer.init' => [
227 | TranslationListener::class => ['initCustomizer', -10],
228 | ],",
229 | ];
230 |
231 | $this->replaceInFile("{$path}/bootstrap.php", $find, $replace);
232 |
233 | // namespace
234 | $this->replaceInFile(
235 | "{$path}/src/TranslationListener.php",
236 | ['#// namespace#'],
237 | ["namespace {$namespace};"],
238 | );
239 | }
240 |
241 | $output->writeln('Module created successfully.');
242 |
243 | return Command::SUCCESS;
244 | }
245 |
246 | protected function replaceInFile(string $file, array $find, array $replace)
247 | {
248 | file_put_contents($file, preg_replace($find, $replace, file_get_contents($file)));
249 | }
250 |
251 | protected function partial(callable $func, ...$args): callable
252 | {
253 | return fn(...$rest) => $func(...$args, ...$rest);
254 | }
255 | }
256 |
--------------------------------------------------------------------------------
/vendor/composer/InstalledVersions.php:
--------------------------------------------------------------------------------
1 |
7 | * Jordi Boggiano
8 | *
9 | * For the full copyright and license information, please view the LICENSE
10 | * file that was distributed with this source code.
11 | */
12 |
13 | namespace Composer;
14 |
15 | use Composer\Autoload\ClassLoader;
16 | use Composer\Semver\VersionParser;
17 |
18 | /**
19 | * This class is copied in every Composer installed project and available to all
20 | *
21 | * See also https://getcomposer.org/doc/07-runtime.md#installed-versions
22 | *
23 | * To require its presence, you can require `composer-runtime-api ^2.0`
24 | *
25 | * @final
26 | */
27 | class InstalledVersions
28 | {
29 | /**
30 | * @var mixed[]|null
31 | * @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array}|array{}|null
32 | */
33 | private static $installed;
34 |
35 | /**
36 | * @var bool|null
37 | */
38 | private static $canGetVendors;
39 |
40 | /**
41 | * @var array[]
42 | * @psalm-var array}>
43 | */
44 | private static $installedByVendor = array();
45 |
46 | /**
47 | * Returns a list of all package names which are present, either by being installed, replaced or provided
48 | *
49 | * @return string[]
50 | * @psalm-return list
51 | */
52 | public static function getInstalledPackages()
53 | {
54 | $packages = array();
55 | foreach (self::getInstalled() as $installed) {
56 | $packages[] = array_keys($installed['versions']);
57 | }
58 |
59 | if (1 === \count($packages)) {
60 | return $packages[0];
61 | }
62 |
63 | return array_keys(array_flip(\call_user_func_array('array_merge', $packages)));
64 | }
65 |
66 | /**
67 | * Returns a list of all package names with a specific type e.g. 'library'
68 | *
69 | * @param string $type
70 | * @return string[]
71 | * @psalm-return list
72 | */
73 | public static function getInstalledPackagesByType($type)
74 | {
75 | $packagesByType = array();
76 |
77 | foreach (self::getInstalled() as $installed) {
78 | foreach ($installed['versions'] as $name => $package) {
79 | if (isset($package['type']) && $package['type'] === $type) {
80 | $packagesByType[] = $name;
81 | }
82 | }
83 | }
84 |
85 | return $packagesByType;
86 | }
87 |
88 | /**
89 | * Checks whether the given package is installed
90 | *
91 | * This also returns true if the package name is provided or replaced by another package
92 | *
93 | * @param string $packageName
94 | * @param bool $includeDevRequirements
95 | * @return bool
96 | */
97 | public static function isInstalled($packageName, $includeDevRequirements = true)
98 | {
99 | foreach (self::getInstalled() as $installed) {
100 | if (isset($installed['versions'][$packageName])) {
101 | return $includeDevRequirements || !isset($installed['versions'][$packageName]['dev_requirement']) || $installed['versions'][$packageName]['dev_requirement'] === false;
102 | }
103 | }
104 |
105 | return false;
106 | }
107 |
108 | /**
109 | * Checks whether the given package satisfies a version constraint
110 | *
111 | * e.g. If you want to know whether version 2.3+ of package foo/bar is installed, you would call:
112 | *
113 | * Composer\InstalledVersions::satisfies(new VersionParser, 'foo/bar', '^2.3')
114 | *
115 | * @param VersionParser $parser Install composer/semver to have access to this class and functionality
116 | * @param string $packageName
117 | * @param string|null $constraint A version constraint to check for, if you pass one you have to make sure composer/semver is required by your package
118 | * @return bool
119 | */
120 | public static function satisfies(VersionParser $parser, $packageName, $constraint)
121 | {
122 | $constraint = $parser->parseConstraints((string) $constraint);
123 | $provided = $parser->parseConstraints(self::getVersionRanges($packageName));
124 |
125 | return $provided->matches($constraint);
126 | }
127 |
128 | /**
129 | * Returns a version constraint representing all the range(s) which are installed for a given package
130 | *
131 | * It is easier to use this via isInstalled() with the $constraint argument if you need to check
132 | * whether a given version of a package is installed, and not just whether it exists
133 | *
134 | * @param string $packageName
135 | * @return string Version constraint usable with composer/semver
136 | */
137 | public static function getVersionRanges($packageName)
138 | {
139 | foreach (self::getInstalled() as $installed) {
140 | if (!isset($installed['versions'][$packageName])) {
141 | continue;
142 | }
143 |
144 | $ranges = array();
145 | if (isset($installed['versions'][$packageName]['pretty_version'])) {
146 | $ranges[] = $installed['versions'][$packageName]['pretty_version'];
147 | }
148 | if (array_key_exists('aliases', $installed['versions'][$packageName])) {
149 | $ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']);
150 | }
151 | if (array_key_exists('replaced', $installed['versions'][$packageName])) {
152 | $ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']);
153 | }
154 | if (array_key_exists('provided', $installed['versions'][$packageName])) {
155 | $ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']);
156 | }
157 |
158 | return implode(' || ', $ranges);
159 | }
160 |
161 | throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
162 | }
163 |
164 | /**
165 | * @param string $packageName
166 | * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
167 | */
168 | public static function getVersion($packageName)
169 | {
170 | foreach (self::getInstalled() as $installed) {
171 | if (!isset($installed['versions'][$packageName])) {
172 | continue;
173 | }
174 |
175 | if (!isset($installed['versions'][$packageName]['version'])) {
176 | return null;
177 | }
178 |
179 | return $installed['versions'][$packageName]['version'];
180 | }
181 |
182 | throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
183 | }
184 |
185 | /**
186 | * @param string $packageName
187 | * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
188 | */
189 | public static function getPrettyVersion($packageName)
190 | {
191 | foreach (self::getInstalled() as $installed) {
192 | if (!isset($installed['versions'][$packageName])) {
193 | continue;
194 | }
195 |
196 | if (!isset($installed['versions'][$packageName]['pretty_version'])) {
197 | return null;
198 | }
199 |
200 | return $installed['versions'][$packageName]['pretty_version'];
201 | }
202 |
203 | throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
204 | }
205 |
206 | /**
207 | * @param string $packageName
208 | * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as reference
209 | */
210 | public static function getReference($packageName)
211 | {
212 | foreach (self::getInstalled() as $installed) {
213 | if (!isset($installed['versions'][$packageName])) {
214 | continue;
215 | }
216 |
217 | if (!isset($installed['versions'][$packageName]['reference'])) {
218 | return null;
219 | }
220 |
221 | return $installed['versions'][$packageName]['reference'];
222 | }
223 |
224 | throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
225 | }
226 |
227 | /**
228 | * @param string $packageName
229 | * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as install path. Packages of type metapackages also have a null install path.
230 | */
231 | public static function getInstallPath($packageName)
232 | {
233 | foreach (self::getInstalled() as $installed) {
234 | if (!isset($installed['versions'][$packageName])) {
235 | continue;
236 | }
237 |
238 | return isset($installed['versions'][$packageName]['install_path']) ? $installed['versions'][$packageName]['install_path'] : null;
239 | }
240 |
241 | throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
242 | }
243 |
244 | /**
245 | * @return array
246 | * @psalm-return array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}
247 | */
248 | public static function getRootPackage()
249 | {
250 | $installed = self::getInstalled();
251 |
252 | return $installed[0]['root'];
253 | }
254 |
255 | /**
256 | * Returns the raw installed.php data for custom implementations
257 | *
258 | * @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect.
259 | * @return array[]
260 | * @psalm-return array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array}
261 | */
262 | public static function getRawData()
263 | {
264 | @trigger_error('getRawData only returns the first dataset loaded, which may not be what you expect. Use getAllRawData() instead which returns all datasets for all autoloaders present in the process.', E_USER_DEPRECATED);
265 |
266 | if (null === self::$installed) {
267 | // only require the installed.php file if this file is loaded from its dumped location,
268 | // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
269 | if (substr(__DIR__, -8, 1) !== 'C') {
270 | self::$installed = include __DIR__ . '/installed.php';
271 | } else {
272 | self::$installed = array();
273 | }
274 | }
275 |
276 | return self::$installed;
277 | }
278 |
279 | /**
280 | * Returns the raw data of all installed.php which are currently loaded for custom implementations
281 | *
282 | * @return array[]
283 | * @psalm-return list}>
284 | */
285 | public static function getAllRawData()
286 | {
287 | return self::getInstalled();
288 | }
289 |
290 | /**
291 | * Lets you reload the static array from another file
292 | *
293 | * This is only useful for complex integrations in which a project needs to use
294 | * this class but then also needs to execute another project's autoloader in process,
295 | * and wants to ensure both projects have access to their version of installed.php.
296 | *
297 | * A typical case would be PHPUnit, where it would need to make sure it reads all
298 | * the data it needs from this class, then call reload() with
299 | * `require $CWD/vendor/composer/installed.php` (or similar) as input to make sure
300 | * the project in which it runs can then also use this class safely, without
301 | * interference between PHPUnit's dependencies and the project's dependencies.
302 | *
303 | * @param array[] $data A vendor/composer/installed.php data set
304 | * @return void
305 | *
306 | * @psalm-param array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} $data
307 | */
308 | public static function reload($data)
309 | {
310 | self::$installed = $data;
311 | self::$installedByVendor = array();
312 | }
313 |
314 | /**
315 | * @return array[]
316 | * @psalm-return list}>
317 | */
318 | private static function getInstalled()
319 | {
320 | if (null === self::$canGetVendors) {
321 | self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders');
322 | }
323 |
324 | $installed = array();
325 |
326 | if (self::$canGetVendors) {
327 | foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) {
328 | if (isset(self::$installedByVendor[$vendorDir])) {
329 | $installed[] = self::$installedByVendor[$vendorDir];
330 | } elseif (is_file($vendorDir.'/composer/installed.php')) {
331 | /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} $required */
332 | $required = require $vendorDir.'/composer/installed.php';
333 | $installed[] = self::$installedByVendor[$vendorDir] = $required;
334 | if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) {
335 | self::$installed = $installed[count($installed) - 1];
336 | }
337 | }
338 | }
339 | }
340 |
341 | if (null === self::$installed) {
342 | // only require the installed.php file if this file is loaded from its dumped location,
343 | // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
344 | if (substr(__DIR__, -8, 1) !== 'C') {
345 | /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} $required */
346 | $required = require __DIR__ . '/installed.php';
347 | self::$installed = $required;
348 | } else {
349 | self::$installed = array();
350 | }
351 | }
352 |
353 | if (self::$installed !== array()) {
354 | $installed[] = self::$installed;
355 | }
356 |
357 | return $installed;
358 | }
359 | }
360 |
--------------------------------------------------------------------------------
/vendor/composer/ClassLoader.php:
--------------------------------------------------------------------------------
1 |
7 | * Jordi Boggiano
8 | *
9 | * For the full copyright and license information, please view the LICENSE
10 | * file that was distributed with this source code.
11 | */
12 |
13 | namespace Composer\Autoload;
14 |
15 | /**
16 | * ClassLoader implements a PSR-0, PSR-4 and classmap class loader.
17 | *
18 | * $loader = new \Composer\Autoload\ClassLoader();
19 | *
20 | * // register classes with namespaces
21 | * $loader->add('Symfony\Component', __DIR__.'/component');
22 | * $loader->add('Symfony', __DIR__.'/framework');
23 | *
24 | * // activate the autoloader
25 | * $loader->register();
26 | *
27 | * // to enable searching the include path (eg. for PEAR packages)
28 | * $loader->setUseIncludePath(true);
29 | *
30 | * In this example, if you try to use a class in the Symfony\Component
31 | * namespace or one of its children (Symfony\Component\Console for instance),
32 | * the autoloader will first look for the class under the component/
33 | * directory, and it will then fallback to the framework/ directory if not
34 | * found before giving up.
35 | *
36 | * This class is loosely based on the Symfony UniversalClassLoader.
37 | *
38 | * @author Fabien Potencier
39 | * @author Jordi Boggiano
40 | * @see https://www.php-fig.org/psr/psr-0/
41 | * @see https://www.php-fig.org/psr/psr-4/
42 | */
43 | class ClassLoader
44 | {
45 | /** @var \Closure(string):void */
46 | private static $includeFile;
47 |
48 | /** @var string|null */
49 | private $vendorDir;
50 |
51 | // PSR-4
52 | /**
53 | * @var array>
54 | */
55 | private $prefixLengthsPsr4 = array();
56 | /**
57 | * @var array>
58 | */
59 | private $prefixDirsPsr4 = array();
60 | /**
61 | * @var list
62 | */
63 | private $fallbackDirsPsr4 = array();
64 |
65 | // PSR-0
66 | /**
67 | * List of PSR-0 prefixes
68 | *
69 | * Structured as array('F (first letter)' => array('Foo\Bar (full prefix)' => array('path', 'path2')))
70 | *
71 | * @var array>>
72 | */
73 | private $prefixesPsr0 = array();
74 | /**
75 | * @var list
76 | */
77 | private $fallbackDirsPsr0 = array();
78 |
79 | /** @var bool */
80 | private $useIncludePath = false;
81 |
82 | /**
83 | * @var array
84 | */
85 | private $classMap = array();
86 |
87 | /** @var bool */
88 | private $classMapAuthoritative = false;
89 |
90 | /**
91 | * @var array
92 | */
93 | private $missingClasses = array();
94 |
95 | /** @var string|null */
96 | private $apcuPrefix;
97 |
98 | /**
99 | * @var array
100 | */
101 | private static $registeredLoaders = array();
102 |
103 | /**
104 | * @param string|null $vendorDir
105 | */
106 | public function __construct($vendorDir = null)
107 | {
108 | $this->vendorDir = $vendorDir;
109 | self::initializeIncludeClosure();
110 | }
111 |
112 | /**
113 | * @return array>
114 | */
115 | public function getPrefixes()
116 | {
117 | if (!empty($this->prefixesPsr0)) {
118 | return call_user_func_array('array_merge', array_values($this->prefixesPsr0));
119 | }
120 |
121 | return array();
122 | }
123 |
124 | /**
125 | * @return array>
126 | */
127 | public function getPrefixesPsr4()
128 | {
129 | return $this->prefixDirsPsr4;
130 | }
131 |
132 | /**
133 | * @return list
134 | */
135 | public function getFallbackDirs()
136 | {
137 | return $this->fallbackDirsPsr0;
138 | }
139 |
140 | /**
141 | * @return list
142 | */
143 | public function getFallbackDirsPsr4()
144 | {
145 | return $this->fallbackDirsPsr4;
146 | }
147 |
148 | /**
149 | * @return array Array of classname => path
150 | */
151 | public function getClassMap()
152 | {
153 | return $this->classMap;
154 | }
155 |
156 | /**
157 | * @param array $classMap Class to filename map
158 | *
159 | * @return void
160 | */
161 | public function addClassMap(array $classMap)
162 | {
163 | if ($this->classMap) {
164 | $this->classMap = array_merge($this->classMap, $classMap);
165 | } else {
166 | $this->classMap = $classMap;
167 | }
168 | }
169 |
170 | /**
171 | * Registers a set of PSR-0 directories for a given prefix, either
172 | * appending or prepending to the ones previously set for this prefix.
173 | *
174 | * @param string $prefix The prefix
175 | * @param list|string $paths The PSR-0 root directories
176 | * @param bool $prepend Whether to prepend the directories
177 | *
178 | * @return void
179 | */
180 | public function add($prefix, $paths, $prepend = false)
181 | {
182 | $paths = (array) $paths;
183 | if (!$prefix) {
184 | if ($prepend) {
185 | $this->fallbackDirsPsr0 = array_merge(
186 | $paths,
187 | $this->fallbackDirsPsr0
188 | );
189 | } else {
190 | $this->fallbackDirsPsr0 = array_merge(
191 | $this->fallbackDirsPsr0,
192 | $paths
193 | );
194 | }
195 |
196 | return;
197 | }
198 |
199 | $first = $prefix[0];
200 | if (!isset($this->prefixesPsr0[$first][$prefix])) {
201 | $this->prefixesPsr0[$first][$prefix] = $paths;
202 |
203 | return;
204 | }
205 | if ($prepend) {
206 | $this->prefixesPsr0[$first][$prefix] = array_merge(
207 | $paths,
208 | $this->prefixesPsr0[$first][$prefix]
209 | );
210 | } else {
211 | $this->prefixesPsr0[$first][$prefix] = array_merge(
212 | $this->prefixesPsr0[$first][$prefix],
213 | $paths
214 | );
215 | }
216 | }
217 |
218 | /**
219 | * Registers a set of PSR-4 directories for a given namespace, either
220 | * appending or prepending to the ones previously set for this namespace.
221 | *
222 | * @param string $prefix The prefix/namespace, with trailing '\\'
223 | * @param list|string $paths The PSR-4 base directories
224 | * @param bool $prepend Whether to prepend the directories
225 | *
226 | * @throws \InvalidArgumentException
227 | *
228 | * @return void
229 | */
230 | public function addPsr4($prefix, $paths, $prepend = false)
231 | {
232 | $paths = (array) $paths;
233 | if (!$prefix) {
234 | // Register directories for the root namespace.
235 | if ($prepend) {
236 | $this->fallbackDirsPsr4 = array_merge(
237 | $paths,
238 | $this->fallbackDirsPsr4
239 | );
240 | } else {
241 | $this->fallbackDirsPsr4 = array_merge(
242 | $this->fallbackDirsPsr4,
243 | $paths
244 | );
245 | }
246 | } elseif (!isset($this->prefixDirsPsr4[$prefix])) {
247 | // Register directories for a new namespace.
248 | $length = strlen($prefix);
249 | if ('\\' !== $prefix[$length - 1]) {
250 | throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
251 | }
252 | $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
253 | $this->prefixDirsPsr4[$prefix] = $paths;
254 | } elseif ($prepend) {
255 | // Prepend directories for an already registered namespace.
256 | $this->prefixDirsPsr4[$prefix] = array_merge(
257 | $paths,
258 | $this->prefixDirsPsr4[$prefix]
259 | );
260 | } else {
261 | // Append directories for an already registered namespace.
262 | $this->prefixDirsPsr4[$prefix] = array_merge(
263 | $this->prefixDirsPsr4[$prefix],
264 | $paths
265 | );
266 | }
267 | }
268 |
269 | /**
270 | * Registers a set of PSR-0 directories for a given prefix,
271 | * replacing any others previously set for this prefix.
272 | *
273 | * @param string $prefix The prefix
274 | * @param list|string $paths The PSR-0 base directories
275 | *
276 | * @return void
277 | */
278 | public function set($prefix, $paths)
279 | {
280 | if (!$prefix) {
281 | $this->fallbackDirsPsr0 = (array) $paths;
282 | } else {
283 | $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
284 | }
285 | }
286 |
287 | /**
288 | * Registers a set of PSR-4 directories for a given namespace,
289 | * replacing any others previously set for this namespace.
290 | *
291 | * @param string $prefix The prefix/namespace, with trailing '\\'
292 | * @param list|string $paths The PSR-4 base directories
293 | *
294 | * @throws \InvalidArgumentException
295 | *
296 | * @return void
297 | */
298 | public function setPsr4($prefix, $paths)
299 | {
300 | if (!$prefix) {
301 | $this->fallbackDirsPsr4 = (array) $paths;
302 | } else {
303 | $length = strlen($prefix);
304 | if ('\\' !== $prefix[$length - 1]) {
305 | throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
306 | }
307 | $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
308 | $this->prefixDirsPsr4[$prefix] = (array) $paths;
309 | }
310 | }
311 |
312 | /**
313 | * Turns on searching the include path for class files.
314 | *
315 | * @param bool $useIncludePath
316 | *
317 | * @return void
318 | */
319 | public function setUseIncludePath($useIncludePath)
320 | {
321 | $this->useIncludePath = $useIncludePath;
322 | }
323 |
324 | /**
325 | * Can be used to check if the autoloader uses the include path to check
326 | * for classes.
327 | *
328 | * @return bool
329 | */
330 | public function getUseIncludePath()
331 | {
332 | return $this->useIncludePath;
333 | }
334 |
335 | /**
336 | * Turns off searching the prefix and fallback directories for classes
337 | * that have not been registered with the class map.
338 | *
339 | * @param bool $classMapAuthoritative
340 | *
341 | * @return void
342 | */
343 | public function setClassMapAuthoritative($classMapAuthoritative)
344 | {
345 | $this->classMapAuthoritative = $classMapAuthoritative;
346 | }
347 |
348 | /**
349 | * Should class lookup fail if not found in the current class map?
350 | *
351 | * @return bool
352 | */
353 | public function isClassMapAuthoritative()
354 | {
355 | return $this->classMapAuthoritative;
356 | }
357 |
358 | /**
359 | * APCu prefix to use to cache found/not-found classes, if the extension is enabled.
360 | *
361 | * @param string|null $apcuPrefix
362 | *
363 | * @return void
364 | */
365 | public function setApcuPrefix($apcuPrefix)
366 | {
367 | $this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null;
368 | }
369 |
370 | /**
371 | * The APCu prefix in use, or null if APCu caching is not enabled.
372 | *
373 | * @return string|null
374 | */
375 | public function getApcuPrefix()
376 | {
377 | return $this->apcuPrefix;
378 | }
379 |
380 | /**
381 | * Registers this instance as an autoloader.
382 | *
383 | * @param bool $prepend Whether to prepend the autoloader or not
384 | *
385 | * @return void
386 | */
387 | public function register($prepend = false)
388 | {
389 | spl_autoload_register(array($this, 'loadClass'), true, $prepend);
390 |
391 | if (null === $this->vendorDir) {
392 | return;
393 | }
394 |
395 | if ($prepend) {
396 | self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders;
397 | } else {
398 | unset(self::$registeredLoaders[$this->vendorDir]);
399 | self::$registeredLoaders[$this->vendorDir] = $this;
400 | }
401 | }
402 |
403 | /**
404 | * Unregisters this instance as an autoloader.
405 | *
406 | * @return void
407 | */
408 | public function unregister()
409 | {
410 | spl_autoload_unregister(array($this, 'loadClass'));
411 |
412 | if (null !== $this->vendorDir) {
413 | unset(self::$registeredLoaders[$this->vendorDir]);
414 | }
415 | }
416 |
417 | /**
418 | * Loads the given class or interface.
419 | *
420 | * @param string $class The name of the class
421 | * @return true|null True if loaded, null otherwise
422 | */
423 | public function loadClass($class)
424 | {
425 | if ($file = $this->findFile($class)) {
426 | $includeFile = self::$includeFile;
427 | $includeFile($file);
428 |
429 | return true;
430 | }
431 |
432 | return null;
433 | }
434 |
435 | /**
436 | * Finds the path to the file where the class is defined.
437 | *
438 | * @param string $class The name of the class
439 | *
440 | * @return string|false The path if found, false otherwise
441 | */
442 | public function findFile($class)
443 | {
444 | // class map lookup
445 | if (isset($this->classMap[$class])) {
446 | return $this->classMap[$class];
447 | }
448 | if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
449 | return false;
450 | }
451 | if (null !== $this->apcuPrefix) {
452 | $file = apcu_fetch($this->apcuPrefix.$class, $hit);
453 | if ($hit) {
454 | return $file;
455 | }
456 | }
457 |
458 | $file = $this->findFileWithExtension($class, '.php');
459 |
460 | // Search for Hack files if we are running on HHVM
461 | if (false === $file && defined('HHVM_VERSION')) {
462 | $file = $this->findFileWithExtension($class, '.hh');
463 | }
464 |
465 | if (null !== $this->apcuPrefix) {
466 | apcu_add($this->apcuPrefix.$class, $file);
467 | }
468 |
469 | if (false === $file) {
470 | // Remember that this class does not exist.
471 | $this->missingClasses[$class] = true;
472 | }
473 |
474 | return $file;
475 | }
476 |
477 | /**
478 | * Returns the currently registered loaders keyed by their corresponding vendor directories.
479 | *
480 | * @return array
481 | */
482 | public static function getRegisteredLoaders()
483 | {
484 | return self::$registeredLoaders;
485 | }
486 |
487 | /**
488 | * @param string $class
489 | * @param string $ext
490 | * @return string|false
491 | */
492 | private function findFileWithExtension($class, $ext)
493 | {
494 | // PSR-4 lookup
495 | $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
496 |
497 | $first = $class[0];
498 | if (isset($this->prefixLengthsPsr4[$first])) {
499 | $subPath = $class;
500 | while (false !== $lastPos = strrpos($subPath, '\\')) {
501 | $subPath = substr($subPath, 0, $lastPos);
502 | $search = $subPath . '\\';
503 | if (isset($this->prefixDirsPsr4[$search])) {
504 | $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
505 | foreach ($this->prefixDirsPsr4[$search] as $dir) {
506 | if (file_exists($file = $dir . $pathEnd)) {
507 | return $file;
508 | }
509 | }
510 | }
511 | }
512 | }
513 |
514 | // PSR-4 fallback dirs
515 | foreach ($this->fallbackDirsPsr4 as $dir) {
516 | if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
517 | return $file;
518 | }
519 | }
520 |
521 | // PSR-0 lookup
522 | if (false !== $pos = strrpos($class, '\\')) {
523 | // namespaced class name
524 | $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
525 | . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
526 | } else {
527 | // PEAR-like class name
528 | $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
529 | }
530 |
531 | if (isset($this->prefixesPsr0[$first])) {
532 | foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
533 | if (0 === strpos($class, $prefix)) {
534 | foreach ($dirs as $dir) {
535 | if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
536 | return $file;
537 | }
538 | }
539 | }
540 | }
541 | }
542 |
543 | // PSR-0 fallback dirs
544 | foreach ($this->fallbackDirsPsr0 as $dir) {
545 | if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
546 | return $file;
547 | }
548 | }
549 |
550 | // PSR-0 include paths.
551 | if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
552 | return $file;
553 | }
554 |
555 | return false;
556 | }
557 |
558 | /**
559 | * @return void
560 | */
561 | private static function initializeIncludeClosure()
562 | {
563 | if (self::$includeFile !== null) {
564 | return;
565 | }
566 |
567 | /**
568 | * Scope isolated include.
569 | *
570 | * Prevents access to $this/self from included files.
571 | *
572 | * @param string $file
573 | * @return void
574 | */
575 | self::$includeFile = \Closure::bind(static function($file) {
576 | include $file;
577 | }, null, null);
578 | }
579 | }
580 |
--------------------------------------------------------------------------------