Skip to content
Snippets Groups Projects
Commit e8cbbfa4 authored by Elmar Ludwig's avatar Elmar Ludwig
Browse files

drop studip-settings editor toolbar icon, fixes #1165

Closes #1165

Merge request studip/studip!694
parent 605d7e7b
No related branches found
No related tags found
No related merge requests found
......@@ -20,41 +20,8 @@
* @author Robert Costa <rcosta@uos.de>
*/
class WysiwygException extends Exception {};
class WysiwygHttpException extends WysiwygException {};
class WysiwygHttpExceptionBadRequest extends WysiwygHttpException
{
public function __construct($message = '', $previous = null) {
parent::__construct($message, 400, $previous);
}
}
class WysiwygHttpExceptionForbidden extends WysiwygHttpException
{
public function __construct($message = '', $previous = null) {
parent::__construct($message, 403, $previous);
}
}
class WysiwygHttpExceptionNotFound extends WysiwygHttpException
{
public function __construct($message = '', $previous = null) {
parent::__construct($message, 404, $previous);
}
}
class WysiwygHttpExceptionMethodNotAllowed extends WysiwygHttpException
{
public function __construct($message = '', $previous = null) {
parent::__construct($message, 405, $previous);
}
}
class WysiwygController extends AuthenticatedController
{
const UPLOAD_PERMISSION = 'autor'; // minimum permission level for uploading
const FOLDER_NAME = 'Wysiwyg Uploads';
const FOLDER_DESCRIPTION = 'Vom WYSIWYG Editor hochgeladene Dateien.';
......@@ -153,327 +120,4 @@ class WysiwygController extends AuthenticatedController
}
$this->render_json($response); // send HTTP response to client
}
/**
* Store or retrieve settings.
*
* Settings are further subdivided into groups. For example: global,
* seminar- and user-specific settings (see below).
*
* HTTP GET
* returns a JSON object with current settings.
*
* HTTP PUT
* expects a JSON object with settings to store and returns
* updated settings as a JSON object. Some settings are read-only,
* others can only be set if the user has the necessary access level.
*
* Currently only the following basic features are supported:
*
* HTTP GET wysiwyg/settings/global
* Always returns:
* {
* "upload": {
* "permission": "autor",
* "folder": {
* "name": "Wysiwyg Uploads",
* "description": "Vom WYSIWYG Editor hochgeladene Dateien."
* }
* }
* }
* }
*
* HTTP GET wysiwyg/settings/users/current
* Always returns following setting for the authenticated user:
* {
* "disabled": false | true
* }
*
* HTTP PUT wysiwyg/settings/users/current
* Allows only to reset or set the disabled state with:
* {
* "disabled": false | true
* }
*
* Below is a specification of possible future extensions to this
* interface, that are based on current feature requests by users
* (mainly people from ELMO, ELAN and ECULT).
*
* wysiwyg/settings/global
* Common settings for all WYSIWYG editors throughout Stud.IP.
* wysiwyg/settings/seminars
* Settings of all seminars.
* Listed seminars depend on access level:
* root => full access to all seminars
* dozent, tutor of a seminar => full access to those seminars
* others => read-access to seminars they are a member of
* wysiwyg/settings/seminars/ID
* Settings of the seminar with the given ID.
* Access permissions: see above.
* wysiwyg/settings/seminars/ID/users
* Seminar's settings for all its users.
* Access permissions: see above.
* wysiwyg/settings/seminars/ID/users/ID
* Seminar's settings for a specific user in that seminar.
* Access permissions: see above.
* wysiwyg/settings/users
* Settings of all users.
* Listed users depend on access level:
* root => full access to all users
* not root => full access to own settings only
* wysiwyg/settings/users/ID
* Settings of the user with the given ID.
* Access permissions: see above.
* wysiwyg/settings/users/ID/seminars
* User's settings for all seminars the user is a member of.
* Access permissions: see above.
* wysiwyg/settings/users/ID/seminars/ID
* User's settings for the seminar with the given ID.
* Access permissions: see above.
*
* The difference of seminar's settings for a user and user's settings
* for a seminar:
*
* A seminar's teacher may want to set the upload directory for each user
* to a separate one, which should not be overwritable by a user, in
* order to make sure that users cannot see other users uploads (there
* are other ways to do this, but it's just an example).
*
* A user might want to have a specific upload directory in order to
* collaborate better with other users in the same seminar (e.g. when
* students form a study group).
*
* For example the ELMO module needs such settings.
*
* JSON scheme for access to wysiwyg/settings:
* {
* "global": { "SETTING": ..., ... },
* "seminars": {
* "ID": {
* "users": { "ID": {...}, ... },
* "SETTING": ...,
* ...
* },
* "ID": {...},
* ...
* },
* "users": {
* "ID": {
* "seminars": { "ID": {...}, ... },
* "SETTING": ...,
* ...
* },
* "ID": {...},
* ...
* }
* }
*
* When accessing a sub-resource that resource's branch of the JSON scheme
* will be returned.
*/
public function settings_action()
{
try {
if (!Request::isGet() && !Request::isPut()) {
throw new WysiwygHttpExceptionMethodNotAllowed(
_('Nur die HTTP-Methoden GET und PUT sind erlaubt.')
);
}
$arguments = func_get_args();
$settingsGroup = array_shift($arguments);
if (Request::isPut()) {
$this->setSettings($settingsGroup, $arguments);
}
$this->render_json($this->objectToArray(
$this->getSettings($settingsGroup, $arguments)
));
} catch (WysiwygHttpException $e) {
$this->set_status($e->getCode());
$this->set_content_type('text/plain; charset=utf-8');
$this->render_text($e->getMessage());
}
}
/**
* Set WYSIWYG settings for a specific group.
*
* Dummy implementation: Currently only accepts setting the
* disabled flag for wysiwyg/settings/users/current.
*
* The HTTP request's body must contain a JSON document of the form:
* {
* "disabled": true | false
* }
*
* If the JSON contains other additional values they will be ignored.
*
* @param string $group Must be set to 'users'.
* @param array $arguments Must contain exactly one entry: 'current'.
*/
private function setSettings($group, $arguments) {
$user = array_shift($arguments);
if ($group !== 'users' || $user !== 'current') {
throw new WysiwygHttpExceptionForbidden(
_('Zugriff verweigert')
);
}
$subgroup = array_shift($arguments);
if (($subgroup !== null && $subgroup !== '') || count($arguments) > 0) {
throw new WysiwygHttpExceptionNotFound(
_('Die Benutzereinstellungen enthalten keine Untergruppen.')
);
}
$data = json_decode(file_get_contents('php://input'));
if (isset($data->disabled)) {
$config = $GLOBALS['user']->cfg;
//$config->WYSIWYG_DISABLED = (boolean)$data->disabled;
$config->store(
'WYSIWYG_DISABLED',
(boolean)$data->disabled
);
} else {
throw new WysiwygHttpExceptionBadRequest(
_('Die Anfrage enthält ungültige Werte.')
);
}
// all unknown parameters are ignored
}
/**
* Return WYSIWYG settings for a specific group.
*
* @param $group string The requested settings group: 'user', 'seminar',
* 'global' or 'all'. If the group is set to 'all' then all levels will be
* returned. If the group is unknown an error will be thrown.
*
* @return object Settings for the requested group.
*/
private function getSettings($group, $arguments)
{
switch ($group) {
case null: return $this->getAllSettings();
case 'global': return $this->getGlobalSettings($arguments);
case 'users': return $this->getUserSettings($arguments);
}
throw new WysiwygHttpExceptionNotFound(
_('Die angeforderte Gruppe von Einstellungen existiert nicht.')
);
}
/**
* Return all WYSIWYG settings.
*
* Returns an object with properties named after settings groups,
* containing the respective group's settings. For example:
*
* {
* "global": {...}
* "seminars": {...},
* "users": {...},
* }
*
* @return object All settings.
*/
private function getAllSettings()
{
$settings = new stdClass;
$settings->global = $this->getGlobalSettings();
$settings->users = $this->getUserSettings();
return $settings;
}
/**
* Return global WYSIWYG settings.
*
* @return object Global settings.
*/
private function getGlobalSettings($arguments = [])
{
$subgroup = array_shift($arguments);
if (($subgroup !== null && $subgroup !== '') || count($arguments) > 0) {
throw new WysiwygHttpExceptionNotFound(_('Die globalen Einstellungen enthalten keine Untergruppen.'));
}
$settings = new stdClass;
$settings->disabled = !\Config::get()->WYSIWYG;
$settings->upload = new stdClass;
$settings->upload->permission = self::UPLOAD_PERMISSION;
$settings->upload->folder = new stdClass;
$settings->upload->folder->name = self::FOLDER_NAME;
$settings->upload->folder->description = self::FOLDER_DESCRIPTION;
return $settings;
}
/**
* Return current user's WYSIWYG settings.
*
* @return object User's settings.
*/
private function getUserSettings($arguments = [])
{
// NOTE simulate a list of users containing only the current
// user until this is implemented correctly
$settings = new stdClass;
$settings->current = $this->getCurrentUserSettings();
$userId = array_shift($arguments);
if ($userId === null || $userId === '' && count($arguments) === 0) {
return $settings;
}
if ($userId === 'current') {
$subgroup = array_shift($arguments);
if (($subgroup !== null && $subgroup !== '') || count($arguments) > 0) {
throw new WysiwygHttpExceptionNotFound(
_('Die Benutzereinstellungen enthalten keine Untergruppen.')
);
}
return $settings->current;
}
throw new WysiwygHttpExceptionForbidden(
_('Zugriff verweigert.')
);
}
/**
* Return current user's WYSIWYG settings.
*
* @return object User's settings.
*/
public function getCurrentUserSettings()
{
$config = $GLOBALS['user']->cfg;
$settings = new stdClass;
$settings->disabled = (boolean)$config->WYSIWYG_DISABLED;
return $settings;
}
/**
* Recursively convert objects to associative arrays.
*
* Workaround for broken StudipController::render_json.
*
* If the data is neither object nor array then it will be
* returned unchanged.
*
* @param mixed $data Data to convert.
*
* @return mixed Converted data.
*/
private function objectToArray($data)
{
if (gettype($data) === 'object') {
$data = (array)$data;
}
if (gettype($data) === 'array') {
foreach ($data as $key => $value) {
$data[$key] = $this->objectToArray($value);
}
}
return $data;
}
}
CKEDITOR.dialog.add('settingsDialog', function (editor) {
var lang = editor.lang['studip-settings'];
// Time span after which the UI will display an abort option
// to the user if the HTTP request hasn't yet finished.
var uiTimeout = 3000;
var settings = {
url: STUDIP.URLHelper.resolveURL(
'dispatch.php/wysiwyg/settings/users/current'
),
save: function (data) {
return $.ajax({
url: this.url,
type: 'PUT',
contentType: 'application/json',
data: JSON.stringify(data)
});
}
};
var
dialog = null,
status = $('<span>').attr('class', 'cke_disabled'),
saveEvents = 0; // remember how many save events are currently active
function save(data) {
status.html(lang.savingChanges);
saveEvents++;
dialog.disableButton('ok');
var request = settings.save(data);
var timeoutId = setTimeout(function () {
status
.append(' (')
.append(
$('<a>')
.text(lang.abort)
.css('text-decoration', 'underline') // TODO use default styles
.click(function (event) {
event.preventDefault();
request.abort();
})
)
.append(')');
}, uiTimeout);
request
.done(function () {
status.html(lang.savedChanges);
})
.fail(function (xhr) {
var $error = $('<a>')
.text(lang.information)
.css('text-decoration', 'underline') // TODO use default styles
.click(function (event) {
event.preventDefault();
alert(
settings.url +
'\n\n' + lang.status + ' ' + xhr.status +
' ' + xhr.statusText +
'\n' + lang.response + ' ' + xhr.responseText
);
});
status
.html(lang.savingFailed + ' (')
.append($error)
.append(')');
})
.always(function () {
clearTimeout(timeoutId);
saveEvents--;
if (saveEvents <= 0) {
dialog.enableButton('ok');
}
});
return request;
}
return {
title: lang.dialogTitle,
width: 400,
height: 200,
resizable: CKEDITOR.DIALOG_RESIZE_NONE,
contents: [{
elements: [{
type: 'checkbox',
id: 'disable',
label: lang.disableEditorLabel,
onClick: function() {
var checkbox = this;
checkbox.disable(); // prevent multiple save events
save({ disabled: checkbox.getValue() })
.done(function (settings) {
checkbox.setValue(settings.disabled);
})
.fail(function () {
checkbox.setValue(!checkbox.getValue());
})
.always(function () {
checkbox.enable();
});
}
}, {
type: 'html',
style: 'white-space: normal',
html: lang.disableEditorInfo
}]
}],
onLoad: function (event) {
$(this.parts.footer.$).append(status);
dialog = this;
},
onShow: function (event) {
status.text('');
}
};
});
CKEDITOR.plugins.setLang('studip-settings', 'de', {
buttonLabel: 'WYSIWYG Einstellungen\n(Editor deaktivieren, usw.)',
savingChanges: '...speichere Änderungen.',
abort: 'Abbrechen',
savedChanges: 'Änderungen wurden gespeichert.',
information: 'Info',
status: 'Status:',
response: 'Response:',
savingFailed: 'Speichern fehlgeschlagen.',
dialogTitle: 'Einstellungen',
disableEditorLabel: 'WYSIWYG Editor ausschalten',
disableEditorInfo: 'Mit dieser Einstellung können Sie den'
+ ' WYSIWYG Editor ausschalten. Dadurch müssen'
+ ' Sie gegebenenfalls Texte in HTML schreiben.'
+ ' Der Editor wird erst vollständig entfernt'
+ ' wenn man die Seite neu lädt.',
});
CKEDITOR.plugins.setLang('studip-settings', 'en', {
buttonLabel: 'WYSIWYG Settings\n(Deactivate the editor, etc.)',
savingChanges: '...saving changes.',
abort: 'Abort',
savedChanges: 'All changes saved.',
information: 'Info',
status: 'Status:',
response: 'Response:',
savingFailed: 'Saving failed.',
dialogTitle: 'Settings',
disableEditorLabel: 'Switch WYSIWYG editor off',
disableEditorInfo: 'This setting will disable the WYSIWYG'
+ ' Editor. You might have to write HTML code if you'
+ ' do so. The editor will only be fully removed after'
+ ' you reload the page.',
});
CKEDITOR.plugins.add('studip-settings', {
icons: 'settings',
hidipi: true,
lang: 'de,en',
init: function (editor) {
CKEDITOR.dialog.add(
'settingsDialog',
this.path + 'dialogs/settings.js'
);
editor.addCommand(
'settings',
new CKEDITOR.dialogCommand('settingsDialog')
);
editor.ui.addButton('settings', {
label: editor.lang['studip-settings'].buttonLabel,
command: 'settings',
toolbar: 'settings'
});
}
});
......@@ -44,41 +44,6 @@ const Toolbar = {
button_set = button_set || Toolbar.buttonSet;
// if WYSIWYG is globally enabled then add a button so
// the user can activate it
if (STUDIP.wysiwyg_enabled && $element.hasClass('wysiwyg')) {
button_set.right.wysiwyg = {
label: 'WYSIWYG',
evaluate: function() {
var question = [
$gettext('Soll der WYSIWYG Editor aktiviert werden?'),
'',
$gettext('Die Seite muss danach neu geladen werden, um den WYSIWYG Editor zu laden.')
].join('\n');
Dialog.confirm(question, function() {
var url = STUDIP.URLHelper.resolveURL('dispatch.php/wysiwyg/settings/users/current');
$.ajax({
url: url,
type: 'PUT',
contentType: 'application/json',
data: JSON.stringify({ disabled: false })
}).fail(function(xhr) {
window.alert(
[
$gettext('Das Aktivieren des WYSIWYG Editors ist fehlgeschlagen.'),
'',
$gettext('URL') + ': ' + url,
$gettext('Status') + ': ' + xhr.status + ' ' + xhr.statusText,
$gettext('Antwort') + ': ' + xhr.responseText
].join('\n')
);
});
});
}
};
}
// Add flag so one element will never have more than one toolbar
$element.data('toolbar-added', true);
......
......@@ -170,7 +170,7 @@ const wysiwyg = {
skin: 'studip,' + STUDIP.ASSETS_URL + 'stylesheets/ckeditor-skin/',
// NOTE codemirror crashes when not explicitely loaded in CKEditor 4.4.7
extraPlugins:
'emojione,studip-floatbar,studip-quote,studip-upload,studip-settings' +
'emojione,studip-floatbar,studip-quote,studip-upload' +
(extraPlugins ? ',' + extraPlugins : ''),
removePlugins: removePlugins ? removePlugins : textarea.closest('.ui-dialog').length ? 'autogrow' : '',
enterMode: CKEDITOR.ENTER_BR,
......@@ -192,8 +192,7 @@ const wysiwyg = {
{ name: 'basicstyles', groups: ['undo', 'basicstyles', 'cleanup'] },
{ name: 'paragraph', groups: ['list', 'indent', 'blocks', 'align', 'quote'] },
'/',
{ name: 'styles', groups: ['styles', 'colors', 'tools', 'links', 'insert'] },
{ name: 'others', groups: ['mode', 'settings'] }
{ name: 'styles', groups: ['styles', 'colors', 'tools', 'links', 'insert', 'mode'] }
],
removeButtons: 'Font,FontSize',
toolbarCanCollapse: true,
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment