(Grav GitSync) Automatic Commit from RealStickman
This commit is contained in:
parent
90b36e98d8
commit
7312e06e60
3
plugins/shortcode-core/.gitignore
vendored
Normal file
3
plugins/shortcode-core/.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
/.idea
|
||||
/vendor/.DS_Store
|
||||
.DS_Store
|
411
plugins/shortcode-core/CHANGELOG.md
Normal file
411
plugins/shortcode-core/CHANGELOG.md
Normal file
@ -0,0 +1,411 @@
|
||||
# v5.1.3
|
||||
## 06/01/2022
|
||||
|
||||
1. [](#improved)
|
||||
* Added a new `display` CLI command to show all registered shortcodes
|
||||
|
||||
# v5.1.2
|
||||
## 05/10/2022
|
||||
|
||||
1. [](#bugfix)
|
||||
* Upgraded `thunderer/shortcode` to 0.7.5 to address a security issue
|
||||
|
||||
# v5.1.1
|
||||
## 01/11/2022
|
||||
|
||||
1. [](#improved)
|
||||
* Improved Twig 2 support
|
||||
* Bugfixes to support latest NextGen version (v1.1.8)
|
||||
|
||||
# v5.1.0
|
||||
## 12/09/2021
|
||||
|
||||
1. [](#new)
|
||||
* Notice shortcode now uses a twig template to allow for easy overriding of style
|
||||
1. [](#improved)
|
||||
* Updated vendor libraries to latest
|
||||
|
||||
# v5.0.7
|
||||
## 09/28/2021
|
||||
|
||||
1. [](#improved)
|
||||
* Added `processShortcodesRaw()` using raw_handlers [#104](https://github.com/getgrav/grav-plugin-shortcode-core/pull/104)
|
||||
* Better vertical alignment for inline shortcodes in NextGen Editor
|
||||
1. [](#bugfix)
|
||||
* NextGen Editor: Ensure content of children shortcode elements, such as UI Tab content, have a new empty line as prefix and suffix, to ensure Markdown lists are not lost [getgrav/grav-premium-issues#123](https://github.com/getgrav/grav-premium-issues/issues/123)
|
||||
|
||||
# v5.0.6
|
||||
## 04/27/2021
|
||||
|
||||
1. [](#improved)
|
||||
* Added the ability to enable/disable built-in notice CSS
|
||||
* NextGen Editor: Added support for multiple editor instances
|
||||
|
||||
# v5.0.5
|
||||
## 03/12/2021
|
||||
|
||||
1. [](#bugfix)
|
||||
* `SafeEmailShortcode` fixed to be compatible with PHP 7.4
|
||||
* Addresses shortcodes getting repeated in modular subpages [#101](https://github.com/getgrav/grav-plugin-shortcode-core/pull/101)
|
||||
|
||||
# v5.0.4
|
||||
## 01/26/2021
|
||||
|
||||
1. [](#bugfix)
|
||||
* NextGen Editor: Fixed regexp regression preventing multiple shortcodes to be parsed in certain circumstances
|
||||
|
||||
# v5.0.3
|
||||
## 01/15/2021
|
||||
|
||||
1. [](#improved)
|
||||
* NextGen Editor: Update to support latest version
|
||||
|
||||
# v5.0.2
|
||||
## 12/18/2020
|
||||
|
||||
1. [](#improved)
|
||||
* NexGen Editor: Added optional `shorthand` to force attributes to full declaration
|
||||
1. [](#bugfix)
|
||||
* NextGen Editor: Fixed regexp preventing attributes with `/` in the value from being captured
|
||||
|
||||
# v5.0.1
|
||||
## 12/02/2020
|
||||
|
||||
1. [](#improved)
|
||||
* Content editing in settings popup
|
||||
|
||||
# v5.0.0
|
||||
## 11/04/2020
|
||||
|
||||
1. [](#new)
|
||||
* Added built-in support for **Nextgen Editor** with powerful GUI capabilities for all core shortcodes
|
||||
* Support for 3rd party shortcode plugins to add their own **Nextgen Editor** integrations.
|
||||
1. [](#improved)
|
||||
* Support for comma-listed language tags in `[lang]` shortcode: `[lang=dk,se,no,fi]`
|
||||
* Support for justified text in align shortcode [#94](https://github.com/getgrav/grav-plugin-shortcode-core/issues/94)
|
||||
* Support for asset collections and arrays [#85](https://github.com/getgrav/grav-plugin-shortcode-core/issues/85)
|
||||
* Support of `duotone` FontAwesome icons [#78](https://github.com/getgrav/grav-plugin-shortcode-core/issues/78)
|
||||
1. [](#bugfix)
|
||||
* Support HTML in Header shortcode
|
||||
|
||||
# v4.2.3
|
||||
## 04/27/2020
|
||||
|
||||
1. [](#improved)
|
||||
* Configuration option to exclude default shortcodes [#86](https://github.com/getgrav/grav-plugin-shortcode-core/issues/86)
|
||||
* Add support for `style` attribute in `[span]` shortcode [#88](https://github.com/getgrav/grav-plugin-shortcode-core/issues/88)
|
||||
* Fix typos [#91](https://github.com/getgrav/grav-plugin-shortcode-core/issues/91)
|
||||
|
||||
# v4.2.2
|
||||
## 03/04/2020
|
||||
|
||||
1. [](#improved)
|
||||
* Added second `$options` parameter to `ShortcodeCore->registerAllShortcodes()`, key `ignore` can be used to ignore class names / files from being loaded
|
||||
1. [](#bugfix)
|
||||
* Fix shortcodes which do not override `init()` method, added deprecation notice instead [#82](https://github.com/getgrav/grav-plugin-shortcode-core/issues/82)
|
||||
* Fixed error message showing up when updating older versions (<4.2.0) of the plugin [#84](https://github.com/getgrav/grav-plugin-shortcode-core/issues/84)
|
||||
|
||||
# v4.2.1
|
||||
## 02/14/2020
|
||||
|
||||
1. [](#improved)
|
||||
* Improved shortcode loading, all shortcodes should now extend `Grav\Plugin\Shortcodes\Shortcode` class
|
||||
1. [](#bugfix)
|
||||
* Fixed `Class 'Grav\Plugin\Shortcodes\Shortcode' not found` error when using some plugins
|
||||
* Fixed fatal error when trying to instantiate bad shortcodes (they will be skipped instead)
|
||||
|
||||
# v4.2.0
|
||||
## 02/11/2020
|
||||
|
||||
1. [](#new)
|
||||
* Pass phpstan level 1 tests
|
||||
* Added autoload support for registering shortcodes with `$grav['shortcode']->registerShortcode($name)`
|
||||
* Moved `ShortcodeObject` classes into `Grav\Plugin\ShortcodeCore` namespace with old alias
|
||||
1. [](#improved)
|
||||
* Major code cleanup
|
||||
|
||||
# v4.1.7
|
||||
## 12/04/2019
|
||||
|
||||
1. [](#new)
|
||||
* Added a new `[lorem]` shortcode for quickly generating lorem ipsum dummy content
|
||||
* Updated Core Thunderer Shortcode library to `0.7.3` for PHP 7.4 compatibility
|
||||
|
||||
# v4.1.6
|
||||
## 10/03/2019
|
||||
|
||||
1. [](#improved)
|
||||
* Support markdown in `Figure` shortcode caption attribute
|
||||
* FlexObjects compatibility: changed references to `Page` class to use `PageInterface`
|
||||
* Reworked the `shortcode` twig var to use a class/method approach for better compatibility in modular/page formats
|
||||
1. [](#bugfix)
|
||||
* Fix issue with `[language]` when `include_default_lang: false` [#76](https://github.com/getgrav/grav-plugin-shortcode-core/issues/76)
|
||||
|
||||
# v4.1.5
|
||||
## 09/05/2019
|
||||
|
||||
1. [](#improved)
|
||||
* Run `onContentProcessed()` event after all other plugins [#75](https://github.com/getgrav/grav-plugin-shortcode-core/issues/75)
|
||||
|
||||
# v4.1.4
|
||||
## 08/11/2019
|
||||
|
||||
1. [](#new)
|
||||
* Added a new `[details][/details]` shortcode [#72](https://github.com/getgrav/grav-plugin-shortcode-core/pull/72)
|
||||
1. [](#improved)
|
||||
* Fixed regression issue introduced in v1.4.3 [#73](https://github.com/getgrav/grav-plugin-shortcode-core/issues/73)
|
||||
|
||||
# v4.1.3
|
||||
## 08/09/2019
|
||||
|
||||
1. [](#improved)
|
||||
* Fix for shortcode objects not being available. For example `[section][/section]` not working previously without `process: twig: true`
|
||||
* `README.md` improvements
|
||||
|
||||
# v4.1.2
|
||||
## 06/22/2019
|
||||
|
||||
1. [](#new)
|
||||
* Added new `h#` tags for `h1` through `h6` supporting `class` and `id` attributes
|
||||
1. [](#improved)
|
||||
* Make `ShortcodeManager::setStates()` more flexible to accept any type of object
|
||||
|
||||
# v4.1.1
|
||||
## 04/23/2019
|
||||
|
||||
1. [](#improved)
|
||||
* Updated Core Thunderer Shortcode library to `0.7.2`
|
||||
|
||||
# v4.1.0
|
||||
## 04/14/2019
|
||||
|
||||
1. [](#new)
|
||||
* Support for a `ShortCodeManager::getRawHandlers()` to support shortcodes that need to process **before** Markdown (like upcoming `Prism-Highlighter`)
|
||||
|
||||
# v4.0.1
|
||||
## 03/21/2019
|
||||
|
||||
1. [](#new)
|
||||
* Added a new `[mark][/mark]` shortcode which makes highlighting in code blocks much simpler!
|
||||
|
||||
# v4.0.0
|
||||
## 03/20/2019
|
||||
|
||||
1. [](#improved)
|
||||
* Improved way to handle shortcodeAssets from `Page::contentMeta()` - Fixes numerous issues
|
||||
* Allow `size` shortcode to handle non-numeric values (e.g. `%`, `x-large`, etc.) [#63](https://github.com/getgrav/grav-plugin-shortcode-core/pull/63)
|
||||
* Added FontAwesome 5 support [#56](https://github.com/getgrav/grav-plugin-shortcode-core/pull/56)
|
||||
|
||||
# v3.1.2
|
||||
## 03/15/2019
|
||||
|
||||
1. [](#improved)
|
||||
* Added a helper method to allow `getBbCode()` to work with `wordpress` parser
|
||||
|
||||
# v3.1.1
|
||||
## 03/12/2019
|
||||
|
||||
1. [](#bugfix)
|
||||
* Reverted accidental change of default parser. Should be `regular`
|
||||
|
||||
# v3.1.0
|
||||
## 02/28/2019
|
||||
|
||||
1. [](#improved)
|
||||
* Modified priority of `onPluginsInitialized` to fire earlier
|
||||
1. [](#bugfix)
|
||||
* New language shortcode, for example `[lang=en]...[/lang]`
|
||||
|
||||
# v3.0.1
|
||||
## 02/03/2019
|
||||
|
||||
1. [](#bugfix)
|
||||
* Fixed issues with `0` param and `regular` parser [#14](https://github.com/getgrav/grav-plugin-shortcode-core/issues/14) [#57](https://github.com/getgrav/grav-plugin-shortcode-core/issues/57) [shortcode-ui#29](https://github.com/getgrav/grav-plugin-shortcode-ui/issues/29) [shortcode-ui#6](https://github.com/getgrav/grav-plugin-shortcode-ui/issues/26)
|
||||
|
||||
# v3.0.0
|
||||
## 12/19/2018
|
||||
|
||||
1. [](#new)
|
||||
* Update to latest Shortcode library `v0.7.0` which has over **10X performance** for default regular parser
|
||||
* Added an option `admin_pages_only` to only process actual `user/pages/` based pages and not dynamic pages to increase performance
|
||||
|
||||
# v2.7.3
|
||||
## 12/07/2018
|
||||
|
||||
1. [](#new)
|
||||
* Added a new `figure` shortcode [#51](https://github.com/getgrav/grav-plugin-shortcode-core/pull/51)
|
||||
1. [](#bugfix)
|
||||
* Fix empty space at the end of a line [#54](https://github.com/getgrav/grav-plugin-shortcode-core/pull/54)
|
||||
|
||||
# v2.7.2
|
||||
## 10/26/2018
|
||||
|
||||
1. [](#new)
|
||||
* Added a new `span` shortcode that supports `class` and `id` attributes
|
||||
1. [](#improved)
|
||||
* Switched default parser to `regular`
|
||||
* Using latest `dev-master` version which has a couple of key fixes
|
||||
|
||||
# v2.7.1
|
||||
## 03/14/2018
|
||||
|
||||
1. [](#improved)
|
||||
* Support shortcodes in theme as well as plugins [#43](https://github.com/getgrav/grav-plugin-shortcode-core/issues/43)
|
||||
|
||||
# v2.7.0
|
||||
## 01/16/2018
|
||||
|
||||
1. [](#new)
|
||||
* Added a new `div` shortcode that supports `class` and `id` attributes
|
||||
|
||||
# v2.6.0
|
||||
## 04/25/2017
|
||||
|
||||
1. [](#new)
|
||||
* Added ability to define a custom shortcode path for you own shortcodes [#36](https://github.com/getgrav/grav-plugin-shortcode-core/issues/36)
|
||||
* Added a twig filter to allow you to use shortcodes directly in Twig templates [#33](https://github.com/getgrav/grav-plugin-shortcode-core/pull/33)
|
||||
|
||||
# v2.5.4
|
||||
## 02/26/2017
|
||||
|
||||
1. [](#bugfix)
|
||||
* Fixed issue with modular Shortcode meta was not getting processed properly (Assets, Sections, etc.)
|
||||
|
||||
# v2.5.3
|
||||
## 02/21/2017
|
||||
|
||||
1. [](#improved)
|
||||
* Added a reference to current Page in `ShortcodeManager`
|
||||
|
||||
# v2.5.2
|
||||
## 01/26/2017
|
||||
|
||||
1. [](#bugfix)
|
||||
* Fixed Mozilla column css prefix
|
||||
|
||||
# v2.5.1
|
||||
## 01/25/2017
|
||||
|
||||
1. [](#improved)
|
||||
* Added `moz-` prefix in column shortcode
|
||||
|
||||
# v2.5.0
|
||||
## 01/25/2017
|
||||
|
||||
1. [](#new)
|
||||
* Added **new** `columns` shortcode for CSS columns support
|
||||
|
||||
# v2.4.0
|
||||
## 01/17/2017
|
||||
|
||||
1. [](#improved)
|
||||
* Switched to `Regex` parser by default (previous was Regex)
|
||||
* Update to latest Shortcode library v0.6.5
|
||||
1. [](#bugfix)
|
||||
* Removed `getParameterAt(0)` hack in favor of `getBbbCode()` that works with Regex parser
|
||||
|
||||
# v2.3.2
|
||||
## 12/15/2016
|
||||
|
||||
1. [](#improved)
|
||||
* Update to latest Shortcode library v0.6.4 to address a parser bug [#25](https://github.com/getgrav/grav-plugin-shortcode-core/issues/25)
|
||||
|
||||
# v2.3.1
|
||||
## 07/14/2016
|
||||
|
||||
1. [](#improved)
|
||||
* renamed internal `contentMeta` variables to `shortcodeMeta` and `shortcodeAssets`
|
||||
* Update to latest Shortcode library
|
||||
|
||||
# v2.3.0
|
||||
## 05/20/2016
|
||||
|
||||
1. [](#improved)
|
||||
* Use new conentmeta approach from Grav 1.1
|
||||
|
||||
# v2.2.1
|
||||
## 05/09/2016
|
||||
|
||||
1. [](#bugfix)
|
||||
* Always initialize current page even if collection exists [#3](https://github.com/getgrav/grav-plugin-shortcode-ui/issues/3)
|
||||
|
||||
# v2.2.0
|
||||
## 04/23/2016
|
||||
|
||||
1. [](#new)
|
||||
* Added **new** `fa` FontAwesome shortcode
|
||||
|
||||
# v2.1.0
|
||||
## 04/21/2016
|
||||
|
||||
1. [](#new)
|
||||
* Added **new** `notice` shortcode
|
||||
1. [](#improved)
|
||||
* Updated to latest Shortcode library version
|
||||
|
||||
# v2.0.2
|
||||
## 02/17/2016
|
||||
|
||||
1. [](#bugfix)
|
||||
* Initialized states in constructor
|
||||
|
||||
# v2.0.1
|
||||
## 02/16/2016
|
||||
|
||||
1. [](#improved)
|
||||
* Support **modular** pages by populating Twig variables in `onTwigPageVariables()` event #8
|
||||
1. [](#bugfix)
|
||||
* Better more flexible regex in the Markdown **block** definition for more reliable markdown in shortcodes. #3
|
||||
|
||||
# v2.0.0
|
||||
## 02/11/2016
|
||||
|
||||
1. [](#new)
|
||||
* Added **new** `section` shortcode
|
||||
* Use new `contentMeta` mechanism for storing/caching objects and assets per page
|
||||
* Added new `ShortcodeManager::reset()` methods
|
||||
1. [](#improved)
|
||||
* Completely refactored the plugin to use a new extensible mechanism that makes it easier to manage multiple shortcodes
|
||||
|
||||
# v1.4.0
|
||||
## 02/03/2016
|
||||
|
||||
1. [](#improved)
|
||||
* Updated Shortcode to latest `dev-master` that includes Events
|
||||
1. [](#bugfix)
|
||||
* Fixed `raw` shortcode to use new `FilterRawEventHandler` so it doesn't process shortcodes at all
|
||||
|
||||
# v1.3.0
|
||||
## 01/29/2016
|
||||
|
||||
1. [](#improved)
|
||||
* Added markdown-shortcode-block support to the plugin
|
||||
1. [](#bugfix)
|
||||
* Updated Core Thunderer Shortcode library with some important fixes
|
||||
|
||||
# v1.2.0
|
||||
## 01/25/2016
|
||||
|
||||
1. [](#improved)
|
||||
* Customizable Parser. Choose from `WordPress`, `Regex`, and `Regular`
|
||||
|
||||
# v1.1.0
|
||||
## 01/24/2016
|
||||
|
||||
1. [](#improved)
|
||||
* Updated to latest Shortcode `dev-master` version that contains some important fixes
|
||||
* Switched to `WordPressParser` for 2x speed improvements
|
||||
|
||||
# v1.0.1
|
||||
## 01/18/2016
|
||||
|
||||
1. [](#bugfix)
|
||||
* Fixed blueprint
|
||||
* Fixed a default yaml state
|
||||
|
||||
|
||||
# v1.0.0
|
||||
## 01/18/2016
|
||||
|
||||
1. [](#new)
|
||||
* ChangeLog started...
|
21
plugins/shortcode-core/LICENSE
Normal file
21
plugins/shortcode-core/LICENSE
Normal file
@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016 Grav
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
575
plugins/shortcode-core/README.md
Normal file
575
plugins/shortcode-core/README.md
Normal file
@ -0,0 +1,575 @@
|
||||
# Grav Shortcode Core Plugin
|
||||
|
||||
## About
|
||||
|
||||
The **Shortcode Core** plugin allow for the development of simple yet powerful shortcode plugins that utilize the common format utilized by **WordPress** and **BBCode**. The core plugin loads the libraries required and fires a new event that other plugins can use. It also provides a mechanism for adding CSS/JS assets that are cached so that shortcodes can work effectively even when the processed page content is cached. This ensures that shortcodes are only processed once and will not impact performance by doing unnecessary work on every page.
|
||||
|
||||
This plugin uses the [Thunderer Advanced shortcode engine](https://github.com/thunderer/Shortcode). For more information please check out that repo on GitHub.
|
||||
|
||||
## Quick Example
|
||||
|
||||
```
|
||||
This is some [u]bb style underline[/u] and not much else
|
||||
|
||||
[center]This is centered[/center]
|
||||
|
||||
This is [size=30]bigger text[/size] and this is [color=blue]blue text[/color]
|
||||
```
|
||||
|
||||
This example functionality is provided with the **Shortcode Core** plugin to provide some functionality that is not available in traditional markdown but is standard **BBCode** used in many form platforms. You can see how the syntax is just a simple open and close element using square brackets.
|
||||
|
||||
This will render:
|
||||
|
||||
![](assets/shortcode-core-1.png)
|
||||
|
||||
The core plugin required for any other shortcode specific plugin. Provides some basic BBCode style syntax such as underline, color, center, and size.
|
||||
|
||||
## Installation
|
||||
|
||||
Typically a plugin should be installed via [GPM](http://learn.getgrav.org/advanced/grav-gpm) (Grav Package Manager):
|
||||
|
||||
```
|
||||
$ bin/gpm install shortcode-core
|
||||
```
|
||||
|
||||
Alternatively it can be installed via the [Admin Plugin](http://learn.getgrav.org/admin-panel/plugins)
|
||||
|
||||
> NOTE: If you install a shortcode plugin such as [grav-plugin-shortcode-ui](https://github.com/getgrav/grav-plugin-shortcode-ui) it may have this core plugin configured as a dependency and install it automatically.
|
||||
|
||||
## Configuration Defaults
|
||||
|
||||
The **Shortcode Core** plugin only has a few options to configure. The default values are:
|
||||
|
||||
```yaml
|
||||
enabled: true
|
||||
active: true
|
||||
active_admin: true
|
||||
admin_pages_only: true
|
||||
parser: regular
|
||||
include_default_shortcodes: true
|
||||
css:
|
||||
notice_enabled: true
|
||||
custom_shortcodes:
|
||||
fontawesome:
|
||||
load: true
|
||||
url: '//maxcdn.bootstrapcdn.com/font-awesome/4.6.1/css/font-awesome.min.css'
|
||||
v5: false
|
||||
```
|
||||
|
||||
* `enabled: true|false` toggles if the shortcodes plugin is turned on or off
|
||||
* `active: true|false` toggles if shortcodes will be enabled site-wide or not
|
||||
* `active_admin: true|false` toggles if shortcodes will be processed in the admin plugin
|
||||
* `admin_pages_only: true|false` toggles if admin should only process shortcodes for Grav pages
|
||||
* `parser: wordpress|regex|regular` let's you configure the parser to use
|
||||
* `include_default_shortcodes: true|false` toggle the inclusion of shortcodes provided by this plugin
|
||||
* `custom_shortcodes:` the path to a directory where you can put your custom shortcodes (e.g. `/user/custom/shortcodes`)
|
||||
* `fontawesome.load: true|false` toggles if the fontawesome icon library should be loaded or not
|
||||
* `fontawesome.url:` the CDN Url to use for fontawesome
|
||||
* `v5:` Version 5 flag as it requires some additional logic
|
||||
|
||||
> NOTE: In previous versions the `wordpress` parser was preferred. However with version `2.4.0`, the `regex` parser is now default. If you have saved configuration, you should manually change this to `regex` or you may receive errors or bad output.
|
||||
|
||||
## Configuration Modifications
|
||||
|
||||
The best approach to make modifications to the core plugin settings is to copy the `shortcode-core.yaml` file from the plugin into your `user/config/plugins/` folder (create it if it doesn't exist). You can modify the settings there.
|
||||
|
||||
> NOTE: If you have the admin plugin installed, you can make modifications to the settings via the **Plugins** page and it will create that overridden file automatically.
|
||||
|
||||
## Per-Page Configuration
|
||||
|
||||
Sometimes you may want to only enable shortcodes on a _page-by-page_ basis. To accomplish this set your plugin defaults to:
|
||||
|
||||
```yaml
|
||||
enabled: true
|
||||
active: false
|
||||
```
|
||||
|
||||
This will ensure the plugin is loaded, but not **active**, then on the page you wish to process shortcodes on simply add this to the page header:
|
||||
|
||||
```yaml
|
||||
shortcode-core:
|
||||
active: true
|
||||
```
|
||||
|
||||
This will ensure the shortcodes are processed on this page only.
|
||||
|
||||
You can also change the parser on a particular page with the following:
|
||||
|
||||
```yaml
|
||||
shortcode-core:
|
||||
parser: regex
|
||||
```
|
||||
|
||||
## Available Shortcodes
|
||||
|
||||
The core plugin contains a few simple shortcodes that can be used as basic examples:
|
||||
|
||||
#### Underline
|
||||
|
||||
Underline a section of text
|
||||
|
||||
```
|
||||
This is some [u]bb style underline[/u] and not much else
|
||||
```
|
||||
|
||||
#### Font Size
|
||||
|
||||
Set the size of some text to a specific pixel size
|
||||
|
||||
```
|
||||
This is [size=30]bigger text[/size]
|
||||
```
|
||||
|
||||
#### Left Align
|
||||
|
||||
Left align the text between this shortcode
|
||||
|
||||
```
|
||||
[left]This text is left aligned[/left]
|
||||
```
|
||||
|
||||
#### Center Align
|
||||
|
||||
Center a selection of text between this shortcode
|
||||
|
||||
```
|
||||
[center]This text is centered[/center]
|
||||
```
|
||||
|
||||
#### Right Align
|
||||
|
||||
Right align the text between this shortcode
|
||||
|
||||
```
|
||||
[right]This text is right aligned[/right]
|
||||
```
|
||||
|
||||
|
||||
#### Div
|
||||
|
||||
Allows you to wrap markdown in an HTML `div` tag that supports both `id` and `classes` attributes
|
||||
|
||||
```
|
||||
[div class="text-center"]
|
||||
This text is **centered** aligned
|
||||
[/div]
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```
|
||||
[div class="table table-striped"]
|
||||
| header 1 | header 2 |
|
||||
|----------|----------|
|
||||
| A 1 | B 1 |
|
||||
| A 2 | B 2 |
|
||||
| A 3 | B 3 |
|
||||
[/div]
|
||||
```
|
||||
|
||||
#### Headers
|
||||
|
||||
Allows you to add `id` and `class` attributes to HTML `h1` through `h6` tags:
|
||||
|
||||
```
|
||||
[h1 class="major"]This is my title[/h1]
|
||||
```
|
||||
|
||||
#### Span
|
||||
|
||||
Allows you to wrap markdown in an HTML `span` tag that supports both `id` and `class` attributes
|
||||
|
||||
```
|
||||
[span class="text-center"]
|
||||
This text is **centered** aligned
|
||||
[/span]
|
||||
```
|
||||
|
||||
#### Columns
|
||||
|
||||
Take advantage of powerful CSS columns support by using this shortcode
|
||||
|
||||
```
|
||||
[columns]
|
||||
### Headline
|
||||
|
||||
Lorem ipsum dolor sit amet, consectetur adipisicing 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.
|
||||
|
||||
Duis aute irure dolor in reprehenderit in voluptate velit esse
|
||||
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
|
||||
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
|
||||
|
||||
Lorem ipsum dolor sit amet, consectetur adipisicing 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.
|
||||
[/columns]
|
||||
```
|
||||
|
||||
Defaults to 2 columns. You can also explicitly set the number of `columns`, `width`, `gap`, and `rule` styling for the column divider:
|
||||
|
||||
```
|
||||
[columns count=3 width=200px gap=30px rule="1px dotted #930"]
|
||||
### Headline
|
||||
|
||||
Lorem ipsum dolor sit amet, consectetur adipisicing 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.
|
||||
|
||||
Duis aute irure dolor in reprehenderit in voluptate velit esse
|
||||
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
|
||||
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
|
||||
|
||||
Lorem ipsum dolor sit amet, consectetur adipisicing 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.
|
||||
[/columns]
|
||||
```
|
||||
|
||||
#### Raw
|
||||
|
||||
Do not process the shortcodes between these raw shortcode tags
|
||||
|
||||
```
|
||||
[raw]This is some [u]bb style underline[/u] and not much else[/raw]
|
||||
```
|
||||
|
||||
#### Safe-Email
|
||||
|
||||
Encode an email address so that it's not so easily 'scrapable' by nefarious scripts. This one has a couple of options: `autolink` toggle to turn the email into a link, and an `icon` option that lets you pick a font-awesome icon to prefix the email. Both settings are optional.
|
||||
|
||||
```
|
||||
Safe-Email Address: [safe-email autolink="true" icon="envelope-o"]user@domain.com[/safe-email]
|
||||
```
|
||||
|
||||
#### Section
|
||||
|
||||
The **section** shortcode is a powerful way to encompass some text in your markdown page with a `[section][/section]` tag and then this is cached by Grav so it can be accessed later. For example you could have a page with a variety of sections described in it that let you create many **chunks** of data. These are then added to Twig as an array of shortcode objects. An example of this would be the following markdown:
|
||||
|
||||
```
|
||||
[section name="author"]
|
||||
![](author.jpg?cropResize=100,100&classes=left)
|
||||
### Johnny Appleseed
|
||||
Johnny Appleseed was an American pioneer nurseryman who introduced apple trees to large parts of Pennsylvania, Ontario, Ohio, Indiana, and Illinois, as well as the northern counties of present-day West Virginia. He became an American legend while still alive, due to his kind, generous ways, his leadership in conservation, and the symbolic importance he attributed to apples.
|
||||
[/section]
|
||||
|
||||
[section name="quote"]
|
||||
> Some are born great, some achieve greatness, and some have greatness thrust upon them.
|
||||
Read more at http://www.brainyquote.com/quotes/topics/topic_great.html#tdqt3strtEYBCH43.99
|
||||
> <cite>William Shakespeare</cite>
|
||||
|
||||
Regular **Markdown** content that will be output as `page.content`
|
||||
[/section]
|
||||
```
|
||||
|
||||
This we be removed from the page content and made available in Twig variables so you could insert these into custom HTML structures, for example:
|
||||
|
||||
```
|
||||
<div id="author">{{ shortcode.section.author }}</div>
|
||||
|
||||
<div id="article">
|
||||
<div class="left">
|
||||
{{ page.content|raw }}
|
||||
</div>
|
||||
<div class="right">
|
||||
{{ shortcode.section.quote }}
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
#### Sections from other pages
|
||||
|
||||
You can even retrieve a section from another page utilizing the shortcodes as they are stored in the page's `contentMeta` with this syntax:
|
||||
|
||||
```
|
||||
<div id="author">{{ page.find('/my/custom/page').contentMeta.shortcodeMeta.shortcode.section.author }}</div>
|
||||
```
|
||||
|
||||
#### Notice
|
||||
|
||||
A useful shortcode that performs a similar job to the [markdown-notices](https://github.com/getgrav/grav-plugin-markdown-notices) plugins, allows you to easily create simple notice blocks as seen on http://learn.getgrav.org and http://getgrav.org. To use simply use the following syntax:
|
||||
|
||||
```
|
||||
[notice]
|
||||
Your **Markdown** text that will appear in the notice
|
||||
[/notice]
|
||||
```
|
||||
|
||||
You can also specifically choose from `note`, `info`, `warning`, `tip` types which provide unique color options:
|
||||
|
||||
```
|
||||
[notice=warning]
|
||||
Danger Will Robinson! Danger, Will Robinson!
|
||||
[/notice]
|
||||
```
|
||||
#### Figure
|
||||
|
||||
Figure elements are the recommended way to add self-contained units of flow content, i.e. images, charts and other visual elements that can be moved away from the main flow of the document without affecting the document's meaning. Figures may include captions through the `caption` attribute. Both `id` and `class` attributes are also available.
|
||||
|
||||
```
|
||||
[figure id="fig1" class="image" caption="**Fig. 1** A beautiful figure."]
|
||||
![Gorgeous image](image.png)
|
||||
[/figure]
|
||||
```
|
||||
|
||||
#### Mark
|
||||
|
||||
The HTML `<mark></mark>` tag is extremely useful to highlight text in your pages, and serves like a highlighter pen. However, as we know that markdown inside of HTML is not processed, using this HTML is often not convenient as it means markdown inside will not be processed.
|
||||
|
||||
Another important usecase is trying to highlight code in a markdown text block, again the HTML tag doesn't work because the result is escaped and treated like any other code and simply displayed.
|
||||
|
||||
The solution is simple, just use the shortcode version instead:
|
||||
|
||||
```
|
||||
This is a sample of text [mark]with this bit **highlighted** with _markdown_ syntax[/mark] and the rest just plain.
|
||||
```
|
||||
|
||||
You can also use the `class` option to specificy a specific a CSS class to add to the `<mark>` HTML tag (useful to color the marked output):
|
||||
|
||||
```
|
||||
This is a sample of text [mark class=blue]with this bit **highlighted** with _markdown_ syntax[/mark] and the rest just plain.
|
||||
```
|
||||
|
||||
It also works great in code blocks:
|
||||
|
||||
```
|
||||
<?php
|
||||
class Pipeline extends PropertyObject
|
||||
{
|
||||
use AssetUtilsTrait;
|
||||
|
||||
[mark]protected const CSS_ASSET = true;[/mark]
|
||||
protected const JS_ASSET = false;
|
||||
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
You can also pass an option `style` attribute of `block` to get a full lines highlighted:
|
||||
|
||||
```
|
||||
<?php
|
||||
class Pipeline extends PropertyObject
|
||||
{
|
||||
use AssetUtilsTrait;
|
||||
|
||||
[mark style=block]
|
||||
protected const CSS_ASSET = true;
|
||||
protected const JS_ASSET = false;
|
||||
[/mark]
|
||||
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
#### Language
|
||||
|
||||
Hooks into Grav's multi-language capabilities to allow you to show certain blocks of code only for the current active language.
|
||||
|
||||
```
|
||||
[lang=en]
|
||||
Or kind rest bred with am shed then.
|
||||
[/lang]
|
||||
|
||||
[lang=fr]
|
||||
Marche diable ombres net non qui.
|
||||
[/lang]
|
||||
|
||||
[lang=de]
|
||||
Genie dahin einem ein gib geben allen.
|
||||
[/lang]
|
||||
```
|
||||
|
||||
#### FontAwesome
|
||||
|
||||
[FontAwesome](https://fortawesome.github.io/Font-Awesome/) is a powerful library of font-based icons. This shortcode makes it simple to add fontawesome icons to your page content without using HTML.
|
||||
|
||||
```
|
||||
[fa=cog /] Simplest Format
|
||||
|
||||
[fa=fa-cog /] Format using `fa-` prefix
|
||||
|
||||
[fa icon=fa-camera-retro /] Explicit format
|
||||
|
||||
[fa icon=fa-grav extras=fab /] Font Awesome 5 format
|
||||
|
||||
[fa icon=fa-camera-retro extras=fa-4x /] Explicit format with extras - [See FontAwesome Examples](https://fortawesome.github.io/Font-Awesome/examples/)
|
||||
|
||||
[fa icon=fa-circle-o-notch extras=fa-spin,fa-3x,fa-fw,margin-bottom /] The full monty! - [See FontAwesome Examples](https://fortawesome.github.io/Font-Awesome/examples/)
|
||||
```
|
||||
|
||||
#### Details/Summary
|
||||
|
||||
The `<details>` element provides a simple show/hide behaviour without JavaScript, and can optionally contain a `<summary>` element that is always shown. Clicking on the summary text toggles the visibility of the content, and when a summary is not provided, it defaults to "Details". The element can be used to provide extra details, or can be combined into an accordion-like structure.
|
||||
|
||||
```
|
||||
[details]
|
||||
Lorem ipsum dolor sit amet...
|
||||
[/details]
|
||||
|
||||
[details="Summary text"]
|
||||
Lorem ipsum dolor sit amet...
|
||||
[/details]
|
||||
|
||||
[details summary="Summary text" class="accordion"]
|
||||
Lorem ipsum dolor sit amet...
|
||||
[/details]
|
||||
```
|
||||
|
||||
**Note:** The show/hide behaviour is not supported in IE 11 or Edge 18, and the element will be permanently open. You can check the current status of browser compatibility at [Can I Use](https://caniuse.com/#search=details).
|
||||
|
||||
#### Lorem Ipsum
|
||||
|
||||
Useful for faking content, you can use a shortcode to quickly generate some random "lorem ipsum" text:
|
||||
|
||||
**Paragraphs:**
|
||||
```
|
||||
[lorem=5 /]
|
||||
|
||||
[lorem p=5 tag=div /]
|
||||
```
|
||||
|
||||
**Sentences:**
|
||||
```
|
||||
[lorem s=4 /]
|
||||
```
|
||||
|
||||
**Words:**
|
||||
```
|
||||
[lorem w=35 /]
|
||||
```
|
||||
|
||||
## Using Shortcodes in Twig
|
||||
|
||||
You can now use shortcodes in Twig templates and process them with the `|shortcodes` filter. For example:
|
||||
|
||||
```
|
||||
{% set twig_text = "This is [size=30]bigger text[/size] and this is [color=green]green text[/color]" %}
|
||||
{{ twig_text|shortcodes }}
|
||||
```
|
||||
|
||||
## Custom Shortcodes
|
||||
|
||||
### Simple Way
|
||||
|
||||
First, configure a directory from which custom shortcodes are loaded. Edit `user/config/plugins/shortcode-core.yaml` like follows (create it if it does not exist):
|
||||
|
||||
```yaml
|
||||
custom_shortcodes: '/user/custom/shortcodes'
|
||||
```
|
||||
|
||||
To add a custom shortcode, create a PHP file that defines a new shortcode class. For example, to create a shortcode for ~~strikethrough~~ text, save the following code as `user/custom/shortcodes/StrikeShortcode.php`:
|
||||
|
||||
```php
|
||||
<?php
|
||||
namespace Grav\Plugin\Shortcodes;
|
||||
|
||||
use Thunder\Shortcode\Shortcode\ShortcodeInterface;
|
||||
|
||||
class StrikeShortcode extends Shortcode
|
||||
{
|
||||
public function init()
|
||||
{
|
||||
$this->shortcode->getHandlers()->add('strike', function(ShortcodeInterface $sc) {
|
||||
return '<del>'.$sc->getContent().'</del>';
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Note that the class name (`StrikeShortcode`) must match the file name for the shortcode to work.
|
||||
|
||||
`[strike]text[/strike]` should now produce strikethrough text.
|
||||
|
||||
### As a Custom Plugin
|
||||
|
||||
The more flexible approach is to create a custom plugin.
|
||||
|
||||
The **Shortcode Core** plugin is developed on the back of the [Thunderer Advanced Shortcode Engine](https://github.com/thunderer/Shortcode) and as such loads the libraries and classes required to build third party shortcode plugins.
|
||||
|
||||
We introduced a new event called `onShortcodeHandlers()` that allows a 3rd party plugin to create and add their own custom handlers. These are then all processed by the core plugin in one shot.
|
||||
|
||||
```php
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return [
|
||||
'onShortcodeHandlers' => ['onShortcodeHandlers', 0]
|
||||
];
|
||||
}
|
||||
```
|
||||
|
||||
Then you just need to listen to the event:
|
||||
|
||||
```php
|
||||
public function onShortcodeHandlers()
|
||||
{
|
||||
$this->grav['shortcode']->registerAllShortcodes(__DIR__.'/shortcodes');
|
||||
}
|
||||
```
|
||||
|
||||
Lastly create your shortcode in the `user/plugins/my-plugin/shortcodes/` folder, in this example we created a simple `[red][/red]` shortcode as `RedShortcode.php`:
|
||||
|
||||
```php
|
||||
<?php
|
||||
namespace Grav\Plugin\Shortcodes;
|
||||
|
||||
use Thunder\Shortcode\Shortcode\ShortcodeInterface;
|
||||
|
||||
class RedShortcode extends Shortcode
|
||||
{
|
||||
public function init()
|
||||
{
|
||||
$this->shortcode->getHandlers()->add('red', function(ShortcodeInterface $sc) {
|
||||
return '<span style="color:red;">'.$sc->getContent().'</span>';
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
> If you have not already done so, I suggest reading the [Grav Plugin Tutorial](http://learn.getgrav.org/plugins/plugin-tutorial) first to gain a full understanding of what you need to develop a Grav plugin.
|
||||
|
||||
The best way to see how to create a new shortcode-based plugins is to look at the **Shortcode UI** plugin that extends the **Shortcode Core** by adding more shortcodes. It also makes use of Twig to handle processing and has some more advanced shortcode techniques.
|
||||
|
||||
* Core Plugin: https://github.com/getgrav/grav-plugin-shortcode-ui/blob/develop/shortcode-ui.php
|
||||
* Tabs Shortcode Example: https://github.com/getgrav/grav-plugin-shortcode-ui/blob/develop/shortcodes/TabsShortcode.php
|
||||
* Color Shortcode Example: https://github.com/getgrav/grav-plugin-shortcode-core/blob/develop/shortcodes/ColorShortcode.php
|
||||
* Section Shortcode Example: https://github.com/getgrav/grav-plugin-shortcode-core/blob/develop/shortcodes/SectionShortcode.php
|
||||
* Section Prism Highlight Example: https://github.com/trilbymedia/grav-plugin-prism-highlight/blob/develop/shortcodes/PrismShortcode.php
|
||||
|
||||
## Processing Shortcodes Before or After Markdown processing
|
||||
|
||||
There are basically two ways of processing a shortcode:
|
||||
|
||||
1. After markdown is processed
|
||||
2. Before markdown is processed
|
||||
|
||||
These two approaches are important because, for the most part, shortcodes make more sense when they can 'wrap' markdown, so they process **after** markdown.
|
||||
|
||||
For example a `[div][/div]` shortcode would be useless if it ran before markdown is processed because it would add the relevant HTML `<div></div>` tags, and then the markdown parser would promptly **skip** all markdown processing between those divs because it won't process markdown **inside** HTML. So this shortcode and most others run after markdown processing has already occurred using this approach:
|
||||
|
||||
```php
|
||||
$this->shortcode->getHandlers()->add('div', function(ShortcodeInterface $sc) { ... }
|
||||
```
|
||||
Notice the `getHandlers()` call is the standard way to add a handler.
|
||||
|
||||
However, there are situations when you need to process the shortcode **before** the markdown processing to ensure markdown **is skipped**, like in the example of a code block. This is why in the [Prism Highlighter](https://github.com/trilbymedia/grav-plugin-prism-highlight) plugin, we use this approach to defining the shortcode:
|
||||
|
||||
```php
|
||||
$this->shortcode->getRawHandlers()->add('prism', function(ProcessedShortcode $sc) { ... }
|
||||
```
|
||||
|
||||
The difference here is it uses `getRawHandlers()` to ensure the handler is processed to the content in the _raw_ state.
|
||||
|
||||
## Display All Shortcodes
|
||||
|
||||
You can now display all available shortcodes by using the CLI command:
|
||||
|
||||
```shell
|
||||
bin/plugin shortcode-core display
|
||||
```
|
BIN
plugins/shortcode-core/assets/shortcode-core-1.png
Normal file
BIN
plugins/shortcode-core/assets/shortcode-core-1.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 16 KiB |
127
plugins/shortcode-core/blueprints.yaml
Normal file
127
plugins/shortcode-core/blueprints.yaml
Normal file
@ -0,0 +1,127 @@
|
||||
name: Shortcode Core
|
||||
slug: shortcode-core
|
||||
type: plugin
|
||||
version: 5.1.3
|
||||
description: "This plugin provides the core functionality for shortcode plugins"
|
||||
icon: code
|
||||
author:
|
||||
name: Team Grav
|
||||
email: devs@getgrav.org
|
||||
url: http://getgrav.org
|
||||
homepage: https://github.com/getgrav/grav-plugin-shortcode-core
|
||||
demo: http://learn.getgrav.org
|
||||
keywords: gui, plugin, tabs, twig
|
||||
bugs: https://github.com/getgrav/grav-plugin-shortcode-core/issues
|
||||
license: MIT
|
||||
|
||||
dependencies:
|
||||
- { name: grav, version: '>=1.6.4' }
|
||||
|
||||
form:
|
||||
validation: strict
|
||||
fields:
|
||||
enabled:
|
||||
type: toggle
|
||||
label: Plugin Enabled
|
||||
highlight: 1
|
||||
default: 1
|
||||
options:
|
||||
1: Enabled
|
||||
0: Disabled
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
active:
|
||||
type: toggle
|
||||
label: Activated
|
||||
help: Site-Wide activation
|
||||
highlight: 1
|
||||
default: 1
|
||||
options:
|
||||
1: Enabled
|
||||
0: Disabled
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
active_admin:
|
||||
type: toggle
|
||||
label: Activated in Admin
|
||||
highlight: 1
|
||||
default: 1
|
||||
options:
|
||||
1: Enabled
|
||||
0: Disabled
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
admin_pages_only:
|
||||
type: toggle
|
||||
label: Admin Real-Pages Only
|
||||
help: When activate, only process real-pages
|
||||
highlight: 1
|
||||
default: 1
|
||||
options:
|
||||
1: Enabled
|
||||
0: Disabled
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
parser:
|
||||
type: select
|
||||
size: medium
|
||||
classes: fancy
|
||||
label: Processor
|
||||
help: Which built-in processor to use. WordPress (fastest), Regular (customizable), Regex (solid)
|
||||
options:
|
||||
wordpress: WordpressParser
|
||||
regex: RegexParser
|
||||
regular: RegularParser
|
||||
|
||||
custom_shortcodes:
|
||||
type: text
|
||||
label: Custom Shortcodes
|
||||
help: The path to a location where you store custom shortcodes.
|
||||
placeholder: '/user/custom/shortcodes'
|
||||
size: large
|
||||
|
||||
css.notice_enabled:
|
||||
type: toggle
|
||||
label: Enable Notice Shortcode CSS
|
||||
help: Enable the default notice CSS by default. Disable if you want to use your own custom CSS.
|
||||
highlight: 1
|
||||
default: 1
|
||||
options:
|
||||
1: Enabled
|
||||
0: Disabled
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
fontawesome.load:
|
||||
type: toggle
|
||||
label: Load Fontawesome Library
|
||||
help: Used by the `safe-email` shortcode if your theme doesn't already load it
|
||||
highlight: 1
|
||||
default: 1
|
||||
options:
|
||||
1: Enabled
|
||||
0: Disabled
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
fontawesome.url:
|
||||
type: text
|
||||
label: Fontawesome URL
|
||||
help: You can change the location of fontawesome by changing this URL
|
||||
size: large
|
||||
|
||||
fontawesome.v5:
|
||||
type: toggle
|
||||
label: Use Fontawesome Version 5
|
||||
help: Allows usage of the 'fab', 'fas' and other new font families of Fontawesome 5.
|
||||
highlight: 0
|
||||
default: 0
|
||||
options:
|
||||
1: Enabled
|
||||
0: Disabled
|
||||
validate:
|
||||
type: bool
|
7
plugins/shortcode-core/classes/Shortcode.php
Normal file
7
plugins/shortcode-core/classes/Shortcode.php
Normal file
@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
// This file is for older Grav versions (needed during plugin update).
|
||||
|
||||
if (!class_exists(\Grav\Plugin\Shortcodes\Shortcode::class, false)) {
|
||||
require_once __DIR__ . '/shortcodes/Shortcode.php';
|
||||
}
|
15
plugins/shortcode-core/classes/ShortcodeManager.php
Normal file
15
plugins/shortcode-core/classes/ShortcodeManager.php
Normal file
@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
// This file is for older Grav versions (needed during plugin update).
|
||||
|
||||
@trigger_error(
|
||||
'\\Grav\\Plugin\\ShortcodeManager class is deprecated, use \\Grav\\Plugin\\ShortcodeCore\\ShortcodeManager instead',
|
||||
E_USER_DEPRECATED
|
||||
);
|
||||
|
||||
if (!class_exists(\Grav\Plugin\ShortcodeCore\ShortcodeManager::class, false)) {
|
||||
require_once __DIR__ . '/plugin/ShortcodeManager.php';
|
||||
}
|
||||
|
||||
// Create alias for the deprecated class.
|
||||
class_alias(\Grav\Plugin\ShortcodeCore\ShortcodeManager::class, \Grav\Plugin\ShortcodeManager::class);
|
7
plugins/shortcode-core/classes/ShortcodeObject.php
Normal file
7
plugins/shortcode-core/classes/ShortcodeObject.php
Normal file
@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
// This file is for older Grav versions (needed during plugin update).
|
||||
|
||||
if (!class_exists(\Grav\Plugin\ShortcodeCore\ShortcodeObject::class, false)) {
|
||||
require_once __DIR__ . '/shortcodes/ShortcodeObject.php';
|
||||
}
|
24
plugins/shortcode-core/classes/plugin/Shortcode.php
Normal file
24
plugins/shortcode-core/classes/plugin/Shortcode.php
Normal file
@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace Grav\Plugin\ShortcodeCore;
|
||||
|
||||
// Check if the new class has been autoloaded. If not, trigger deprecation error.
|
||||
if (!class_exists(\Grav\Plugin\Shortcodes\Shortcode::class, false)) {
|
||||
@trigger_error(
|
||||
Shortcode::class . ' class is deprecated, use \\Grav\\Plugin\\Shortcodes\\Shortcode instead',
|
||||
E_USER_DEPRECATED
|
||||
);
|
||||
}
|
||||
|
||||
// Create alias for the deprecated class.
|
||||
class_alias(\Grav\Plugin\Shortcodes\Shortcode::class, Shortcode::class);
|
||||
|
||||
// Make sure that both IDE and composer knows about the deprecated class.
|
||||
if (false) {
|
||||
/**
|
||||
* @deprecated 4.2.1 This was a bad idea, reverting back to the old class.
|
||||
*/
|
||||
abstract class Shortcode extends \Grav\Plugin\Shortcodes\Shortcode
|
||||
{
|
||||
}
|
||||
}
|
383
plugins/shortcode-core/classes/plugin/ShortcodeManager.php
Normal file
383
plugins/shortcode-core/classes/plugin/ShortcodeManager.php
Normal file
@ -0,0 +1,383 @@
|
||||
<?php
|
||||
|
||||
namespace Grav\Plugin\ShortcodeCore;
|
||||
|
||||
use Grav\Common\Config\Config;
|
||||
use Grav\Common\Data\Data;
|
||||
use Grav\Common\Grav;
|
||||
use Grav\Common\Page\Interfaces\PageInterface;
|
||||
use Thunder\Shortcode\EventContainer\EventContainer;
|
||||
use Thunder\Shortcode\HandlerContainer\HandlerContainer;
|
||||
use Thunder\Shortcode\Parser\RegexParser;
|
||||
use Thunder\Shortcode\Parser\RegularParser;
|
||||
use Thunder\Shortcode\Parser\WordpressParser;
|
||||
use Thunder\Shortcode\Processor\Processor;
|
||||
use Thunder\Shortcode\Shortcode\ShortcodeInterface;
|
||||
use Thunder\Shortcode\Syntax\CommonSyntax;
|
||||
|
||||
class ShortcodeManager
|
||||
{
|
||||
|
||||
/** @var Grav $grav */
|
||||
protected $grav;
|
||||
|
||||
/** @var Config */
|
||||
protected $config;
|
||||
|
||||
/** @var PageInterface $page */
|
||||
protected $page;
|
||||
|
||||
/** @var HandlerContainer $handlers */
|
||||
protected $handlers;
|
||||
|
||||
/** @var HandlerContainer $raw_handlers */
|
||||
protected $raw_handlers;
|
||||
|
||||
/** @var EventContainer $events */
|
||||
protected $events;
|
||||
|
||||
/** @var array */
|
||||
protected $assets;
|
||||
|
||||
/** @var array */
|
||||
protected $states;
|
||||
|
||||
/** @var array */
|
||||
protected $objects;
|
||||
|
||||
/**
|
||||
* initialize some internal instance variables
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->grav = Grav::instance();
|
||||
$this->config = $this->grav['config'];
|
||||
$this->handlers = new HandlerContainer();
|
||||
$this->raw_handlers = new HandlerContainer();
|
||||
$this->events = new EventContainer();
|
||||
$this->states = [];
|
||||
$this->assets = [];
|
||||
$this->objects = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* add CSS and JS assets to the Manager so that they can be saved to cache
|
||||
* for subsequent cached pages
|
||||
*
|
||||
* @param mixed $actionOrAsset the type of asset (JS or CSS) or, if the second parameter is omitted,
|
||||
* a collection or an array of asset.
|
||||
* @param string $asset the asset path in question
|
||||
*/
|
||||
public function addAssets($actionOrAsset, $asset = null)
|
||||
{
|
||||
if ($asset == null) {
|
||||
if (is_array($actionOrAsset)) {
|
||||
$this->assets[''] = array_merge($this->assets[''] ?? array(), $actionOrAsset);
|
||||
} else {
|
||||
$this->assets[''] [] = $actionOrAsset;
|
||||
}
|
||||
} else {
|
||||
if (isset($this->assets[$actionOrAsset]) && in_array($asset, $this->assets[$actionOrAsset], true)) {
|
||||
return;
|
||||
}
|
||||
$this->assets[$actionOrAsset] [] = $asset;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* return a multi-dimensional array of all the assets
|
||||
*
|
||||
* @return array the assets array
|
||||
*/
|
||||
public function getAssets()
|
||||
{
|
||||
return $this->assets;
|
||||
}
|
||||
|
||||
/**
|
||||
* reset the assets
|
||||
*/
|
||||
public function resetAssets()
|
||||
{
|
||||
$this->assets = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* adds ad object
|
||||
* @param string $key The key to look up the object
|
||||
* @param object $object The object to store
|
||||
*/
|
||||
public function addObject($key, $object)
|
||||
{
|
||||
$new = [$object->name() => $object];
|
||||
if (array_key_exists($key, $this->objects)) {
|
||||
$current = (array)$this->objects[$key];
|
||||
$this->objects[$key] = $current + $new;
|
||||
} else {
|
||||
$this->objects[$key] = $new;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* sets all the objects
|
||||
* @param array $objects The objects array
|
||||
*/
|
||||
public function setObjects($objects)
|
||||
{
|
||||
$this->objects = $objects;
|
||||
}
|
||||
|
||||
/**
|
||||
* return all the objects
|
||||
* @return array The objects array
|
||||
*/
|
||||
public function getObjects()
|
||||
{
|
||||
return $this->objects;
|
||||
}
|
||||
|
||||
/**
|
||||
* reset the objects
|
||||
*/
|
||||
public function resetObjects()
|
||||
{
|
||||
$this->objects = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the current handler container object
|
||||
*
|
||||
* @return HandlerContainer
|
||||
*/
|
||||
public function getHandlers()
|
||||
{
|
||||
return $this->handlers;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the current raw handler container object
|
||||
*
|
||||
* @return HandlerContainer
|
||||
*/
|
||||
public function getRawHandlers()
|
||||
{
|
||||
return $this->raw_handlers;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the current event container object
|
||||
*
|
||||
* @return EventContainer
|
||||
*/
|
||||
public function getEvents()
|
||||
{
|
||||
return $this->events;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register an individual shortcode with the manager so it can be operated on by the Shortcode library
|
||||
*
|
||||
* @param string $name the name of the shortcode (should match the classname)
|
||||
* @param string|null $directory directory where the shortcode is located
|
||||
*/
|
||||
public function registerShortcode($name, $directory = null)
|
||||
{
|
||||
$className = 'Grav\\Plugin\\Shortcodes\\' . basename($name, '.php');
|
||||
if (!class_exists($className) && $directory) {
|
||||
$path = rtrim($directory, '/').'/'.$name;
|
||||
|
||||
require_once $path;
|
||||
}
|
||||
|
||||
// Make sure the class exists, extends Shortcode and is not abstract.
|
||||
if (class_exists($className) && is_subclass_of($className, \Grav\Plugin\Shortcodes\Shortcode::class)) {
|
||||
$reflection = new \ReflectionClass($className);
|
||||
if (!$reflection->isAbstract()) {
|
||||
/** @var \Grav\Plugin\Shortcodes\Shortcode $shortcode */
|
||||
$shortcode = new $className();
|
||||
$shortcode->init();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* register all files as shortcodes in a particular directory
|
||||
* @param string $directory directory where the shortcodes are located
|
||||
* @param array $options Extra options
|
||||
*/
|
||||
public function registerAllShortcodes($directory, array $options = [])
|
||||
{
|
||||
try {
|
||||
$ignore = $options['ignore'] ?? [];
|
||||
foreach (new \DirectoryIterator($directory) as $file) {
|
||||
if ($file->isDot() || \in_array($file->getBasename('.php'), $ignore, true)) {
|
||||
continue;
|
||||
}
|
||||
$this->registerShortcode($file->getFilename(), $directory);
|
||||
}
|
||||
} catch (\UnexpectedValueException $e) {
|
||||
Grav::instance()['log']->error('ShortcodeCore Plugin: Directory not found => ' . $directory);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* setup the markdown parser to handle shortcodes properly
|
||||
*
|
||||
* @param object $markdown the markdown parser object
|
||||
*/
|
||||
public function setupMarkdown($markdown)
|
||||
{
|
||||
$markdown->addBlockType('[', 'ShortCodes', true, false);
|
||||
|
||||
$markdown->blockShortCodes = function($Line) {
|
||||
$valid_shortcodes = implode('|', $this->handlers->getNames());
|
||||
$regex = '/^\[\/?(?:' . $valid_shortcodes . ')[^\]]*\]$/';
|
||||
|
||||
if (preg_match($regex, trim($Line['body']), $matches)) {
|
||||
return [
|
||||
'markup' => $Line['body'],
|
||||
];
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* process the content by running over all the known shortcodes with the
|
||||
* chosen parser
|
||||
*
|
||||
* @param PageInterface $page the page to work on
|
||||
* @param Data $config configuration merged with the page config
|
||||
* @param null $handlers
|
||||
* @return string
|
||||
*/
|
||||
public function processContent(PageInterface $page, Data $config, $handlers = null)
|
||||
{
|
||||
$parser = $this->getParser($config->get('parser'));
|
||||
|
||||
if (!$handlers) {
|
||||
$handlers = $this->handlers;
|
||||
}
|
||||
|
||||
if ($page && $config->get('enabled')) {
|
||||
$this->page = $page;
|
||||
$content = $page->getRawContent();
|
||||
$processor = new Processor(new $parser(new CommonSyntax()), $handlers);
|
||||
$processor = $processor->withEventContainer($this->events);
|
||||
|
||||
return $processor->process($content);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function processRawContent(PageInterface $page, Data $config)
|
||||
{
|
||||
return $this->processContent($page, $config, $this->raw_handlers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow the processing of shortcodes directly on a string
|
||||
* For example when used by Twig directly
|
||||
*
|
||||
* @param $str
|
||||
* @param null $handlers
|
||||
* @return string
|
||||
*/
|
||||
public function processShortcodes($str, $handlers = null)
|
||||
{
|
||||
$parser = $this->getParser($this->config->get('parser'));
|
||||
|
||||
if (!$handlers) {
|
||||
$handlers = $this->handlers;
|
||||
}
|
||||
|
||||
$processor = new Processor(new $parser(new CommonSyntax()), $handlers);
|
||||
|
||||
return $processor->process($str);
|
||||
}
|
||||
|
||||
public function processShortcodesRaw($str)
|
||||
{
|
||||
return $this->processShortcodes($str, $this->raw_handlers);
|
||||
}
|
||||
|
||||
/**
|
||||
* set a state of a particular item with a hash for retrieval later
|
||||
*
|
||||
* @param string $hash a unique hash code
|
||||
* @param object $item some item to store
|
||||
*/
|
||||
public function setStates($hash, $item)
|
||||
{
|
||||
$this->states[$hash][] = $item;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the shortcode of a specific hash
|
||||
*
|
||||
* @param string $hash unique id of state
|
||||
* @return ShortcodeInterface shortcode stored for this hash
|
||||
*/
|
||||
public function getStates($hash)
|
||||
{
|
||||
if (array_key_exists($hash, $this->states)) {
|
||||
return $this->states[$hash];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* helper method to create a unique shortcode based on the content
|
||||
*
|
||||
* @param ShortcodeInterface $shortcode
|
||||
* @return string
|
||||
*/
|
||||
public function getId(ShortcodeInterface $shortcode)
|
||||
{
|
||||
return substr(md5($shortcode->getShortcodeText()), -10);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current page context
|
||||
*
|
||||
* @param PageInterface $page
|
||||
*/
|
||||
public function setPage(PageInterface $page)
|
||||
{
|
||||
$this->page = $page;
|
||||
}
|
||||
|
||||
/** gets the current page context if set */
|
||||
public function getPage()
|
||||
{
|
||||
return $this->page;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the appropriate parser object
|
||||
*
|
||||
* @param $parser
|
||||
* @return string
|
||||
*/
|
||||
protected function getParser($parser)
|
||||
{
|
||||
switch($parser)
|
||||
{
|
||||
case 'regular':
|
||||
$parser = RegularParser::class;
|
||||
break;
|
||||
case 'wordpress':
|
||||
$parser = WordpressParser::class;
|
||||
break;
|
||||
default:
|
||||
$parser = RegexParser::class;
|
||||
break;
|
||||
}
|
||||
|
||||
return $parser;
|
||||
}
|
||||
}
|
33
plugins/shortcode-core/classes/plugin/ShortcodeObject.php
Normal file
33
plugins/shortcode-core/classes/plugin/ShortcodeObject.php
Normal file
@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace Grav\Plugin\ShortcodeCore;
|
||||
|
||||
class ShortcodeObject
|
||||
{
|
||||
protected $obj_name;
|
||||
protected $obj_object;
|
||||
|
||||
public function __construct($name, $object)
|
||||
{
|
||||
$this->obj_name = $name;
|
||||
$this->obj_object = $object;
|
||||
}
|
||||
|
||||
public function __toString()
|
||||
{
|
||||
return $this->obj_object;
|
||||
}
|
||||
|
||||
public function name()
|
||||
{
|
||||
return $this->obj_name;
|
||||
}
|
||||
|
||||
public function object()
|
||||
{
|
||||
return $this->obj_object;
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure we also autoload the deprecated class.
|
||||
class_exists(\Grav\Plugin\Shortcodes\ShortcodeObject::class);
|
27
plugins/shortcode-core/classes/plugin/ShortcodeTwigVar.php
Normal file
27
plugins/shortcode-core/classes/plugin/ShortcodeTwigVar.php
Normal file
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace Grav\Plugin\ShortcodeCore;
|
||||
|
||||
use Grav\Common\Grav;
|
||||
|
||||
class ShortcodeTwigVar
|
||||
{
|
||||
public function __call($name, $args)
|
||||
{
|
||||
/** @var ShortcodeManager $shortcode */
|
||||
$shortcode = Grav::instance()['shortcode'];
|
||||
$objects = $shortcode->getObjects();
|
||||
|
||||
if ($objects) {
|
||||
return $objects[$name] ?? [];
|
||||
}
|
||||
|
||||
$page_meta = Grav::instance()['page']->getContentMeta('shortcodeMeta');
|
||||
if (isset($page_meta['shortcode'])) {
|
||||
$objects = (array) $page_meta['shortcode'];
|
||||
return $objects[$name] ?? [];
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
}
|
26
plugins/shortcode-core/classes/shortcodes/AlignShortcode.php
Normal file
26
plugins/shortcode-core/classes/shortcodes/AlignShortcode.php
Normal file
@ -0,0 +1,26 @@
|
||||
<?php
|
||||
namespace Grav\Plugin\Shortcodes;
|
||||
|
||||
use Thunder\Shortcode\Shortcode\ShortcodeInterface;
|
||||
|
||||
class AlignShortcode extends Shortcode
|
||||
{
|
||||
public function init()
|
||||
{
|
||||
$this->shortcode->getHandlers()->add('center', static function(ShortcodeInterface $sc) {
|
||||
return '<div style="text-align: center;">' . $sc->getContent() . '</div>';
|
||||
});
|
||||
|
||||
$this->shortcode->getHandlers()->add('left', static function(ShortcodeInterface $sc) {
|
||||
return '<div style="text-align: left;">' . $sc->getContent() . '</div>';
|
||||
});
|
||||
|
||||
$this->shortcode->getHandlers()->add('right', static function(ShortcodeInterface $sc) {
|
||||
return '<div style="text-align: right;">' . $sc->getContent() . '</div>';
|
||||
});
|
||||
|
||||
$this->shortcode->getHandlers()->add('justify', static function(ShortcodeInterface $sc) {
|
||||
return '<div style="text-align: justify;">' . $sc->getContent() . '</div>';
|
||||
});
|
||||
}
|
||||
}
|
16
plugins/shortcode-core/classes/shortcodes/ColorShortcode.php
Normal file
16
plugins/shortcode-core/classes/shortcodes/ColorShortcode.php
Normal file
@ -0,0 +1,16 @@
|
||||
<?php
|
||||
namespace Grav\Plugin\Shortcodes;
|
||||
|
||||
use Thunder\Shortcode\Shortcode\ShortcodeInterface;
|
||||
|
||||
class ColorShortcode extends Shortcode
|
||||
{
|
||||
public function init()
|
||||
{
|
||||
$this->shortcode->getHandlers()->add('color', function(ShortcodeInterface $sc) {
|
||||
$color = $sc->getParameter('color', $this->getBbCode($sc));
|
||||
|
||||
return '<span style="color: ' . $color . ';">' . $sc->getContent() . '</span>';
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
namespace Grav\Plugin\Shortcodes;
|
||||
|
||||
use Thunder\Shortcode\Shortcode\ShortcodeInterface;
|
||||
|
||||
class ColumnsShortcode extends Shortcode
|
||||
{
|
||||
public function init()
|
||||
{
|
||||
$this->shortcode->getHandlers()->add('columns', static function(ShortcodeInterface $sc) {
|
||||
$column_count = (int)$sc->getParameter('count', 2);
|
||||
$column_width = $sc->getParameter('width', 'auto');
|
||||
$column_gap = $sc->getParameter('gap', 'normal');
|
||||
$column_rule = $sc->getParameter('rule', false);
|
||||
|
||||
$css_style = 'columns:' . $column_count . ' ' . $column_width . ';-moz-columns:' . $column_count . ' ' . $column_width . ';';
|
||||
$css_style .= 'column-gap:' . $column_gap . ';-moz-column-gap:' . $column_gap . ';';
|
||||
|
||||
if ($column_rule) {
|
||||
$css_style .= 'column-rule:' . $column_rule . ';-moz-column-rule:' . $column_rule . ';';
|
||||
}
|
||||
|
||||
return '<div class="sc-columns" style="' . $css_style . '">' . $sc->getContent() . '</div>';
|
||||
});
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
<?php
|
||||
namespace Grav\Plugin\Shortcodes;
|
||||
|
||||
use Thunder\Shortcode\Shortcode\ShortcodeInterface;
|
||||
|
||||
class DetailsShortcode extends Shortcode
|
||||
{
|
||||
public function init()
|
||||
{
|
||||
$this->shortcode->getHandlers()->add('details', function(ShortcodeInterface $sc) {
|
||||
// Get summary/title
|
||||
$summary = $sc->getParameter('summary', $this->getBbCode($sc));
|
||||
$summaryHTML = $summary ? '<summary>' . $summary . '</summary>' : '';
|
||||
|
||||
// Get classes for details
|
||||
$class = $sc->getParameter('class', $this->getBbCode($sc));
|
||||
$classHTML = (isset($class) and $class !== $summary) ? 'class="' . $class . '"' : '';
|
||||
|
||||
// Get content
|
||||
$content = $sc->getContent();
|
||||
|
||||
// Return the details/summary block
|
||||
return '<details ' . $classHTML . '>' . $summaryHTML . $content . '</details>';
|
||||
});
|
||||
}
|
||||
}
|
22
plugins/shortcode-core/classes/shortcodes/DivShortcode.php
Normal file
22
plugins/shortcode-core/classes/shortcodes/DivShortcode.php
Normal file
@ -0,0 +1,22 @@
|
||||
<?php
|
||||
namespace Grav\Plugin\Shortcodes;
|
||||
|
||||
use Thunder\Shortcode\Shortcode\ShortcodeInterface;
|
||||
|
||||
class DivShortcode extends Shortcode
|
||||
{
|
||||
public function init()
|
||||
{
|
||||
$this->shortcode->getHandlers()->add('div', static function(ShortcodeInterface $sc) {
|
||||
$id = $sc->getParameter('id');
|
||||
$class = $sc->getParameter('class');
|
||||
$style = $sc->getParameter('style');
|
||||
|
||||
$id_output = $id ? ' id="' . $id . '" ': '';
|
||||
$class_output = $class ? ' class="' . $class . '"' : '';
|
||||
$style_output = $style ? ' style="' . $style . '"' : '';
|
||||
|
||||
return '<div ' . $id_output . $class_output . $style_output . '>' . $sc->getContent() . '</div>';
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
namespace Grav\Plugin\Shortcodes;
|
||||
|
||||
use Grav\Common\Utils;
|
||||
use Thunder\Shortcode\Shortcode\ShortcodeInterface;
|
||||
|
||||
class FigureShortcode extends Shortcode
|
||||
{
|
||||
public function init()
|
||||
{
|
||||
$this->shortcode->getHandlers()->add('figure', function(ShortcodeInterface $sc) {
|
||||
$id = $sc->getParameter('id');
|
||||
$class = $sc->getParameter('class');
|
||||
$caption = $sc->getParameter('caption');
|
||||
$page = $this->grav['page'];
|
||||
|
||||
// Process any markdown on caption
|
||||
$caption = Utils::processMarkdown($caption, false, $page);
|
||||
|
||||
$id_output = $id ? 'id="' . $id . '" ': '';
|
||||
$class_output = $class ? 'class="' . $class . '"' : '';
|
||||
$caption_output = $caption ? '<figcaption>' . $caption . '</figcaption>' : '';
|
||||
|
||||
return '<figure ' . $id_output . ' ' . $class_output . '>'.$sc->getContent(). $caption_output . '</figure>';
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
<?php
|
||||
namespace Grav\Plugin\Shortcodes;
|
||||
|
||||
use Grav\Common\Utils;
|
||||
use Thunder\Shortcode\Shortcode\ShortcodeInterface;
|
||||
|
||||
class FontAwesomeShortcode extends Shortcode
|
||||
{
|
||||
public function init()
|
||||
{
|
||||
$this->shortcode->getHandlers()->add('fa', function(ShortcodeInterface $sc) {
|
||||
// Load assets if required
|
||||
if ($this->config->get('plugins.shortcode-core.fontawesome.load', false)) {
|
||||
$this->shortcode->addAssets('css', $this->config->get('plugins.shortcode-core.fontawesome.url'));
|
||||
}
|
||||
if ($this->config->get('plugins.shortcode-core.fontawesome.v5', false)) {
|
||||
$v5classes = ['fab', 'fal', 'fas', 'far', 'fad'];
|
||||
} else {
|
||||
$v5classes = [];
|
||||
}
|
||||
|
||||
// Get shortcode content and parameters
|
||||
$str = $sc->getContent();
|
||||
$icon = $sc->getParameter('icon', $sc->getParameter('fa', $this->getBbCode($sc)));
|
||||
|
||||
if (!Utils::startsWith($icon, 'fa-')) {
|
||||
$icon = 'fa-'.$icon;
|
||||
}
|
||||
|
||||
if ($icon) {
|
||||
$fa_class = 'fa';
|
||||
$extras = explode(',', $sc->getParameter('extras', ''));
|
||||
|
||||
foreach($extras as $extra) {
|
||||
if(!empty($extra)) {
|
||||
if(in_array($extra, $v5classes, true)) {
|
||||
$fa_class = $extra;
|
||||
continue;
|
||||
}
|
||||
if(!Utils::startsWith($extra, 'fa-')) {
|
||||
$extra = 'fa-' . $extra;
|
||||
}
|
||||
$icon .= ' ' . $extra;
|
||||
}
|
||||
}
|
||||
|
||||
return '<i class="' . $fa_class . ' ' . $icon . '">' . $str . '</i>';
|
||||
}
|
||||
|
||||
return '';
|
||||
});
|
||||
}
|
||||
}
|
48
plugins/shortcode-core/classes/shortcodes/HShortcode.php
Normal file
48
plugins/shortcode-core/classes/shortcodes/HShortcode.php
Normal file
@ -0,0 +1,48 @@
|
||||
<?php
|
||||
namespace Grav\Plugin\Shortcodes;
|
||||
|
||||
use Thunder\Shortcode\Shortcode\ShortcodeInterface;
|
||||
|
||||
class HShortcode extends Shortcode
|
||||
{
|
||||
public function init()
|
||||
{
|
||||
$this->shortcode->getHandlers()->add('h1', function(ShortcodeInterface $sc) {
|
||||
return $this->header(1, $sc);
|
||||
});
|
||||
|
||||
$this->shortcode->getHandlers()->add('h2', function(ShortcodeInterface $sc) {
|
||||
return $this->header(2, $sc);
|
||||
});
|
||||
|
||||
$this->shortcode->getHandlers()->add('h3', function(ShortcodeInterface $sc) {
|
||||
return $this->header(3, $sc);
|
||||
});
|
||||
|
||||
$this->shortcode->getHandlers()->add('h4', function(ShortcodeInterface $sc) {
|
||||
return $this->header(4, $sc);
|
||||
});
|
||||
|
||||
$this->shortcode->getHandlers()->add('h5', function(ShortcodeInterface $sc) {
|
||||
return $this->header(5, $sc);
|
||||
});
|
||||
|
||||
$this->shortcode->getHandlers()->add('h6', function(ShortcodeInterface $sc) {
|
||||
return $this->header(6, $sc);
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
protected function header($level, ShortcodeInterface $sc)
|
||||
{
|
||||
$id = $sc->getParameter('id');
|
||||
$class = $sc->getParameter('class');
|
||||
$tag = 'h' . $level;
|
||||
|
||||
$id_output = $id ? ' id="' . $id . '" ': '';
|
||||
$class_output = $class ? ' class="' . $class . '"' : '';
|
||||
|
||||
return "<{$tag}{$id_output}{$class_output}>{$sc->getContent()}</{$tag}>";
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
<?php
|
||||
namespace Grav\Plugin\Shortcodes;
|
||||
|
||||
use Grav\Common\Language\Language;
|
||||
use Thunder\Shortcode\Shortcode\ShortcodeInterface;
|
||||
|
||||
class LanguageShortcode extends Shortcode
|
||||
{
|
||||
|
||||
public function init()
|
||||
{
|
||||
$this->shortcode->getHandlers()->add('lang', function(ShortcodeInterface $sc) {
|
||||
$lang = $this->getBbCode($sc);
|
||||
|
||||
if ($lang) {
|
||||
$list = explode(',', $lang);
|
||||
array_walk($list, 'trim');
|
||||
|
||||
/** @var Language $language */
|
||||
$language = $this->grav['language'];
|
||||
$current = $language->getLanguage();
|
||||
|
||||
if (in_array($current, $list)) {
|
||||
return $sc->getContent();
|
||||
}
|
||||
}
|
||||
|
||||
return '';
|
||||
});
|
||||
}
|
||||
}
|
360
plugins/shortcode-core/classes/shortcodes/LoremShortcode.php
Normal file
360
plugins/shortcode-core/classes/shortcodes/LoremShortcode.php
Normal file
@ -0,0 +1,360 @@
|
||||
<?php
|
||||
/**
|
||||
* Based on Lorem Ipsum Generator by Josh Sherman
|
||||
*
|
||||
* Licensed under The MIT License.
|
||||
* Redistribution of these files must retain the above copyright notice.
|
||||
*
|
||||
* @author Josh Sherman <hello@joshtronic.com>
|
||||
* @copyright Copyright 2014, 2015, 2016, 2017, 2018, 2019 Josh Sherman
|
||||
* @license http://www.opensource.org/licenses/mit-license.html
|
||||
* @link https://github.com/joshtronic/php-loremipsum
|
||||
*/
|
||||
|
||||
namespace Grav\Plugin\Shortcodes;
|
||||
|
||||
use Thunder\Shortcode\Shortcode\ShortcodeInterface;
|
||||
|
||||
class LoremShortcode extends Shortcode
|
||||
{
|
||||
/**
|
||||
* First
|
||||
*
|
||||
* Whether or not we should be starting the string with "Lorem ipsum..."
|
||||
*
|
||||
* @access private
|
||||
* @var boolean
|
||||
*/
|
||||
private $first = true;
|
||||
/**
|
||||
* Words
|
||||
*
|
||||
* A lorem ipsum vocabulary of sorts. Not a complete list as I'm unsure if
|
||||
* a complete list exists and if so, where to get it.
|
||||
*
|
||||
* @access private
|
||||
* @var array
|
||||
*/
|
||||
public $words = [
|
||||
// Lorem ipsum...
|
||||
'lorem', 'ipsum', 'dolor', 'sit', 'amet', 'consectetur', 'adipiscing', 'elit',
|
||||
// and the rest of the vocabulary
|
||||
'a', 'ac', 'accumsan', 'ad', 'aenean', 'aliquam', 'aliquet', 'ante',
|
||||
'aptent', 'arcu', 'at', 'auctor', 'augue', 'bibendum', 'blandit',
|
||||
'class', 'commodo', 'condimentum', 'congue', 'consequat', 'conubia',
|
||||
'convallis', 'cras', 'cubilia', 'curabitur', 'curae', 'cursus',
|
||||
'dapibus', 'diam', 'dictum', 'dictumst', 'dignissim', 'dis', 'donec',
|
||||
'dui', 'duis', 'efficitur', 'egestas', 'eget', 'eleifend', 'elementum',
|
||||
'enim', 'erat', 'eros', 'est', 'et', 'etiam', 'eu', 'euismod', 'ex',
|
||||
'facilisi', 'facilisis', 'fames', 'faucibus', 'felis', 'fermentum',
|
||||
'feugiat', 'finibus', 'fringilla', 'fusce', 'gravida', 'habitant',
|
||||
'habitasse', 'hac', 'hendrerit', 'himenaeos', 'iaculis', 'id',
|
||||
'imperdiet', 'in', 'inceptos', 'integer', 'interdum', 'justo',
|
||||
'lacinia', 'lacus', 'laoreet', 'lectus', 'leo', 'libero', 'ligula',
|
||||
'litora', 'lobortis', 'luctus', 'maecenas', 'magna', 'magnis',
|
||||
'malesuada', 'massa', 'mattis', 'mauris', 'maximus', 'metus', 'mi',
|
||||
'molestie', 'mollis', 'montes', 'morbi', 'mus', 'nam', 'nascetur',
|
||||
'natoque', 'nec', 'neque', 'netus', 'nibh', 'nisi', 'nisl', 'non',
|
||||
'nostra', 'nulla', 'nullam', 'nunc', 'odio', 'orci', 'ornare',
|
||||
'parturient', 'pellentesque', 'penatibus', 'per', 'pharetra',
|
||||
'phasellus', 'placerat', 'platea', 'porta', 'porttitor', 'posuere',
|
||||
'potenti', 'praesent', 'pretium', 'primis', 'proin', 'pulvinar',
|
||||
'purus', 'quam', 'quis', 'quisque', 'rhoncus', 'ridiculus', 'risus',
|
||||
'rutrum', 'sagittis', 'sapien', 'scelerisque', 'sed', 'sem', 'semper',
|
||||
'senectus', 'sociosqu', 'sodales', 'sollicitudin', 'suscipit',
|
||||
'suspendisse', 'taciti', 'tellus', 'tempor', 'tempus', 'tincidunt',
|
||||
'torquent', 'tortor', 'tristique', 'turpis', 'ullamcorper', 'ultrices',
|
||||
'ultricies', 'urna', 'ut', 'varius', 'vehicula', 'vel', 'velit',
|
||||
'venenatis', 'vestibulum', 'vitae', 'vivamus', 'viverra', 'volutpat',
|
||||
'vulputate',
|
||||
];
|
||||
|
||||
public function init()
|
||||
{
|
||||
$this->shortcode->getHandlers()->add('lorem', function(ShortcodeInterface $sc) {
|
||||
$paragraphs = $sc->getParameter('p', $this->getBbCode($sc));
|
||||
$paragraph_tag = $sc->getParameter('tag', 'p');
|
||||
$sentences = $sc->getParameter('s');
|
||||
$words = $sc->getParameter('w');
|
||||
|
||||
if ($words) {
|
||||
return $this->words($words);
|
||||
}
|
||||
if ($sentences) {
|
||||
return $this->sentences($sentences);
|
||||
}
|
||||
|
||||
return $this->paragraphs($paragraphs ?? 1, $paragraph_tag);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Word
|
||||
*
|
||||
* Generates a single word of lorem ipsum.
|
||||
*
|
||||
* @access public
|
||||
* @param mixed $tags string or array of HTML tags to wrap output with
|
||||
* @return string generated lorem ipsum word
|
||||
*/
|
||||
public function word($tags = false)
|
||||
{
|
||||
return $this->words(1, $tags);
|
||||
}
|
||||
/**
|
||||
* Words Array
|
||||
*
|
||||
* Generates an array of lorem ipsum words.
|
||||
*
|
||||
* @access public
|
||||
* @param integer $count how many words to generate
|
||||
* @param mixed $tags string or array of HTML tags to wrap output with
|
||||
* @return array generated lorem ipsum words
|
||||
*/
|
||||
public function wordsArray($count = 1, $tags = false)
|
||||
{
|
||||
return $this->words($count, $tags, true);
|
||||
}
|
||||
/**
|
||||
* Words
|
||||
*
|
||||
* Generates words of lorem ipsum.
|
||||
*
|
||||
* @access public
|
||||
* @param integer $count how many words to generate
|
||||
* @param mixed $tags string or array of HTML tags to wrap output with
|
||||
* @param boolean $array whether an array or a string should be returned
|
||||
* @return mixed string or array of generated lorem ipsum words
|
||||
*/
|
||||
public function words($count = 1, $tags = false, $array = false)
|
||||
{
|
||||
$words = [];
|
||||
$word_count = 0;
|
||||
// Shuffles and appends the word list to compensate for count
|
||||
// arguments that exceed the size of our vocabulary list
|
||||
while ($word_count < $count) {
|
||||
$shuffle = true;
|
||||
while ($shuffle) {
|
||||
$this->shuffle();
|
||||
// Checks that the last word of the list and the first word of
|
||||
// the list that's about to be appended are not the same
|
||||
if (!$word_count || $words[$word_count - 1] != $this->words[0]) {
|
||||
$words = array_merge($words, $this->words);
|
||||
$word_count = count($words);
|
||||
$shuffle = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
$words = array_slice($words, 0, $count);
|
||||
|
||||
return $this->output($words, $tags, $array);
|
||||
}
|
||||
/**
|
||||
* Sentence
|
||||
*
|
||||
* Generates a full sentence of lorem ipsum.
|
||||
*
|
||||
* @access public
|
||||
* @param mixed $tags string or array of HTML tags to wrap output with
|
||||
* @return string generated lorem ipsum sentence
|
||||
*/
|
||||
public function sentence($tags = false)
|
||||
{
|
||||
return $this->sentences(1, $tags);
|
||||
}
|
||||
/**
|
||||
* Sentences Array
|
||||
*
|
||||
* Generates an array of lorem ipsum sentences.
|
||||
*
|
||||
* @access public
|
||||
* @param integer $count how many sentences to generate
|
||||
* @param mixed $tags string or array of HTML tags to wrap output with
|
||||
* @return array generated lorem ipsum sentences
|
||||
*/
|
||||
public function sentencesArray($count = 1, $tags = false)
|
||||
{
|
||||
return $this->sentences($count, $tags, true);
|
||||
}
|
||||
/**
|
||||
* Sentences
|
||||
*
|
||||
* Generates sentences of lorem ipsum.
|
||||
*
|
||||
* @access public
|
||||
* @param integer $count how many sentences to generate
|
||||
* @param mixed $tags string or array of HTML tags to wrap output with
|
||||
* @param boolean $array whether an array or a string should be returned
|
||||
* @return mixed string or array of generated lorem ipsum sentences
|
||||
*/
|
||||
public function sentences($count = 1, $tags = false, $array = false)
|
||||
{
|
||||
$sentences = [];
|
||||
for ($i = 0; $i < $count; $i++) {
|
||||
$sentences[] = $this->wordsArray($this->gauss(24.46, 5.08));
|
||||
}
|
||||
$this->punctuate($sentences);
|
||||
|
||||
return $this->output($sentences, $tags, $array);
|
||||
}
|
||||
/**
|
||||
* Paragraph
|
||||
*
|
||||
* Generates a full paragraph of lorem ipsum.
|
||||
*
|
||||
* @access public
|
||||
* @param mixed $tags string or array of HTML tags to wrap output with
|
||||
* @return string generated lorem ipsum paragraph
|
||||
*/
|
||||
public function paragraph($tags = false)
|
||||
{
|
||||
return $this->paragraphs(1, $tags);
|
||||
}
|
||||
/**
|
||||
* Paragraph Array
|
||||
*
|
||||
* Generates an array of lorem ipsum paragraphs.
|
||||
*
|
||||
* @access public
|
||||
* @param integer $count how many paragraphs to generate
|
||||
* @param mixed $tags string or array of HTML tags to wrap output with
|
||||
* @return array generated lorem ipsum paragraphs
|
||||
*/
|
||||
public function paragraphsArray($count = 1, $tags = false)
|
||||
{
|
||||
return $this->paragraphs($count, $tags, true);
|
||||
}
|
||||
/**
|
||||
* Paragraphss
|
||||
*
|
||||
* Generates paragraphs of lorem ipsum.
|
||||
*
|
||||
* @access public
|
||||
* @param integer $count how many paragraphs to generate
|
||||
* @param mixed $tags string or array of HTML tags to wrap output with
|
||||
* @param boolean $array whether an array or a string should be returned
|
||||
* @return mixed string or array of generated lorem ipsum paragraphs
|
||||
*/
|
||||
public function paragraphs($count = 1, $tags = false, $array = false)
|
||||
{
|
||||
$paragraphs = [];
|
||||
for ($i = 0; $i < $count; $i++) {
|
||||
$paragraphs[] = $this->sentences($this->gauss(5.8, 1.93));
|
||||
}
|
||||
|
||||
return $this->output($paragraphs, $tags, $array, "\n\n");
|
||||
}
|
||||
/**
|
||||
* Gaussian Distribution
|
||||
*
|
||||
* This is some smart kid stuff. I went ahead and combined the N(0,1) logic
|
||||
* with the N(m,s) logic into this single function. Used to calculate the
|
||||
* number of words in a sentence, the number of sentences in a paragraph
|
||||
* and the distribution of commas in a sentence.
|
||||
*
|
||||
* @access private
|
||||
* @param double $mean average value
|
||||
* @param double $std_dev stadnard deviation
|
||||
* @return double calculated distribution
|
||||
*/
|
||||
private function gauss($mean, $std_dev)
|
||||
{
|
||||
$x = mt_rand() / mt_getrandmax();
|
||||
$y = mt_rand() / mt_getrandmax();
|
||||
$z = sqrt(-2 * log($x)) * cos(2 * pi() * $y);
|
||||
|
||||
return $z * $std_dev + $mean;
|
||||
}
|
||||
/**
|
||||
* Shuffle
|
||||
*
|
||||
* Shuffles the words, forcing "Lorem ipsum..." at the beginning if it is
|
||||
* the first time we are generating the text.
|
||||
*
|
||||
* @access private
|
||||
*/
|
||||
private function shuffle()
|
||||
{
|
||||
if ($this->first) {
|
||||
$this->first = array_slice($this->words, 0, 8);
|
||||
$this->words = array_slice($this->words, 8);
|
||||
shuffle($this->words);
|
||||
$this->words = $this->first + $this->words;
|
||||
$this->first = false;
|
||||
} else {
|
||||
shuffle($this->words);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Punctuate
|
||||
*
|
||||
* Applies punctuation to a sentence. This includes a period at the end,
|
||||
* the injection of commas as well as capitalizing the first letter of the
|
||||
* first word of the sentence.
|
||||
*
|
||||
* @access private
|
||||
* @param array $sentences the sentences we would like to punctuate
|
||||
*/
|
||||
private function punctuate(&$sentences)
|
||||
{
|
||||
foreach ($sentences as $key => $sentence) {
|
||||
$words = count($sentence);
|
||||
// Only worry about commas on sentences longer than 4 words
|
||||
if ($words > 4) {
|
||||
$mean = log($words, 6);
|
||||
$std_dev = $mean / 6;
|
||||
$commas = round($this->gauss($mean, $std_dev));
|
||||
for ($i = 1; $i <= $commas; $i++) {
|
||||
$word = round($i * $words / ($commas + 1));
|
||||
if ($word < ($words - 1) && $word > 0) {
|
||||
$sentence[$word] .= ',';
|
||||
}
|
||||
}
|
||||
}
|
||||
$sentences[$key] = ucfirst(implode(' ', $sentence) . '.');
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Output
|
||||
*
|
||||
* Does the rest of the processing of the strings. This includes wrapping
|
||||
* the strings in HTML tags, handling transformations with the ability of
|
||||
* back referencing and determining if the passed array should be converted
|
||||
* into a string or not.
|
||||
*
|
||||
* @access private
|
||||
* @param string|string[] $strings an array of generated strings
|
||||
* @param mixed $tags string or array of HTML tags to wrap output with
|
||||
* @param boolean $array whether an array or a string should be returned
|
||||
* @param string $delimiter the string to use when calling implode()
|
||||
* @return string|string[] string or array of generated lorem ipsum text
|
||||
*/
|
||||
private function output($strings, $tags, $array, $delimiter = ' ')
|
||||
{
|
||||
if ($tags) {
|
||||
if (!is_array($tags)) {
|
||||
$tags = [$tags];
|
||||
} else {
|
||||
// Flips the array so we can work from the inside out
|
||||
$tags = array_reverse($tags);
|
||||
}
|
||||
foreach ($strings as $key => $string) {
|
||||
foreach ($tags as $tag) {
|
||||
// Detects / applies back reference
|
||||
if ($tag[0] === '<') {
|
||||
$string = str_replace('$1', $string, $tag);
|
||||
} else {
|
||||
$string = sprintf('<%1$s>%2$s</%1$s>', $tag, $string);
|
||||
}
|
||||
$strings[$key] = $string;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!$array) {
|
||||
$strings = implode($delimiter, $strings);
|
||||
}
|
||||
|
||||
return $strings;
|
||||
}
|
||||
|
||||
}
|
27
plugins/shortcode-core/classes/shortcodes/MarkShortcode.php
Normal file
27
plugins/shortcode-core/classes/shortcodes/MarkShortcode.php
Normal file
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
namespace Grav\Plugin\Shortcodes;
|
||||
|
||||
use Thunder\Shortcode\Shortcode\ShortcodeInterface;
|
||||
|
||||
class MarkShortcode extends Shortcode
|
||||
{
|
||||
public function init()
|
||||
{
|
||||
$this->shortcode->getHandlers()->add('mark', function(ShortcodeInterface $sc) {
|
||||
$style = $sc->getParameter('style', $this->getBbCode($sc));
|
||||
$class = $sc->getParameter('class', 'default');
|
||||
|
||||
$css_class = 'class="mark-class-' . $class . '"';
|
||||
|
||||
if ($style === 'block') {
|
||||
$css_style = 'style="display:block;"';
|
||||
$content = trim($sc->getContent(), "\n");
|
||||
} else {
|
||||
$css_style = '';
|
||||
$content = $sc->getContent();
|
||||
}
|
||||
|
||||
return "<mark {$css_class} {$css_style}>{$content}</mark>";
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
<?php
|
||||
namespace Grav\Plugin\Shortcodes;
|
||||
|
||||
use Thunder\Shortcode\Shortcode\ShortcodeInterface;
|
||||
|
||||
class NoticeShortcode extends Shortcode
|
||||
{
|
||||
public function init()
|
||||
{
|
||||
$this->shortcode->getHandlers()->add('notice', function(ShortcodeInterface $sc) {
|
||||
$css_enabled = $this->grav['config']->get('plugins.shortcode-core.css.notice_enabled', true);
|
||||
if ($css_enabled) {
|
||||
$this->shortcode->addAssets('css', 'plugin://shortcode-core/css/shortcode-notice.css');
|
||||
}
|
||||
|
||||
$output = $this->twig->processTemplate('shortcodes/notice.html.twig', [
|
||||
'type' => $sc->getParameter('notice', $this->getBbCode($sc)) ?: 'info',
|
||||
'content' => $sc->getContent(),
|
||||
]);
|
||||
|
||||
return $output;
|
||||
});
|
||||
}
|
||||
}
|
18
plugins/shortcode-core/classes/shortcodes/RawShortcode.php
Normal file
18
plugins/shortcode-core/classes/shortcodes/RawShortcode.php
Normal file
@ -0,0 +1,18 @@
|
||||
<?php
|
||||
namespace Grav\Plugin\Shortcodes;
|
||||
|
||||
use Thunder\Shortcode\EventHandler\FilterRawEventHandler;
|
||||
use Thunder\Shortcode\Events;
|
||||
use Thunder\Shortcode\Shortcode\ShortcodeInterface;
|
||||
|
||||
class RawShortcode extends Shortcode
|
||||
{
|
||||
public function init()
|
||||
{
|
||||
$this->shortcode->getHandlers()->add('raw', static function(ShortcodeInterface $sc) {
|
||||
return trim($sc->getContent());
|
||||
});
|
||||
|
||||
$this->shortcode->getEvents()->addListener(Events::FILTER_SHORTCODES, new FilterRawEventHandler(['raw']));
|
||||
}
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
<?php
|
||||
namespace Grav\Plugin\Shortcodes;
|
||||
|
||||
use Thunder\Shortcode\Shortcode\ShortcodeInterface;
|
||||
|
||||
class SafeEmailShortcode extends Shortcode
|
||||
{
|
||||
public function init()
|
||||
{
|
||||
$this->shortcode->getHandlers()->add('safe-email', function(ShortcodeInterface $sc) {
|
||||
// Load assets if required
|
||||
if ($this->config->get('plugins.shortcode-core.fontawesome.load', false)) {
|
||||
$this->shortcode->addAssets('css', $this->config->get('plugins.shortcode-core.fontawesome.url'));
|
||||
}
|
||||
|
||||
// Get shortcode content and parameters
|
||||
$str = $sc->getContent();
|
||||
$icon = $sc->getParameter('icon', false);
|
||||
$icon_base = "fa fa-";
|
||||
$autolink = $sc->getParameter('autolink', false);
|
||||
|
||||
// Encode email
|
||||
$email = '';
|
||||
$str_len = strlen($str);
|
||||
for ($i = 0; $i < $str_len; $i++) {
|
||||
$email .= '&#' . ord($str[$i]). ';';
|
||||
}
|
||||
|
||||
// Handle autolinking
|
||||
if ($autolink) {
|
||||
$output = '<a href="mailto:' . $email . '">' . $email . '</a>';
|
||||
} else {
|
||||
$output = $email;
|
||||
}
|
||||
|
||||
// Handle icon option
|
||||
if ($icon) {
|
||||
if ($this->config->get('plugins.shortcode-core.fontawesome.v5', false)) {
|
||||
if (preg_match("/^(?P<weight>fa[srlbd]) fa-(?<icon>.+)/", $icon, $icon_parts)) {
|
||||
$icon_base = $icon_parts["weight"] . " fa-";
|
||||
$icon = $icon_parts["icon"];
|
||||
}
|
||||
}
|
||||
|
||||
$output = '<i class="'. $icon_base . $icon . '"></i> ' . $output;
|
||||
}
|
||||
|
||||
return $output;
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
<?php
|
||||
namespace Grav\Plugin\Shortcodes;
|
||||
|
||||
use Thunder\Shortcode\Shortcode\ShortcodeInterface;
|
||||
|
||||
class SectionShortcode extends Shortcode
|
||||
{
|
||||
public function init()
|
||||
{
|
||||
$this->shortcode->getHandlers()->add('section', function(ShortcodeInterface $sc) {
|
||||
$name = $sc->getParameter('name');
|
||||
$object = new \Grav\Plugin\ShortcodeCore\ShortcodeObject($name, $sc->getContent());
|
||||
$this->shortcode->addObject($sc->getName(), $object);
|
||||
});
|
||||
|
||||
}
|
||||
}
|
91
plugins/shortcode-core/classes/shortcodes/Shortcode.php
Normal file
91
plugins/shortcode-core/classes/shortcodes/Shortcode.php
Normal file
@ -0,0 +1,91 @@
|
||||
<?php
|
||||
|
||||
namespace Grav\Plugin\Shortcodes;
|
||||
|
||||
use Grav\Common\Config\Config;
|
||||
use Grav\Common\Grav;
|
||||
use Grav\Common\Twig\Twig;
|
||||
use Grav\Plugin\ShortcodeCore\ShortcodeManager;
|
||||
use Thunder\Shortcode\Shortcode\ShortcodeInterface;
|
||||
|
||||
abstract class Shortcode
|
||||
{
|
||||
/** @var ShortcodeManager */
|
||||
protected $shortcode;
|
||||
|
||||
/** @var Grav */
|
||||
protected $grav;
|
||||
|
||||
/** @var Config */
|
||||
protected $config;
|
||||
|
||||
/** @var Twig */
|
||||
protected $twig;
|
||||
|
||||
/**
|
||||
* Shortcode constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->grav = Grav::instance();
|
||||
$this->shortcode = $this->grav['shortcode'];
|
||||
$this->config = $this->grav['config'];
|
||||
$this->twig = $this->grav['twig'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize shortcode handler
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
user_error(__METHOD__ . '() method will be abstract in the future, please override it!', E_USER_DEPRECATED);
|
||||
|
||||
// FIXME: This code had to be put back because of some plugins do not properly initialize themselves.
|
||||
$this->shortcode->getHandlers()->add('u', static function(ShortcodeInterface $shortcode) {
|
||||
return $shortcode->getContent();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the class if required
|
||||
*
|
||||
* @return string the name of the class
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return get_class($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getParser()
|
||||
{
|
||||
return $this->config->get('plugins.shortcode-core.parser');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ShortcodeInterface $sc
|
||||
* @param string|null $default
|
||||
* @return string|null
|
||||
*/
|
||||
public function getBbCode(ShortcodeInterface $sc, $default = null)
|
||||
{
|
||||
$code = $default;
|
||||
|
||||
if ($this->getParser() === 'wordpress') {
|
||||
$params = $sc->getParameters();
|
||||
if (is_array($params)) {
|
||||
$keys = array_keys($params);
|
||||
$code = trim(array_shift($keys), '=');
|
||||
}
|
||||
} else {
|
||||
$code = $sc->getBbCode();
|
||||
}
|
||||
|
||||
return $code;
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure we also autoload the deprecated class.
|
||||
class_exists(\Grav\Plugin\ShortcodeCore\Shortcode::class);
|
@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace Grav\Plugin\Shortcodes;
|
||||
|
||||
// Check if the new class has been autoloaded. If not, trigger deprecation error.
|
||||
if (!class_exists(\Grav\Plugin\ShortcodeCore\ShortcodeObject::class, false)) {
|
||||
@trigger_error(
|
||||
ShortcodeObject::class . ' class is deprecated, use \\Grav\\Plugin\\ShortcodeCore\\ShortcodeObject instead',
|
||||
E_USER_DEPRECATED
|
||||
);
|
||||
}
|
||||
|
||||
// Create alias for the deprecated class.
|
||||
class_alias(\Grav\Plugin\ShortcodeCore\ShortcodeObject::class, ShortcodeObject::class);
|
||||
|
||||
// Make sure that both IDE and composer knows about the deprecated class.
|
||||
if (false) {
|
||||
/**
|
||||
* @deprecated 4.2.0 Use \Grav\Plugin\ShortcodeCore\ShortcodeObject instead
|
||||
*/
|
||||
class ShortcodeObject extends \Grav\Plugin\ShortcodeCore\ShortcodeObject
|
||||
{
|
||||
}
|
||||
}
|
19
plugins/shortcode-core/classes/shortcodes/SizeShortcode.php
Normal file
19
plugins/shortcode-core/classes/shortcodes/SizeShortcode.php
Normal file
@ -0,0 +1,19 @@
|
||||
<?php
|
||||
namespace Grav\Plugin\Shortcodes;
|
||||
|
||||
use Thunder\Shortcode\Shortcode\ShortcodeInterface;
|
||||
|
||||
class SizeShortcode extends Shortcode
|
||||
{
|
||||
public function init()
|
||||
{
|
||||
$this->shortcode->getHandlers()->add('size', function(ShortcodeInterface $sc) {
|
||||
$size = $sc->getParameter('size', $this->getBbCode($sc));
|
||||
if (is_numeric($size)) {
|
||||
$size .= 'px';
|
||||
}
|
||||
|
||||
return '<span style="font-size: ' . $size . ';">' . $sc->getContent() . '</span>';
|
||||
});
|
||||
}
|
||||
}
|
22
plugins/shortcode-core/classes/shortcodes/SpanShortcode.php
Normal file
22
plugins/shortcode-core/classes/shortcodes/SpanShortcode.php
Normal file
@ -0,0 +1,22 @@
|
||||
<?php
|
||||
namespace Grav\Plugin\Shortcodes;
|
||||
|
||||
use Thunder\Shortcode\Shortcode\ShortcodeInterface;
|
||||
|
||||
class SpanShortcode extends Shortcode
|
||||
{
|
||||
public function init()
|
||||
{
|
||||
$this->shortcode->getHandlers()->add('span', static function(ShortcodeInterface $sc) {
|
||||
$id = $sc->getParameter('id');
|
||||
$class = $sc->getParameter('class');
|
||||
$style = $sc->getParameter('style');
|
||||
|
||||
$id_output = $id ? 'id="' . $id . '" ': '';
|
||||
$class_output = $class ? 'class="' . $class . '"' : '';
|
||||
$style_output = $style ? 'style="' . $style . '"' : '';
|
||||
|
||||
return '<span ' . $id_output . ' ' . $class_output . ' ' . $style_output . '>' . $sc->getContent() . '</span>';
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
<?php
|
||||
namespace Grav\Plugin\Shortcodes;
|
||||
|
||||
use Thunder\Shortcode\Shortcode\ShortcodeInterface;
|
||||
|
||||
class UnderlineShortcode extends Shortcode
|
||||
{
|
||||
public function init()
|
||||
{
|
||||
$this->shortcode->getHandlers()->add('u', static function(ShortcodeInterface $sc) {
|
||||
return '<span style="text-decoration: underline;">' . $sc->getContent() . '</span>';
|
||||
});
|
||||
}
|
||||
}
|
55
plugins/shortcode-core/cli/ShortcodesCommand.php
Normal file
55
plugins/shortcode-core/cli/ShortcodesCommand.php
Normal file
@ -0,0 +1,55 @@
|
||||
<?php
|
||||
namespace Grav\Plugin\Console;
|
||||
|
||||
use Grav\Common\Grav;
|
||||
use Grav\Common\Twig\Twig;
|
||||
use Grav\Console\ConsoleCommand;
|
||||
use Grav\Plugin\CloudflarePlugin;
|
||||
use Symfony\Component\Console\Helper\ProgressBar;
|
||||
use Symfony\Component\Console\Helper\Table;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
|
||||
/**
|
||||
* Class CloudflareIPsCommand
|
||||
*
|
||||
* @package Grav\Plugin\Console
|
||||
*/
|
||||
class ShortcodesCommand extends ConsoleCommand
|
||||
{
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('display')
|
||||
->setDescription('Display a list the available shortcodes that are registered');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int|null|void
|
||||
*/
|
||||
protected function serve()
|
||||
{
|
||||
$io = new SymfonyStyle($this->input, $this->output);
|
||||
$this->initializePlugins();
|
||||
$this->initializeThemes();
|
||||
|
||||
$shortcodes = Grav::instance()['shortcode'];
|
||||
|
||||
$io->title('Available Shortcodes');
|
||||
$io->section('Regular Handlers:');
|
||||
foreach ($shortcodes->getHandlers()->getNames() as $name) {
|
||||
$io->writeln($name);
|
||||
}
|
||||
$io->section('Raw Handlers:');
|
||||
foreach ($shortcodes->getRawHandlers()->getNames() as $name) {
|
||||
$io->writeln($name);
|
||||
}
|
||||
|
||||
$io->newLine();
|
||||
|
||||
}
|
||||
}
|
32
plugins/shortcode-core/composer.json
Normal file
32
plugins/shortcode-core/composer.json
Normal file
@ -0,0 +1,32 @@
|
||||
{
|
||||
"name": "getgrav/shortcode-core",
|
||||
"type": "grav-plugin",
|
||||
"description": "Shortcode Core plugin for Grav CMS",
|
||||
"keywords": ["shortcode"],
|
||||
"homepage": "https://github.com/getgrav/grav-plugin-shortcode-core/",
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Team Grav",
|
||||
"email": "devs@getgrav.org",
|
||||
"homepage": "http://getgrav.org",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=7.1.3",
|
||||
"thunderer/shortcode": "~0.7"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Grav\\Plugin\\ShortcodeCore\\": "classes/plugin",
|
||||
"Grav\\Plugin\\Shortcodes\\": "classes/shortcodes"
|
||||
},
|
||||
"classmap": ["shortcode-core.php"]
|
||||
},
|
||||
"config": {
|
||||
"platform": {
|
||||
"php": "7.1.3"
|
||||
}
|
||||
}
|
||||
}
|
80
plugins/shortcode-core/composer.lock
generated
Normal file
80
plugins/shortcode-core/composer.lock
generated
Normal file
@ -0,0 +1,80 @@
|
||||
{
|
||||
"_readme": [
|
||||
"This file locks the dependencies of your project to a known state",
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "95ac1934b2d5e35cff7d71f6744b2666",
|
||||
"packages": [
|
||||
{
|
||||
"name": "thunderer/shortcode",
|
||||
"version": "v0.7.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/thunderer/Shortcode.git",
|
||||
"reference": "a4fee30613bd46efb421f8305aff0466a3268a99"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/thunderer/Shortcode/zipball/a4fee30613bd46efb421f8305aff0466a3268a99",
|
||||
"reference": "a4fee30613bd46efb421f8305aff0466a3268a99",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": ">=4.1",
|
||||
"symfony/yaml": ">=2.0"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-dom": "if you want to use XML serializer",
|
||||
"ext-json": "if you want to use JSON serializer",
|
||||
"symfony/yaml": "if you want to use YAML serializer"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Thunder\\Shortcode\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Tomasz Kowalczyk",
|
||||
"email": "tomasz@kowalczyk.cc"
|
||||
}
|
||||
],
|
||||
"description": "Advanced shortcode (BBCode) parser and engine for PHP",
|
||||
"keywords": [
|
||||
"bbcode",
|
||||
"engine",
|
||||
"library",
|
||||
"parser",
|
||||
"shortcode"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/thunderer/Shortcode/issues",
|
||||
"source": "https://github.com/thunderer/Shortcode/tree/v0.7.5"
|
||||
},
|
||||
"time": "2022-01-13T18:53:33+00:00"
|
||||
}
|
||||
],
|
||||
"packages-dev": [],
|
||||
"aliases": [],
|
||||
"minimum-stability": "stable",
|
||||
"stability-flags": [],
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false,
|
||||
"platform": {
|
||||
"php": ">=7.1.3"
|
||||
},
|
||||
"platform-dev": [],
|
||||
"platform-overrides": {
|
||||
"php": "7.1.3"
|
||||
},
|
||||
"plugin-api-version": "2.3.0"
|
||||
}
|
64
plugins/shortcode-core/css/shortcode-notice.css
Normal file
64
plugins/shortcode-core/css/shortcode-notice.css
Normal file
@ -0,0 +1,64 @@
|
||||
.sc-notice {
|
||||
margin: 30px 0;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.sc-notice > div {
|
||||
padding: 5px 20px;
|
||||
display: block;
|
||||
margin-top: 0rem;
|
||||
margin-bottom: 0rem;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.sc-notice > div:before {
|
||||
position: absolute;
|
||||
top: 2px;
|
||||
color: #fff;
|
||||
font-family: FontAwesome;
|
||||
content: '';
|
||||
left: 10px;
|
||||
}
|
||||
|
||||
.sc-notice > div:first-child:after {
|
||||
position: absolute;
|
||||
top: 2px;
|
||||
color: #fff;
|
||||
left: 30px;
|
||||
}
|
||||
|
||||
.sc-notice.info > div:first-child {
|
||||
border-top: 30px solid #F0B37E;
|
||||
background: #FFF2DB;
|
||||
}
|
||||
|
||||
.sc-notice.info > div:first-child:after {
|
||||
content: 'Info';
|
||||
}
|
||||
|
||||
.sc-notice.warning > div:first-child {
|
||||
border-top: 30px solid #DF6F6C;
|
||||
background: #FAE2E2;
|
||||
}
|
||||
|
||||
.sc-notice.warning > div:first-child:after {
|
||||
content: 'Warning';
|
||||
}
|
||||
|
||||
.sc-notice.note > div:first-child {
|
||||
border-top: 30px solid #6AB0DE;
|
||||
background: #E7F2FA;
|
||||
}
|
||||
|
||||
.sc-notice.note > div:first-child:after {
|
||||
content: 'Note';
|
||||
}
|
||||
|
||||
.sc-notice.tip > div:first-child {
|
||||
border-top: 30px solid #77C577;
|
||||
background: #E6F9E6;
|
||||
}
|
||||
|
||||
.sc-notice.tip > div:first-child:after {
|
||||
content: 'Tip';
|
||||
}
|
2
plugins/shortcode-core/nextgen-editor/.browserslistrc
Normal file
2
plugins/shortcode-core/nextgen-editor/.browserslistrc
Normal file
@ -0,0 +1,2 @@
|
||||
> 1%
|
||||
last 2 versions
|
7
plugins/shortcode-core/nextgen-editor/.editorconfig
Normal file
7
plugins/shortcode-core/nextgen-editor/.editorconfig
Normal file
@ -0,0 +1,7 @@
|
||||
[*.{js,jsx,ts,tsx,vue}]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
end_of_line = lf
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
max_line_length = 100
|
2
plugins/shortcode-core/nextgen-editor/.env
Normal file
2
plugins/shortcode-core/nextgen-editor/.env
Normal file
@ -0,0 +1,2 @@
|
||||
DEV_HOST=localhost
|
||||
DEV_PORT=2001
|
27
plugins/shortcode-core/nextgen-editor/.eslintrc.js
Normal file
27
plugins/shortcode-core/nextgen-editor/.eslintrc.js
Normal file
@ -0,0 +1,27 @@
|
||||
module.exports = {
|
||||
root: true,
|
||||
env: {
|
||||
node: true,
|
||||
},
|
||||
extends: [
|
||||
'plugin:vue/recommended',
|
||||
'@vue/airbnb',
|
||||
],
|
||||
parserOptions: {
|
||||
parser: 'babel-eslint',
|
||||
},
|
||||
rules: {
|
||||
'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off',
|
||||
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
|
||||
'import/extensions': 'off',
|
||||
'import/no-unresolved': 'off',
|
||||
'import/no-extraneous-dependencies': ['error', { devDependencies: true }],
|
||||
'no-restricted-syntax': ['off', 'ForOfStatement'],
|
||||
'no-param-reassign': ['error', { props: false }],
|
||||
'class-methods-use-this': 'off',
|
||||
'object-curly-newline': 'off',
|
||||
'no-nested-ternary': 'off',
|
||||
'no-await-in-loop': 'off',
|
||||
'max-len': 'off',
|
||||
},
|
||||
};
|
20
plugins/shortcode-core/nextgen-editor/.gitignore
vendored
Normal file
20
plugins/shortcode-core/nextgen-editor/.gitignore
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
.DS_Store
|
||||
node_modules
|
||||
|
||||
# local env files
|
||||
.env.local
|
||||
.env.*.local
|
||||
|
||||
# Log files
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# Editor directories and files
|
||||
.idea
|
||||
.vscode
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
24
plugins/shortcode-core/nextgen-editor/README.md
Normal file
24
plugins/shortcode-core/nextgen-editor/README.md
Normal file
@ -0,0 +1,24 @@
|
||||
# app
|
||||
|
||||
## Project setup
|
||||
```
|
||||
yarn install
|
||||
```
|
||||
|
||||
### Compiles and hot-reloads for development
|
||||
```
|
||||
yarn serve
|
||||
```
|
||||
|
||||
### Compiles and minifies for production
|
||||
```
|
||||
yarn build
|
||||
```
|
||||
|
||||
### Lints and fixes files
|
||||
```
|
||||
yarn lint
|
||||
```
|
||||
|
||||
### Customize configuration
|
||||
See [Configuration Reference](https://cli.vuejs.org/config/).
|
5
plugins/shortcode-core/nextgen-editor/babel.config.js
Normal file
5
plugins/shortcode-core/nextgen-editor/babel.config.js
Normal file
@ -0,0 +1,5 @@
|
||||
module.exports = {
|
||||
presets: [
|
||||
'@vue/cli-plugin-babel/preset',
|
||||
],
|
||||
};
|
1
plugins/shortcode-core/nextgen-editor/dist/css/app.css
vendored
Normal file
1
plugins/shortcode-core/nextgen-editor/dist/css/app.css
vendored
Normal file
File diff suppressed because one or more lines are too long
2
plugins/shortcode-core/nextgen-editor/dist/js/app.js
vendored
Normal file
2
plugins/shortcode-core/nextgen-editor/dist/js/app.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
plugins/shortcode-core/nextgen-editor/dist/js/app.js.map
vendored
Normal file
1
plugins/shortcode-core/nextgen-editor/dist/js/app.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
24
plugins/shortcode-core/nextgen-editor/package.json
Normal file
24
plugins/shortcode-core/nextgen-editor/package.json
Normal file
@ -0,0 +1,24 @@
|
||||
{
|
||||
"name": "nextgen-editor",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "vue-cli-service serve",
|
||||
"serve": "vue-cli-service serve",
|
||||
"build": "vue-cli-service build",
|
||||
"lint": "vue-cli-service lint"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vue/cli-plugin-babel": "~4.5.13",
|
||||
"@vue/cli-plugin-eslint": "~4.5.13",
|
||||
"@vue/cli-service": "~4.5.13",
|
||||
"@vue/eslint-config-airbnb": "^5.3.0",
|
||||
"babel-eslint": "^10.1.0",
|
||||
"directory-named-webpack-plugin": "^4.0.1",
|
||||
"eslint": "^7.32.0",
|
||||
"eslint-plugin-import": "^2.24.2",
|
||||
"eslint-plugin-vue": "^7.18.0",
|
||||
"node-sass": "^6.0.1",
|
||||
"sass-loader": "^12.1.0"
|
||||
}
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
window.nextgenEditor.addHook('hookInit', () => {
|
||||
window.nextgenEditor.addButtonGroup('shortcode-core-align', {
|
||||
icon: '<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M2.75 1h-.01c-.56 0-1 .44-1 1v20c0 .55.44.99 1 .99.55-.01.99-.45.99-1.01v-20c0-.56-.45-1-1-1z"/><rect style="width:11px;height:6px;" x="5.25" rx="1.5" y="5"/><rect style="width:17px;height:6px;" x="5.25" rx="1.5" y="13"/></svg>',
|
||||
label: 'SC Align',
|
||||
});
|
||||
});
|
||||
|
||||
window.nextgenEditor.addShortcode('left', {
|
||||
type: 'block',
|
||||
plugin: 'shortcode-core',
|
||||
title: 'Align Left',
|
||||
button: {
|
||||
group: 'shortcode-core-align',
|
||||
label: 'Align Left',
|
||||
},
|
||||
content() {
|
||||
return '<div style="text-align:left">{{content_editable}}</div>';
|
||||
},
|
||||
});
|
||||
|
||||
window.nextgenEditor.addShortcode('center', {
|
||||
type: 'block',
|
||||
title: 'Align Center',
|
||||
button: {
|
||||
group: 'shortcode-core-align',
|
||||
label: 'Align Center',
|
||||
},
|
||||
content() {
|
||||
return '<div style="text-align:center">{{content_editable}}</div>';
|
||||
},
|
||||
});
|
||||
|
||||
window.nextgenEditor.addShortcode('right', {
|
||||
type: 'block',
|
||||
title: 'Align Right',
|
||||
button: {
|
||||
group: 'shortcode-core-align',
|
||||
label: 'Align Right',
|
||||
},
|
||||
content() {
|
||||
return '<div style="text-align:right">{{content_editable}}</div>';
|
||||
},
|
||||
});
|
||||
|
||||
window.nextgenEditor.addShortcode('justify', {
|
||||
type: 'block',
|
||||
title: 'Justify',
|
||||
button: {
|
||||
group: 'shortcode-core-align',
|
||||
label: 'Justify',
|
||||
},
|
||||
content() {
|
||||
return '<div style="text-align:justify">{{content_editable}}</div>';
|
||||
},
|
||||
});
|
@ -0,0 +1,22 @@
|
||||
window.nextgenEditor.addShortcode('color', {
|
||||
type: 'inline',
|
||||
plugin: 'shortcode-core',
|
||||
title: 'Color',
|
||||
button: {
|
||||
group: 'shortcode-core',
|
||||
label: 'Color',
|
||||
icon: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9.3 24a1 1 0 00.756-.345L22.523 9.277a2 2 0 00-.212-2.822l-2.45-2.105a1 1 0 00-1.3 1.517l2.072 1.775a.5.5 0 01.052.707l-7.8 9a.25.25 0 01-.423-.251l4.671-12.614a2 2 0 00-1.181-2.57L12.609.675a1 1 0 10-.7 1.875l2.876 1.065a.5.5 0 01.295.643l-4.602 12.419a.25.25 0 01-.485-.087V1.5a1.5 1.5 0 00-1.5-1.5h-6a1.5 1.5 0 00-1.5 1.5v21a1.5 1.5 0 001.5 1.5zM3.493 9.75a.5.5 0 01.5-.5h3a.5.5 0 01.5.5v3a.5.5 0 01-.5.5h-3a.5.5 0 01-.5-.5zm0-3.75V3a.5.5 0 01.5-.5h3a.5.5 0 01.5.5v3a.5.5 0 01-.5.5h-3a.5.5 0 01-.5-.5zm0 10.5a.5.5 0 01.5-.5h3a.5.5 0 01.5.5v3a.5.5 0 01-.5.5h-3a.5.5 0 01-.5-.5z"/></svg>',
|
||||
},
|
||||
attributes: {
|
||||
color: {
|
||||
type: String,
|
||||
title: 'Color',
|
||||
bbcode: true,
|
||||
widget: 'input-text',
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
content({ attributes }) {
|
||||
return `<span style="color:${attributes.color}">{{content_editable}}</span>`;
|
||||
},
|
||||
});
|
@ -0,0 +1,58 @@
|
||||
window.nextgenEditor.addShortcode('columns', {
|
||||
type: 'block',
|
||||
plugin: 'shortcode-core',
|
||||
title: 'Columns',
|
||||
button: {
|
||||
group: 'shortcode-core',
|
||||
label: 'Columns',
|
||||
icon: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M22 0H2a2 2 0 00-2 2v20a2 2 0 002 2h20a2 2 0 002-2V2a2 2 0 00-2-2zm-7 2.5v19a.5.5 0 01-.5.5h-5a.5.5 0 01-.5-.5v-19a.5.5 0 01.5-.5h5a.5.5 0 01.5.5zM2.5 2h4a.5.5 0 01.5.5v19a.5.5 0 01-.5.5h-4a.5.5 0 01-.5-.5v-19a.5.5 0 01.5-.5zm19 20h-4a.5.5 0 01-.5-.5v-19a.5.5 0 01.5-.5h4a.5.5 0 01.5.5v19a.5.5 0 01-.5.5z"/></svg>',
|
||||
},
|
||||
attributes: {
|
||||
count: {
|
||||
type: Number,
|
||||
title: 'Count',
|
||||
widget: {
|
||||
type: 'input-number',
|
||||
min: 1,
|
||||
max: 12,
|
||||
},
|
||||
default: 2,
|
||||
},
|
||||
width: {
|
||||
type: String,
|
||||
title: 'Width',
|
||||
widget: 'input-text',
|
||||
default: 'auto',
|
||||
},
|
||||
gap: {
|
||||
type: String,
|
||||
title: 'Gap',
|
||||
widget: 'input-text',
|
||||
default: 'normal',
|
||||
},
|
||||
rule: {
|
||||
type: String,
|
||||
title: 'Rule',
|
||||
widget: 'input-text',
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
titlebar({ attributes }) {
|
||||
return `columns: <strong>${attributes.count}</strong>`;
|
||||
},
|
||||
content({ attributes }) {
|
||||
const styles = []
|
||||
.concat([
|
||||
`columns:${attributes.count} ${attributes.width}`,
|
||||
`-moz-columns:${attributes.count} ${attributes.width}`,
|
||||
`column-gap:${attributes.gap}`,
|
||||
`-moz-column-gap:${attributes.gap}`,
|
||||
attributes.rule ? `column-rule:${attributes.rule}` : null,
|
||||
attributes.rule ? `-moz-column-rule:${attributes.rule}` : null,
|
||||
])
|
||||
.filter((item) => !!item)
|
||||
.join(';');
|
||||
|
||||
return `<div style="${styles}">{{content_editable}}</div>`;
|
||||
},
|
||||
});
|
@ -0,0 +1,8 @@
|
||||
shortcode-block[name="details"] summary {
|
||||
margin: 8px 8px;
|
||||
}
|
||||
|
||||
shortcode-block[name="details"] summary > p {
|
||||
display: inline;
|
||||
margin: 0;
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
window.nextgenEditor.addShortcode('details', {
|
||||
type: 'block',
|
||||
plugin: 'shortcode-core',
|
||||
title: 'Details',
|
||||
button: {
|
||||
group: 'shortcode-core',
|
||||
label: 'Details',
|
||||
icon: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M2.2 8.348a1 1 0 001.4.2l3.465-2.6a1.5 1.5 0 000-2.4L3.6.948a1 1 0 00-1.2 1.6l2.666 2a.25.25 0 010 .4l-2.666 2a1 1 0 00-.2 1.4zM23 21.248H1a1 1 0 000 2h22a1 1 0 000-2zM23 16.248H1a1 1 0 000 2h22a1 1 0 000-2zM23 11.248H1a1 1 0 000 2h22a1 1 0 000-2zM24 7.248a1 1 0 00-1-1H12a1 1 0 000 2h11a1 1 0 001-1zM12 3.248h11a1 1 0 000-2H12a1 1 0 000 2z"/></svg>',
|
||||
},
|
||||
attributes: {
|
||||
summary: {
|
||||
type: String,
|
||||
title: 'Summary',
|
||||
bbcode: true,
|
||||
widget: 'input-text',
|
||||
default: '',
|
||||
},
|
||||
class: {
|
||||
type: String,
|
||||
title: 'Class',
|
||||
widget: 'input-text',
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
titlebar({ attributes }) {
|
||||
return attributes.class
|
||||
? `class: <strong>${attributes.class}</strong>`
|
||||
: '';
|
||||
},
|
||||
content({ attributes }) {
|
||||
let output = '';
|
||||
|
||||
output += `<details class="${attributes.class || ''}" open>`;
|
||||
|
||||
if (attributes.summary) {
|
||||
output += `<summary>${attributes.summary}</summary>`;
|
||||
}
|
||||
|
||||
output += '{{content_editable}}';
|
||||
output += '</details>';
|
||||
|
||||
return output;
|
||||
},
|
||||
preserve: {
|
||||
block: [
|
||||
'details',
|
||||
'summary',
|
||||
],
|
||||
},
|
||||
});
|
47
plugins/shortcode-core/nextgen-editor/shortcodes/div/div.js
Normal file
47
plugins/shortcode-core/nextgen-editor/shortcodes/div/div.js
Normal file
@ -0,0 +1,47 @@
|
||||
window.nextgenEditor.addShortcode('div', {
|
||||
type: 'block',
|
||||
plugin: 'shortcode-core',
|
||||
title: 'Div',
|
||||
button: {
|
||||
group: 'shortcode-core',
|
||||
label: 'Div',
|
||||
icon: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M24 4.5a3 3 0 00-3-3H3a3 3 0 00-3 3v15a3 3 0 003 3h18a3 3 0 003-3zM3 5a1 1 0 111 1 1 1 0 01-1-1zm3 0a1 1 0 111 1 1 1 0 01-1-1zm3 0a1 1 0 111 1 1 1 0 01-1-1zm13 14.5a1 1 0 01-1 1H3a1 1 0 01-1-1V9a.5.5 0 01.5-.5h19a.5.5 0 01.5.5z"/><path d="M7.75 12a.75.75 0 00.75.75.25.25 0 01.25.25v4a.75.75 0 001.5 0v-4a.25.25 0 01.25-.25.75.75 0 000-1.5h-2a.75.75 0 00-.75.75zM4 17.75a.75.75 0 00.75-.75v-1a.25.25 0 01.5 0v1a.75.75 0 001.5 0v-5a.75.75 0 00-1.5 0v2a.25.25 0 01-.5 0v-2a.75.75 0 00-1.5 0v5a.75.75 0 00.75.75zM17.75 16a1.752 1.752 0 001.75 1.75h1a.75.75 0 000-1.5h-1a.25.25 0 01-.25-.25v-4a.75.75 0 00-1.5 0zM13 17.75a.75.75 0 00.75-.75v-2.085a.057.057 0 01.106-.029.781.781 0 001.288 0 .057.057 0 01.106.029V17a.75.75 0 001.5 0v-5a.751.751 0 00-1.394-.386l-.642 1.071a.25.25 0 01-.428 0l-.642-1.071A.751.751 0 0012.25 12v5a.75.75 0 00.75.75z"/></svg>',
|
||||
},
|
||||
attributes: {
|
||||
id: {
|
||||
type: String,
|
||||
title: 'ID',
|
||||
widget: 'input-text',
|
||||
default: '',
|
||||
},
|
||||
class: {
|
||||
type: String,
|
||||
title: 'Class',
|
||||
widget: 'input-text',
|
||||
default: '',
|
||||
},
|
||||
style: {
|
||||
type: String,
|
||||
title: 'Style',
|
||||
widget: 'input-text',
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
titlebar({ attributes }) {
|
||||
return []
|
||||
.concat([
|
||||
attributes.id ? `id: <strong>${attributes.id}</strong>` : null,
|
||||
attributes.class ? `class: <strong>${attributes.class}</strong>` : null,
|
||||
attributes.style ? `style: <strong>${attributes.style}</strong>` : null,
|
||||
])
|
||||
.filter((item) => !!item)
|
||||
.join(', ');
|
||||
},
|
||||
content({ attributes }) {
|
||||
const id = attributes.id || '';
|
||||
const cclass = attributes.class || '';
|
||||
const style = attributes.style || '';
|
||||
|
||||
return `<div id="${id}" class="${cclass}" style="${style}">{{content_editable}}</div>`;
|
||||
},
|
||||
});
|
@ -0,0 +1,46 @@
|
||||
window.nextgenEditor.addShortcode('figure', {
|
||||
type: 'block',
|
||||
plugin: 'shortcode-core',
|
||||
title: 'Figure',
|
||||
button: {
|
||||
group: 'shortcode-core',
|
||||
label: 'Figure',
|
||||
icon: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M24 3a3 3 0 00-3-3H3a3 3 0 00-3 3v18a3 3 0 003 3h18a3 3 0 003-3zm-2 18a1 1 0 01-1 1H3a1 1 0 01-1-1V3a1 1 0 011-1h18a1 1 0 011 1z"/><circle cx="14" cy="9.5" r="3"/><path d="M14 5.25a.75.75 0 00.75-.75V4a.75.75 0 00-1.5 0v.5a.75.75 0 00.75.75zM9.935 6.494A.75.75 0 1011 5.434l-.353-.354a.75.75 0 00-1.066 1.061zM8.5 10.25H9a.75.75 0 000-1.5h-.5a.75.75 0 000 1.5zM18.065 12.506a.75.75 0 00-1.06 1.06l.353.354a.75.75 0 001.061-1.061zM18.25 9.5a.75.75 0 00.75.75h.5a.75.75 0 000-1.5H19a.75.75 0 00-.75.75zM17.535 6.715a.743.743 0 00.53-.221l.354-.353a.75.75 0 00-1.061-1.061l-.353.354a.751.751 0 00.53 1.281zM15.8 16.086a4.573 4.573 0 00-1.449.234.249.249 0 00-.12.388 7.827 7.827 0 011.518 3.654.161.161 0 00.159.138h3.154a1.536 1.536 0 001.264-.663 4.607 4.607 0 00-4.526-3.751zM7.914 14.551a6.875 6.875 0 00-4.32 1.518.25.25 0 00-.094.2v2.7A1.535 1.535 0 005.035 20.5h9.427a.251.251 0 00.193-.09.249.249 0 00.053-.205 6.909 6.909 0 00-6.794-5.654z"/></svg>',
|
||||
},
|
||||
attributes: {
|
||||
id: {
|
||||
type: String,
|
||||
title: 'ID',
|
||||
widget: 'input-text',
|
||||
default: '',
|
||||
},
|
||||
class: {
|
||||
type: String,
|
||||
title: 'Class',
|
||||
widget: 'input-text',
|
||||
default: '',
|
||||
},
|
||||
caption: {
|
||||
type: String,
|
||||
title: 'Caption',
|
||||
widget: 'input-text',
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
titlebar({attributes }) {
|
||||
return []
|
||||
.concat([
|
||||
attributes.id ? `id: <strong>${attributes.id}</strong>` : null,
|
||||
attributes.class ? `class: <strong>${attributes.class}</strong>` : null,
|
||||
])
|
||||
.filter((item) => !!item)
|
||||
.join(', ');
|
||||
},
|
||||
content({ attributes }) {
|
||||
const id = attributes.id || '';
|
||||
const cclass = attributes.class || '';
|
||||
const caption = attributes.caption || '';
|
||||
|
||||
return `<div id="${id}" class="${cclass}">{{content_editable}}<div style="margin:0 8px;">${caption}</div></div>`;
|
||||
},
|
||||
});
|
@ -0,0 +1,50 @@
|
||||
window.nextgenEditor.addShortcode('fa', {
|
||||
type: 'inline',
|
||||
plugin: 'shortcode-core',
|
||||
title: 'Font Awesome',
|
||||
wrapOnInsert: false,
|
||||
button: {
|
||||
group: 'shortcode-core',
|
||||
label: 'Font Awesome',
|
||||
icon: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M11.093 18.527a1.5 1.5 0 01-.65.382.25.25 0 00-.181.212l-.227 1.941a1.03 1.03 0 001.752.849l2.671-2.671a7.688 7.688 0 001.622-2.446 12.4 12.4 0 00.366-3.007.25.25 0 00-.427-.186zM5.484 12.92l4.952-4.964a.251.251 0 00-.184-.427 12.988 12.988 0 00-3.087.349A7.687 7.687 0 004.75 9.531l-2.662 2.662a1.031 1.031 0 00.727 1.759c.035 0 1.572-.185 2.091-.248a.251.251 0 00.209-.174 1.5 1.5 0 01.369-.61zM6.038 16.536c-.845-.847-2.125-.7-3.183.353-.749.75-1.519 3.166-2.033 5.062a1 1 0 001.23 1.226c1.889-.52 4.3-1.3 5.046-2.045 1.057-1.057 1.2-2.337.354-3.182zM22.62.8c-1.248.252-3.756.838-4.534 1.616-.648.643-9.961 9.984-11.364 11.384a.25.25 0 000 .353l3.134 3.137a.25.25 0 00.353 0L21.587 5.913c.779-.779 1.365-3.287 1.616-4.534A.495.495 0 0022.62.8z"/></svg>',
|
||||
},
|
||||
attributes: {
|
||||
icon: {
|
||||
type: String,
|
||||
title: 'Icon',
|
||||
bbcode: true,
|
||||
widget: 'input-text',
|
||||
default: 'grav',
|
||||
},
|
||||
extras: {
|
||||
type: String,
|
||||
title: 'Extras',
|
||||
widget: 'input-text',
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
content({ attributes }) {
|
||||
let faclass = 'fa';
|
||||
|
||||
let icon = attributes.icon && !attributes.icon.startsWith('fa-')
|
||||
? `fa-${attributes.icon}`
|
||||
: attributes.icon;
|
||||
|
||||
if (attributes.extras) {
|
||||
attributes.extras.split(',').forEach((extra) => {
|
||||
if (extra) {
|
||||
if (['fab', 'fal', 'fas', 'far', 'fad'].includes(extra)) {
|
||||
faclass = extra;
|
||||
return;
|
||||
}
|
||||
|
||||
icon += !extra.startsWith('fa-')
|
||||
? ` fa-${extra}`
|
||||
: ` ${extra}`;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return `<span class="${faclass} ${icon}" style="margin:4px"></span>`;
|
||||
},
|
||||
});
|
@ -0,0 +1,32 @@
|
||||
shortcode-block[name="h1"] .sc-content,
|
||||
shortcode-block[name="h2"] .sc-content,
|
||||
shortcode-block[name="h3"] .sc-content,
|
||||
shortcode-block[name="h4"] .sc-content,
|
||||
shortcode-block[name="h5"] .sc-content,
|
||||
shortcode-block[name="h6"] .sc-content {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
shortcode-block[name="h1"] .sc-content {
|
||||
font-size: 30px;
|
||||
}
|
||||
|
||||
shortcode-block[name="h2"] .sc-content {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
shortcode-block[name="h3"] .sc-content {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
shortcode-block[name="h4"] .sc-content {
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
shortcode-block[name="h5"] .sc-content {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
shortcode-block[name="h6"] .sc-content {
|
||||
font-size: 14px;
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
window.nextgenEditor.addHook('hookInit', () => {
|
||||
window.nextgenEditor.addButtonGroup('shortcode-core-headers', {
|
||||
icon: '<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M17.567 20.509h-.61a.274.274 0 01-.24-.17L10.62 2.5l-.01-.01c-.21-.6-.76-1-1.39-1H9.2c-.63 0-1.19.39-1.39.99L1.74 20.29v-.01c-.04.09-.13.16-.24.16H.9a.976.976 0 10-.08 1.95h3l-.01-.001c.54 0 .97-.44.98-.98v-.02a.96.96 0 00-.82-.96l-.01-.001c-.07-.02-.14-.06-.17-.12a.245.245 0 01-.03-.2l1.5-4.413h-.01c.03-.1.12-.17.23-.17h7.23l-.01-.001c.1 0 .19.06.23.16l1.5 4.41c.04.12-.03.26-.16.31h-.04c-.47.07-.8.48-.8.95v-.01c-.01.54.43.97.97.98h2.94c.54.01.99-.41 1.01-.95.01-.55-.41-1-.95-1.02-.03-.01-.05-.01-.07-.01zM6.47 13.669v-.001c-.14 0-.25-.11-.25-.25-.01-.03 0-.06.01-.08L9 5.178h-.01c.04-.13.18-.2.31-.16.07.02.12.08.15.15l2.78 8.153c.02.07.01.15-.04.22h-.01c-.05.06-.13.1-.2.09z"/><path d="M23.02 20.509h-.22l-.01-.001a.274.274 0 01-.24-.17L18.29 7.87a1.53 1.53 0 00-1.94-.97c-.46.15-.81.5-.97.96l-1.15 3.38h-.01c-.18.51.09 1.06.61 1.24.51.17 1.06-.1 1.24-.62l.51-1.513v-.01c.04-.13.18-.2.31-.16.07.02.12.08.15.15l1.46 4.3c.04.12-.03.26-.16.31-.03 0-.06.01-.09.01h-1.37v-.01c-.55.01-.97.46-.95 1.01.01.51.43.93.94.94h2.2l-.01-.001c.1 0 .19.06.23.16l1.1 3.21a.25.25 0 01-.12.3v-.01c-.32.16-.52.49-.52.84v-.01c-.01.54.43.97.97.98h2.17c.54.01.99-.41 1.01-.95.01-.55-.41-1-.95-1.02-.03-.01-.05-.01-.07-.01z"/></svg>',
|
||||
label: 'SC Headers',
|
||||
});
|
||||
});
|
||||
|
||||
for (let i = 1; i <= 6; i += 1) {
|
||||
window.nextgenEditor.addShortcode(`h${i}`, {
|
||||
type: 'block',
|
||||
plugin: 'shortcode-core',
|
||||
title: `H${i}`,
|
||||
button: {
|
||||
group: 'shortcode-core-headers',
|
||||
label: `H${i}`,
|
||||
},
|
||||
attributes: {
|
||||
id: {
|
||||
type: String,
|
||||
title: 'ID',
|
||||
widget: 'input-text',
|
||||
default: '',
|
||||
},
|
||||
class: {
|
||||
type: String,
|
||||
title: 'Class',
|
||||
widget: 'input-text',
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
titlebar({ attributes }) {
|
||||
return []
|
||||
.concat([
|
||||
attributes.id ? `id: <strong>${attributes.id}</strong>` : null,
|
||||
attributes.class ? `class: <strong>${attributes.class}</strong>` : null,
|
||||
])
|
||||
.filter((item) => !!item)
|
||||
.join(', ');
|
||||
},
|
||||
content({ attributes }) {
|
||||
const id = attributes.id || '';
|
||||
const cclass = attributes.class || '';
|
||||
|
||||
return `<div id="${id}" class="${cclass}">{{content_editable}}</div>`;
|
||||
},
|
||||
});
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
window.nextgenEditor.addShortcode('lang', {
|
||||
type: 'block',
|
||||
plugin: 'shortcode-core',
|
||||
title: 'Language',
|
||||
button: {
|
||||
group: 'shortcode-core',
|
||||
label: 'Language',
|
||||
icon: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M22.917 11H15.5a.5.5 0 00-.5.5v.417A3.083 3.083 0 0111.917 15H11.5a.5.5 0 00-.5.5v7.417A1.083 1.083 0 0012.083 24h10.834A1.083 1.083 0 0024 22.915V12.081A1.083 1.083 0 0022.917 11zm-2.153 11.2a.741.741 0 01-.264.048.749.749 0 01-.7-.486l-.507-1.352a.251.251 0 00-.234-.162h-3.116a.251.251 0 00-.234.162l-.509 1.352a.75.75 0 01-1.4-.528l2.532-6.751a1.25 1.25 0 012.34 0l1.758 4.687a.889.889 0 01.038.1l.736 1.963a.75.75 0 01-.44.967z"/><path d="M16.459 18.41a.25.25 0 00.234.338h1.614a.25.25 0 00.234-.338l-.807-2.151a.25.25 0 00-.468 0zM7.779 5.607a.251.251 0 00-.226-.359H5.447a.251.251 0 00-.226.359 7.962 7.962 0 001.088 1.667.249.249 0 00.382 0 7.962 7.962 0 001.088-1.667z"/><path d="M11.917 13A1.083 1.083 0 0013 11.915V1.081A1.083 1.083 0 0011.917 0H1.083A1.083 1.083 0 000 1.081v10.834A1.083 1.083 0 001.083 13zm-1.193-2.3a.751.751 0 01-.724.554.782.782 0 01-.2-.026A9.212 9.212 0 016.651 9.67a.249.249 0 00-.3 0A9.212 9.212 0 013.2 11.222a.782.782 0 01-.2.026.749.749 0 01-.2-1.473 7.707 7.707 0 002.365-1.1.253.253 0 00.11-.175.248.248 0 00-.058-.2A9.508 9.508 0 013.53 5.412a.249.249 0 00-.23-.164h-.769a.75.75 0 010-1.5H5.5a.25.25 0 00.25-.25v-1a.75.75 0 111.5 0v1a.25.25 0 00.25.25h3a.75.75 0 010 1.5h-.795a.249.249 0 00-.235.164A9.508 9.508 0 017.783 8.3a.25.25 0 00.048.368 7.707 7.707 0 002.365 1.1.749.749 0 01.528.926zM17.646 5.352A.5.5 0 0018.5 5v-.31a.25.25 0 01.367-.221A4 4 0 0121 8a1 1 0 102 0 6 6 0 00-4.32-5.753.25.25 0 01-.18-.24V1a.5.5 0 00-.309-.462.506.506 0 00-.545.109l-2 2a.5.5 0 000 .707zM2 14a1 1 0 00-1 .992V15a6 6 0 004.32 5.753.25.25 0 01.18.24V22a.5.5 0 00.854.354l2-2a.5.5 0 000-.707l-2-2A.5.5 0 005.5 18v.31a.252.252 0 01-.121.215.248.248 0 01-.246.006A4 4 0 013 15a1 1 0 00-1-1z"/></svg>',
|
||||
},
|
||||
attributes: {
|
||||
lang: {
|
||||
type: String,
|
||||
title: 'Language',
|
||||
bbcode: true,
|
||||
widget: 'input-text',
|
||||
default: 'en',
|
||||
},
|
||||
},
|
||||
titlebar({ attributes }) {
|
||||
return `language: <strong>${attributes.lang}</strong>`;
|
||||
},
|
||||
content() {
|
||||
return '{{content_editable}}';
|
||||
},
|
||||
});
|
@ -0,0 +1,80 @@
|
||||
const sentence = 'Lorem ipsum dolor sit amet consectetur adipiscing elit, molestie tortor cubilia eu facilisi ex varius, convallis pretium dapibus fusce porta ligula.';
|
||||
const words = [].concat(...Array(1000).fill(sentence.toLowerCase().replace(/[.|,]/g, '').split(' ')));
|
||||
const paragraph = Array(2).fill(sentence).join(' ');
|
||||
|
||||
window.nextgenEditor.addShortcode('lorem', {
|
||||
type: 'block',
|
||||
plugin: 'shortcode-core',
|
||||
title: 'Lorem',
|
||||
wrapOnInsert: false,
|
||||
button: {
|
||||
group: 'shortcode-core',
|
||||
label: 'Lorem',
|
||||
icon: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M7.54 9a.48.48 0 00.172-.031A14.327 14.327 0 0112 8a14.327 14.327 0 014.288.969.507.507 0 00.172.031H19a.454.454 0 00.394-.678 8.553 8.553 0 00-4.206-3.685.5.5 0 00-.688.463v.4a.5.5 0 01-1 0v-4a1.5 1.5 0 00-3 0v4a.5.5 0 01-1 0v-.4a.5.5 0 00-.688-.463 8.555 8.555 0 00-4.206 3.684A.454.454 0 005 9zM20.5 12a1.5 1.5 0 00-1.5-1.5h-2.813a.493.493 0 01-.178-.033A14 14 0 0012 9.5a14 14 0 00-4.009.967.493.493 0 01-.178.033H5A1.5 1.5 0 003.5 12v6.639a3.5 3.5 0 001.2 2.633l2.87 2.512A.866.866 0 009 23.136V17a1.5 1.5 0 00-1.5-1.5H6.25a.75.75 0 010-1.5H9a1.5 1.5 0 011.5 1.5v2.793a.993.993 0 00.293.707l.5.5a1 1 0 001.414 0l.5-.5a.993.993 0 00.293-.707V15.5A1.5 1.5 0 0115 14h2.75a.75.75 0 010 1.5H16.5A1.5 1.5 0 0015 17v6.137a.864.864 0 001.432.649l2.873-2.514a3.5 3.5 0 001.2-2.633z"/></svg>',
|
||||
},
|
||||
attributes: {
|
||||
p: {
|
||||
type: Number,
|
||||
title: 'Paragraphs',
|
||||
bbcode: true,
|
||||
widget: {
|
||||
type: 'input-number',
|
||||
min: 0,
|
||||
max: 10,
|
||||
},
|
||||
default: 2,
|
||||
},
|
||||
tag: {
|
||||
type: String,
|
||||
title: 'Tag',
|
||||
widget: 'input-text',
|
||||
default: 'p',
|
||||
},
|
||||
s: {
|
||||
type: Number,
|
||||
title: 'Sentences',
|
||||
widget: 'input-number',
|
||||
default: 0,
|
||||
},
|
||||
w: {
|
||||
type: Number,
|
||||
title: 'Words',
|
||||
widget: 'input-number',
|
||||
default: 0,
|
||||
},
|
||||
},
|
||||
titlebar({ attributes }) {
|
||||
if (attributes.w) {
|
||||
return `words: <strong>${attributes.w}</strong>`;
|
||||
}
|
||||
|
||||
if (attributes.s) {
|
||||
return `sentences: <strong>${attributes.s}</strong>`;
|
||||
}
|
||||
|
||||
if (attributes.p) {
|
||||
return `paragraphs: <strong>${attributes.p}</strong>`;
|
||||
}
|
||||
|
||||
return '';
|
||||
},
|
||||
content({ attributes }) {
|
||||
let output = '';
|
||||
|
||||
output += '<div style="margin:16px 16px">';
|
||||
|
||||
if (attributes.w) {
|
||||
output += words.slice(0, attributes.w).join(' ');
|
||||
} else if (attributes.s) {
|
||||
output += Array(attributes.s).fill(sentence).join(' ');
|
||||
} else if (attributes.p) {
|
||||
[...Array(attributes.p)].forEach(() => {
|
||||
output += `<p>${paragraph}</p>`;
|
||||
});
|
||||
}
|
||||
|
||||
output += '</div>';
|
||||
|
||||
return output;
|
||||
},
|
||||
});
|
@ -0,0 +1,7 @@
|
||||
shortcode-inline[name="mark"] > .sc-content > span {
|
||||
background: #ffe9b3;
|
||||
border-bottom: .05rem solid #ffd367;
|
||||
border-radius: .1rem;
|
||||
color: #50596c;
|
||||
padding: .05rem .1rem 0;
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
window.nextgenEditor.addShortcode('mark', {
|
||||
type: 'inline',
|
||||
plugin: 'shortcode-core',
|
||||
title: 'Mark',
|
||||
button: {
|
||||
group: 'shortcode-core',
|
||||
label: 'Mark',
|
||||
icon: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M3.448 18a.253.253 0 00-.184-.073.25.25 0 00-.179.083L.192 21.247A.75.75 0 00.751 22.5H4a.752.752 0 00.507-.2L6 20.929a.244.244 0 00.081-.178.25.25 0 00-.073-.183zM7.27 20.035a1.256 1.256 0 001.7.068c.611-.524 1.8-1.278 2.894-.447a1.269 1.269 0 001.7-.171l.182-.227a.25.25 0 00-.018-.333l-8.673-8.667a.249.249 0 00-.341-.011l-.273.238a1.257 1.257 0 00-.111 1.641c.832 1.094.078 2.282-.444 2.894a1.254 1.254 0 00.065 1.7zM14.312 18.1a.249.249 0 00.372-.021L23.1 7.6a1.884 1.884 0 00-.133-2.486L18.379.523A1.841 1.841 0 0015.9.443L5.844 9.256a.25.25 0 00-.012.365zM24 23a1 1 0 00-1-1H9a1 1 0 000 2h14a1 1 0 001-1z"/></svg>',
|
||||
},
|
||||
attributes: {
|
||||
style: {
|
||||
type: String,
|
||||
title: 'Style',
|
||||
bbcode: true,
|
||||
widget: {
|
||||
type: 'radios',
|
||||
values: [
|
||||
{ value: 'inline', label: 'Inline' },
|
||||
{ value: 'block', label: 'Block' },
|
||||
],
|
||||
},
|
||||
default: 'inline',
|
||||
},
|
||||
class: {
|
||||
type: String,
|
||||
title: 'Class',
|
||||
widget: 'input-text',
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
titlebar({ attributes }) {
|
||||
return []
|
||||
.concat([
|
||||
attributes.style ? `style: <strong>${attributes.style}</strong>` : null,
|
||||
attributes.class ? `class: <strong>${attributes.class}</strong>` : null,
|
||||
])
|
||||
.filter((item) => !!item)
|
||||
.join(', ');
|
||||
},
|
||||
content({ attributes }) {
|
||||
const style = attributes.style === 'block'
|
||||
? 'display:block'
|
||||
: '';
|
||||
|
||||
const cclass = `mark-class-${attributes.class}`;
|
||||
|
||||
return `<span class="${cclass}" style="${style}">{{content_editable}}</span>`;
|
||||
},
|
||||
});
|
@ -0,0 +1,63 @@
|
||||
shortcode-block[name="notice"] .sc-notice {
|
||||
color: #666;
|
||||
font-size: 16px;
|
||||
line-height: 24px;
|
||||
margin: 8px 8px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
shortcode-block[name="notice"] .sc-notice .sc-notice-wrapper {
|
||||
padding: 4px 12px;
|
||||
}
|
||||
|
||||
shortcode-block[name="notice"] .sc-notice .sc-notice-wrapper:before {
|
||||
color: rgb(255, 255, 255);
|
||||
content: "";
|
||||
font-family: FontAwesome;
|
||||
left: 10px;
|
||||
position: absolute;
|
||||
top: 2px;
|
||||
}
|
||||
|
||||
shortcode-block[name="notice"] .sc-notice .sc-notice-wrapper:after {
|
||||
color: #fff;
|
||||
left: 30px;
|
||||
position: absolute;
|
||||
top: 3px;
|
||||
}
|
||||
|
||||
shortcode-block[name="notice"] .sc-notice-info .sc-notice-wrapper {
|
||||
border-top: 30px solid #F0B37E;
|
||||
background: #FFF2DB;
|
||||
}
|
||||
|
||||
shortcode-block[name="notice"] .sc-notice-warning .sc-notice-wrapper {
|
||||
border-top: 30px solid #DF6F6C;
|
||||
background: #FAE2E2;
|
||||
}
|
||||
|
||||
shortcode-block[name="notice"] .sc-notice-note .sc-notice-wrapper {
|
||||
border-top: 30px solid #6AB0DE;
|
||||
background: #E7F2FA;
|
||||
}
|
||||
|
||||
shortcode-block[name="notice"] .sc-notice-tip .sc-notice-wrapper {
|
||||
border-top: 30px solid #77C577;
|
||||
background: #E6F9E6;
|
||||
}
|
||||
|
||||
shortcode-block[name="notice"] .sc-notice-info .sc-notice-wrapper:after {
|
||||
content: 'Info';
|
||||
}
|
||||
|
||||
shortcode-block[name="notice"] .sc-notice-warning .sc-notice-wrapper:after {
|
||||
content: 'Warning';
|
||||
}
|
||||
|
||||
shortcode-block[name="notice"] .sc-notice-note .sc-notice-wrapper:after {
|
||||
content: 'Note';
|
||||
}
|
||||
|
||||
shortcode-block[name="notice"] .sc-notice-tip .sc-notice-wrapper:after {
|
||||
content: 'Tip';
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
window.nextgenEditor.addShortcode('notice', {
|
||||
type: 'block',
|
||||
plugin: 'shortcode-core',
|
||||
title: 'Notice',
|
||||
button: {
|
||||
group: 'shortcode-core',
|
||||
label: 'Notice',
|
||||
icon: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M8.5 14a1 1 0 00-.665.252L5 16.773V15a1 1 0 00-1-1H2.25a.251.251 0 01-.25-.253V2.25A.249.249 0 012.251 2h18a.25.25 0 01.25.25v10.007a.248.248 0 00.028.116l1.316 2.509a.25.25 0 00.445 0A1.939 1.939 0 0022.5 14V2a2 2 0 00-2-2H2a2 2 0 00-2 2v12.053A1.953 1.953 0 002 16h1v3a1 1 0 001.664.748L8.881 16h3.537a.251.251 0 00.221-.134l.787-1.5a.249.249 0 00-.007-.245.252.252 0 00-.214-.121z"/><path d="M18.782 12.271a1.45 1.45 0 00-2.562 0l-5.055 9.634a1.433 1.433 0 00.048 1.409 1.457 1.457 0 001.232.686h10.111a1.459 1.459 0 001.234-.687 1.434 1.434 0 00.047-1.408zM17.5 15.25a.75.75 0 01.75.75v3a.75.75 0 01-1.5 0v-3a.75.75 0 01.75-.75zm0 7a1 1 0 111-1 1 1 0 01-1 1z"/></svg>',
|
||||
},
|
||||
attributes: {
|
||||
notice: {
|
||||
type: String,
|
||||
title: 'Type',
|
||||
bbcode: true,
|
||||
widget: {
|
||||
type: 'radios',
|
||||
values: [
|
||||
{ value: 'info', label: 'Info' },
|
||||
{ value: 'warning', label: 'Warning' },
|
||||
{ value: 'note', label: 'Note' },
|
||||
{ value: 'tip', label: 'Tip' },
|
||||
],
|
||||
},
|
||||
default: 'info',
|
||||
},
|
||||
},
|
||||
titlebar({ attributes }) {
|
||||
const notice = attributes.notice
|
||||
? this.attributes.notice.widget.values.find((item) => item.value === attributes.notice)
|
||||
: '';
|
||||
|
||||
const type = notice
|
||||
? notice.label
|
||||
: '';
|
||||
|
||||
return `type: <strong>${type}</strong>`;
|
||||
},
|
||||
content({ attributes }) {
|
||||
return `<div class="sc-notice sc-notice-${attributes.notice}"><div class="sc-notice-wrapper">{{content_editable}}</div></div>`;
|
||||
},
|
||||
});
|
13
plugins/shortcode-core/nextgen-editor/shortcodes/raw/raw.js
Normal file
13
plugins/shortcode-core/nextgen-editor/shortcodes/raw/raw.js
Normal file
@ -0,0 +1,13 @@
|
||||
window.nextgenEditor.addShortcode('raw', {
|
||||
type: 'block',
|
||||
plugin: 'shortcode-core',
|
||||
title: 'Raw',
|
||||
button: {
|
||||
group: 'shortcode-core',
|
||||
label: 'Raw',
|
||||
icon: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 15.034 9"><path d="M5.726 0a.5.5 0 00-.5.5h-2.25a2.744 2.744 0 00-1.807 4.813A1.998 1.998 0 00.226 7c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2 0-.488-.186-.93-.48-1.277l2.177.963a.75.75 0 10.606-1.372l-1.81-.802 1.63-.272a.75.75 0 10-.246-1.48l-2.13.355C11.484 1.952 10.264.784 8.226.55V.5a.5.5 0 00-.5-.5h-2zm.5 1h1v7h-1V1zm3.5 4c.259 0 .464.197.49.45l.076-.134a.5.5 0 11.866.5l-.258.448a.986.986 0 01.326.736c0 .563-.437 1-1 1h-2V6h1v-.5c0-.277.223-.5.5-.5zm-7.06.07a.498.498 0 01.494.246l.2.348a.493.493 0 01.366-.164c.277 0 .5.223.5.5h1v2h-3c-.563 0-1-.437-1-1s.437-1 1-1H2.4l-.106-.184a.497.497 0 01.371-.746z"/></svg>',
|
||||
},
|
||||
content() {
|
||||
return '{{content_editable}}';
|
||||
},
|
||||
});
|
@ -0,0 +1,48 @@
|
||||
window.nextgenEditor.addShortcode('safe-email', {
|
||||
type: 'inline',
|
||||
plugin: 'shortcode-core',
|
||||
title: 'Safe Email',
|
||||
button: {
|
||||
group: 'shortcode-core',
|
||||
label: 'Safe Email',
|
||||
icon: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M19 9.25a4.924 4.924 0 011.666.291.25.25 0 00.334-.236V1.75a.158.158 0 00-.1-.147.16.16 0 00-.173.034L12.2 10.164a2.407 2.407 0 01-3.4 0L.271 1.637A.159.159 0 000 1.75v10.5A1.749 1.749 0 001.75 14h12.043a.25.25 0 00.249-.226A4.992 4.992 0 0119 9.25z"/><path d="M9.726 9.236a1.094 1.094 0 001.547 0L19.748.761A.437.437 0 0019.5.019 1.62 1.62 0 0019.249 0h-17.5A1.62 1.62 0 001.5.019a.437.437 0 00-.352.3.441.441 0 00.102.442zM22.5 15.5v-1.25a3.5 3.5 0 00-7 0v1.25A1.5 1.5 0 0014 17v5.5a1.5 1.5 0 001.5 1.5h7a1.5 1.5 0 001.5-1.5V17a1.5 1.5 0 00-1.5-1.5zM19 12.75a1.5 1.5 0 011.5 1.5v1.25h-3v-1.25a1.5 1.5 0 011.5-1.5zm1 7.5a1 1 0 11-1-1 1 1 0 011 1z"/></svg>',
|
||||
},
|
||||
attributes: {
|
||||
icon: {
|
||||
type: String,
|
||||
title: 'Icon',
|
||||
bbcode: true,
|
||||
widget: 'input-text',
|
||||
default: 'grav',
|
||||
},
|
||||
autolink: {
|
||||
type: String,
|
||||
title: 'Autolink',
|
||||
widget: {
|
||||
type: 'checkbox',
|
||||
valueType: String,
|
||||
label: 'Yes',
|
||||
},
|
||||
default: 'false',
|
||||
},
|
||||
},
|
||||
content({ attributes }) {
|
||||
let output = '';
|
||||
|
||||
if (attributes.autolink === 'true') {
|
||||
output += '<span style="color:#1c90fb">';
|
||||
}
|
||||
|
||||
if (attributes.icon) {
|
||||
output += `<span class="fa fa-${attributes.icon}" style="margin-left:4px"></span>`;
|
||||
}
|
||||
|
||||
output += '{{content_editable}}';
|
||||
|
||||
if (attributes.autolink === 'true') {
|
||||
output += '</span>';
|
||||
}
|
||||
|
||||
return output;
|
||||
},
|
||||
});
|
@ -0,0 +1,26 @@
|
||||
window.nextgenEditor.addShortcode('section', {
|
||||
type: 'block',
|
||||
plugin: 'shortcode-core',
|
||||
title: 'Section',
|
||||
button: {
|
||||
group: 'shortcode-core',
|
||||
label: 'Section',
|
||||
icon: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20.242 18.827a6.523 6.523 0 10-1.414 1.414l3.465 3.465a1.014 1.014 0 001.414 0 1 1 0 000-1.414zM15 10.5a4.5 4.5 0 11-4.5 4.5 4.505 4.505 0 014.5-4.5z"/><path d="M13 15.749h1.25V17a.75.75 0 001.5 0v-1.25H17a.75.75 0 000-1.5h-1.25V13a.75.75 0 00-1.5 0v1.25H13a.75.75 0 000 1.5zM3.933 0H1.957A1.959 1.959 0 000 1.956v1.977a1 1 0 002 0L1.957 2h1.976a1 1 0 000-2zM3.933 22L2 22.042v-1.976a1 1 0 00-2 0v1.976A1.959 1.959 0 001.957 24h1.976a1 1 0 000-2zM1 11.533a1 1 0 001-1V7.6a1 1 0 00-2 0v2.934a1 1 0 001 .999zM1 17.4a1 1 0 001-1v-2.934a1 1 0 00-2 0V16.4a1 1 0 001 1zM23 6.6a1 1 0 00-1 1v2.934a1 1 0 102 0V7.6a1 1 0 00-1-1zM7.6 2H10a1 1 0 000-2H7.6a1 1 0 000 2zM14 2h2.4a1 1 0 000-2H14a1 1 0 000 2zM20.067 2L22 1.956v1.977a1 1 0 002 0V1.956A1.959 1.959 0 0022.043 0h-1.976a1 1 0 000 2zM10.533 22H7.6a1 1 0 100 2h2.933a1 1 0 000-2z"/></svg>',
|
||||
},
|
||||
attributes: {
|
||||
name: {
|
||||
type: String,
|
||||
title: 'Name',
|
||||
widget: 'input-text',
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
titlebar({ attributes }) {
|
||||
return attributes.name
|
||||
? `name: <strong>${attributes.name}</strong>`
|
||||
: '';
|
||||
},
|
||||
content() {
|
||||
return '{{content_editable}}';
|
||||
},
|
||||
});
|
@ -0,0 +1,10 @@
|
||||
window.nextgenEditor.addHook('hookInit', () => {
|
||||
window.nextgenEditor.addShortcodePlugin('shortcode-core', {
|
||||
title: 'Shortcode Core',
|
||||
});
|
||||
|
||||
window.nextgenEditor.addButtonGroup('shortcode-core', {
|
||||
icon: '<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M22 0H1.99c-1.11 0-2 .89-2 2v7-.01c-.01 1.1.89 2 1.99 2h20l-.01-.001c1.1 0 2-.9 2-2v-7a2 2 0 00-2-2zm-7.25 8.5c0 .27-.23.5-.5.5H2.49a.51.51 0 01-.5-.51V2.479c0-.28.22-.5.5-.5h11.75-.01c.27-.01.5.22.5.49zM21 6.85h-.01c-.01.4-.33.72-.73.72a.824.824 0 01-.46-.16l-1.75-1.4-.01-.01a.733.733 0 01-.12-1.03c.03-.05.07-.09.11-.12l1.74-1.4h-.01c.31-.26.77-.21 1.02.11.1.13.16.29.15.46z"/><path d="M4 4.75h7.5l-.01-.001a.749.749 0 100-1.5H3.98c-.42 0-.75.33-.75.75 0 .41.33.75.75.75zM4 7.75h4.5l-.01-.001a.749.749 0 100-1.5H3.98c-.42 0-.75.33-.75.75 0 .41.33.75.75.75zM22 13H1.99c-1.11 0-2 .89-2 2v7-.01c-.01 1.1.89 2 1.99 2h20l-.01-.001c1.1 0 2-.9 2-2v-7a2 2 0 00-2-2zm-7.25 8.5c0 .27-.23.5-.5.5H2.49a.51.51 0 01-.5-.51v-6c-.01-.28.22-.51.49-.51h11.75-.01c.27-.01.5.22.5.49zM21 19.85h-.01c-.01.4-.33.72-.73.72a.824.824 0 01-.46-.16l-1.75-1.4-.01-.01a.733.733 0 01-.12-1.03c.03-.05.07-.09.11-.12l1.74-1.4h-.01c.31-.26.77-.21 1.02.11.1.13.16.29.15.46z"/><path d="M4 17.75h7.5-.01a.749.749 0 100-1.5H3.98c-.42 0-.75.33-.75.75 0 .41.33.75.75.75zM4 20.75h4.5-.01a.749.749 0 100-1.5H3.98c-.42 0-.75.33-.75.75 0 .41.33.75.75.75z"/></svg>',
|
||||
label: 'Shortcode Core',
|
||||
});
|
||||
});
|
@ -0,0 +1,26 @@
|
||||
window.nextgenEditor.addShortcode('size', {
|
||||
type: 'inline',
|
||||
plugin: 'shortcode-core',
|
||||
title: 'Font Size',
|
||||
button: {
|
||||
group: 'shortcode-core',
|
||||
label: 'Font Size',
|
||||
icon: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M13 3.993H2a2 2 0 00-2 2v2a1 1 0 002 0v-1.75a.249.249 0 01.25-.25h4a.249.249 0 01.25.25v12.5a.25.25 0 01-.25.25H4.5a1 1 0 000 2h6a1 1 0 000-2H8.75a.25.25 0 01-.25-.25v-12.5a.249.249 0 01.25-.25h4a.249.249 0 01.25.25v1.75a1 1 0 102 0v-2a2 2 0 00-2-2zM23.5 18.493h-1.75a.25.25 0 01-.25-.25v-12.5a.249.249 0 01.25-.25h1.75a.5.5 0 00.4-.8l-3-4a.518.518 0 00-.8 0l-3 4a.5.5 0 00.4.8h1.75a.249.249 0 01.25.25v12.5a.25.25 0 01-.25.25H17.5a.5.5 0 00-.4.8l3 4a.5.5 0 00.8 0l3-4a.5.5 0 00-.4-.8z"/></svg>',
|
||||
},
|
||||
attributes: {
|
||||
size: {
|
||||
type: String,
|
||||
title: 'Size',
|
||||
bbcode: true,
|
||||
widget: 'input-text',
|
||||
default: '14',
|
||||
},
|
||||
},
|
||||
content({ attributes }) {
|
||||
const size = !Number.isNaN(+attributes.size)
|
||||
? `${attributes.size}px`
|
||||
: attributes.size;
|
||||
|
||||
return `<span style="font-size:${size}">{{content_editable}}</span>`;
|
||||
},
|
||||
});
|
@ -0,0 +1,37 @@
|
||||
window.nextgenEditor.addShortcode('span', {
|
||||
type: 'inline',
|
||||
plugin: 'shortcode-core',
|
||||
title: 'Span',
|
||||
button: {
|
||||
group: 'shortcode-core',
|
||||
label: 'Span',
|
||||
icon: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M24 4.5a3 3 0 00-3-3H3a3 3 0 00-3 3v15a3 3 0 003 3h18a3 3 0 003-3zM3 5a1 1 0 111 1 1 1 0 01-1-1zm3 0a1 1 0 111 1 1 1 0 01-1-1zm3 0a1 1 0 111 1 1 1 0 01-1-1zm13 14.5a1 1 0 01-1 1H3a1 1 0 01-1-1V9a.5.5 0 01.5-.5h19a.5.5 0 01.5.5z"/><path d="M7.75 12a.75.75 0 00.75.75.25.25 0 01.25.25v4a.75.75 0 001.5 0v-4a.25.25 0 01.25-.25.75.75 0 000-1.5h-2a.75.75 0 00-.75.75zM4 17.75a.75.75 0 00.75-.75v-1a.25.25 0 01.5 0v1a.75.75 0 001.5 0v-5a.75.75 0 00-1.5 0v2a.25.25 0 01-.5 0v-2a.75.75 0 00-1.5 0v5a.75.75 0 00.75.75zM17.75 16a1.752 1.752 0 001.75 1.75h1a.75.75 0 000-1.5h-1a.25.25 0 01-.25-.25v-4a.75.75 0 00-1.5 0zM13 17.75a.75.75 0 00.75-.75v-2.085a.057.057 0 01.106-.029.781.781 0 001.288 0 .057.057 0 01.106.029V17a.75.75 0 001.5 0v-5a.751.751 0 00-1.394-.386l-.642 1.071a.25.25 0 01-.428 0l-.642-1.071A.751.751 0 0012.25 12v5a.75.75 0 00.75.75z"/></svg>',
|
||||
},
|
||||
attributes: {
|
||||
id: {
|
||||
type: String,
|
||||
title: 'ID',
|
||||
widget: 'input-text',
|
||||
default: '',
|
||||
},
|
||||
class: {
|
||||
type: String,
|
||||
title: 'Class',
|
||||
widget: 'input-text',
|
||||
default: '',
|
||||
},
|
||||
style: {
|
||||
type: String,
|
||||
title: 'Style',
|
||||
widget: 'input-text',
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
content({ attributes }) {
|
||||
const id = attributes.id || '';
|
||||
const cclass = attributes.class || '';
|
||||
const style = attributes.style || '';
|
||||
|
||||
return `<span id="${id}" class="${cclass}" style="${style}">{{content_editable}}</span>`;
|
||||
},
|
||||
});
|
13
plugins/shortcode-core/nextgen-editor/shortcodes/u/u.js
Normal file
13
plugins/shortcode-core/nextgen-editor/shortcodes/u/u.js
Normal file
@ -0,0 +1,13 @@
|
||||
window.nextgenEditor.addShortcode('u', {
|
||||
type: 'inline',
|
||||
plugin: 'shortcode-core',
|
||||
title: 'Underline',
|
||||
button: {
|
||||
group: 'shortcode-core',
|
||||
label: 'Underline',
|
||||
icon: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M22.5 21.248h-21a1.25 1.25 0 000 2.5h21a1.25 1.25 0 000-2.5zM1.978 2.748h1.363a.25.25 0 01.25.25v8.523a8.409 8.409 0 0016.818 0V3a.25.25 0 01.25-.25h1.363a1.25 1.25 0 000-2.5H16.3a1.25 1.25 0 000 2.5h1.363a.25.25 0 01.25.25v8.523a5.909 5.909 0 01-11.818 0V3a.25.25 0 01.25-.25H7.7a1.25 1.25 0 100-2.5H1.978a1.25 1.25 0 000 2.5z"/></svg>',
|
||||
},
|
||||
content() {
|
||||
return '<span style="text-decoration:underline">{{content_editable}}</span>';
|
||||
},
|
||||
});
|
30
plugins/shortcode-core/nextgen-editor/src/collapse.js
Normal file
30
plugins/shortcode-core/nextgen-editor/src/collapse.js
Normal file
@ -0,0 +1,30 @@
|
||||
export default function collapse(input) {
|
||||
let output = input;
|
||||
|
||||
output = output.replace(/<figure class="image">((((?!(<\/figure>)).)|\n)*)<\/figure>/gm, '$1');
|
||||
|
||||
const domOutput = new DOMParser().parseFromString(output, 'text/html');
|
||||
|
||||
[...domOutput.querySelectorAll('shortcode-block, shortcode-inline')].forEach((domShortcode) => {
|
||||
domShortcode.setAttribute('sc-rendered', false);
|
||||
});
|
||||
|
||||
let domShortcode = domOutput.querySelector('shortcode-block[sc-rendered], shortcode-inline[sc-rendered]');
|
||||
|
||||
while (domShortcode) {
|
||||
const name = domShortcode.getAttribute('name');
|
||||
const shortcode = window.nextgenEditor.shortcodes[name];
|
||||
|
||||
domShortcode.removeAttribute('class');
|
||||
domShortcode.removeAttribute('sc-rendered');
|
||||
|
||||
const domInnerContent = domShortcode.querySelector(`shortcode-${shortcode.type}-editable, shortcode-${shortcode.type}-readonly`);
|
||||
domShortcode.innerHTML = (domInnerContent && domInnerContent.innerHTML) || '';
|
||||
|
||||
domShortcode = domOutput.querySelector('shortcode-block[sc-rendered], shortcode-inline[sc-rendered]');
|
||||
}
|
||||
|
||||
output = domOutput.body.innerHTML;
|
||||
|
||||
return output;
|
||||
}
|
153
plugins/shortcode-core/nextgen-editor/src/command.js
Normal file
153
plugins/shortcode-core/nextgen-editor/src/command.js
Normal file
@ -0,0 +1,153 @@
|
||||
import collapse from './collapse';
|
||||
import uncollapse from './uncollapse';
|
||||
|
||||
const Command = window.nextgenEditor.classes.core.command.class;
|
||||
|
||||
window.nextgenEditor.addPlugin('GravShortcodeCoreCommand', {
|
||||
init() {
|
||||
Object.values(window.nextgenEditor.shortcodes).forEach((shortcode) => {
|
||||
const commandName = `shortcode_${shortcode.name}`;
|
||||
|
||||
class GravShortcodeCoreCommand extends Command {
|
||||
execute(args) {
|
||||
this.editor.model.change((modelWriter) => {
|
||||
let dataShortcode = '';
|
||||
const argsForUncollapse = {};
|
||||
|
||||
const wrapOnInsert = !shortcode.child && !shortcode.parent
|
||||
? shortcode.wrapOnInsert !== undefined
|
||||
? shortcode.wrapOnInsert
|
||||
: true
|
||||
: false;
|
||||
|
||||
const selectedBlocks = [...this.editor.model.document.selection.getSelectedBlocks()];
|
||||
const selectedItems = [...this.editor.model.document.selection.getFirstRange().getItems({ shallow: true })];
|
||||
|
||||
const firstSelectedBlock = selectedBlocks[0];
|
||||
const firstBlockSelectedItems = selectedItems.filter((item) => item.parent === firstSelectedBlock);
|
||||
|
||||
const attributes = Object.keys(shortcode.attributes).reduce((acc, attrName) => {
|
||||
acc[attrName] = shortcode.attributes[attrName].default.value;
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
dataShortcode += `<shortcode-${shortcode.type} name="${shortcode.name}" attributes="${encodeURIComponent(JSON.stringify(attributes))}">`;
|
||||
|
||||
if (wrapOnInsert) {
|
||||
if (shortcode.type === 'block') {
|
||||
const modelSelectedBlocks = modelWriter.createDocumentFragment();
|
||||
selectedBlocks.forEach((block) => modelWriter.append(modelWriter.cloneElement(block), modelSelectedBlocks));
|
||||
|
||||
const viewSelectedBlocks = this.editor.data.toView(modelSelectedBlocks);
|
||||
const dataSelectedBlocks = this.editor.data.processor.toData(viewSelectedBlocks);
|
||||
|
||||
dataShortcode += collapse(dataSelectedBlocks);
|
||||
}
|
||||
|
||||
if (shortcode.type === 'inline') {
|
||||
const modelSelectedBlocks = modelWriter.createDocumentFragment();
|
||||
|
||||
firstBlockSelectedItems.forEach((item) => {
|
||||
const block = item.textNode
|
||||
? modelWriter.createText(item.data)
|
||||
: modelWriter.cloneElement(item);
|
||||
|
||||
modelWriter.append(block, modelSelectedBlocks);
|
||||
});
|
||||
|
||||
const viewSelectedBlocks = this.editor.data.toView(modelSelectedBlocks);
|
||||
const dataSelectedBlocks = this.editor.data.processor.toData(viewSelectedBlocks);
|
||||
|
||||
dataShortcode += collapse(dataSelectedBlocks);
|
||||
}
|
||||
}
|
||||
|
||||
if (shortcode.parent) {
|
||||
dataShortcode += '<p> </p>';
|
||||
}
|
||||
|
||||
dataShortcode += `</shortcode-${shortcode.type}>`;
|
||||
|
||||
if (shortcode.parent) {
|
||||
if (args && args.modelParentShortcode) {
|
||||
argsForUncollapse.parentAttributes = JSON.parse(decodeURIComponent(args.modelParentShortcode.getAttribute('attributes')));
|
||||
}
|
||||
}
|
||||
|
||||
dataShortcode = uncollapse(dataShortcode, argsForUncollapse);
|
||||
|
||||
const convertContext = shortcode.type === 'inline'
|
||||
? '$block'
|
||||
: '$root';
|
||||
|
||||
const viewShortcode = this.editor.data.processor.toView(dataShortcode).getChild(0);
|
||||
const modelShortcode = this.editor.data.toModel(viewShortcode, convertContext).getChild(0);
|
||||
|
||||
let insertPosition = modelWriter.createPositionAt(this.editor.model.document.getRoot(), 0);
|
||||
|
||||
if (!args || !args.insertPosition) {
|
||||
if (shortcode.type === 'block') {
|
||||
const firstBlock = selectedBlocks[0];
|
||||
const lastBlock = selectedBlocks[selectedBlocks.length - 1];
|
||||
|
||||
if (wrapOnInsert) {
|
||||
insertPosition = modelWriter.createPositionBefore(firstBlock);
|
||||
|
||||
modelWriter.remove(
|
||||
modelWriter.createRange(
|
||||
modelWriter.createPositionBefore(firstBlock),
|
||||
modelWriter.createPositionAfter(lastBlock),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
insertPosition = modelWriter.createPositionAfter(lastBlock);
|
||||
|
||||
if (lastBlock && lastBlock.name === 'paragraph' && lastBlock.childCount === 0) {
|
||||
insertPosition = modelWriter.createPositionBefore(lastBlock);
|
||||
modelWriter.remove(lastBlock);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (shortcode.type === 'inline') {
|
||||
const firstItem = firstBlockSelectedItems.length
|
||||
? firstBlockSelectedItems[0]
|
||||
: null;
|
||||
|
||||
const lastItem = firstBlockSelectedItems.length
|
||||
? firstBlockSelectedItems[firstBlockSelectedItems.length - 1]
|
||||
: null;
|
||||
|
||||
if (wrapOnInsert) {
|
||||
insertPosition = firstItem
|
||||
? modelWriter.createPositionBefore(firstItem)
|
||||
: this.editor.model.document.selection.getFirstPosition();
|
||||
|
||||
if (firstItem) {
|
||||
modelWriter.remove(
|
||||
modelWriter.createRange(
|
||||
modelWriter.createPositionBefore(firstItem),
|
||||
modelWriter.createPositionAfter(lastItem),
|
||||
),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
insertPosition = lastItem
|
||||
? modelWriter.createPositionAfter(lastItem)
|
||||
: this.editor.model.document.selection.getFirstPosition();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
insertPosition = args.insertPosition;
|
||||
}
|
||||
|
||||
modelWriter.insert(modelShortcode, insertPosition);
|
||||
modelWriter.setSelection(modelShortcode, 'on');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
this.editor.commands.add(commandName, new GravShortcodeCoreCommand(this.editor));
|
||||
});
|
||||
},
|
||||
});
|
150
plugins/shortcode-core/nextgen-editor/src/converters.js
Normal file
150
plugins/shortcode-core/nextgen-editor/src/converters.js
Normal file
@ -0,0 +1,150 @@
|
||||
const Widget = window.nextgenEditor.classes.widget.class;
|
||||
const { toWidget, toWidgetEditable } = window.nextgenEditor.classes.widget.utils;
|
||||
|
||||
window.nextgenEditor.addPlugin('GravShortcodeCoreConvertersBlock', {
|
||||
requires: [Widget],
|
||||
init() {
|
||||
this.editor.model.schema.register('shortcode-block', {
|
||||
isBlock: true,
|
||||
isObject: true,
|
||||
allowWhere: '$block',
|
||||
allowContentOf: '$root',
|
||||
allowAttributes: [
|
||||
'name',
|
||||
'attributes',
|
||||
'class',
|
||||
],
|
||||
});
|
||||
|
||||
this.editor.conversion.for('upcast').elementToElement({
|
||||
view: 'shortcode-block',
|
||||
model(viewElement, { writer }) {
|
||||
return writer.createElement('shortcode-block', viewElement.getAttributes());
|
||||
},
|
||||
});
|
||||
|
||||
this.editor.conversion.for('dataDowncast').elementToElement({
|
||||
model: 'shortcode-block',
|
||||
view(modelElement, { writer }) {
|
||||
return writer.createContainerElement('shortcode-block', modelElement.getAttributes());
|
||||
},
|
||||
});
|
||||
|
||||
this.editor.conversion.for('editingDowncast').elementToElement({
|
||||
model: 'shortcode-block',
|
||||
view(modelElement, { writer }) {
|
||||
const container = writer.createContainerElement('shortcode-block', modelElement.getAttributes());
|
||||
return toWidget(container, writer);
|
||||
},
|
||||
});
|
||||
|
||||
this.editor.model.schema.register('shortcode-block-editable', {
|
||||
isLimit: true,
|
||||
allowWhere: '$block',
|
||||
allowContentOf: '$root',
|
||||
});
|
||||
|
||||
this.editor.conversion.for('upcast').elementToElement({
|
||||
view: 'shortcode-block-editable',
|
||||
model: 'shortcode-block-editable',
|
||||
});
|
||||
|
||||
this.editor.conversion.for('dataDowncast').elementToElement({
|
||||
model: 'shortcode-block-editable',
|
||||
view: 'shortcode-block-editable',
|
||||
});
|
||||
|
||||
this.editor.conversion.for('editingDowncast').elementToElement({
|
||||
model: 'shortcode-block-editable',
|
||||
view(modelElement, { writer }) {
|
||||
const container = writer.createEditableElement('shortcode-block-editable', modelElement.getAttributes());
|
||||
return toWidgetEditable(container, writer);
|
||||
},
|
||||
});
|
||||
|
||||
this.editor.model.schema.register('shortcode-block-readonly', {
|
||||
isLimit: true,
|
||||
allowWhere: '$block',
|
||||
allowContentOf: '$root',
|
||||
});
|
||||
|
||||
this.editor.conversion.elementToElement({
|
||||
view: 'shortcode-block-readonly',
|
||||
model: 'shortcode-block-readonly',
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
window.nextgenEditor.addPlugin('GravShortcodeCoreConvertersInline', {
|
||||
requires: [Widget],
|
||||
init() {
|
||||
this.editor.model.schema.register('shortcode-inline', {
|
||||
isObject: true,
|
||||
isInline: true,
|
||||
allowWhere: '$text',
|
||||
allowContentOf: '$block',
|
||||
allowAttributes: [
|
||||
'name',
|
||||
'attributes',
|
||||
'class',
|
||||
],
|
||||
});
|
||||
|
||||
this.editor.conversion.for('upcast').elementToElement({
|
||||
view: 'shortcode-inline',
|
||||
model(viewElement, { writer }) {
|
||||
return writer.createElement('shortcode-inline', viewElement.getAttributes());
|
||||
},
|
||||
});
|
||||
|
||||
this.editor.conversion.for('dataDowncast').elementToElement({
|
||||
model: 'shortcode-inline',
|
||||
view(modelElement, { writer }) {
|
||||
return writer.createContainerElement('shortcode-inline', modelElement.getAttributes());
|
||||
},
|
||||
});
|
||||
|
||||
this.editor.conversion.for('editingDowncast').elementToElement({
|
||||
model: 'shortcode-inline',
|
||||
view(modelElement, { writer }) {
|
||||
const container = writer.createContainerElement('shortcode-inline', modelElement.getAttributes());
|
||||
return toWidget(container, writer);
|
||||
},
|
||||
});
|
||||
|
||||
this.editor.model.schema.register('shortcode-inline-editable', {
|
||||
isLimit: true,
|
||||
allowWhere: '$text',
|
||||
allowContentOf: '$block',
|
||||
});
|
||||
|
||||
this.editor.conversion.for('upcast').elementToElement({
|
||||
view: 'shortcode-inline-editable',
|
||||
model: 'shortcode-inline-editable',
|
||||
});
|
||||
|
||||
this.editor.conversion.for('dataDowncast').elementToElement({
|
||||
model: 'shortcode-inline-editable',
|
||||
view: 'shortcode-inline-editable',
|
||||
});
|
||||
|
||||
this.editor.conversion.for('editingDowncast').elementToElement({
|
||||
model: 'shortcode-inline-editable',
|
||||
view(modelElement, { writer }) {
|
||||
const container = writer.createEditableElement('shortcode-inline-editable', modelElement.getAttributes());
|
||||
return toWidgetEditable(container, writer);
|
||||
},
|
||||
});
|
||||
|
||||
this.editor.model.schema.register('shortcode-inline-readonly', {
|
||||
isLimit: true,
|
||||
allowWhere: '$text',
|
||||
allowContentOf: '$block',
|
||||
});
|
||||
|
||||
this.editor.conversion.elementToElement({
|
||||
view: 'shortcode-inline-readonly',
|
||||
model: 'shortcode-inline-readonly',
|
||||
});
|
||||
},
|
||||
});
|
86
plugins/shortcode-core/nextgen-editor/src/events.js
Normal file
86
plugins/shortcode-core/nextgen-editor/src/events.js
Normal file
@ -0,0 +1,86 @@
|
||||
import displaySettings from './settings';
|
||||
|
||||
window.scDisplaySettings = function scDisplaySettings() {
|
||||
const domShortcode = this.closest('shortcode-block, shortcode-inline');
|
||||
|
||||
if (domShortcode) {
|
||||
displaySettings(domShortcode);
|
||||
}
|
||||
};
|
||||
|
||||
window.scBlockAddChildFromParent = function scBlockAddChildFromParent() {
|
||||
const { editors } = window.nextgenEditor;
|
||||
|
||||
const domShortcode = this.parentNode;
|
||||
const editor = (editors.filter((instance) => instance.ui.view.element.contains(domShortcode)) || []).shift();
|
||||
|
||||
const name = domShortcode.getAttribute('name');
|
||||
const shortcode = window.nextgenEditor.shortcodes[name];
|
||||
|
||||
if (editor) {
|
||||
const viewShortcode = editor.editing.view.domConverter.mapDomToView(domShortcode);
|
||||
const modelShortcode = editor.editing.mapper.toModelElement(viewShortcode);
|
||||
|
||||
const domShortcodeBlockReadOnly = domShortcode.querySelector('shortcode-block-readonly');
|
||||
const viewShortcodeBlockReadOnly = editor.editing.view.domConverter.mapDomToView(domShortcodeBlockReadOnly);
|
||||
const modelShortcodeBlockReadOnly = editor.editing.mapper.toModelElement(viewShortcodeBlockReadOnly);
|
||||
|
||||
editor.model.change((modelWriter) => {
|
||||
const insertPosition = modelWriter.createPositionAt(modelShortcodeBlockReadOnly, 0);
|
||||
editor.execute(`shortcode_${shortcode.child.name}`, { insertPosition, modelParentShortcode: modelShortcode });
|
||||
|
||||
domShortcode.querySelector('.sc-add-child').classList.remove('sc-visible');
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
window.scBlockAddChild = function scBlockAddChild(event, where) {
|
||||
const { editors } = window.nextgenEditor;
|
||||
|
||||
const domShortcode = this.parentNode;
|
||||
const editor = (editors.filter((instance) => instance.ui.view.element.contains(domShortcode)) || []).shift();
|
||||
|
||||
const name = domShortcode.getAttribute('name');
|
||||
const shortcode = window.nextgenEditor.shortcodes[name];
|
||||
|
||||
if (editor) {
|
||||
const viewShortcode = editor.editing.view.domConverter.mapDomToView(domShortcode);
|
||||
const modelShortcode = editor.editing.mapper.toModelElement(viewShortcode);
|
||||
|
||||
editor.model.change((modelWriter) => {
|
||||
let modelParentShortcode = modelShortcode.parent;
|
||||
const insertPosition = modelWriter.createPositionAt(modelShortcode, where);
|
||||
|
||||
while (modelParentShortcode && modelParentShortcode.name !== 'shortcode-block') {
|
||||
modelParentShortcode = modelParentShortcode.parent;
|
||||
}
|
||||
|
||||
if (modelParentShortcode) {
|
||||
editor.execute(`shortcode_${shortcode.name}`, { insertPosition, modelParentShortcode });
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
window.scBlockMoveChild = function scBlockMove(event, where) {
|
||||
const { editors } = window.nextgenEditor;
|
||||
|
||||
const domShortcode = this.parentNode;
|
||||
const editor = (editors.filter((instance) => instance.ui.view.element.contains(domShortcode)) || []).shift();
|
||||
|
||||
if (editor) {
|
||||
const viewShortcode = editor.editing.view.domConverter.mapDomToView(domShortcode);
|
||||
const modelShortcode = editor.editing.mapper.toModelElement(viewShortcode);
|
||||
|
||||
const domSiblingShortcode = where === 'up'
|
||||
? domShortcode.previousSibling
|
||||
: domShortcode.nextSibling;
|
||||
|
||||
const viewSiblingShortcode = editor.editing.view.domConverter.mapDomToView(domSiblingShortcode);
|
||||
const modelSiblingShortcode = editor.editing.mapper.toModelElement(viewSiblingShortcode);
|
||||
|
||||
editor.model.change((modelWriter) => {
|
||||
modelWriter.move(modelWriter.createRangeOn(modelShortcode), modelSiblingShortcode, where === 'up' ? 'before' : 'after');
|
||||
});
|
||||
}
|
||||
};
|
45
plugins/shortcode-core/nextgen-editor/src/init.js
Normal file
45
plugins/shortcode-core/nextgen-editor/src/init.js
Normal file
@ -0,0 +1,45 @@
|
||||
window.nextgenEditor.addHook('hookInit', () => {
|
||||
Object.values(window.nextgenEditor.shortcodes).forEach((shortcode) => {
|
||||
shortcode.attributes = shortcode.attributes || {};
|
||||
|
||||
if (!shortcode.button) {
|
||||
shortcode.button = { label: shortcode.title };
|
||||
}
|
||||
|
||||
Object.values(shortcode.attributes).forEach((attribute) => {
|
||||
if (attribute.default === undefined) {
|
||||
attribute.default = '';
|
||||
}
|
||||
if (typeof attribute.default !== 'object') {
|
||||
attribute.default = { value: attribute.default };
|
||||
}
|
||||
if (attribute.shorthand === undefined) {
|
||||
attribute.shorthand = true;
|
||||
}
|
||||
});
|
||||
|
||||
if (shortcode.type === 'block' && !shortcode.titlebar) {
|
||||
shortcode.titlebar = () => '';
|
||||
}
|
||||
if (!shortcode.content) {
|
||||
shortcode.content = () => '';
|
||||
}
|
||||
|
||||
if (shortcode.preserve) {
|
||||
if (shortcode.preserve.block) {
|
||||
window.nextgenEditor.addVariable('preserveBlockTags', shortcode.preserve.block);
|
||||
}
|
||||
|
||||
if (shortcode.preserve.inline) {
|
||||
window.nextgenEditor.addVariable('preserveInlineTags', shortcode.preserve.inline);
|
||||
}
|
||||
}
|
||||
|
||||
if (!shortcode.parent) {
|
||||
window.nextgenEditor.addButton(`shortcode_${shortcode.name}`, {
|
||||
command: `shortcode_${shortcode.name}`,
|
||||
...shortcode.button,
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
278
plugins/shortcode-core/nextgen-editor/src/main.css
Normal file
278
plugins/shortcode-core/nextgen-editor/src/main.css
Normal file
@ -0,0 +1,278 @@
|
||||
shortcode-block {
|
||||
background: #fff;
|
||||
border: 1px solid #ccc;
|
||||
display: block;
|
||||
margin: 16px 0;
|
||||
}
|
||||
|
||||
#admin-main .ck.ck-editor__editable_inline > :first-child {
|
||||
margin-top: 16px;
|
||||
}
|
||||
#admin-main .ck.ck-editor__editable_inline > :last-child {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
#admin-main .ck-editor shortcode-block.ck-shortcode-child:hover {
|
||||
outline-color: #1f89e5;
|
||||
}
|
||||
|
||||
#admin-main .ck-editor shortcode-block > .sc-header > .sc-title > p,
|
||||
#admin-main .ck-editor shortcode-block > .sc-header > .sc-titlebar > p,
|
||||
#admin-main .ck-editor shortcode-block > .sc-header > .sc-settings > p,
|
||||
#admin-main .ck-editor shortcode-block > .sc-add > p,
|
||||
#admin-main .ck-editor shortcode-block > .sc-move > p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
shortcode-block > .sc-header {
|
||||
align-items: center;
|
||||
border-bottom: 1px solid #ccc;
|
||||
display: flex;
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
padding: 8px 8px;
|
||||
}
|
||||
|
||||
shortcode-block > .sc-header > .sc-title > p > .sc-value {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
shortcode-block > .sc-header > .sc-titlebar {
|
||||
margin-left: 24px;
|
||||
}
|
||||
|
||||
shortcode-block > .sc-header > .sc-settings {
|
||||
color: #ffc83d;
|
||||
cursor: pointer;
|
||||
font-size: 0;
|
||||
line-height: 0;
|
||||
margin-left: auto;
|
||||
opacity: 0;
|
||||
transition: opacity .2s ease, color .2s ease;
|
||||
}
|
||||
|
||||
shortcode-block > .sc-header > .sc-settings:hover,
|
||||
shortcode-block.ck-shortcode-child > .sc-header > .sc-settings,
|
||||
shortcode-block.ck-widget_selected > .sc-header > .sc-settings {
|
||||
color: #1f89e5;
|
||||
}
|
||||
|
||||
shortcode-block.ck-widget_selected > .sc-header > .sc-settings:hover,
|
||||
shortcode-block.ck-shortcode-child > .sc-header > .sc-settings:hover {
|
||||
opacity: .5
|
||||
}
|
||||
|
||||
shortcode-block:hover > .sc-header > .sc-settings,
|
||||
shortcode-block.ck-widget_selected > .sc-header > .sc-settings {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
shortcode-block > .sc-header > .sc-settings > p > svg {
|
||||
height: 24px;
|
||||
width: 24px;
|
||||
}
|
||||
|
||||
shortcode-block-editable,
|
||||
shortcode-block-readonly {
|
||||
display: block;
|
||||
padding: 0 8px;
|
||||
}
|
||||
|
||||
shortcode-block-readonly > [data-cke-filler] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#admin-main .ck-editor shortcode-block-editable > :first-child {
|
||||
margin-top: 14px;
|
||||
}
|
||||
|
||||
#admin-main .ck-editor shortcode-block.ck-shortcode-child .ck-widget__type-around__button_after,
|
||||
#admin-main .ck-editor shortcode-block.ck-shortcode-child .ck-widget__type-around__button_before {
|
||||
display: none;
|
||||
}
|
||||
|
||||
shortcode-block > .sc-add-child {
|
||||
align-items: center;
|
||||
display: none;
|
||||
justify-content: center;
|
||||
margin: 16px 0;
|
||||
opacity: 0;
|
||||
transition: opacity .2s ease;
|
||||
}
|
||||
|
||||
shortcode-block > .sc-add-child.sc-visible {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
shortcode-block:hover > .sc-add-child,
|
||||
shortcode-block.ck-widget_selected > .sc-add-child {
|
||||
opacity: 1;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
shortcode-block > .sc-add-child > p {
|
||||
align-items: center;
|
||||
background: #ffc83d;
|
||||
border-radius: 50%;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
height: 24px;
|
||||
justify-content: center;
|
||||
margin: 0!important;
|
||||
transition: opacity .2s ease, background .2s ease;
|
||||
width: 24px;
|
||||
}
|
||||
|
||||
shortcode-block > .sc-add-child > p:hover,
|
||||
shortcode-block.ck-widget_selected > .sc-add-child > p {
|
||||
background: #1f89e5;
|
||||
}
|
||||
|
||||
shortcode-block.ck-widget_selected > .sc-add-child > p:hover {
|
||||
opacity: .5;
|
||||
}
|
||||
|
||||
shortcode-block > .sc-add-child > p > svg {
|
||||
color: #fff;
|
||||
height: 20px;
|
||||
transition: opacity .2s ease;
|
||||
width: 20px;
|
||||
}
|
||||
|
||||
shortcode-block > .sc-add {
|
||||
left: 30px;
|
||||
opacity: 0;
|
||||
position: absolute;
|
||||
transition: opacity .2s ease;
|
||||
top: -12px;
|
||||
}
|
||||
|
||||
shortcode-block > .sc-add-after {
|
||||
bottom: -11px;
|
||||
left: auto;
|
||||
right: 30px;
|
||||
top: auto;
|
||||
}
|
||||
|
||||
shortcode-block:hover > .sc-add {
|
||||
opacity: 1;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
shortcode-block > .sc-add > p {
|
||||
align-items: center;
|
||||
background: #1f89e5;
|
||||
border-radius: 50%;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
height: 20px;
|
||||
justify-content: center;
|
||||
width: 20px;
|
||||
}
|
||||
|
||||
shortcode-block > .sc-add > p > svg {
|
||||
color: #fff;
|
||||
height: 16px;
|
||||
transition: opacity .2s ease;
|
||||
width: 16px;
|
||||
}
|
||||
|
||||
shortcode-block > .sc-add:hover > p > svg {
|
||||
opacity: .5;
|
||||
}
|
||||
|
||||
shortcode-block > .sc-move {
|
||||
background: #1f89e5;
|
||||
border-radius: 50%;
|
||||
cursor: pointer;
|
||||
height: 20px;
|
||||
opacity: 0;
|
||||
position: absolute;
|
||||
right: -12px;
|
||||
transition: opacity .2s ease;
|
||||
width: 20px;
|
||||
top: 46px;
|
||||
}
|
||||
|
||||
shortcode-block > .sc-move-up {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
shortcode-block:first-child > .sc-move-up,
|
||||
shortcode-block:last-child > .sc-move-down {
|
||||
display: none;
|
||||
}
|
||||
|
||||
shortcode-block > .sc-move-down {
|
||||
bottom: 4px;
|
||||
left: auto;
|
||||
top: auto;
|
||||
}
|
||||
|
||||
shortcode-block:hover > .sc-move {
|
||||
opacity: 1;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
shortcode-block > .sc-move > p > svg {
|
||||
color: #fff;
|
||||
height: 20px;
|
||||
left: 1.5px;
|
||||
position: absolute;
|
||||
top: 2px;
|
||||
transition: opacity .2s ease;
|
||||
width: 20px;
|
||||
}
|
||||
|
||||
shortcode-block > .sc-move:hover > p > svg {
|
||||
opacity: .5;
|
||||
}
|
||||
|
||||
shortcode-inline {
|
||||
background: #fff;
|
||||
border: 1px solid #ccc;
|
||||
display: inline-flex;
|
||||
margin-left: 2px;
|
||||
margin-right: 1px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
shortcode-inline-editable,
|
||||
shortcode-inline-readonly {
|
||||
display: inline;
|
||||
padding: 1px 4px 2px;
|
||||
}
|
||||
|
||||
shortcode-inline > .sc-content {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
shortcode-inline > .sc-settings {
|
||||
align-items: center;
|
||||
border-left: 1px solid #ccc;
|
||||
cursor: pointer;
|
||||
display: inline-flex;
|
||||
font-size: 0;
|
||||
line-height: 0;
|
||||
padding: 0 2px;
|
||||
transition: opacity .2s ease, color .2s ease;
|
||||
}
|
||||
|
||||
shortcode-inline:hover > .sc-settings {
|
||||
color: #ffc83d;
|
||||
}
|
||||
|
||||
shortcode-inline > .sc-settings:hover,
|
||||
shortcode-inline.ck-widget_selected > .sc-settings {
|
||||
color: #1f89e5;
|
||||
}
|
||||
|
||||
shortcode-inline.ck-widget_selected > .sc-settings:hover {
|
||||
opacity: .5;
|
||||
}
|
||||
|
||||
shortcode-inline > .sc-settings > svg {
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
}
|
10
plugins/shortcode-core/nextgen-editor/src/main.js
Normal file
10
plugins/shortcode-core/nextgen-editor/src/main.js
Normal file
@ -0,0 +1,10 @@
|
||||
import './command';
|
||||
import './converters';
|
||||
import './events';
|
||||
import './init';
|
||||
import './prerender';
|
||||
import './postsave';
|
||||
import './remove';
|
||||
import './render';
|
||||
import './save';
|
||||
import './main.css';
|
95
plugins/shortcode-core/nextgen-editor/src/postsave.js
Normal file
95
plugins/shortcode-core/nextgen-editor/src/postsave.js
Normal file
@ -0,0 +1,95 @@
|
||||
window.nextgenEditor.addHook('hookHTMLtoMarkdown', {
|
||||
weight: 50,
|
||||
handler(options, editor, input) {
|
||||
let output = input;
|
||||
|
||||
const realNames = Object.values(window.nextgenEditor.shortcodes).map((shortcode) => shortcode.realName)
|
||||
.filter((value, index, self) => self.indexOf(value) === index);
|
||||
|
||||
const openingRegexp = realNames
|
||||
.map((name) => `(\\[${name}[^\\]]*\\])`).join('|');
|
||||
|
||||
const hashMap = {};
|
||||
let shortcodeCounter = 1;
|
||||
|
||||
while (shortcodeCounter > 0) {
|
||||
shortcodeCounter = 0;
|
||||
|
||||
// eslint-disable-next-line no-loop-func
|
||||
Object.values(window.nextgenEditor.shortcodes).forEach((shortcode) => {
|
||||
const regexp = `(?<opening>\\[${shortcode.realName}[^\\]]*\\])(?<content>(((?!(${openingRegexp}|(\\[\\/${shortcode.realName}\\]))).)|\\n)*)(?<closing>\\[\\/${shortcode.realName}\\])`;
|
||||
|
||||
output = output.replace(new RegExp(regexp, 'g'), (...matches) => {
|
||||
shortcodeCounter += 1;
|
||||
|
||||
const hash = Math.random().toString(36).slice(2);
|
||||
hashMap[hash] = { shortcode, matches };
|
||||
|
||||
if (shortcode.child) {
|
||||
const childName = shortcode.child.realName;
|
||||
|
||||
Object.keys(hashMap).forEach((childHash) => {
|
||||
const childShortcode = hashMap[childHash].shortcode;
|
||||
|
||||
if (childShortcode === shortcode.child && childShortcode.name !== `${shortcode.realName}_${childName}` && matches[0].includes(childHash)) {
|
||||
hashMap[childHash].shortcode = window.nextgenEditor.shortcodes[`${shortcode.realName}_${childName}`];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return hash;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
shortcodeCounter = 1;
|
||||
|
||||
while (shortcodeCounter > 0) {
|
||||
shortcodeCounter = 0;
|
||||
|
||||
// eslint-disable-next-line no-loop-func
|
||||
Object.keys(hashMap).forEach((hash) => {
|
||||
if (!output.includes(hash)) {
|
||||
return;
|
||||
}
|
||||
|
||||
shortcodeCounter += 1;
|
||||
|
||||
const { shortcode, matches } = hashMap[hash];
|
||||
const groups = matches.pop();
|
||||
|
||||
if (shortcode.type === 'block') {
|
||||
let content = groups.content.replace(/^\n/, '').replace(/\n$/, '');
|
||||
|
||||
if (shortcode.child) {
|
||||
content = content.trim().split('\n').filter((line) => !!line).join('\n');
|
||||
content = `\n${content}\n`;
|
||||
}
|
||||
|
||||
if (shortcode.parent) {
|
||||
content = `\n${content}\n`;
|
||||
}
|
||||
|
||||
output = output.replace(hash, `${groups.opening}${content}${groups.closing}`);
|
||||
}
|
||||
|
||||
if (shortcode.type === 'inline') {
|
||||
output = output.replace(hash, matches[0]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
Object.values(window.nextgenEditor.shortcodes).forEach((shortcode) => {
|
||||
const regexp = `(?<opening>\\[${shortcode.realName}[^\\]]*\\])\n(?<content>(((?!(${openingRegexp}|(\\[\\/${shortcode.realName}\\]))).))*)\n(?<closing>\\[\\/${shortcode.realName}\\])`;
|
||||
|
||||
output = output.replace(new RegExp(regexp, 'g'), (...matches) => {
|
||||
const groups = matches.pop();
|
||||
return `${groups.opening}${groups.content}${groups.closing}`;
|
||||
});
|
||||
});
|
||||
*/
|
||||
|
||||
return output;
|
||||
},
|
||||
});
|
100
plugins/shortcode-core/nextgen-editor/src/prerender.js
Normal file
100
plugins/shortcode-core/nextgen-editor/src/prerender.js
Normal file
@ -0,0 +1,100 @@
|
||||
window.nextgenEditor.addHook('hookMarkdowntoHTML', {
|
||||
weight: -50,
|
||||
handler(options, input) {
|
||||
let output = input;
|
||||
|
||||
const realNames = Object.values(window.nextgenEditor.shortcodes).map((shortcode) => shortcode.realName)
|
||||
.filter((value, index, self) => self.indexOf(value) === index);
|
||||
|
||||
const openingRegexp = realNames
|
||||
.map((name) => `(\\[${name}[^\\]]*\\])`).join('|');
|
||||
|
||||
realNames.forEach((name) => {
|
||||
const regexp = `\\[${name}(?<attributes>(=| +).+?(?=/]))?\\/\\]`;
|
||||
|
||||
output = output.replace(new RegExp(regexp, 'g'), (...matches) => {
|
||||
const groups = matches.pop();
|
||||
|
||||
const attributes = groups.attributes.trim()
|
||||
? `${groups.attributes}`
|
||||
: '';
|
||||
|
||||
return `[${name}${attributes}][/${name}]`;
|
||||
});
|
||||
});
|
||||
|
||||
const hashMap = {};
|
||||
let shortcodeCounter = 1;
|
||||
|
||||
while (shortcodeCounter > 0) {
|
||||
shortcodeCounter = 0;
|
||||
|
||||
// eslint-disable-next-line no-loop-func
|
||||
Object.values(window.nextgenEditor.shortcodes).forEach((shortcode) => {
|
||||
const regexp = `(?<spaces_before> *)\\[${shortcode.realName}(?<attributes>(=| +)[^\\]]*)?\\](?<content>(((?!(${openingRegexp}|(\\[\\/${shortcode.realName}\\]))).)|\\n)*)\\[\\/${shortcode.realName}\\](?<spaces_after> *)`;
|
||||
|
||||
output = output.replace(new RegExp(regexp, 'g'), (...matches) => {
|
||||
shortcodeCounter += 1;
|
||||
|
||||
const hash = Math.random().toString(36).slice(2);
|
||||
hashMap[hash] = { shortcode, matches };
|
||||
|
||||
if (shortcode.child) {
|
||||
const childName = shortcode.child.realName;
|
||||
|
||||
Object.keys(hashMap).forEach((childHash) => {
|
||||
const childShortcode = hashMap[childHash].shortcode;
|
||||
|
||||
if (childShortcode === shortcode.child && childShortcode.name !== `${shortcode.realName}_${childName}` && matches[0].includes(childHash)) {
|
||||
hashMap[childHash].shortcode = window.nextgenEditor.shortcodes[`${shortcode.realName}_${childName}`];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return hash;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
shortcodeCounter = 1;
|
||||
|
||||
while (shortcodeCounter > 0) {
|
||||
shortcodeCounter = 0;
|
||||
|
||||
// eslint-disable-next-line no-loop-func
|
||||
Object.keys(hashMap).forEach((hash) => {
|
||||
if (!output.includes(hash)) {
|
||||
return;
|
||||
}
|
||||
|
||||
shortcodeCounter += 1;
|
||||
|
||||
const { shortcode, matches } = hashMap[hash];
|
||||
const groups = matches.pop();
|
||||
|
||||
const spacesBefore = groups.spaces_before.replace(/ /g, ' ');
|
||||
const spacesAfter = groups.spaces_after.replace(/ /g, ' ');
|
||||
|
||||
if (shortcode.type === 'block') {
|
||||
let content = groups.content.trim();
|
||||
|
||||
if (groups.spaces_before.length) {
|
||||
content = content.replace(new RegExp(`^( ){${groups.spaces_before.length}}`, 'gm'), '');
|
||||
}
|
||||
|
||||
const replacement = `\n\n[${shortcode.name}${groups.attributes || ''}]\n\n${content}\n\n[/${shortcode.name}]\n\n`;
|
||||
|
||||
output = output.replace(new RegExp(`(\\n)?(\\n)?${hash}(\\n)?(\\n)?`), replacement);
|
||||
}
|
||||
|
||||
if (shortcode.type === 'inline') {
|
||||
output = output.replace(hash, `${spacesBefore}[${shortcode.name}${groups.attributes || ''}]${groups.content}[/${shortcode.name}]${spacesAfter}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
output = output.replace(/^\n\n/, '').replace(/\n\n$/, '');
|
||||
|
||||
return output;
|
||||
},
|
||||
});
|
55
plugins/shortcode-core/nextgen-editor/src/remove.js
Normal file
55
plugins/shortcode-core/nextgen-editor/src/remove.js
Normal file
@ -0,0 +1,55 @@
|
||||
window.nextgenEditor.addPlugin('GravShortcodeCoreRemove', {
|
||||
init() {
|
||||
const deleteBackwardCommand = this.editor.commands.get('delete');
|
||||
const deleteForwardCommand = this.editor.commands.get('forwardDelete');
|
||||
|
||||
const preDelete = (event) => {
|
||||
const selectedElement = this.editor.model.document.selection.getSelectedElement();
|
||||
|
||||
if (selectedElement && selectedElement.name === 'shortcode-block') {
|
||||
const name = selectedElement.getAttribute('name');
|
||||
const shortcode = window.nextgenEditor.shortcodes[name];
|
||||
|
||||
if (shortcode.parent) {
|
||||
const viewShortcode = this.editor.editing.mapper.toViewElement(selectedElement);
|
||||
const domShortcode = this.editor.editing.view.domConverter.mapViewToDom(viewShortcode);
|
||||
const domParentShortcode = domShortcode.closest(`shortcode-block[name="${shortcode.parent.name}"]`);
|
||||
|
||||
event.childShortcodeDeleted = true;
|
||||
event.modelShortcodeBlockReadOnly = selectedElement.parent;
|
||||
event.domParentShortcode = domParentShortcode;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const postDelete = (event) => {
|
||||
if (event.childShortcodeDeleted) {
|
||||
const { domParentShortcode, modelShortcodeBlockReadOnly } = event;
|
||||
|
||||
const children = [...modelShortcodeBlockReadOnly.getChildren()];
|
||||
const scChildren = children.filter((child) => child.name === 'shortcode-block');
|
||||
const otherChildren = children.filter((child) => child.name !== 'shortcode-block');
|
||||
|
||||
setTimeout(() => {
|
||||
this.editor.model.change((modelWriter) => {
|
||||
otherChildren.forEach((modelChild) => {
|
||||
if (modelChild.name === 'paragraph' && modelChild.childCount === 0) {
|
||||
modelWriter.remove(modelChild);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
if (!scChildren.length) {
|
||||
domParentShortcode.querySelector('shortcode-block > .sc-add-child').classList.add('sc-visible');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
deleteBackwardCommand.on('execute', preDelete, { priority: 'highest' });
|
||||
deleteForwardCommand.on('execute', preDelete, { priority: 'highest' });
|
||||
|
||||
deleteBackwardCommand.on('execute', postDelete, { priority: 'lowest' });
|
||||
deleteForwardCommand.on('execute', postDelete, { priority: 'lowest' });
|
||||
},
|
||||
});
|
95
plugins/shortcode-core/nextgen-editor/src/render.js
Normal file
95
plugins/shortcode-core/nextgen-editor/src/render.js
Normal file
@ -0,0 +1,95 @@
|
||||
import uncollapse from './uncollapse';
|
||||
|
||||
window.nextgenEditor.addHook('hookMarkdowntoHTML', {
|
||||
weight: 50,
|
||||
handler(options, input) {
|
||||
let output = input;
|
||||
|
||||
let shortcodeCounter = 1;
|
||||
const openingRegexp = Object.keys(window.nextgenEditor.shortcodes).map((name) => `(\\[${name}[^\\]]*\\])`).join('|');
|
||||
|
||||
while (shortcodeCounter > 0) {
|
||||
shortcodeCounter = 0;
|
||||
|
||||
// eslint-disable-next-line no-loop-func
|
||||
Object.values(window.nextgenEditor.shortcodes).forEach((shortcode) => {
|
||||
const regexp = `(?<p1><p>)?\\[${shortcode.name}(?<attributes>(=| +)[^\\]]*)?\\](<\\/p>)?(?<content>(((?!(${openingRegexp}|(\\[\\/${shortcode.name}\\]))).)|\\n)*)\\[\\/${shortcode.name}\\](?<p2><\\/p>)?`;
|
||||
|
||||
output = output.replace(new RegExp(regexp, 'g'), (...matches) => {
|
||||
shortcodeCounter += 1;
|
||||
|
||||
const groups = matches.pop();
|
||||
|
||||
let content = shortcode.type === 'block'
|
||||
? groups.content.replace(/<p>$/, '')
|
||||
: groups.content;
|
||||
|
||||
const bbcode = Object.keys(shortcode.attributes).reduce((acc, attrName) => acc || (shortcode.attributes[attrName].bbcode && shortcode.attributes[attrName].shorthand && attrName), '');
|
||||
const innerHTMLAttribute = Object.keys(shortcode.attributes).reduce((acc, attrName) => acc || (shortcode.attributes[attrName].innerHTML && attrName), '');
|
||||
|
||||
let attrGroup = bbcode && groups.attributes && groups.attributes.startsWith('=')
|
||||
? `${bbcode}${groups.attributes}`
|
||||
: groups.attributes || '';
|
||||
|
||||
if (innerHTMLAttribute) {
|
||||
const innerHTML = shortcode.type === 'block'
|
||||
? content.replace(/^<p>/, '').replace(/<\/p>$/, '').replace(/^ $/, '')
|
||||
: content.replace(/^ $/, '');
|
||||
|
||||
attrGroup = attrGroup
|
||||
? `${attrGroup} ${innerHTMLAttribute}="${innerHTML}"`
|
||||
: `${innerHTMLAttribute}="${innerHTML}"`;
|
||||
|
||||
content = '';
|
||||
}
|
||||
|
||||
const domAttributes = new DOMParser().parseFromString(`<div ${attrGroup}></div>`, 'text/html').body.firstChild.attributes;
|
||||
|
||||
const attributes = Object.keys(shortcode.attributes).reduce((acc, attrName) => {
|
||||
const attribute = shortcode.attributes[attrName];
|
||||
|
||||
let attrValue = domAttributes.getNamedItem(attrName)
|
||||
? domAttributes.getNamedItem(attrName).value
|
||||
: attribute.default.value;
|
||||
|
||||
if (attribute.type === Boolean && domAttributes.getNamedItem(attrName)) {
|
||||
attrValue = domAttributes.getNamedItem(attrName) !== 'false';
|
||||
}
|
||||
|
||||
if (attribute.type === Number) {
|
||||
attrValue = +attrValue;
|
||||
}
|
||||
|
||||
acc[attrName] = attrValue;
|
||||
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
let replacement = '';
|
||||
|
||||
const attributesEncoded = encodeURIComponent(JSON.stringify(attributes));
|
||||
|
||||
if (shortcode.type === 'block') {
|
||||
replacement += `<shortcode-block name="${shortcode.name}" attributes="${attributesEncoded}">`;
|
||||
replacement += content;
|
||||
replacement += '</shortcode-block>';
|
||||
}
|
||||
|
||||
if (shortcode.type === 'inline') {
|
||||
replacement += groups.p1 || '';
|
||||
replacement += `<shortcode-inline name="${shortcode.name}" attributes="${attributesEncoded}">`;
|
||||
replacement += content;
|
||||
replacement += '</shortcode-inline>';
|
||||
replacement += groups.p2 || '';
|
||||
}
|
||||
|
||||
return replacement;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
output = uncollapse(output);
|
||||
|
||||
return output;
|
||||
},
|
||||
});
|
80
plugins/shortcode-core/nextgen-editor/src/save.js
Normal file
80
plugins/shortcode-core/nextgen-editor/src/save.js
Normal file
@ -0,0 +1,80 @@
|
||||
import collapse from './collapse';
|
||||
|
||||
window.nextgenEditor.addHook('hookHTMLtoMarkdown', {
|
||||
weight: -50,
|
||||
handler(options, editor, input) {
|
||||
let output = input;
|
||||
|
||||
output = collapse(output);
|
||||
|
||||
const domOutput = new DOMParser().parseFromString(output, 'text/html');
|
||||
|
||||
let domShortcode = domOutput.querySelector('shortcode-block, shortcode-inline');
|
||||
|
||||
while (domShortcode) {
|
||||
const name = domShortcode.getAttribute('name');
|
||||
const shortcode = window.nextgenEditor.shortcodes[name];
|
||||
const attributes = JSON.parse(decodeURIComponent(domShortcode.getAttribute('attributes')));
|
||||
|
||||
const innerHTMLAttribute = Object.keys(shortcode.attributes).reduce((acc, attrName) => acc || (shortcode.attributes[attrName].innerHTML && attrName), '');
|
||||
|
||||
const attrLine = Object.keys(shortcode.attributes).reduce((acc, attrName) => {
|
||||
const attribute = shortcode.attributes[attrName];
|
||||
|
||||
if (attribute.type === Boolean) {
|
||||
return attributes[attrName]
|
||||
? `${acc} ${attrName}`
|
||||
: acc;
|
||||
}
|
||||
|
||||
if (attributes[attrName] === attribute.default.value && !attribute.default.preserve) {
|
||||
return acc;
|
||||
}
|
||||
|
||||
if (attribute.bbcode && attribute.shorthand) {
|
||||
return `="${attributes[attrName]}"${acc}`;
|
||||
}
|
||||
|
||||
if (attribute.innerHTML) {
|
||||
return acc;
|
||||
}
|
||||
|
||||
return `${acc} ${attrName}="${attributes[attrName]}"`;
|
||||
}, '');
|
||||
|
||||
if (shortcode.type === 'block') {
|
||||
if (domShortcode.innerHTML === '<p> </p>') {
|
||||
domShortcode.innerHTML = '';
|
||||
}
|
||||
|
||||
if (innerHTMLAttribute) {
|
||||
domShortcode.outerHTML = `<p>[${shortcode.realName}${attrLine}]${attributes[innerHTMLAttribute]}[/${shortcode.realName}]</p>`;
|
||||
} else if (domShortcode.innerHTML) {
|
||||
domShortcode.outerHTML = `<p>[${shortcode.realName}${attrLine}]</p>${domShortcode.innerHTML}<p>[/${shortcode.realName}]</p>`;
|
||||
} else {
|
||||
domShortcode.outerHTML = `<p>[${shortcode.realName}${attrLine} /]</p>`;
|
||||
}
|
||||
}
|
||||
|
||||
if (shortcode.type === 'inline') {
|
||||
if (domShortcode.innerHTML === ' ') {
|
||||
domShortcode.innerHTML = '';
|
||||
}
|
||||
|
||||
if (innerHTMLAttribute) {
|
||||
domShortcode.outerHTML = `[${shortcode.realName}${attrLine}]${attributes[innerHTMLAttribute]}[/${shortcode.realName}]`;
|
||||
} else if (domShortcode.innerHTML) {
|
||||
domShortcode.outerHTML = `[${shortcode.realName}${attrLine}]${domShortcode.innerHTML}[/${shortcode.realName}]`;
|
||||
} else {
|
||||
domShortcode.outerHTML = `[${shortcode.realName}${attrLine} /]`;
|
||||
}
|
||||
}
|
||||
|
||||
domShortcode = domOutput.querySelector('shortcode-block, shortcode-inline');
|
||||
}
|
||||
|
||||
output = domOutput.body.innerHTML;
|
||||
|
||||
return output;
|
||||
},
|
||||
});
|
153
plugins/shortcode-core/nextgen-editor/src/settings.js
Normal file
153
plugins/shortcode-core/nextgen-editor/src/settings.js
Normal file
@ -0,0 +1,153 @@
|
||||
import collapse from './collapse';
|
||||
import uncollapse from './uncollapse';
|
||||
|
||||
const { showSettingsPopup } = window.nextgenEditor.exports;
|
||||
|
||||
export default function displaySettings(domShortcode) {
|
||||
const { editors } = window.nextgenEditor;
|
||||
const editor = (editors.filter((instance) => instance.ui.view.element.contains(domShortcode)) || []).shift();
|
||||
|
||||
const name = domShortcode.getAttribute('name');
|
||||
const shortcode = window.nextgenEditor.shortcodes[name];
|
||||
const plugin = window.nextgenEditor.shortcodePlugins[shortcode.plugin];
|
||||
|
||||
if (editor) {
|
||||
const viewShortcode = editor.editing.view.domConverter.mapDomToView(domShortcode);
|
||||
let modelShortcode = editor.editing.mapper.toModelElement(viewShortcode);
|
||||
|
||||
const currentAttributes = JSON.parse(decodeURIComponent(domShortcode.getAttribute('attributes')));
|
||||
|
||||
const domDisplayPoint = shortcode.type === 'block'
|
||||
? domShortcode.querySelector('.sc-header > .sc-settings')
|
||||
: domShortcode;
|
||||
|
||||
const title = []
|
||||
.concat([
|
||||
(plugin && plugin.title) || '',
|
||||
(shortcode.parent && shortcode.parent.title) || '',
|
||||
shortcode.title || '',
|
||||
])
|
||||
.filter((item) => !!item)
|
||||
.join(' / ');
|
||||
|
||||
const argsForPopup = {
|
||||
title,
|
||||
domDisplayPoint,
|
||||
debounceDelay: 1000,
|
||||
attributes: shortcode.attributes,
|
||||
currentAttributes,
|
||||
parentAttributes: null,
|
||||
childAttributes: null,
|
||||
};
|
||||
|
||||
if (shortcode.parent) {
|
||||
const domParentShortcode = domShortcode.closest(`shortcode-block[name="${shortcode.parent.name}"]`);
|
||||
|
||||
argsForPopup.parentAttributes = domParentShortcode
|
||||
? JSON.parse(decodeURIComponent(domParentShortcode.getAttribute('attributes')))
|
||||
: {};
|
||||
}
|
||||
|
||||
if (shortcode.child) {
|
||||
argsForPopup.childAttributes = [];
|
||||
|
||||
const childNodes = [...domShortcode.querySelectorAll(`shortcode-block shortcode-block[name="${shortcode.child.name}"]`)];
|
||||
const deepChildNodes = [...domShortcode.querySelectorAll(`shortcode-block shortcode-block shortcode-block[name="${shortcode.child.name}"]`)];
|
||||
|
||||
childNodes
|
||||
.filter((domChildShortcode) => !deepChildNodes.includes(domChildShortcode))
|
||||
.forEach((domChildShortcode) => {
|
||||
const childAttributes = JSON.parse(decodeURIComponent(domChildShortcode.getAttribute('attributes')));
|
||||
argsForPopup.childAttributes.push(childAttributes);
|
||||
});
|
||||
}
|
||||
|
||||
argsForPopup.deleteItem = () => editor.execute('delete');
|
||||
|
||||
argsForPopup.changeAttributes = () => {
|
||||
editor.model.change((modelWriter) => {
|
||||
modelWriter.setAttribute('attributes', encodeURIComponent(JSON.stringify(currentAttributes)), modelShortcode);
|
||||
|
||||
const convertContext = shortcode.type === 'inline'
|
||||
? '$block'
|
||||
: '$root';
|
||||
|
||||
if (shortcode.parent) {
|
||||
const viewOldShortcode = editor.editing.mapper.toViewElement(modelShortcode);
|
||||
const domOldShortcode = editor.editing.view.domConverter.mapViewToDom(viewOldShortcode);
|
||||
|
||||
if (!domOldShortcode) {
|
||||
return;
|
||||
}
|
||||
|
||||
const domOldParentShortcode = domOldShortcode.parentNode.closest('shortcode-block');
|
||||
const viewOldParentShortcode = editor.editing.view.domConverter.mapDomToView(domOldParentShortcode);
|
||||
const modelOldParentShortcode = editor.editing.mapper.toModelElement(viewOldParentShortcode);
|
||||
|
||||
const childNodes = [...domOldParentShortcode.querySelectorAll('shortcode-block shortcode-block')];
|
||||
const deepChildNodes = [...domOldParentShortcode.querySelectorAll('shortcode-block shortcode-block shortcode-block')];
|
||||
|
||||
const childIndex = childNodes
|
||||
.filter((domChildShortcode) => !deepChildNodes.includes(domChildShortcode))
|
||||
.indexOf(domOldShortcode);
|
||||
|
||||
const insertPosition = modelWriter.createPositionBefore(modelOldParentShortcode);
|
||||
const modelOldParentClonedShortcode = modelWriter.cloneElement(modelOldParentShortcode);
|
||||
|
||||
const modelOldParentFragment = modelWriter.createDocumentFragment();
|
||||
modelWriter.append(modelOldParentClonedShortcode, modelOldParentFragment);
|
||||
|
||||
const viewOldParentClonedShortcode = editor.data.toView(modelOldParentFragment).getChild(0);
|
||||
const dataOldParentClonedShortcode = editor.data.processor.toData(viewOldParentClonedShortcode);
|
||||
|
||||
const dataNewParentShortcode = uncollapse(collapse(dataOldParentClonedShortcode));
|
||||
const viewNewParentShortcode = editor.data.processor.toView(dataNewParentShortcode).getChild(0);
|
||||
const modelNewParentShortcode = editor.data.toModel(viewNewParentShortcode, convertContext).getChild(0);
|
||||
|
||||
modelWriter.remove(modelOldParentShortcode);
|
||||
modelWriter.insert(modelNewParentShortcode, insertPosition);
|
||||
|
||||
setTimeout(() => {
|
||||
const viewParentShortcode = editor.editing.mapper.toViewElement(modelNewParentShortcode);
|
||||
const domParentShortcode = editor.editing.view.domConverter.mapViewToDom(viewParentShortcode);
|
||||
|
||||
const childNewNodes = [...domParentShortcode.querySelectorAll('shortcode-block shortcode-block')];
|
||||
const deepNewChildNodes = [...domParentShortcode.querySelectorAll('shortcode-block shortcode-block shortcode-block')];
|
||||
|
||||
const domNewShortcode = childNewNodes.filter((domChildShortcode) => !deepNewChildNodes.includes(domChildShortcode))[childIndex];
|
||||
const viewNewShortcode = editor.editing.view.domConverter.mapDomToView(domNewShortcode);
|
||||
const modelNewShortcode = editor.editing.mapper.toModelElement(viewNewShortcode);
|
||||
|
||||
editor.model.change((modelWriter2) => {
|
||||
modelWriter2.setSelection(modelNewShortcode, 'on');
|
||||
modelShortcode = modelNewShortcode;
|
||||
});
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const insertPosition = modelWriter.createPositionBefore(modelShortcode);
|
||||
const modelOldShortcode = modelWriter.cloneElement(modelShortcode);
|
||||
|
||||
const modelOldFragment = modelWriter.createDocumentFragment();
|
||||
modelWriter.append(modelOldShortcode, modelOldFragment);
|
||||
|
||||
const viewOldShortcode = editor.data.toView(modelOldFragment).getChild(0);
|
||||
const dataOldShortcode = editor.data.processor.toData(viewOldShortcode);
|
||||
|
||||
const dataNewShortcode = uncollapse(collapse(dataOldShortcode));
|
||||
const viewNewShortcode = editor.data.processor.toView(dataNewShortcode).getChild(0);
|
||||
const modelNewShortcode = editor.data.toModel(viewNewShortcode, convertContext).getChild(0);
|
||||
|
||||
modelWriter.remove(modelShortcode);
|
||||
modelWriter.insert(modelNewShortcode, insertPosition);
|
||||
modelWriter.setSelection(modelNewShortcode, 'on');
|
||||
|
||||
modelShortcode = modelNewShortcode;
|
||||
});
|
||||
};
|
||||
|
||||
showSettingsPopup(argsForPopup);
|
||||
}
|
||||
}
|
164
plugins/shortcode-core/nextgen-editor/src/uncollapse.js
Normal file
164
plugins/shortcode-core/nextgen-editor/src/uncollapse.js
Normal file
@ -0,0 +1,164 @@
|
||||
export default function uncollapse(input, args) {
|
||||
const domOutput = new DOMParser().parseFromString(input, 'text/html');
|
||||
[...domOutput.querySelectorAll('shortcode-block, shortcode-inline')].forEach((domShortcode) => {
|
||||
domShortcode.setAttribute('sc-rendered', false);
|
||||
});
|
||||
|
||||
let domShortcode = domOutput.querySelector('shortcode-block[sc-rendered], shortcode-inline[sc-rendered]');
|
||||
|
||||
while (domShortcode) {
|
||||
const name = domShortcode.getAttribute('name');
|
||||
const shortcode = window.nextgenEditor.shortcodes[name];
|
||||
const attributes = JSON.parse(decodeURIComponent(domShortcode.getAttribute('attributes')));
|
||||
|
||||
domShortcode.classList.add('ck-shortcode');
|
||||
domShortcode.classList.add(`ck-shortcode-${shortcode.type}`);
|
||||
domShortcode.removeAttribute('sc-rendered');
|
||||
|
||||
const argsForRender = {
|
||||
shortcode,
|
||||
attributes,
|
||||
innerHTML: domShortcode.innerHTML,
|
||||
parentAttributes: null,
|
||||
childAttributes: null,
|
||||
};
|
||||
|
||||
let innerHTML = '';
|
||||
|
||||
if (shortcode.type === 'block') {
|
||||
if (shortcode.parent) {
|
||||
domShortcode.classList.add('ck-shortcode-child');
|
||||
|
||||
const domParentShortcode = domShortcode.closest(`shortcode-block[name="${shortcode.parent.name}"]`);
|
||||
|
||||
argsForRender.parentAttributes = !args || !args.parentAttributes
|
||||
? domParentShortcode
|
||||
? JSON.parse(decodeURIComponent(domParentShortcode.getAttribute('attributes')))
|
||||
: {}
|
||||
: args.parentAttributes;
|
||||
}
|
||||
|
||||
if (shortcode.child) {
|
||||
argsForRender.childAttributes = [];
|
||||
domShortcode.classList.add('ck-shortcode-parent');
|
||||
|
||||
const childNodes = [...domShortcode.querySelectorAll(`shortcode-block shortcode-block[name="${shortcode.child.name}"]`)];
|
||||
const deepChildNodes = [...domShortcode.querySelectorAll(`shortcode-block shortcode-block shortcode-block[name="${shortcode.child.name}"]`)];
|
||||
|
||||
childNodes
|
||||
.filter((domChildShortcode) => !deepChildNodes.includes(domChildShortcode))
|
||||
.forEach((domChildShortcode) => {
|
||||
const childAttributes = JSON.parse(decodeURIComponent(domChildShortcode.getAttribute('attributes')));
|
||||
argsForRender.childAttributes.push(childAttributes);
|
||||
});
|
||||
}
|
||||
|
||||
/* eslint-disable indent, no-multi-spaces */
|
||||
innerHTML += '<div class="sc-header">';
|
||||
innerHTML += `<div class="sc-title">Shortcode - <span class="sc-value">${shortcode.title}</span></div>`;
|
||||
innerHTML += `<div class="sc-titlebar">${shortcode.titlebar(argsForRender)}</div>`;
|
||||
innerHTML += '<div class="sc-settings">';
|
||||
innerHTML += '<svg viewBox="0 0 24 24" fill="currentColor" stroke="none">';
|
||||
innerHTML += '<path d="M9 4.58V4c0-1.1.9-2 2-2h2a2 2 0 0 1 2 2v.58a8 8 0 0 1 1.92 1.11l.5-.29a2 2 0 0 1 2.74.73l1 1.74a2 2 0 0 1-.73 2.73l-.5.29a8.06 8.06 0 0 1 0 2.22l.5.3a2 2 0 0 1 .73 2.72l-1 1.74a2 2 0 0 1-2.73.73l-.5-.3A8 8 0 0 1 15 19.43V20a2 2 0 0 1-2 2h-2a2 2 0 0 1-2-2v-.58a8 8 0 0 1-1.92-1.11l-.5.29a2 2 0 0 1-2.74-.73l-1-1.74a2 2 0 0 1 .73-2.73l.5-.29a8.06 8.06 0 0 1 0-2.22l-.5-.3a2 2 0 0 1-.73-2.72l1-1.74a2 2 0 0 1 2.73-.73l.5.3A8 8 0 0 1 9 4.57zM7.88 7.64l-.54.51-1.77-1.02-1 1.74 1.76 1.01-.17.73a6.02 6.02 0 0 0 0 2.78l.17.73-1.76 1.01 1 1.74 1.77-1.02.54.51a6 6 0 0 0 2.4 1.4l.72.2V20h2v-2.04l.71-.2a6 6 0 0 0 2.41-1.4l.54-.51 1.77 1.02 1-1.74-1.76-1.01.17-.73a6.02 6.02 0 0 0 0-2.78l-.17-.73 1.76-1.01-1-1.74-1.77 1.02-.54-.51a6 6 0 0 0-2.4-1.4l-.72-.2V4h-2v2.04l-.71.2a6 6 0 0 0-2.41 1.4zM12 16a4 4 0 1 1 0-8 4 4 0 0 1 0 8zm0-2a2 2 0 1 0 0-4 2 2 0 0 0 0 4z"></path>';
|
||||
innerHTML += '</svg>';
|
||||
innerHTML += '</div>';
|
||||
innerHTML += '</div>';
|
||||
innerHTML += '<div class="sc-content">';
|
||||
innerHTML += shortcode.content(argsForRender)
|
||||
.replace('{{content_editable}}', `<shortcode-block-editable>${domShortcode.innerHTML}</shortcode-block-editable>`)
|
||||
.replace('{{content_readonly}}', `<shortcode-block-readonly>${domShortcode.innerHTML}</shortcode-block-readonly>`);
|
||||
innerHTML += '</div>';
|
||||
|
||||
if (shortcode.child) {
|
||||
const visible = !domShortcode.innerHTML ? ' sc-visible' : '';
|
||||
innerHTML += `<div class="sc-add-child${visible}" title="Insert new ${shortcode.child.title}">`;
|
||||
innerHTML += '<svg viewBox="0 0 24 24" fill="currentColor" stroke="none">';
|
||||
innerHTML += '<path d="M17 11a1 1 0 0 1 0 2h-4v4a1 1 0 0 1-2 0v-4H7a1 1 0 0 1 0-2h4V7a1 1 0 0 1 2 0v4h4z"></path>';
|
||||
innerHTML += '</svg>';
|
||||
innerHTML += '</div>';
|
||||
}
|
||||
|
||||
if (shortcode.parent) {
|
||||
['before', 'after'].forEach((where) => {
|
||||
innerHTML += `<div class="sc-add sc-add-${where}" title="Insert new ${shortcode.title} ${where}">`;
|
||||
innerHTML += '<svg viewBox="0 0 24 24" fill="currentColor" stroke="none">';
|
||||
innerHTML += '<path d="M17 11a1 1 0 0 1 0 2h-4v4a1 1 0 0 1-2 0v-4H7a1 1 0 0 1 0-2h4V7a1 1 0 0 1 2 0v4h4z"></path>';
|
||||
innerHTML += '</svg>';
|
||||
innerHTML += '</div>';
|
||||
});
|
||||
|
||||
['up', 'down'].forEach((where) => {
|
||||
innerHTML += `<div class="sc-move sc-move-${where}" title="Move ${shortcode.title} ${where}">`;
|
||||
innerHTML += '<svg viewBox="0 0 24 24" fill="currentColor" stroke="none">';
|
||||
innerHTML += '<path fill-rule="evenodd" clip-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"></path>';
|
||||
innerHTML += '</svg>';
|
||||
innerHTML += '</div>';
|
||||
});
|
||||
}
|
||||
/* eslint-enable indent, no-multi-spaces */
|
||||
}
|
||||
|
||||
if (shortcode.type === 'inline') {
|
||||
/* eslint-disable indent, no-multi-spaces */
|
||||
innerHTML += '<span class="sc-content">';
|
||||
innerHTML += shortcode.content(argsForRender)
|
||||
.replace('{{content_editable}}', `<shortcode-inline-editable>${domShortcode.innerHTML}</shortcode-inline-editable>`)
|
||||
.replace('{{content_readonly}}', `<shortcode-inline-readonly>${domShortcode.innerHTML}</shortcode-inline-readonly>`);
|
||||
innerHTML += '</span>';
|
||||
innerHTML += '<span class="sc-settings">';
|
||||
innerHTML += '<svg viewBox="0 0 24 24" fill="currentColor" stroke="none">';
|
||||
innerHTML += '<path d="M9 4.58V4c0-1.1.9-2 2-2h2a2 2 0 0 1 2 2v.58a8 8 0 0 1 1.92 1.11l.5-.29a2 2 0 0 1 2.74.73l1 1.74a2 2 0 0 1-.73 2.73l-.5.29a8.06 8.06 0 0 1 0 2.22l.5.3a2 2 0 0 1 .73 2.72l-1 1.74a2 2 0 0 1-2.73.73l-.5-.3A8 8 0 0 1 15 19.43V20a2 2 0 0 1-2 2h-2a2 2 0 0 1-2-2v-.58a8 8 0 0 1-1.92-1.11l-.5.29a2 2 0 0 1-2.74-.73l-1-1.74a2 2 0 0 1 .73-2.73l.5-.29a8.06 8.06 0 0 1 0-2.22l-.5-.3a2 2 0 0 1-.73-2.72l1-1.74a2 2 0 0 1 2.73-.73l.5.3A8 8 0 0 1 9 4.57zM7.88 7.64l-.54.51-1.77-1.02-1 1.74 1.76 1.01-.17.73a6.02 6.02 0 0 0 0 2.78l.17.73-1.76 1.01 1 1.74 1.77-1.02.54.51a6 6 0 0 0 2.4 1.4l.72.2V20h2v-2.04l.71-.2a6 6 0 0 0 2.41-1.4l.54-.51 1.77 1.02 1-1.74-1.76-1.01.17-.73a6.02 6.02 0 0 0 0-2.78l-.17-.73 1.76-1.01-1-1.74-1.77 1.02-.54-.51a6 6 0 0 0-2.4-1.4l-.72-.2V4h-2v2.04l-.71.2a6 6 0 0 0-2.41 1.4zM12 16a4 4 0 1 1 0-8 4 4 0 0 1 0 8zm0-2a2 2 0 1 0 0-4 2 2 0 0 0 0 4z"></path>';
|
||||
innerHTML += '</svg>';
|
||||
innerHTML += '</span>';
|
||||
/* eslint-enable indent, no-multi-spaces */
|
||||
}
|
||||
|
||||
domShortcode.innerHTML = innerHTML;
|
||||
domShortcode = domOutput.querySelector('shortcode-block[sc-rendered], shortcode-inline[sc-rendered]');
|
||||
}
|
||||
|
||||
return domOutput.body.innerHTML;
|
||||
}
|
||||
|
||||
document.addEventListener('click', (event) => {
|
||||
const { target } = event;
|
||||
const list = ['sc-settings', 'sc-move', 'sc-add', 'sc-add-child'];
|
||||
const action = { element: null, className: null };
|
||||
const isAction = list.some((item) => {
|
||||
let match = target.classList.contains(item);
|
||||
|
||||
if (match) {
|
||||
action.element = target;
|
||||
action.className = item;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
match = target.closest(`.${item}`);
|
||||
if (match) {
|
||||
action.element = match;
|
||||
action.className = item;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
if (isAction) {
|
||||
switch (action.className) {
|
||||
case 'sc-move':
|
||||
window.scBlockMoveChild.call(action.element, event, action.element.classList.contains('sc-move-up') ? 'up' : 'down');
|
||||
break;
|
||||
case 'sc-add':
|
||||
window.scBlockAddChild.call(action.element, event, action.element.classList.contains('sc-add-before') ? 'before' : 'after');
|
||||
break;
|
||||
case 'sc-add-child':
|
||||
window.scBlockAddChildFromParent.call(action.element, event);
|
||||
break;
|
||||
case 'sc-settings':
|
||||
default:
|
||||
window.scDisplaySettings.call(action.element, event);
|
||||
}
|
||||
}
|
||||
});
|
31
plugins/shortcode-core/nextgen-editor/vue.config.js
Normal file
31
plugins/shortcode-core/nextgen-editor/vue.config.js
Normal file
@ -0,0 +1,31 @@
|
||||
const DirectoryNamedWebpackPlugin = require('directory-named-webpack-plugin');
|
||||
|
||||
module.exports = {
|
||||
filenameHashing: false,
|
||||
publicPath: process.env.NODE_ENV === 'development'
|
||||
? `http://${process.env.DEV_HOST}:${process.env.DEV_PORT}/`
|
||||
: '/',
|
||||
configureWebpack: {
|
||||
resolve: {
|
||||
plugins: [
|
||||
new DirectoryNamedWebpackPlugin(),
|
||||
],
|
||||
},
|
||||
optimization: {
|
||||
splitChunks: false,
|
||||
},
|
||||
},
|
||||
chainWebpack: (webpackConfig) => {
|
||||
webpackConfig.plugins.delete('html');
|
||||
webpackConfig.plugins.delete('preload');
|
||||
webpackConfig.plugins.delete('prefetch');
|
||||
},
|
||||
devServer: {
|
||||
host: process.env.DEV_HOST,
|
||||
port: process.env.DEV_PORT,
|
||||
disableHostCheck: true,
|
||||
headers: {
|
||||
'Access-Control-Allow-Origin': '*',
|
||||
},
|
||||
},
|
||||
};
|
9534
plugins/shortcode-core/nextgen-editor/yarn.lock
Normal file
9534
plugins/shortcode-core/nextgen-editor/yarn.lock
Normal file
File diff suppressed because it is too large
Load Diff
293
plugins/shortcode-core/shortcode-core.php
Normal file
293
plugins/shortcode-core/shortcode-core.php
Normal file
@ -0,0 +1,293 @@
|
||||
<?php
|
||||
namespace Grav\Plugin;
|
||||
|
||||
use Composer\Autoload\ClassLoader;
|
||||
use Grav\Common\Assets;
|
||||
use Grav\Common\Page\Interfaces\PageInterface;
|
||||
use Grav\Common\Plugin;
|
||||
use Grav\Common\Utils;
|
||||
use Grav\Plugin\ShortcodeCore\ShortcodeManager;
|
||||
use Grav\Plugin\ShortcodeCore\ShortcodeTwigVar;
|
||||
use RocketTheme\Toolbox\Event\Event;
|
||||
use Twig\TwigFilter;
|
||||
|
||||
|
||||
class ShortcodeCorePlugin extends Plugin
|
||||
{
|
||||
/** @var ShortcodeManager $shortcodes */
|
||||
protected $shortcodes;
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return [
|
||||
'onPluginsInitialized' => [
|
||||
['autoload', 100001],
|
||||
['onPluginsInitialized', 10]
|
||||
],
|
||||
'registerNextGenEditorPlugin' => [
|
||||
['registerNextGenEditorPlugin', 0],
|
||||
['registerNextGenEditorPluginShortcodes', 0],
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* [onPluginsInitialized:100000] Composer autoload.
|
||||
*
|
||||
* @return ClassLoader
|
||||
*/
|
||||
public function autoload()
|
||||
{
|
||||
return require __DIR__ . '/vendor/autoload.php';
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize configuration
|
||||
*/
|
||||
public function onPluginsInitialized()
|
||||
{
|
||||
$this->config = $this->grav['config'];
|
||||
|
||||
// don't continue if this is admin and plugin is disabled for admin
|
||||
if (!$this->config->get('plugins.shortcode-core.active_admin') && $this->isAdmin()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->enable([
|
||||
'onThemeInitialized' => ['onThemeInitialized', 0],
|
||||
'onMarkdownInitialized' => ['onMarkdownInitialized', 0],
|
||||
'onShortcodeHandlers' => ['onShortcodeHandlers', 0],
|
||||
'onPageContentRaw' => ['onPageContentRaw', 0],
|
||||
'onPageContentProcessed' => ['onPageContentProcessed', -10],
|
||||
'onPageContent' => ['onPageContent', 0],
|
||||
'onTwigInitialized' => ['onTwigInitialized', 0],
|
||||
'onTwigTemplatePaths' => ['onTwigTemplatePaths', 0],
|
||||
]);
|
||||
|
||||
$this->grav['shortcode'] = $this->shortcodes = new ShortcodeManager();
|
||||
}
|
||||
|
||||
/**
|
||||
* Theme initialization is best place to fire onShortcodeHandler event
|
||||
* in order to support both plugins and themes
|
||||
*/
|
||||
public function onThemeInitialized()
|
||||
{
|
||||
$this->grav->fireEvent('onShortcodeHandlers');
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the markdown Initialized event by setting up shortcode block tags
|
||||
*
|
||||
* @param Event $event the event containing the markdown parser
|
||||
*/
|
||||
public function onMarkdownInitialized(Event $event)
|
||||
{
|
||||
$this->shortcodes->setupMarkdown($event['markdown']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process shortcodes before Grav's processing
|
||||
*
|
||||
* @param Event $e
|
||||
*/
|
||||
public function onPageContentRaw(Event $e)
|
||||
{
|
||||
$this->processShortcodes($e['page'], 'processRawContent');
|
||||
}
|
||||
|
||||
/**
|
||||
* Process shortcodes after Grav's processing, but before caching
|
||||
*
|
||||
* @param Event $e
|
||||
*/
|
||||
public function onPageContentProcessed(Event $e)
|
||||
{
|
||||
$this->processShortcodes($e['page'], 'processContent');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param PageInterface $page
|
||||
* @param string $type
|
||||
*/
|
||||
protected function processShortcodes(PageInterface $page, $type = 'processContent') {
|
||||
$meta = [];
|
||||
$this->shortcodes->resetObjects(); // clear shortcodes that may have been processed in this execution thread before
|
||||
$config = $this->mergeConfig($page);
|
||||
|
||||
// Don't run in admin pages other than content
|
||||
$admin_pages_only = $config['admin_pages_only'] ?? true;
|
||||
if ($admin_pages_only && $this->isAdmin() && !Utils::startsWith($page->filePath(), $this->grav['locator']->findResource('page://'))) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->active = $config->get('active', true);
|
||||
|
||||
// if the plugin is not active (either global or on page) exit
|
||||
if (!$this->active) {
|
||||
return;
|
||||
}
|
||||
|
||||
// process the content for shortcodes
|
||||
$page->setRawContent($this->shortcodes->$type($page, $config));
|
||||
|
||||
// if objects found set them as page content meta
|
||||
$shortcode_objects = $this->shortcodes->getObjects();
|
||||
if (!empty($shortcode_objects)) {
|
||||
$meta['shortcode'] = $shortcode_objects;
|
||||
}
|
||||
|
||||
// if assets founds set them as page content meta
|
||||
$shortcode_assets = $this->shortcodes->getAssets();
|
||||
if (!empty($shortcode_assets)) {
|
||||
$meta['shortcodeAssets'] = $shortcode_assets;
|
||||
}
|
||||
|
||||
// if we have meta set, let's add it to the content meta
|
||||
if (!empty($meta)) {
|
||||
$page->addContentMeta('shortcodeMeta', $meta);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param PageInterface $page
|
||||
* @return \Grav\Common\Data\Data
|
||||
*/
|
||||
protected function getConfig(PageInterface $page)
|
||||
{
|
||||
$config = $this->mergeConfig($page);
|
||||
$this->active = false;
|
||||
|
||||
// Don't run in admin pages other than content
|
||||
$admin_pages_only = isset($config['admin_pages_only']) ? $config['admin_pages_only'] : true;
|
||||
if ($admin_pages_only &&
|
||||
$this->isAdmin() &&
|
||||
!Utils::startsWith($page->filePath(), $this->grav['locator']->findResource('page://'))) {
|
||||
|
||||
} else {
|
||||
$this->active = $config->get('active', true);
|
||||
}
|
||||
|
||||
return $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the assets that might be associated with this page
|
||||
*/
|
||||
public function onPageContent(Event $event)
|
||||
{
|
||||
if (!$this->active) {
|
||||
return;
|
||||
}
|
||||
|
||||
$page = $event['page'];
|
||||
|
||||
// get the meta and check for assets
|
||||
$page_meta = $page->getContentMeta('shortcodeMeta');
|
||||
|
||||
if (is_array($page_meta)) {
|
||||
if (isset($page_meta['shortcodeAssets'])) {
|
||||
|
||||
$page_assets = (array) $page_meta['shortcodeAssets'];
|
||||
|
||||
/** @var Assets $assets */
|
||||
$assets = $this->grav['assets'];
|
||||
// if we actually have data now, add it to asset manager
|
||||
foreach ($page_assets as $type => $asset) {
|
||||
foreach ($asset as $item) {
|
||||
$method = 'add'.ucfirst($type);
|
||||
if (is_array($item)) {
|
||||
$assets->$method($item[0], $item[1]);
|
||||
} else {
|
||||
$assets->$method($item);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Event that handles registering handler for shortcodes
|
||||
*/
|
||||
public function onShortcodeHandlers()
|
||||
{
|
||||
$include_default_shortcodes = $this->config->get('plugins.shortcode-core.include_default_shortcodes', true);
|
||||
if ($include_default_shortcodes) {
|
||||
$this->shortcodes->registerAllShortcodes(__DIR__ . '/classes/shortcodes', ['ignore' => ['Shortcode', 'ShortcodeObject']]);
|
||||
}
|
||||
|
||||
// Add custom shortcodes directory if provided
|
||||
$custom_shortcodes = $this->config->get('plugins.shortcode-core.custom_shortcodes');
|
||||
if (isset($custom_shortcodes)) {
|
||||
$this->shortcodes->registerAllShortcodes(GRAV_ROOT . $custom_shortcodes);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a twig filter for processing shortcodes in templates
|
||||
*/
|
||||
public function onTwigInitialized()
|
||||
{
|
||||
$this->grav['twig']->twig()->addFilter(new TwigFilter('shortcodes', [$this->shortcodes, 'processShortcodes']));
|
||||
$this->grav['twig']->twig_vars['shortcode'] = new ShortcodeTwigVar();
|
||||
}
|
||||
|
||||
public function onTwigTemplatePaths()
|
||||
{
|
||||
$this->grav['twig']->twig_paths[] = __DIR__ . '/templates';
|
||||
}
|
||||
|
||||
public function registerNextGenEditorPlugin($event) {
|
||||
$config = $this->config->get('plugins.shortcode-core.nextgen-editor');
|
||||
$plugins = $event['plugins'];
|
||||
|
||||
if ($config['env'] !== 'development') {
|
||||
$plugins['css'][] = 'plugin://shortcode-core/nextgen-editor/dist/css/app.css';
|
||||
$plugins['js'][] = 'plugin://shortcode-core/nextgen-editor/dist/js/app.js';
|
||||
} else {
|
||||
$plugins['js'][] = 'http://' . $config['dev_host'] . ':' . $config['dev_port'] . '/js/app.js';
|
||||
}
|
||||
|
||||
$event['plugins'] = $plugins;
|
||||
return $event;
|
||||
}
|
||||
|
||||
public function registerNextGenEditorPluginShortcodes($event) {
|
||||
$include_default_shortcodes = $this->config->get('plugins.shortcode-core.include_default_shortcodes', true);
|
||||
if ($include_default_shortcodes) {
|
||||
$plugins = $event['plugins'];
|
||||
|
||||
$plugins['js'][] = 'plugin://shortcode-core/nextgen-editor/shortcodes/shortcode-core.js';
|
||||
$plugins['js'][] = 'plugin://shortcode-core/nextgen-editor/shortcodes/align/align.js';
|
||||
$plugins['js'][] = 'plugin://shortcode-core/nextgen-editor/shortcodes/color/color.js';
|
||||
$plugins['js'][] = 'plugin://shortcode-core/nextgen-editor/shortcodes/columns/columns.js';
|
||||
$plugins['css'][] = 'plugin://shortcode-core/nextgen-editor/shortcodes/details/details.css';
|
||||
$plugins['js'][] = 'plugin://shortcode-core/nextgen-editor/shortcodes/details/details.js';
|
||||
$plugins['js'][] = 'plugin://shortcode-core/nextgen-editor/shortcodes/div/div.js';
|
||||
$plugins['js'][] = 'plugin://shortcode-core/nextgen-editor/shortcodes/figure/figure.js';
|
||||
$plugins['js'][] = 'plugin://shortcode-core/nextgen-editor/shortcodes/fontawesome/fontawesome.js';
|
||||
$plugins['css'][] = 'plugin://shortcode-core/nextgen-editor/shortcodes/headers/headers.css';
|
||||
$plugins['js'][] = 'plugin://shortcode-core/nextgen-editor/shortcodes/headers/headers.js';
|
||||
$plugins['js'][] = 'plugin://shortcode-core/nextgen-editor/shortcodes/language/language.js';
|
||||
$plugins['js'][] = 'plugin://shortcode-core/nextgen-editor/shortcodes/lorem/lorem.js';
|
||||
$plugins['css'][] = 'plugin://shortcode-core/nextgen-editor/shortcodes/mark/mark.css';
|
||||
$plugins['js'][] = 'plugin://shortcode-core/nextgen-editor/shortcodes/mark/mark.js';
|
||||
$plugins['css'][] = 'plugin://shortcode-core/nextgen-editor/shortcodes/notice/notice.css';
|
||||
$plugins['js'][] = 'plugin://shortcode-core/nextgen-editor/shortcodes/notice/notice.js';
|
||||
$plugins['js'][] = 'plugin://shortcode-core/nextgen-editor/shortcodes/raw/raw.js';
|
||||
$plugins['js'][] = 'plugin://shortcode-core/nextgen-editor/shortcodes/safe-email/safe-email.js';
|
||||
$plugins['js'][] = 'plugin://shortcode-core/nextgen-editor/shortcodes/section/section.js';
|
||||
$plugins['js'][] = 'plugin://shortcode-core/nextgen-editor/shortcodes/size/size.js';
|
||||
$plugins['js'][] = 'plugin://shortcode-core/nextgen-editor/shortcodes/span/span.js';
|
||||
$plugins['js'][] = 'plugin://shortcode-core/nextgen-editor/shortcodes/u/u.js';
|
||||
|
||||
$event['plugins'] = $plugins;
|
||||
}
|
||||
return $event;
|
||||
}
|
||||
|
||||
}
|
17
plugins/shortcode-core/shortcode-core.yaml
Normal file
17
plugins/shortcode-core/shortcode-core.yaml
Normal file
@ -0,0 +1,17 @@
|
||||
enabled: true
|
||||
active: true
|
||||
active_admin: true
|
||||
admin_pages_only: true
|
||||
parser: regular
|
||||
include_default_shortcodes: true
|
||||
css:
|
||||
notice_enabled: true
|
||||
custom_shortcodes:
|
||||
fontawesome:
|
||||
load: true
|
||||
url: '//maxcdn.bootstrapcdn.com/font-awesome/4.6.1/css/font-awesome.min.css'
|
||||
v5: false
|
||||
nextgen-editor:
|
||||
env: production
|
||||
dev_host: localhost
|
||||
dev_port: 2001
|
@ -0,0 +1,3 @@
|
||||
<div class="sc-notice {{ type }}">
|
||||
<div>{{ content|raw }}</div>
|
||||
</div>
|
12
plugins/shortcode-core/vendor/autoload.php
vendored
Normal file
12
plugins/shortcode-core/vendor/autoload.php
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
// autoload.php @generated by Composer
|
||||
|
||||
if (PHP_VERSION_ID < 50600) {
|
||||
echo 'Composer 2.3.0 dropped support for autoloading on PHP <5.6 and you are running '.PHP_VERSION.', please upgrade PHP or use Composer 2.2 LTS via "composer self-update --2.2". Aborting.'.PHP_EOL;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
require_once __DIR__ . '/composer/autoload_real.php';
|
||||
|
||||
return ComposerAutoloaderInit20dff4ef15e2090e54c04a9aa83321b9::getLoader();
|
572
plugins/shortcode-core/vendor/composer/ClassLoader.php
vendored
Normal file
572
plugins/shortcode-core/vendor/composer/ClassLoader.php
vendored
Normal file
@ -0,0 +1,572 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Composer.
|
||||
*
|
||||
* (c) Nils Adermann <naderman@naderman.de>
|
||||
* Jordi Boggiano <j.boggiano@seld.be>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Composer\Autoload;
|
||||
|
||||
/**
|
||||
* ClassLoader implements a PSR-0, PSR-4 and classmap class loader.
|
||||
*
|
||||
* $loader = new \Composer\Autoload\ClassLoader();
|
||||
*
|
||||
* // register classes with namespaces
|
||||
* $loader->add('Symfony\Component', __DIR__.'/component');
|
||||
* $loader->add('Symfony', __DIR__.'/framework');
|
||||
*
|
||||
* // activate the autoloader
|
||||
* $loader->register();
|
||||
*
|
||||
* // to enable searching the include path (eg. for PEAR packages)
|
||||
* $loader->setUseIncludePath(true);
|
||||
*
|
||||
* In this example, if you try to use a class in the Symfony\Component
|
||||
* namespace or one of its children (Symfony\Component\Console for instance),
|
||||
* the autoloader will first look for the class under the component/
|
||||
* directory, and it will then fallback to the framework/ directory if not
|
||||
* found before giving up.
|
||||
*
|
||||
* This class is loosely based on the Symfony UniversalClassLoader.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||
* @see https://www.php-fig.org/psr/psr-0/
|
||||
* @see https://www.php-fig.org/psr/psr-4/
|
||||
*/
|
||||
class ClassLoader
|
||||
{
|
||||
/** @var ?string */
|
||||
private $vendorDir;
|
||||
|
||||
// PSR-4
|
||||
/**
|
||||
* @var array[]
|
||||
* @psalm-var array<string, array<string, int>>
|
||||
*/
|
||||
private $prefixLengthsPsr4 = array();
|
||||
/**
|
||||
* @var array[]
|
||||
* @psalm-var array<string, array<int, string>>
|
||||
*/
|
||||
private $prefixDirsPsr4 = array();
|
||||
/**
|
||||
* @var array[]
|
||||
* @psalm-var array<string, string>
|
||||
*/
|
||||
private $fallbackDirsPsr4 = array();
|
||||
|
||||
// PSR-0
|
||||
/**
|
||||
* @var array[]
|
||||
* @psalm-var array<string, array<string, string[]>>
|
||||
*/
|
||||
private $prefixesPsr0 = array();
|
||||
/**
|
||||
* @var array[]
|
||||
* @psalm-var array<string, string>
|
||||
*/
|
||||
private $fallbackDirsPsr0 = array();
|
||||
|
||||
/** @var bool */
|
||||
private $useIncludePath = false;
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
* @psalm-var array<string, string>
|
||||
*/
|
||||
private $classMap = array();
|
||||
|
||||
/** @var bool */
|
||||
private $classMapAuthoritative = false;
|
||||
|
||||
/**
|
||||
* @var bool[]
|
||||
* @psalm-var array<string, bool>
|
||||
*/
|
||||
private $missingClasses = array();
|
||||
|
||||
/** @var ?string */
|
||||
private $apcuPrefix;
|
||||
|
||||
/**
|
||||
* @var self[]
|
||||
*/
|
||||
private static $registeredLoaders = array();
|
||||
|
||||
/**
|
||||
* @param ?string $vendorDir
|
||||
*/
|
||||
public function __construct($vendorDir = null)
|
||||
{
|
||||
$this->vendorDir = $vendorDir;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getPrefixes()
|
||||
{
|
||||
if (!empty($this->prefixesPsr0)) {
|
||||
return call_user_func_array('array_merge', array_values($this->prefixesPsr0));
|
||||
}
|
||||
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array[]
|
||||
* @psalm-return array<string, array<int, string>>
|
||||
*/
|
||||
public function getPrefixesPsr4()
|
||||
{
|
||||
return $this->prefixDirsPsr4;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array[]
|
||||
* @psalm-return array<string, string>
|
||||
*/
|
||||
public function getFallbackDirs()
|
||||
{
|
||||
return $this->fallbackDirsPsr0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array[]
|
||||
* @psalm-return array<string, string>
|
||||
*/
|
||||
public function getFallbackDirsPsr4()
|
||||
{
|
||||
return $this->fallbackDirsPsr4;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[] Array of classname => path
|
||||
* @psalm-return array<string, string>
|
||||
*/
|
||||
public function getClassMap()
|
||||
{
|
||||
return $this->classMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[] $classMap Class to filename map
|
||||
* @psalm-param array<string, string> $classMap
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function addClassMap(array $classMap)
|
||||
{
|
||||
if ($this->classMap) {
|
||||
$this->classMap = array_merge($this->classMap, $classMap);
|
||||
} else {
|
||||
$this->classMap = $classMap;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a set of PSR-0 directories for a given prefix, either
|
||||
* appending or prepending to the ones previously set for this prefix.
|
||||
*
|
||||
* @param string $prefix The prefix
|
||||
* @param string[]|string $paths The PSR-0 root directories
|
||||
* @param bool $prepend Whether to prepend the directories
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function add($prefix, $paths, $prepend = false)
|
||||
{
|
||||
if (!$prefix) {
|
||||
if ($prepend) {
|
||||
$this->fallbackDirsPsr0 = array_merge(
|
||||
(array) $paths,
|
||||
$this->fallbackDirsPsr0
|
||||
);
|
||||
} else {
|
||||
$this->fallbackDirsPsr0 = array_merge(
|
||||
$this->fallbackDirsPsr0,
|
||||
(array) $paths
|
||||
);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$first = $prefix[0];
|
||||
if (!isset($this->prefixesPsr0[$first][$prefix])) {
|
||||
$this->prefixesPsr0[$first][$prefix] = (array) $paths;
|
||||
|
||||
return;
|
||||
}
|
||||
if ($prepend) {
|
||||
$this->prefixesPsr0[$first][$prefix] = array_merge(
|
||||
(array) $paths,
|
||||
$this->prefixesPsr0[$first][$prefix]
|
||||
);
|
||||
} else {
|
||||
$this->prefixesPsr0[$first][$prefix] = array_merge(
|
||||
$this->prefixesPsr0[$first][$prefix],
|
||||
(array) $paths
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a set of PSR-4 directories for a given namespace, either
|
||||
* appending or prepending to the ones previously set for this namespace.
|
||||
*
|
||||
* @param string $prefix The prefix/namespace, with trailing '\\'
|
||||
* @param string[]|string $paths The PSR-4 base directories
|
||||
* @param bool $prepend Whether to prepend the directories
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function addPsr4($prefix, $paths, $prepend = false)
|
||||
{
|
||||
if (!$prefix) {
|
||||
// Register directories for the root namespace.
|
||||
if ($prepend) {
|
||||
$this->fallbackDirsPsr4 = array_merge(
|
||||
(array) $paths,
|
||||
$this->fallbackDirsPsr4
|
||||
);
|
||||
} else {
|
||||
$this->fallbackDirsPsr4 = array_merge(
|
||||
$this->fallbackDirsPsr4,
|
||||
(array) $paths
|
||||
);
|
||||
}
|
||||
} elseif (!isset($this->prefixDirsPsr4[$prefix])) {
|
||||
// Register directories for a new namespace.
|
||||
$length = strlen($prefix);
|
||||
if ('\\' !== $prefix[$length - 1]) {
|
||||
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
|
||||
}
|
||||
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
|
||||
$this->prefixDirsPsr4[$prefix] = (array) $paths;
|
||||
} elseif ($prepend) {
|
||||
// Prepend directories for an already registered namespace.
|
||||
$this->prefixDirsPsr4[$prefix] = array_merge(
|
||||
(array) $paths,
|
||||
$this->prefixDirsPsr4[$prefix]
|
||||
);
|
||||
} else {
|
||||
// Append directories for an already registered namespace.
|
||||
$this->prefixDirsPsr4[$prefix] = array_merge(
|
||||
$this->prefixDirsPsr4[$prefix],
|
||||
(array) $paths
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a set of PSR-0 directories for a given prefix,
|
||||
* replacing any others previously set for this prefix.
|
||||
*
|
||||
* @param string $prefix The prefix
|
||||
* @param string[]|string $paths The PSR-0 base directories
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function set($prefix, $paths)
|
||||
{
|
||||
if (!$prefix) {
|
||||
$this->fallbackDirsPsr0 = (array) $paths;
|
||||
} else {
|
||||
$this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a set of PSR-4 directories for a given namespace,
|
||||
* replacing any others previously set for this namespace.
|
||||
*
|
||||
* @param string $prefix The prefix/namespace, with trailing '\\'
|
||||
* @param string[]|string $paths The PSR-4 base directories
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setPsr4($prefix, $paths)
|
||||
{
|
||||
if (!$prefix) {
|
||||
$this->fallbackDirsPsr4 = (array) $paths;
|
||||
} else {
|
||||
$length = strlen($prefix);
|
||||
if ('\\' !== $prefix[$length - 1]) {
|
||||
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
|
||||
}
|
||||
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
|
||||
$this->prefixDirsPsr4[$prefix] = (array) $paths;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Turns on searching the include path for class files.
|
||||
*
|
||||
* @param bool $useIncludePath
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setUseIncludePath($useIncludePath)
|
||||
{
|
||||
$this->useIncludePath = $useIncludePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Can be used to check if the autoloader uses the include path to check
|
||||
* for classes.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function getUseIncludePath()
|
||||
{
|
||||
return $this->useIncludePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Turns off searching the prefix and fallback directories for classes
|
||||
* that have not been registered with the class map.
|
||||
*
|
||||
* @param bool $classMapAuthoritative
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setClassMapAuthoritative($classMapAuthoritative)
|
||||
{
|
||||
$this->classMapAuthoritative = $classMapAuthoritative;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should class lookup fail if not found in the current class map?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isClassMapAuthoritative()
|
||||
{
|
||||
return $this->classMapAuthoritative;
|
||||
}
|
||||
|
||||
/**
|
||||
* APCu prefix to use to cache found/not-found classes, if the extension is enabled.
|
||||
*
|
||||
* @param string|null $apcuPrefix
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setApcuPrefix($apcuPrefix)
|
||||
{
|
||||
$this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* The APCu prefix in use, or null if APCu caching is not enabled.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getApcuPrefix()
|
||||
{
|
||||
return $this->apcuPrefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers this instance as an autoloader.
|
||||
*
|
||||
* @param bool $prepend Whether to prepend the autoloader or not
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register($prepend = false)
|
||||
{
|
||||
spl_autoload_register(array($this, 'loadClass'), true, $prepend);
|
||||
|
||||
if (null === $this->vendorDir) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($prepend) {
|
||||
self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders;
|
||||
} else {
|
||||
unset(self::$registeredLoaders[$this->vendorDir]);
|
||||
self::$registeredLoaders[$this->vendorDir] = $this;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisters this instance as an autoloader.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function unregister()
|
||||
{
|
||||
spl_autoload_unregister(array($this, 'loadClass'));
|
||||
|
||||
if (null !== $this->vendorDir) {
|
||||
unset(self::$registeredLoaders[$this->vendorDir]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the given class or interface.
|
||||
*
|
||||
* @param string $class The name of the class
|
||||
* @return true|null True if loaded, null otherwise
|
||||
*/
|
||||
public function loadClass($class)
|
||||
{
|
||||
if ($file = $this->findFile($class)) {
|
||||
includeFile($file);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the path to the file where the class is defined.
|
||||
*
|
||||
* @param string $class The name of the class
|
||||
*
|
||||
* @return string|false The path if found, false otherwise
|
||||
*/
|
||||
public function findFile($class)
|
||||
{
|
||||
// class map lookup
|
||||
if (isset($this->classMap[$class])) {
|
||||
return $this->classMap[$class];
|
||||
}
|
||||
if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
|
||||
return false;
|
||||
}
|
||||
if (null !== $this->apcuPrefix) {
|
||||
$file = apcu_fetch($this->apcuPrefix.$class, $hit);
|
||||
if ($hit) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
|
||||
$file = $this->findFileWithExtension($class, '.php');
|
||||
|
||||
// Search for Hack files if we are running on HHVM
|
||||
if (false === $file && defined('HHVM_VERSION')) {
|
||||
$file = $this->findFileWithExtension($class, '.hh');
|
||||
}
|
||||
|
||||
if (null !== $this->apcuPrefix) {
|
||||
apcu_add($this->apcuPrefix.$class, $file);
|
||||
}
|
||||
|
||||
if (false === $file) {
|
||||
// Remember that this class does not exist.
|
||||
$this->missingClasses[$class] = true;
|
||||
}
|
||||
|
||||
return $file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the currently registered loaders indexed by their corresponding vendor directories.
|
||||
*
|
||||
* @return self[]
|
||||
*/
|
||||
public static function getRegisteredLoaders()
|
||||
{
|
||||
return self::$registeredLoaders;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $class
|
||||
* @param string $ext
|
||||
* @return string|false
|
||||
*/
|
||||
private function findFileWithExtension($class, $ext)
|
||||
{
|
||||
// PSR-4 lookup
|
||||
$logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
|
||||
|
||||
$first = $class[0];
|
||||
if (isset($this->prefixLengthsPsr4[$first])) {
|
||||
$subPath = $class;
|
||||
while (false !== $lastPos = strrpos($subPath, '\\')) {
|
||||
$subPath = substr($subPath, 0, $lastPos);
|
||||
$search = $subPath . '\\';
|
||||
if (isset($this->prefixDirsPsr4[$search])) {
|
||||
$pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
|
||||
foreach ($this->prefixDirsPsr4[$search] as $dir) {
|
||||
if (file_exists($file = $dir . $pathEnd)) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// PSR-4 fallback dirs
|
||||
foreach ($this->fallbackDirsPsr4 as $dir) {
|
||||
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
|
||||
// PSR-0 lookup
|
||||
if (false !== $pos = strrpos($class, '\\')) {
|
||||
// namespaced class name
|
||||
$logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
|
||||
. strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
|
||||
} else {
|
||||
// PEAR-like class name
|
||||
$logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
|
||||
}
|
||||
|
||||
if (isset($this->prefixesPsr0[$first])) {
|
||||
foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
|
||||
if (0 === strpos($class, $prefix)) {
|
||||
foreach ($dirs as $dir) {
|
||||
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// PSR-0 fallback dirs
|
||||
foreach ($this->fallbackDirsPsr0 as $dir) {
|
||||
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
|
||||
// PSR-0 include paths.
|
||||
if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
|
||||
return $file;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Scope isolated include.
|
||||
*
|
||||
* Prevents access to $this/self from included files.
|
||||
*
|
||||
* @param string $file
|
||||
* @return void
|
||||
* @private
|
||||
*/
|
||||
function includeFile($file)
|
||||
{
|
||||
include $file;
|
||||
}
|
352
plugins/shortcode-core/vendor/composer/InstalledVersions.php
vendored
Normal file
352
plugins/shortcode-core/vendor/composer/InstalledVersions.php
vendored
Normal file
@ -0,0 +1,352 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Composer.
|
||||
*
|
||||
* (c) Nils Adermann <naderman@naderman.de>
|
||||
* Jordi Boggiano <j.boggiano@seld.be>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Composer;
|
||||
|
||||
use Composer\Autoload\ClassLoader;
|
||||
use Composer\Semver\VersionParser;
|
||||
|
||||
/**
|
||||
* This class is copied in every Composer installed project and available to all
|
||||
*
|
||||
* See also https://getcomposer.org/doc/07-runtime.md#installed-versions
|
||||
*
|
||||
* To require its presence, you can require `composer-runtime-api ^2.0`
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class InstalledVersions
|
||||
{
|
||||
/**
|
||||
* @var mixed[]|null
|
||||
* @psalm-var array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}|array{}|null
|
||||
*/
|
||||
private static $installed;
|
||||
|
||||
/**
|
||||
* @var bool|null
|
||||
*/
|
||||
private static $canGetVendors;
|
||||
|
||||
/**
|
||||
* @var array[]
|
||||
* @psalm-var array<string, array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}>
|
||||
*/
|
||||
private static $installedByVendor = array();
|
||||
|
||||
/**
|
||||
* Returns a list of all package names which are present, either by being installed, replaced or provided
|
||||
*
|
||||
* @return string[]
|
||||
* @psalm-return list<string>
|
||||
*/
|
||||
public static function getInstalledPackages()
|
||||
{
|
||||
$packages = array();
|
||||
foreach (self::getInstalled() as $installed) {
|
||||
$packages[] = array_keys($installed['versions']);
|
||||
}
|
||||
|
||||
if (1 === \count($packages)) {
|
||||
return $packages[0];
|
||||
}
|
||||
|
||||
return array_keys(array_flip(\call_user_func_array('array_merge', $packages)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of all package names with a specific type e.g. 'library'
|
||||
*
|
||||
* @param string $type
|
||||
* @return string[]
|
||||
* @psalm-return list<string>
|
||||
*/
|
||||
public static function getInstalledPackagesByType($type)
|
||||
{
|
||||
$packagesByType = array();
|
||||
|
||||
foreach (self::getInstalled() as $installed) {
|
||||
foreach ($installed['versions'] as $name => $package) {
|
||||
if (isset($package['type']) && $package['type'] === $type) {
|
||||
$packagesByType[] = $name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $packagesByType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the given package is installed
|
||||
*
|
||||
* This also returns true if the package name is provided or replaced by another package
|
||||
*
|
||||
* @param string $packageName
|
||||
* @param bool $includeDevRequirements
|
||||
* @return bool
|
||||
*/
|
||||
public static function isInstalled($packageName, $includeDevRequirements = true)
|
||||
{
|
||||
foreach (self::getInstalled() as $installed) {
|
||||
if (isset($installed['versions'][$packageName])) {
|
||||
return $includeDevRequirements || empty($installed['versions'][$packageName]['dev_requirement']);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the given package satisfies a version constraint
|
||||
*
|
||||
* e.g. If you want to know whether version 2.3+ of package foo/bar is installed, you would call:
|
||||
*
|
||||
* Composer\InstalledVersions::satisfies(new VersionParser, 'foo/bar', '^2.3')
|
||||
*
|
||||
* @param VersionParser $parser Install composer/semver to have access to this class and functionality
|
||||
* @param string $packageName
|
||||
* @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
|
||||
* @return bool
|
||||
*/
|
||||
public static function satisfies(VersionParser $parser, $packageName, $constraint)
|
||||
{
|
||||
$constraint = $parser->parseConstraints($constraint);
|
||||
$provided = $parser->parseConstraints(self::getVersionRanges($packageName));
|
||||
|
||||
return $provided->matches($constraint);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a version constraint representing all the range(s) which are installed for a given package
|
||||
*
|
||||
* It is easier to use this via isInstalled() with the $constraint argument if you need to check
|
||||
* whether a given version of a package is installed, and not just whether it exists
|
||||
*
|
||||
* @param string $packageName
|
||||
* @return string Version constraint usable with composer/semver
|
||||
*/
|
||||
public static function getVersionRanges($packageName)
|
||||
{
|
||||
foreach (self::getInstalled() as $installed) {
|
||||
if (!isset($installed['versions'][$packageName])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$ranges = array();
|
||||
if (isset($installed['versions'][$packageName]['pretty_version'])) {
|
||||
$ranges[] = $installed['versions'][$packageName]['pretty_version'];
|
||||
}
|
||||
if (array_key_exists('aliases', $installed['versions'][$packageName])) {
|
||||
$ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']);
|
||||
}
|
||||
if (array_key_exists('replaced', $installed['versions'][$packageName])) {
|
||||
$ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']);
|
||||
}
|
||||
if (array_key_exists('provided', $installed['versions'][$packageName])) {
|
||||
$ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']);
|
||||
}
|
||||
|
||||
return implode(' || ', $ranges);
|
||||
}
|
||||
|
||||
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $packageName
|
||||
* @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
|
||||
*/
|
||||
public static function getVersion($packageName)
|
||||
{
|
||||
foreach (self::getInstalled() as $installed) {
|
||||
if (!isset($installed['versions'][$packageName])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isset($installed['versions'][$packageName]['version'])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $installed['versions'][$packageName]['version'];
|
||||
}
|
||||
|
||||
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $packageName
|
||||
* @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
|
||||
*/
|
||||
public static function getPrettyVersion($packageName)
|
||||
{
|
||||
foreach (self::getInstalled() as $installed) {
|
||||
if (!isset($installed['versions'][$packageName])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isset($installed['versions'][$packageName]['pretty_version'])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $installed['versions'][$packageName]['pretty_version'];
|
||||
}
|
||||
|
||||
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $packageName
|
||||
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as reference
|
||||
*/
|
||||
public static function getReference($packageName)
|
||||
{
|
||||
foreach (self::getInstalled() as $installed) {
|
||||
if (!isset($installed['versions'][$packageName])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isset($installed['versions'][$packageName]['reference'])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $installed['versions'][$packageName]['reference'];
|
||||
}
|
||||
|
||||
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $packageName
|
||||
* @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.
|
||||
*/
|
||||
public static function getInstallPath($packageName)
|
||||
{
|
||||
foreach (self::getInstalled() as $installed) {
|
||||
if (!isset($installed['versions'][$packageName])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return isset($installed['versions'][$packageName]['install_path']) ? $installed['versions'][$packageName]['install_path'] : null;
|
||||
}
|
||||
|
||||
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
* @psalm-return array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}
|
||||
*/
|
||||
public static function getRootPackage()
|
||||
{
|
||||
$installed = self::getInstalled();
|
||||
|
||||
return $installed[0]['root'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the raw installed.php data for custom implementations
|
||||
*
|
||||
* @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.
|
||||
* @return array[]
|
||||
* @psalm-return array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}
|
||||
*/
|
||||
public static function getRawData()
|
||||
{
|
||||
@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);
|
||||
|
||||
if (null === self::$installed) {
|
||||
// only require the installed.php file if this file is loaded from its dumped location,
|
||||
// and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
|
||||
if (substr(__DIR__, -8, 1) !== 'C') {
|
||||
self::$installed = include __DIR__ . '/installed.php';
|
||||
} else {
|
||||
self::$installed = array();
|
||||
}
|
||||
}
|
||||
|
||||
return self::$installed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the raw data of all installed.php which are currently loaded for custom implementations
|
||||
*
|
||||
* @return array[]
|
||||
* @psalm-return list<array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}>
|
||||
*/
|
||||
public static function getAllRawData()
|
||||
{
|
||||
return self::getInstalled();
|
||||
}
|
||||
|
||||
/**
|
||||
* Lets you reload the static array from another file
|
||||
*
|
||||
* This is only useful for complex integrations in which a project needs to use
|
||||
* this class but then also needs to execute another project's autoloader in process,
|
||||
* and wants to ensure both projects have access to their version of installed.php.
|
||||
*
|
||||
* A typical case would be PHPUnit, where it would need to make sure it reads all
|
||||
* the data it needs from this class, then call reload() with
|
||||
* `require $CWD/vendor/composer/installed.php` (or similar) as input to make sure
|
||||
* the project in which it runs can then also use this class safely, without
|
||||
* interference between PHPUnit's dependencies and the project's dependencies.
|
||||
*
|
||||
* @param array[] $data A vendor/composer/installed.php data set
|
||||
* @return void
|
||||
*
|
||||
* @psalm-param array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>} $data
|
||||
*/
|
||||
public static function reload($data)
|
||||
{
|
||||
self::$installed = $data;
|
||||
self::$installedByVendor = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array[]
|
||||
* @psalm-return list<array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}>
|
||||
*/
|
||||
private static function getInstalled()
|
||||
{
|
||||
if (null === self::$canGetVendors) {
|
||||
self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders');
|
||||
}
|
||||
|
||||
$installed = array();
|
||||
|
||||
if (self::$canGetVendors) {
|
||||
foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) {
|
||||
if (isset(self::$installedByVendor[$vendorDir])) {
|
||||
$installed[] = self::$installedByVendor[$vendorDir];
|
||||
} elseif (is_file($vendorDir.'/composer/installed.php')) {
|
||||
$installed[] = self::$installedByVendor[$vendorDir] = require $vendorDir.'/composer/installed.php';
|
||||
if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) {
|
||||
self::$installed = $installed[count($installed) - 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (null === self::$installed) {
|
||||
// only require the installed.php file if this file is loaded from its dumped location,
|
||||
// and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
|
||||
if (substr(__DIR__, -8, 1) !== 'C') {
|
||||
self::$installed = require __DIR__ . '/installed.php';
|
||||
} else {
|
||||
self::$installed = array();
|
||||
}
|
||||
}
|
||||
$installed[] = self::$installed;
|
||||
|
||||
return $installed;
|
||||
}
|
||||
}
|
21
plugins/shortcode-core/vendor/composer/LICENSE
vendored
Normal file
21
plugins/shortcode-core/vendor/composer/LICENSE
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
|
||||
Copyright (c) Nils Adermann, Jordi Boggiano
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is furnished
|
||||
to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
11
plugins/shortcode-core/vendor/composer/autoload_classmap.php
vendored
Normal file
11
plugins/shortcode-core/vendor/composer/autoload_classmap.php
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
// autoload_classmap.php @generated by Composer
|
||||
|
||||
$vendorDir = dirname(__DIR__);
|
||||
$baseDir = dirname($vendorDir);
|
||||
|
||||
return array(
|
||||
'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
|
||||
'Grav\\Plugin\\ShortcodeCorePlugin' => $baseDir . '/shortcode-core.php',
|
||||
);
|
9
plugins/shortcode-core/vendor/composer/autoload_namespaces.php
vendored
Normal file
9
plugins/shortcode-core/vendor/composer/autoload_namespaces.php
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
// autoload_namespaces.php @generated by Composer
|
||||
|
||||
$vendorDir = dirname(__DIR__);
|
||||
$baseDir = dirname($vendorDir);
|
||||
|
||||
return array(
|
||||
);
|
12
plugins/shortcode-core/vendor/composer/autoload_psr4.php
vendored
Normal file
12
plugins/shortcode-core/vendor/composer/autoload_psr4.php
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
// autoload_psr4.php @generated by Composer
|
||||
|
||||
$vendorDir = dirname(__DIR__);
|
||||
$baseDir = dirname($vendorDir);
|
||||
|
||||
return array(
|
||||
'Thunder\\Shortcode\\' => array($vendorDir . '/thunderer/shortcode/src'),
|
||||
'Grav\\Plugin\\Shortcodes\\' => array($baseDir . '/classes/shortcodes'),
|
||||
'Grav\\Plugin\\ShortcodeCore\\' => array($baseDir . '/classes/plugin'),
|
||||
);
|
38
plugins/shortcode-core/vendor/composer/autoload_real.php
vendored
Normal file
38
plugins/shortcode-core/vendor/composer/autoload_real.php
vendored
Normal file
@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
// autoload_real.php @generated by Composer
|
||||
|
||||
class ComposerAutoloaderInit20dff4ef15e2090e54c04a9aa83321b9
|
||||
{
|
||||
private static $loader;
|
||||
|
||||
public static function loadClassLoader($class)
|
||||
{
|
||||
if ('Composer\Autoload\ClassLoader' === $class) {
|
||||
require __DIR__ . '/ClassLoader.php';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Composer\Autoload\ClassLoader
|
||||
*/
|
||||
public static function getLoader()
|
||||
{
|
||||
if (null !== self::$loader) {
|
||||
return self::$loader;
|
||||
}
|
||||
|
||||
require __DIR__ . '/platform_check.php';
|
||||
|
||||
spl_autoload_register(array('ComposerAutoloaderInit20dff4ef15e2090e54c04a9aa83321b9', 'loadClassLoader'), true, true);
|
||||
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
|
||||
spl_autoload_unregister(array('ComposerAutoloaderInit20dff4ef15e2090e54c04a9aa83321b9', 'loadClassLoader'));
|
||||
|
||||
require __DIR__ . '/autoload_static.php';
|
||||
call_user_func(\Composer\Autoload\ComposerStaticInit20dff4ef15e2090e54c04a9aa83321b9::getInitializer($loader));
|
||||
|
||||
$loader->register(true);
|
||||
|
||||
return $loader;
|
||||
}
|
||||
}
|
50
plugins/shortcode-core/vendor/composer/autoload_static.php
vendored
Normal file
50
plugins/shortcode-core/vendor/composer/autoload_static.php
vendored
Normal file
@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
// autoload_static.php @generated by Composer
|
||||
|
||||
namespace Composer\Autoload;
|
||||
|
||||
class ComposerStaticInit20dff4ef15e2090e54c04a9aa83321b9
|
||||
{
|
||||
public static $prefixLengthsPsr4 = array (
|
||||
'T' =>
|
||||
array (
|
||||
'Thunder\\Shortcode\\' => 18,
|
||||
),
|
||||
'G' =>
|
||||
array (
|
||||
'Grav\\Plugin\\Shortcodes\\' => 23,
|
||||
'Grav\\Plugin\\ShortcodeCore\\' => 26,
|
||||
),
|
||||
);
|
||||
|
||||
public static $prefixDirsPsr4 = array (
|
||||
'Thunder\\Shortcode\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/thunderer/shortcode/src',
|
||||
),
|
||||
'Grav\\Plugin\\Shortcodes\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/../..' . '/classes/shortcodes',
|
||||
),
|
||||
'Grav\\Plugin\\ShortcodeCore\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/../..' . '/classes/plugin',
|
||||
),
|
||||
);
|
||||
|
||||
public static $classMap = array (
|
||||
'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
|
||||
'Grav\\Plugin\\ShortcodeCorePlugin' => __DIR__ . '/../..' . '/shortcode-core.php',
|
||||
);
|
||||
|
||||
public static function getInitializer(ClassLoader $loader)
|
||||
{
|
||||
return \Closure::bind(function () use ($loader) {
|
||||
$loader->prefixLengthsPsr4 = ComposerStaticInit20dff4ef15e2090e54c04a9aa83321b9::$prefixLengthsPsr4;
|
||||
$loader->prefixDirsPsr4 = ComposerStaticInit20dff4ef15e2090e54c04a9aa83321b9::$prefixDirsPsr4;
|
||||
$loader->classMap = ComposerStaticInit20dff4ef15e2090e54c04a9aa83321b9::$classMap;
|
||||
|
||||
}, null, ClassLoader::class);
|
||||
}
|
||||
}
|
65
plugins/shortcode-core/vendor/composer/installed.json
vendored
Normal file
65
plugins/shortcode-core/vendor/composer/installed.json
vendored
Normal file
@ -0,0 +1,65 @@
|
||||
{
|
||||
"packages": [
|
||||
{
|
||||
"name": "thunderer/shortcode",
|
||||
"version": "v0.7.5",
|
||||
"version_normalized": "0.7.5.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/thunderer/Shortcode.git",
|
||||
"reference": "a4fee30613bd46efb421f8305aff0466a3268a99"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/thunderer/Shortcode/zipball/a4fee30613bd46efb421f8305aff0466a3268a99",
|
||||
"reference": "a4fee30613bd46efb421f8305aff0466a3268a99",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": ">=4.1",
|
||||
"symfony/yaml": ">=2.0"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-dom": "if you want to use XML serializer",
|
||||
"ext-json": "if you want to use JSON serializer",
|
||||
"symfony/yaml": "if you want to use YAML serializer"
|
||||
},
|
||||
"time": "2022-01-13T18:53:33+00:00",
|
||||
"type": "library",
|
||||
"installation-source": "dist",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Thunder\\Shortcode\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Tomasz Kowalczyk",
|
||||
"email": "tomasz@kowalczyk.cc"
|
||||
}
|
||||
],
|
||||
"description": "Advanced shortcode (BBCode) parser and engine for PHP",
|
||||
"keywords": [
|
||||
"bbcode",
|
||||
"engine",
|
||||
"library",
|
||||
"parser",
|
||||
"shortcode"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/thunderer/Shortcode/issues",
|
||||
"source": "https://github.com/thunderer/Shortcode/tree/v0.7.5"
|
||||
},
|
||||
"install-path": "../thunderer/shortcode"
|
||||
}
|
||||
],
|
||||
"dev": false,
|
||||
"dev-package-names": []
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user