Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

warn about callback fn when switching from js to json config #180

Merged
merged 3 commits into from
Mar 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Release Notes for CKEditor for Craft CMS

## Unreleased

- CKEditor config edit pages now warn when switching the Config Options setting from JavaScript to JSON if the JavaScript code contains any functions. ([#152](https://github.com/craftcms/ckeditor/issues/152), [#180](https://github.com/craftcms/ckeditor/pull/180))

## 3.8.0 - 2024-02-21

- Added support for creating anchor links. ([#169](https://github.com/craftcms/ckeditor/discussions/169))
Expand Down
1 change: 1 addition & 0 deletions src/translations/en/ckeditor.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
'View available settings' => 'View available settings',
'Word Limit' => 'Word Limit',
'You can save custom {name} configs as {ext} files in {path}.' => 'You can save custom {name} configs as {ext} files in {path}.',
'Your JavaScript config contains functions. If you switch to JSON, they will be lost. Would you like to continue?',
'{attribute} isn’t valid JSON.' => '{attribute} isn’t valid JSON.',
'{field} should contain at most {max, number} {max, plural, one{word} other{words}}.' => '{field} should contain at most {max, number} {max, plural, one{word} other{words}}.',
];
2 changes: 1 addition & 1 deletion src/web/assets/ckeconfig/dist/ckeconfig.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/web/assets/ckeconfig/dist/ckeconfig.js.map

Large diffs are not rendered by default.

70 changes: 67 additions & 3 deletions src/web/assets/ckeconfig/src/ConfigOptions.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,21 +35,53 @@ export default Garnish.Base.extend({

this.defaults = {};

let lastJsValue = null;

new Craft.Listbox($languagePicker, {
onChange: ($selectedOption) => {
this.language = $selectedOption.data('language');
switch (this.language) {
case 'json':
// get the js value
lastJsValue = this.jsEditor.getModel().getValue();
// check if the js value has any functions in it
if (this.jsContainsFunctions(lastJsValue)) {
// if it does - show the confirmation dialogue
if (
!confirm(
Craft.t(
'ckeditor',
'Your JavaScript config contains functions. If you switch to JSON, they will be lost. Would you like to continue?',
),
)
) {
// if user cancels - go back to the previous option (js)
let listbox = $languagePicker.data('listbox');
listbox.$options.not('[data-language="json"]').trigger('click');
break;
}
}
// if user confirms that they want to proceed, or we don't have functions in the js value,
// go ahead and switch
this.$jsonContainer.removeClass('hidden');
this.$jsContainer.addClass('hidden');
const json = this.js2json(this.jsEditor.getModel().getValue());
const json = this.js2json(lastJsValue);
lastJsValue = null;
this.jsonEditor.getModel().setValue(json || '{\n \n}');
this.jsEditor.getModel().setValue('');
break;
case 'js':
this.$jsonContainer.addClass('hidden');
this.$jsContainer.removeClass('hidden');
const js = this.json2js(this.jsonEditor.getModel().getValue());
let js;
// if we have the last remembered js value, it means we're switching back after cancelled confirmation,
// so let's use it
if (lastJsValue !== null) {
js = lastJsValue;
lastJsValue = null;
} else {
js = this.json2js(this.jsonEditor.getModel().getValue());
}
this.jsEditor.getModel().setValue(js || 'return {\n \n}');
this.jsonEditor.getModel().setValue('');
break;
Expand Down Expand Up @@ -204,6 +236,27 @@ export default Garnish.Base.extend({
this.defaults[setting] = schema.$defs[defName].default;
},

replacer: function (key, value) {
if (typeof value === 'function') {
return '__HAS__FUNCTION__';
}
return value;
},

jsContainsFunctions: function (js) {
let config = this.getValidJsonConfig(js);
if (config === false) {
return true;
}

let json = JSON.stringify(config, this.replacer, 2);
if (json.match(/__HAS__FUNCTION__/)) {
return true;
}

return false;
},

config2json: function (config) {
let json = JSON.stringify(config, null, 2);
if (json === '{}') {
Expand All @@ -212,7 +265,7 @@ export default Garnish.Base.extend({
return json;
},

js2json: function (js) {
getValidJsonConfig: function (js) {
const m = (js || '').match(/return\s*(\{[\w\W]*})/);
if (!m) {
return false;
Expand All @@ -225,6 +278,17 @@ export default Garnish.Base.extend({
// oh well
return false;
}

return config;
},

js2json: function (js) {
let config = this.getValidJsonConfig(js);

if (config === false) {
return false;
}

return this.config2json(config);
},

Expand Down