MDL-80571 tiny_premium: Premium plugins can be individually enabled

This commit is contained in:
David Woloszyn 2024-04-30 09:40:15 +10:00
parent 792698af00
commit ed42b2e92b
14 changed files with 620 additions and 64 deletions

View File

@ -1,3 +1,3 @@
define("tiny_premium/configuration",["exports","editor_tiny/utils"],(function(_exports,_utils){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.configure=void 0;_exports.configure=instanceConfig=>{let plugins=instanceConfig.plugins,menu=instanceConfig.menu,toolbar=(toolbar=>(toolbar=(0,_utils.addToolbarSection)(toolbar,"premium_a","advanced",!0),(0,_utils.addToolbarSection)(toolbar,"premium_b","formatting",!0)))(instanceConfig.toolbar),contextmenu=instanceConfig.contextmenu;return plugins+=" advtable",menu=(0,_utils.addMenubarItem)(menu,"table","| advtablerownumbering","advtablesort"),plugins+=" editimage",toolbar=(0,_utils.addToolbarButton)(toolbar,"content","editimage","tiny_media_image"),instanceConfig.editimage_toolbar="rotateleft rotateright flipv fliph editimage",plugins+=" export",menu=(0,_utils.addMenubarItem)(menu,"tools","| export"),plugins+=" pageembed",toolbar=(0,_utils.addToolbarButton)(toolbar,"content","pageembed","tiny_media_video"),plugins+=" typography",toolbar=(0,_utils.addToolbarButton)(toolbar,"premium_b","typography"),plugins+=" casechange",toolbar=(0,_utils.addToolbarButton)(toolbar,"premium_a","casechange"),plugins+=" checklist",toolbar=(0,_utils.addToolbarButton)(toolbar,"lists","checklist"),plugins+=" tinymcespellchecker",menu=(0,_utils.addMenubarItem)(menu,"tools","spellcheckdialog","spellcheckerlanguage"),contextmenu=(0,_utils.addContextmenuItem)(contextmenu,"spellchecker"),toolbar=(0,_utils.addToolbarButton)(toolbar,"premium_a","spellcheckdialog"),plugins+=" autocorrect",menu=(0,_utils.addMenubarItem)(menu,"tools","| autocorrect capitalization","spellcheckdialog"),plugins+=" permanentpen",menu=(0,_utils.addMenubarItem)(menu,"format","| permanentpen configurepermanentpen"),toolbar=(0,_utils.addToolbarButton)(toolbar,"premium_a","permanentpen"),contextmenu=(0,_utils.addContextmenuItem)(contextmenu,"configurepermanentpen"),plugins+=" formatpainter",toolbar=(0,_utils.addToolbarButton)(toolbar,"premium_a","formatpainter"),plugins+=" linkchecker",contextmenu=(0,_utils.addContextmenuItem)(contextmenu,"linkchecker"),plugins+=" tableofcontents",toolbar=(0,_utils.addToolbarButton)(toolbar,"premium_a","tableofcontents"),plugins+=" footnotes",toolbar=(0,_utils.addToolbarButton)(toolbar,"premium_a","footnotes"),menu=(0,_utils.addMenubarItem)(menu,"insert","footnotes","tableofcontents"),plugins+=" powerpaste",{plugins:plugins,toolbar:toolbar,menu:menu,contextmenu:contextmenu}}}));
define("tiny_premium/configuration",["exports","editor_tiny/utils","editor_tiny/options"],(function(_exports,_utils,_options){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.configure=void 0;_exports.configure=(instanceConfig,options)=>{const enabledPremiumPlugins=(0,_options.getInitialPluginConfiguration)(options)[(0,_options.getPluginOptionName)("tiny_premium/plugin","premiumplugins")].split(",");let plugins=instanceConfig.plugins,menu=instanceConfig.menu,toolbar=(toolbar=>(toolbar=(0,_utils.addToolbarSection)(toolbar,"premium_a","advanced",!0),(0,_utils.addToolbarSection)(toolbar,"premium_b","formatting",!0)))(instanceConfig.toolbar),contextmenu=instanceConfig.contextmenu;return-1!==enabledPremiumPlugins.indexOf("advtable")&&(plugins+=" advtable",menu=(0,_utils.addMenubarItem)(menu,"table","| advtablerownumbering","advtablesort")),-1!==enabledPremiumPlugins.indexOf("editimage")&&(plugins+=" editimage",toolbar=(0,_utils.addToolbarButton)(toolbar,"content","editimage","tiny_media_image"),instanceConfig.editimage_toolbar="rotateleft rotateright flipv fliph editimage"),-1!==enabledPremiumPlugins.indexOf("export")&&(plugins+=" export",menu=(0,_utils.addMenubarItem)(menu,"tools","| export")),-1!==enabledPremiumPlugins.indexOf("pageembed")&&(plugins+=" pageembed",toolbar=(0,_utils.addToolbarButton)(toolbar,"content","pageembed","tiny_media_video")),-1!==enabledPremiumPlugins.indexOf("typography")&&(plugins+=" typography",toolbar=(0,_utils.addToolbarButton)(toolbar,"premium_b","typography")),-1!==enabledPremiumPlugins.indexOf("casechange")&&(plugins+=" casechange",toolbar=(0,_utils.addToolbarButton)(toolbar,"premium_a","casechange")),-1!==enabledPremiumPlugins.indexOf("checklist")&&(plugins+=" checklist",toolbar=(0,_utils.addToolbarButton)(toolbar,"lists","checklist")),-1!==enabledPremiumPlugins.indexOf("tinymcespellchecker")&&(plugins+=" tinymcespellchecker",menu=(0,_utils.addMenubarItem)(menu,"tools","spellcheckdialog","spellcheckerlanguage"),contextmenu=(0,_utils.addContextmenuItem)(contextmenu,"spellchecker"),toolbar=(0,_utils.addToolbarButton)(toolbar,"premium_a","spellcheckdialog")),-1!==enabledPremiumPlugins.indexOf("autocorrect")&&(plugins+=" autocorrect",menu=(0,_utils.addMenubarItem)(menu,"tools","| autocorrect capitalization","spellcheckdialog")),-1!==enabledPremiumPlugins.indexOf("permanentpen")&&(plugins+=" permanentpen",menu=(0,_utils.addMenubarItem)(menu,"format","| permanentpen configurepermanentpen"),toolbar=(0,_utils.addToolbarButton)(toolbar,"premium_a","permanentpen"),contextmenu=(0,_utils.addContextmenuItem)(contextmenu,"configurepermanentpen")),-1!==enabledPremiumPlugins.indexOf("formatpainter")&&(plugins+=" formatpainter",toolbar=(0,_utils.addToolbarButton)(toolbar,"premium_a","formatpainter")),-1!==enabledPremiumPlugins.indexOf("linkchecker")&&(plugins+=" linkchecker",contextmenu=(0,_utils.addContextmenuItem)(contextmenu,"linkchecker")),-1!==enabledPremiumPlugins.indexOf("tableofcontents")&&(plugins+=" tableofcontents",toolbar=(0,_utils.addToolbarButton)(toolbar,"premium_a","tableofcontents")),-1!==enabledPremiumPlugins.indexOf("footnotes")&&(plugins+=" footnotes",toolbar=(0,_utils.addToolbarButton)(toolbar,"premium_a","footnotes"),menu=(0,_utils.addMenubarItem)(menu,"insert","footnotes","tableofcontents")),-1!==enabledPremiumPlugins.indexOf("powerpaste")&&(plugins+=" powerpaste"),{plugins:plugins,toolbar:toolbar,menu:menu,contextmenu:contextmenu}}}));
//# sourceMappingURL=configuration.min.js.map

File diff suppressed because one or more lines are too long

View File

@ -27,6 +27,10 @@ import {
addToolbarSection,
addContextmenuItem
} from 'editor_tiny/utils';
import {
getInitialPluginConfiguration,
getPluginOptionName
} from 'editor_tiny/options';
const configureToolbar = (toolbar) => {
// Add premium toolbar sections to house all the plugins with no natural home.
@ -35,9 +39,12 @@ const configureToolbar = (toolbar) => {
return toolbar;
};
export const configure = (instanceConfig) => {
// There is some manipulating of the plugin menu, toolbar, context and quickbar items.
// This was necessary to enhance user experience and closer align to the Tiny demo site.
export const configure = (instanceConfig, options) => {
// Get the namespaced options for Tiny Premium before they are officially initialised.
// Due to the timing the plugin options are available, we need to get at the options in this slightly unconventional way.
const pluginOptions = getInitialPluginConfiguration(options);
const enabledPremiumPlugins = pluginOptions[getPluginOptionName('tiny_premium/plugin', 'premiumplugins')].split(',');
let plugins = instanceConfig.plugins;
let menu = instanceConfig.menu;
let toolbar = configureToolbar(instanceConfig.toolbar);
@ -45,71 +52,87 @@ export const configure = (instanceConfig) => {
let pluginsettings = {};
// Advanced Table.
plugins += ` advtable`;
menu = addMenubarItem(menu, 'table', '| advtablerownumbering', 'advtablesort');
if (enabledPremiumPlugins.indexOf('advtable') !== -1) {
plugins += ` advtable`;
menu = addMenubarItem(menu, 'table', '| advtablerownumbering', 'advtablesort');
}
// Enhanced Image Editing.
plugins += ` editimage`;
toolbar = addToolbarButton(toolbar, 'content', 'editimage', 'tiny_media_image');
// Remove the duplicate image button from the quickbar toolbar by redefining the values without 'imageoptions'.
// eslint-disable-next-line camelcase
instanceConfig.editimage_toolbar = 'rotateleft rotateright flipv fliph editimage';
if (enabledPremiumPlugins.indexOf('editimage') !== -1) {
plugins += ` editimage`;
toolbar = addToolbarButton(toolbar, 'content', 'editimage', 'tiny_media_image');
// Remove the duplicate image button from the quickbar toolbar by redefining the values without 'imageoptions'.
// eslint-disable-next-line camelcase
instanceConfig.editimage_toolbar = 'rotateleft rotateright flipv fliph editimage';
}
// Export.
plugins += ` export`;
menu = addMenubarItem(menu, 'tools', '| export');
if (enabledPremiumPlugins.indexOf('export') !== -1) {
plugins += ` export`;
menu = addMenubarItem(menu, 'tools', '| export');
}
// Page Embed.
plugins += ` pageembed`;
toolbar = addToolbarButton(toolbar, 'content', 'pageembed', 'tiny_media_video');
if (enabledPremiumPlugins.indexOf('pageembed') !== -1) {
plugins += ` pageembed`;
toolbar = addToolbarButton(toolbar, 'content', 'pageembed', 'tiny_media_video');
}
// Advanced Typography.
plugins += ` typography`;
toolbar = addToolbarButton(toolbar, 'premium_b', 'typography');
if (enabledPremiumPlugins.indexOf('typography') !== -1) {
plugins += ` typography`;
toolbar = addToolbarButton(toolbar, 'premium_b', 'typography');
}
// Case Change.
plugins += ` casechange`;
toolbar = addToolbarButton(toolbar, 'premium_a', 'casechange');
if (enabledPremiumPlugins.indexOf('casechange') !== -1) {
plugins += ` casechange`;
toolbar = addToolbarButton(toolbar, 'premium_a', 'casechange');
}
// Checklist.
plugins += ` checklist`;
toolbar = addToolbarButton(toolbar, 'lists', 'checklist');
if (enabledPremiumPlugins.indexOf('checklist') !== -1) {
plugins += ` checklist`;
toolbar = addToolbarButton(toolbar, 'lists', 'checklist');
}
// Spell Checker Pro.
plugins += ` tinymcespellchecker`;
menu = addMenubarItem(menu, 'tools', 'spellcheckdialog', 'spellcheckerlanguage');
contextmenu = addContextmenuItem(contextmenu, 'spellchecker');
toolbar = addToolbarButton(toolbar, 'premium_a', 'spellcheckdialog');
if (enabledPremiumPlugins.indexOf('tinymcespellchecker') !== -1) {
plugins += ` tinymcespellchecker`;
menu = addMenubarItem(menu, 'tools', 'spellcheckdialog', 'spellcheckerlanguage');
contextmenu = addContextmenuItem(contextmenu, 'spellchecker');
toolbar = addToolbarButton(toolbar, 'premium_a', 'spellcheckdialog');
}
// Spelling Autocorrect.
plugins += ` autocorrect`;
menu = addMenubarItem(menu, 'tools', '| autocorrect capitalization', 'spellcheckdialog');
if (enabledPremiumPlugins.indexOf('autocorrect') !== -1) {
plugins += ` autocorrect`;
menu = addMenubarItem(menu, 'tools', '| autocorrect capitalization', 'spellcheckdialog');
}
// Permanent Pen.
plugins += ` permanentpen`;
menu = addMenubarItem(menu, 'format', '| permanentpen configurepermanentpen');
toolbar = addToolbarButton(toolbar, 'premium_a', 'permanentpen');
contextmenu = addContextmenuItem(contextmenu, 'configurepermanentpen');
if (enabledPremiumPlugins.indexOf('permanentpen') !== -1) {
plugins += ` permanentpen`;
menu = addMenubarItem(menu, 'format', '| permanentpen configurepermanentpen');
toolbar = addToolbarButton(toolbar, 'premium_a', 'permanentpen');
contextmenu = addContextmenuItem(contextmenu, 'configurepermanentpen');
}
// Format Painter.
plugins += ` formatpainter`;
toolbar = addToolbarButton(toolbar, 'premium_a', 'formatpainter');
if (enabledPremiumPlugins.indexOf('formatpainter') !== -1) {
plugins += ` formatpainter`;
toolbar = addToolbarButton(toolbar, 'premium_a', 'formatpainter');
}
// Link Checker.
plugins += ` linkchecker`;
contextmenu = addContextmenuItem(contextmenu, 'linkchecker');
if (enabledPremiumPlugins.indexOf('linkchecker') !== -1) {
plugins += ` linkchecker`;
contextmenu = addContextmenuItem(contextmenu, 'linkchecker');
}
// Table of Contents.
plugins += ` tableofcontents`;
toolbar = addToolbarButton(toolbar, 'premium_a', 'tableofcontents');
if (enabledPremiumPlugins.indexOf('tableofcontents') !== -1) {
plugins += ` tableofcontents`;
toolbar = addToolbarButton(toolbar, 'premium_a', 'tableofcontents');
}
// Footnotes.
plugins += ` footnotes`;
toolbar = addToolbarButton(toolbar, 'premium_a', 'footnotes');
menu = addMenubarItem(menu, 'insert', 'footnotes', 'tableofcontents');
if (enabledPremiumPlugins.indexOf('footnotes') !== -1) {
plugins += ` footnotes`;
toolbar = addToolbarButton(toolbar, 'premium_a', 'footnotes');
menu = addMenubarItem(menu, 'insert', 'footnotes', 'tableofcontents');
}
// Powerpaste.
plugins += ` powerpaste`;
if (enabledPremiumPlugins.indexOf('powerpaste') !== -1) {
plugins += ` powerpaste`;
}
return {
plugins,

View File

@ -0,0 +1,151 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace tiny_premium\local;
use tiny_premium\manager;
/**
* Admin setting for managing Tiny Premium plugins.
*
* @package tiny_premium
* @copyright 2024 David Woloszyn <david.woloszyn@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class admin_setting_tiny_premium_plugins extends \admin_setting {
/**
* Calls parent::__construct with specific arguments.
*/
public function __construct() {
$this->nosave = true;
parent::__construct(
name: 'tiny_premium/premiumplugins',
visiblename: new \lang_string('premiumplugins', 'tiny_premium'),
description: new \lang_string('premiumplugins_desc', 'tiny_premium'),
defaultsetting: '',
);
}
/**
* Always returns true.
*
* @return bool
*/
public function get_setting(): bool {
return true;
}
/**
* Always returns '' and doesn't write anything.
*
* @param mixed $data
* @return string Always returns ''
*/
public function write_setting($data): string {
return '';
}
/**
* Builds the HTML to display the Tiny Premium plugins table.
*
* @param mixed $data Unused
* @param string $query
* @return string highlight
*/
public function output_html($data, $query=''): string {
global $OUTPUT;
$return = '';
// Warn users about an empty API key when displaying enabled plugins.
if (empty(get_config('tiny_premium', 'apikey')) && !empty(manager::get_enabled_plugins())) {
$return .= \core\notification::warning(get_string('emptyapikeywarning', 'tiny_premium'));
}
$return .= $OUTPUT->box_start('generalbox');
$return .= $OUTPUT->heading(get_string('premiumplugins', 'tiny_premium'), 3);
$return .= \html_writer::tag('p', get_string('premiumplugins_desc', 'tiny_premium'));
$return .= $this->define_manage_tiny_premium_plugins_table();
$return .= $OUTPUT->box_end();
return highlight($query, $return);
}
/**
* Defines table for managing Tiny Premium plugins.
*
* @return string HTML for table
*/
public function define_manage_tiny_premium_plugins_table(): string {
global $OUTPUT;
$sesskey = sesskey();
// Set up table.
$table = new \html_table();
$table->id = 'managetinypremiumpluginstable';
$table->attributes['class'] = 'admintable generaltable';
$table->head = [
get_string('name'),
get_string('enable'),
];
$table->colclasses = [
'leftalign',
'centeralign',
];
$table->data = [];
// Keep enabled plugins on top.
$plugins = manager::get_plugins();
$enabledplugins = manager::get_enabled_plugins();
$disabledplugins = array_diff($plugins, $enabledplugins);
$plugins = array_merge($enabledplugins, $disabledplugins);
foreach ($plugins as $plugin) {
$pluginname = get_string('premiumplugin:' . $plugin, 'tiny_premium');
// Determine plugin actions.
if (manager::is_plugin_enabled($plugin)) {
$action = 'disable';
$icon = $OUTPUT->pix_icon('t/hide', get_string('disableplugin', 'core_admin', $pluginname));
$class = '';
} else {
$action = 'enable';
$icon = $OUTPUT->pix_icon('t/show', get_string('enableplugin', 'core_admin', $pluginname));
$class = 'dimmed_text';
}
// Prepare a link to perform the action.
$hideshowurl = new \moodle_url('/lib/editor/tiny/plugins/premium/pluginsettings.php', [
'action' => $action,
'plugin' => $plugin,
'sesskey' => $sesskey,
]);
$hideshowlink = \html_writer::link($hideshowurl, $icon);
// Populate table row.
$row = new \html_table_row([
$pluginname,
$hideshowlink,
]);
$row->attributes['class'] = $class;
$table->data[] = $row;
}
return \html_writer::table($table);
}
}

View File

@ -0,0 +1,109 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace tiny_premium;
/**
* Tiny Premium manager.
*
* @package tiny_premium
* @copyright 2024 David Woloszyn <david.woloszyn@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class manager {
/**
* Get all Tiny Premium plugins currently supported.
*
* The plugin identifiers are taken from Tiny Cloud (https://www.tiny.cloud/docs/tinymce/6/plugins/#premium-plugins).
*
* @return array The array of plugins.
*/
public static function get_plugins(): array {
return [
'advtable',
'typography',
'casechange',
'checklist',
'editimage',
'export',
'footnotes',
'formatpainter',
'linkchecker',
'pageembed',
'permanentpen',
'powerpaste',
'tinymcespellchecker',
'autocorrect',
'tableofcontents',
];
}
/**
* Get enabled Tiny Premium plugins.
*
* @return array The array of enabled plugins.
*/
public static function get_enabled_plugins(): array {
$plugins = self::get_plugins();
$enabledplugins = [];
foreach ($plugins as $plugin) {
if (self::is_plugin_enabled($plugin)) {
$enabledplugins[] = $plugin;
}
}
return $enabledplugins;
}
/**
* Check if a Tiny Premium plugin is enabled in config.
*
* @param string $plugin The plugin to check.
* @return bool Return true if enabled.
*/
public static function is_plugin_enabled(string $plugin): bool {
$config = get_config('tiny_premium_' . $plugin, 'enabled');
return ($config == 1);
}
/**
* Set a new value for a Tiny Premium plugin config.
*
* @param array $data The data to set.
* @param string $plugin The plugin to use.
*/
public static function set_plugin_config(array $data, string $plugin): void {
// Check this is a valid premium plugin.
if (!in_array($plugin, self::get_plugins())) {
return;
}
$plugin = 'tiny_premium_' . $plugin;
foreach ($data as $key => $newvalue) {
// Get the old value for the log.
$oldvalue = get_config($plugin, $key) ?? null;
add_to_config_log($key, $oldvalue, $newvalue, $plugin);
// If we are disabling the plugin, remove it, otherwise, set the new value.
if ($key === 'enabled' && $newvalue == 0) {
unset_config($key, $plugin);
} else {
set_config($key, $newvalue, $plugin);
}
}
}
}

View File

@ -19,6 +19,8 @@ namespace tiny_premium;
use context;
use editor_tiny\editor;
use editor_tiny\plugin;
use editor_tiny\plugin_with_configuration;
use tiny_premium\manager;
/**
* Tiny Premium plugin.
@ -27,7 +29,7 @@ use editor_tiny\plugin;
* @copyright 2023 David Woloszyn <david.woloszyn@moodle.com>
* @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class plugininfo extends plugin {
class plugininfo extends plugin implements plugin_with_configuration {
/**
* Determine if the plugin should be enabled by checking the capability and if the Tiny Premium API key is set.
@ -46,4 +48,24 @@ class plugininfo extends plugin {
): bool {
return has_capability('tiny/premium:accesspremium', $context) && (get_config('tiny_premium', 'apikey') != false);
}
/**
* Get a list of enabled Tiny Premium plugins set by the admin.
*
* @param context $context The context that the editor is used within
* @param array $options The options passed in when requesting the editor
* @param array $fpoptions The filepicker options passed in when requesting the editor
* @param editor|null $editor The editor instance in which the plugin is initialised
* @return array
*/
public static function get_plugin_configuration_for_context(
context $context,
array $options,
array $fpoptions,
?editor $editor = null
): array {
return [
'premiumplugins' => implode(',', manager::get_enabled_plugins()),
];
}
}

View File

@ -0,0 +1,55 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
//
/**
* Upgrade code for tiny_premium.
*
* @package tiny_premium
* @copyright 2024 David Woloszyn <david.woloszyn@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
/**
* Function to upgrade tiny_premium.
*
* @param int $oldversion the version we are upgrading from
* @return bool result
*/
function xmldb_tiny_premium_upgrade($oldversion) {
// Automatically generated Moodle v4.1.0 release upgrade line.
// Put any upgrade step following this.
// Automatically generated Moodle v4.2.0 release upgrade line.
// Put any upgrade step following this.
// Automatically generated Moodle v4.3.0 release upgrade line.
// Put any upgrade step following this.
if ($oldversion < 2024042400) {
// Only enable the premium plugins if we have an API key.
if (!empty(get_config('tiny_premium', 'apikey'))) {
$premiumplugins = \tiny_premium\manager::get_plugins();
foreach ($premiumplugins as $plugin) {
\tiny_premium\manager::set_plugin_config(['enabled' => 1], $plugin);
};
}
upgrade_plugin_savepoint(true, 2024042400, 'tiny', 'premium');
}
return true;
}

View File

@ -25,9 +25,28 @@
defined('MOODLE_INTERNAL') || die();
$string['pluginname'] = 'TinyMCE Premium';
$string['apikey'] = 'API key';
$string['apikey_desc'] = '<p>Your API key is available on your <a href="https://www.tiny.cloud">Tiny Cloud</a> account page if you have purchased a subscription, or if you are on a free trial.</p><p>See the list of available TinyMCE Premium features for Moodle in the documentation <a href="https://docs.moodle.org/en/TinyMCE_editor">TinyMCE editor</a>.</p>';
$string['apikey_desc'] = 'Your API key is available on your <a target="_blank" href="https://www.tiny.cloud">Tiny Cloud</a> account page if you have purchased a subscription, or if you are on a free trial.';
$string['emptyapikeywarning'] = 'Enabled TinyMCE Premium plugins will not be available until an API key is added.';
$string['helplinktext'] = 'Premium plugins';
$string['pluginname'] = 'TinyMCE Premium';
$string['pluginnotfound'] = 'Tiny Premium plugin {$a} not found.';
$string['premium:accesspremium'] = 'Access TinyMCE Premium features';
$string['privacy:metadata'] = 'The TinyMCE Premium plugin does not store any personal data.';
$string['premiumplugin:advtable'] = 'Advanced Table';
$string['premiumplugin:autocorrect'] = 'Spelling Autocorrect';
$string['premiumplugin:casechange'] = 'Case Change';
$string['premiumplugin:checklist'] = 'Checklist';
$string['premiumplugin:editimage'] = 'Enhanced Image Editing';
$string['premiumplugin:export'] = 'Export';
$string['premiumplugin:footnotes'] = 'Footnotes';
$string['premiumplugin:formatpainter'] = 'Format Painter';
$string['premiumplugin:linkchecker'] = 'Link Checker';
$string['premiumplugin:pageembed'] = 'Page Embed';
$string['premiumplugin:permanentpen'] = 'Permanent Pen';
$string['premiumplugin:powerpaste'] = 'Powerpaste';
$string['premiumplugin:tableofcontents'] = 'Table of Contents';
$string['premiumplugin:tinymcespellchecker'] = 'Spell Checker Pro';
$string['premiumplugin:typography'] = 'Advanced Typography';
$string['premiumplugins'] = 'Premium plugins';
$string['premiumplugins_desc'] = 'Access to TinyMCE Premium plugins requires an API key. Not all listed plugins may be available with your TinyMCE Premium subscription. You can check available plugins on your <a target="_blank" href="https://www.tiny.cloud/my-account/integrate/">Tiny Cloud</a> account page.';
$string['privacy:metadata'] = 'The Tiny premium plugin for TinyMCE does not store any personal data.';

View File

@ -0,0 +1,74 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* TinyMCE Premium plugins configuration page.
*
* @package tiny_premium
* @copyright 2024 David Woloszyn <david.woloszyn@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
require_once(__DIR__ . '/../../../../../config.php');
require_once($CFG->libdir.'/adminlib.php');
$action = required_param('action', PARAM_ALPHANUMEXT);
$plugin = required_param('plugin', PARAM_ALPHANUMEXT);
$syscontext = context_system::instance();
$PAGE->set_url('/lib/editor/tiny/plugins/premium/pluginsettings.php');
$PAGE->set_context($syscontext);
require_admin();
require_sesskey();
$return = new moodle_url('/admin/settings.php', ['section' => 'tiny_premium_settings']);
// Get all Tiny Premium plugins.
$premiumplugins = \tiny_premium\manager::get_plugins();
if (!in_array($plugin, $premiumplugins)) {
throw new moodle_exception('pluginnotfound', 'tiny_premium', $return, $plugin);
}
// Get enabled Tiny Premium plugins.
$enabledplugins = \tiny_premium\manager::get_enabled_plugins();
$pluginname = get_string('premiumplugin:' . $plugin, 'tiny_premium');
switch ($action) {
case 'disable':
if (in_array($plugin, $enabledplugins)) {
\tiny_premium\manager::set_plugin_config(['enabled' => 0], $plugin);
\core\notification::add(
get_string('plugin_disabled', 'core_admin', $pluginname),
\core\notification::SUCCESS
);
}
break;
case 'enable':
if (!in_array($plugin, $enabledplugins)) {
\tiny_premium\manager::set_plugin_config(['enabled' => 1], $plugin);
\core\notification::add(
get_string('plugin_enabled', 'core_admin', $pluginname),
\core\notification::SUCCESS
);
}
break;
}
redirect($return);

View File

@ -4,9 +4,12 @@ A request to Tiny Cloud is made in the plugin.js file of this plugin.
This request passes the Tiny Premium API key as part of a URL.
The URL also contains the major version of Tiny and may need to be updated.
The URL looks like this: https://cdn.tiny.cloud/1/YOUR_API_KEY/tinymce/6/plugins.min.js
Notice that the version (6) is baked into the URL and may need revision.
The URL looks like this: https://cdn.tiny.cloud/1/YOUR_API_KEY/tinymce/VERSION/plugins.min.js
When upgrading, check Tiny Cloud's documentation regarding the correct API URL
to use. Go to https://www.tiny.cloud/docs/tinymce
TinyMCE Premium plugins can be individually enabled/disabled by admins.
Each release of TinyMCE may have a different selection of plugins available.
When upgrading, please check the list of available TinyMCE Premium plugins and update the list
with the revisions (lib/editor/tiny/plugins/premium/classes/manager.php).

View File

@ -28,6 +28,7 @@ defined('MOODLE_INTERNAL') || die();
if ($hassiteconfig) {
// phpcs:ignore Generic.CodeAnalysis.EmptyStatement.DetectedIf
if ($ADMIN->fulltree) {
// Set API key.
$setting = new admin_setting_configpasswordunmask(
'tiny_premium/apikey',
get_string('apikey', 'tiny_premium'),
@ -35,5 +36,8 @@ if ($hassiteconfig) {
'',
);
$settings->add($setting);
// Set individual Tiny Premium plugins.
$settings->add(new \tiny_premium\local\admin_setting_tiny_premium_plugins());
}
}

View File

@ -0,0 +1,23 @@
@editor @editor_tiny
Feature: Check the features of the TinyMCE Premium settings
In order to use TinyMCE Premium features
As an admin
I need TinyMCE Premium settings to be configured correctly
Background:
Given I am logged in as "admin"
And I navigate to "Plugins > Text editors > TinyMCE editor > TinyMCE Premium" in site administration
@javascript
Scenario: I can see a warning banner when I enable a TinyMCE premium plugin without an API key set
When I click on "Enable Advanced Table" "link"
Then I should see "Advanced Table enabled."
And I should see "Enabled TinyMCE Premium plugins will not be available until an API key is added."
@javascript
Scenario: I cannot see a warning banner when I enable a TinyMCE premium plugin with an API key set
Given the following config values are set as admin:
| apikey | "123456" | tiny_premium |
When I click on "Enable Advanced Table" "link"
Then I should see "Advanced Table enabled."
And I should not see "Enabled TinyMCE Premium plugins will not be available until an API key is added."

View File

@ -0,0 +1,73 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace tiny_premium;
/**
* Manager tests class for tiny_premium.
*
* @package tiny_premium
* @category test
* @copyright 2024 David Woloszyn <david.woloszyn@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
final class manager_test extends \advanced_testcase {
/**
* Test the getting of all available Tiny Premium plugins.
*
* @covers \tiny_premium\manager
*/
public function test_get_plugins(): void {
$this->resetAfterTest();
$this->setAdminUser();
// Check all Tiny Premium plugins are returned.
$premiumplugins = manager::get_plugins();
$this->assertCount(15, $premiumplugins);
}
/**
* Test the getting and setting of enabled Tiny Premium plugins.
*
* @covers \tiny_premium\manager
*/
public function test_get_and_set_enabled_plugins(): void {
$this->resetAfterTest();
$this->setAdminUser();
// Check all enabled Tiny Premium plugins are returned (all disabled by default).
$enabledpremiumplugins = manager::get_enabled_plugins();
$this->assertCount(0, $enabledpremiumplugins);
// Enable a couple premium plugins.
manager::set_plugin_config(['enabled' => 1], 'advtable');
manager::set_plugin_config(['enabled' => 1], 'formatpainter');
// Check the premium plugins are enabled.
$enabledpremiumplugins = manager::get_enabled_plugins();
$this->assertCount(2, $enabledpremiumplugins);
$this->assertTrue(manager::is_plugin_enabled('advtable'));
$this->assertTrue(manager::is_plugin_enabled('formatpainter'));
// Disable a premium plugin.
manager::set_plugin_config(['enabled' => 0], 'advtable');
// Check the correct premium plugins are enabled.
$enabledpremiumplugins = manager::get_enabled_plugins();
$this->assertCount(1, $enabledpremiumplugins);
$this->assertFalse(manager::is_plugin_enabled('advtable'));
$this->assertTrue(manager::is_plugin_enabled('formatpainter'));
}
}

View File

@ -24,6 +24,6 @@
defined('MOODLE_INTERNAL') || die();
$plugin->version = 2024042200;
$plugin->version = 2024043000;
$plugin->requires = 2024041600;
$plugin->component = 'tiny_premium';