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

Remove inline Javascript, part I #9513

Open
wants to merge 56 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
a0bdebc
Create and initialize `rcmail` in external JS file
pabzm Jun 20, 2024
c233a41
Replace inline scripts by JSON-data with instructions
pabzm Jun 21, 2024
28edc31
Put footer scripts after footer data
pabzm Jun 21, 2024
4d66faf
De-inline elastic dark-mode switch
pabzm Jun 21, 2024
aa144eb
De-inline markasjunk
pabzm Jun 21, 2024
218e18f
De-inline jquery-ui
pabzm Jun 21, 2024
c04dad5
De-inline managesieve
pabzm Jun 21, 2024
66361e6
De-inline googiespell
pabzm Jun 21, 2024
6a0a98e
De-inline compose.php
pabzm Jun 21, 2024
bc2ce23
De-inline new_user_dialog
pabzm Jun 21, 2024
600e864
Initialize rcmail from app.js
pabzm Jul 9, 2024
a6a052c
Initialize googiespell in editor.js, not external file
pabzm Jul 9, 2024
b70065f
Remove redundant json-encoding
pabzm Jul 9, 2024
11ccc83
Use data-attribute for js-data to avoid getting data encoded
pabzm Jul 9, 2024
125f992
Clean up spellchecker initialization
pabzm Jul 10, 2024
56e3eaa
Strip check for 'plugin.'-prefix of JS-calls
pabzm Jul 17, 2024
f879564
Trigger JS only via methods on rcmail, not events
pabzm Jul 17, 2024
00ed0d8
Rename rcmail_output_html's `commands` to `js_calls`
pabzm Jul 17, 2024
0b7d4d1
Add eventListeners from data-attributes
pabzm Jun 13, 2024
1d773b6
De-inline event handlers from plugins+actions
pabzm Jun 21, 2024
b64dbd0
html class: Allow to pass array as content
pabzm Jul 15, 2024
be692ff
Git-ignore *.min.js
pabzm Jul 15, 2024
1f0bcb4
De-inline installer
pabzm Jul 17, 2024
f322b76
Remove support for inline event handlers from html class
pabzm Jul 18, 2024
137d7ff
Fix codestyle errors
pabzm Jul 18, 2024
6885cff
fixup! Trigger JS only via methods on rcmail, not events
pabzm Jul 18, 2024
6cb1052
fixup! De-inline new_user_dialog
pabzm Jul 18, 2024
f919f89
fixup! Trigger JS only via methods on rcmail, not events
pabzm Jul 18, 2024
ea75d9e
fixup! Trigger JS only via methods on rcmail, not events
pabzm Jul 18, 2024
ac2bb21
fixup! Replace inline scripts by JSON-data with instructions
pabzm Jul 18, 2024
9098a60
fixup! De-inline event handlers from plugins+actions
pabzm Jul 19, 2024
846bf9b
fixup! De-inline event handlers from plugins+actions
pabzm Jul 19, 2024
4062096
fixup! De-inline event handlers from plugins+actions
pabzm Jul 19, 2024
7e8010b
Make a browser test a little more resilient
pabzm Jul 19, 2024
04937df
Let browser wait longer for downloads
pabzm Jul 22, 2024
e64be8f
Allow to run event-listener-attacher for given root element
pabzm Jul 22, 2024
d93b381
Fix subscription toggle of newly created folders
pabzm Jul 22, 2024
a76698d
De-inline program/include
pabzm Jul 24, 2024
8b71716
Move rcube_webmail static methods to instance
pabzm Jul 24, 2024
f7c63e0
fixup: de-inline program/actions
pabzm Jul 24, 2024
31233ec
fixup de-inline actions
pabzm Jul 24, 2024
e15b8e1
De-inline skins/elastic
pabzm Jul 24, 2024
c180952
fixup de-inline program/include
pabzm Jul 24, 2024
00babee
WIP: Send strict CSP (strict for JS)
pabzm Jul 25, 2024
73958c5
De-eval HTTP response handling
pabzm Jul 24, 2024
d08d6cb
WIP: TODO comment
pabzm Jul 24, 2024
4909f13
Fix log statement
pabzm Jul 25, 2024
e7bc61a
json_encode in html class
pabzm Jul 25, 2024
f9abd32
Remove useless call
pabzm Jul 25, 2024
bf1faee
De-inline app.js, part 1
pabzm Jul 25, 2024
e08c14a
Fix image upload
pabzm Jul 26, 2024
d6daeed
Hand around Nodes instead of using innerHTML
pabzm Jul 26, 2024
de84737
Use jQuery event setters and helpers to get rid of innerHTML
pabzm Jul 26, 2024
6e2e1a1
innerText is enough here, don't need innerHTML
pabzm Jul 26, 2024
a927b13
Re-add lost preventDefault
pabzm Jul 26, 2024
fedc7d2
WIP: Use jQuery to attach event-handlers based on attributes
pabzm Aug 23, 2024
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ program/js/jquery.min.js
program/js/jstz.min.js
program/js/publickey.js
program/js/tinymce/
**/*.min.js

# eslint dependencies
/node_modules
Expand Down
2 changes: 1 addition & 1 deletion index.php
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@
}

if ($RCMAIL->output->ajax_call || $RCMAIL->output->get_env('framed')) {
$RCMAIL->output->command('session_error', $RCMAIL->url(['_err' => 'session']));
$RCMAIL->output->add_js_call('session_error', $RCMAIL->url(['_err' => 'session']));
$RCMAIL->output->send('iframe');
}

Expand Down
32 changes: 32 additions & 0 deletions installer/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,35 @@ function removehostfield(row) {
var container = document.getElementById('defaulthostlist');
container.removeChild(row);
}

function addOnclickCallback(id, callback) {
var elem = document.getElementById(id);
if (!elem) {
console.error('No element found with ID "' + id + '", cannot add callback!');
return false;
}
elem.addEventListener('click', callback);
}

document.addEventListener('DOMContentLoaded', function () {
addOnclickCallback('button-save-config', function () {
document.getElementById('getconfig_form').submit();
});

addOnclickCallback('button-download-config', function () {
location.href = 'index.php?_getconfig=1';
});

addOnclickCallback('button-continue-step-3', function () {
location.href = './index.php?_step=3';
});

addOnclickCallback('remove-host-field', function (event) {
removehostfield(event.target.parentNode);
return false;
});

addOnclickCallback('add-host-field', function () {
addhostfield();
});
});
10 changes: 5 additions & 5 deletions installer/config.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,13 @@
echo '<input name="_getconfig" value="2" /></form>';

$button_txt = html::quote('Save in ' . $dir);
$save_button = '&nbsp;<input type="button" onclick="document.getElementById(\'getconfig_form\').submit()" value="' . $button_txt . '" />';
$save_button = '&nbsp;<input type="button" id="button-save-config" value="' . $button_txt . '" />';
}

echo '<p class="notice">Copy or download the following configuration and save it';
echo ' as <tt><b>config.inc.php</b></tt> within the <tt>' . RCUBE_CONFIG_DIR . '</tt> directory of your Roundcube installation.<br/>';
echo ' Make sure that there are no characters before the <tt>&lt;?php</tt> bracket when saving the file.';
echo '&nbsp;<input type="button" onclick="location.href=\'index.php?_getconfig=1\'" value="Download" />';
echo '&nbsp;<input type="button" id="button-download-config" value="Download" />';
echo $save_button;

if ($RCI->legacy_config) {
Expand All @@ -65,7 +65,7 @@
echo '<p class="hint">Of course there are more options to configure.
Have a look at the defaults.inc.php file or visit <a href="https://github.com/roundcube/roundcubemail/wiki/Configuration" target="_blank">Howto_Config</a> to find out.</p>';

echo '<p><input type="button" onclick="location.href=\'./index.php?_step=3\'" value="CONTINUE" /></p>';
echo '<p><input type="button" id="button-continue-step-3" value="CONTINUE" /></p>';

// echo '<style type="text/css"> .configblock { display:none } </style>';
echo "\n<hr style='margin-bottom:1.6em' />\n";
Expand Down Expand Up @@ -327,14 +327,14 @@
foreach ($default_hosts as $host) {
echo '<div id="defaulthostentry' . $i . '">' . $text_imaphost->show($host);
if ($i++ > 0) {
echo '<a href="#" onclick="removehostfield(this.parentNode);return false" class="removelink" title="Remove this entry">remove</a>';
echo '<a href="#" id="remove-host-field" class="removelink" title="Remove this entry">remove</a>';
}
echo '</div>';
}

?>
</div>
<div><a href="javascript:addhostfield()" class="addlink" title="Add another field">add</a></div>
<div><a href="#" id="add-host-field" class="addlink" title="Add another field">add</a></div>

<div>The IMAP host(s) chosen to perform the log-in</div>
<p class="hint">Leave blank to show a textbox at login. To use SSL/STARTTLS connection add ssl:// or tls:// prefix. It can also contain the port number, e.g. tls://imap.domain.tld:143.
Expand Down
8 changes: 4 additions & 4 deletions plugins/acl/acl.php
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ public function acl_autocomplete()
$users = array_values($keys);
}

$this->rc->output->command('ksearch_query_results', $users, $search, $reqid);
$this->rc->output->add_js_call('ksearch_query_results', $users, $search, $reqid);
$this->rc->output->send();
}

Expand Down Expand Up @@ -533,7 +533,7 @@ private function action_save()
if ($user != $self && $username != $self) {
if ($this->rc->storage->set_acl($mbox, $user, $acl)) {
$display = $this->resolve_acl_identifier($username, $title);
$this->rc->output->command('acl_update', [
$this->rc->output->add_js_call('acl_update', [
'id' => rcube_utils::html_identifier($user),
'username' => $username,
'title' => $title,
Expand Down Expand Up @@ -566,7 +566,7 @@ private function action_delete()
foreach ($user as $u) {
$u = trim($u);
if ($this->rc->storage->delete_acl($mbox, $u)) {
$this->rc->output->command('acl_remove_row', rcube_utils::html_identifier($u));
$this->rc->output->add_js_call('acl_remove_row', rcube_utils::html_identifier($u));
} else {
$error = true;
}
Expand Down Expand Up @@ -599,7 +599,7 @@ private function action_list()

$out = preg_replace(['/^<table[^>]+>/', '/<\/table>$/'], '', $out);

$this->rc->output->command('acl_list_update', $out);
$this->rc->output->add_js_call('acl_list_update', $out);
}

/**
Expand Down
2 changes: 1 addition & 1 deletion plugins/acl/skins/elastic/templates/table.html
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ <h3 id="aria-label-aclactions" class="voice"><roundcube:label name="acl.arialabe
<roundcube:button command="acl-edit" label="edit" type="link-menuitem" class="edit disabled" classAct="edit active" />
<roundcube:button command="acl-delete" label="delete" type="link-menuitem" class="delete disabled" classAct="delete active" />
<roundcube:if condition="!in_array('acl_advanced_mode', (array)config:dont_override)" />
<roundcube:button name="acl-switch" type="link-menuitem" class="active check" id="acl-switch" onclick="rcmail.command('acl-mode-switch')" label="acl.advanced" />
<roundcube:button name="acl-switch" type="link-menuitem" class="active check" id="acl-switch" data-onclick='["command","acl-mode-switch"]' label="acl.advanced" />
<roundcube:endif />
</ul>
</div>
Expand Down
14 changes: 7 additions & 7 deletions plugins/archive/archive.php
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ public function move_messages()
// @phpstan-ignore-next-line
if ($this->result['error']) {
if (!$from_show_action) {
$rcmail->output->command('list_mailbox');
$rcmail->output->add_js_call('list_mailbox');
}

$rcmail->output->show_message($this->gettext('archiveerror'), 'warning');
Expand All @@ -236,7 +236,7 @@ public function move_messages()

if (!empty($_POST['_refresh'])) {
// FIXME: send updated message rows instead of reloading the entire list
$rcmail->output->command('refresh_list');
$rcmail->output->add_js_call('refresh_list');
$addrows = false;
} else {
$addrows = true;
Expand All @@ -249,9 +249,9 @@ public function move_messages()

if ($from_show_action) {
if ($next = rcube_utils::get_input_string('_next_uid', rcube_utils::INPUT_GPC)) {
$rcmail->output->command('show_message', $next);
$rcmail->output->add_js_call('show_message', $next);
} else {
$rcmail->output->command('command', 'list');
$rcmail->output->add_js_call('command', 'list');
}

$rcmail->output->send();
Expand Down Expand Up @@ -287,8 +287,8 @@ public function move_messages()
$rcmail->output->set_env('current_page', $page);
$rcmail->output->set_env('pagecount', $pages);
$rcmail->output->set_env('exists', $exists);
$rcmail->output->command('set_quota', rcmail_action::quota_content(null, $quota_root));
$rcmail->output->command('set_rowcount', rcmail_action_mail_index::get_messagecount_text($msg_count), $mbox);
$rcmail->output->add_js_call('set_quota', rcmail_action::quota_content(null, $quota_root));
$rcmail->output->add_js_call('set_rowcount', rcmail_action_mail_index::get_messagecount_text($msg_count), $mbox);

if ($threading) {
$count = rcube_utils::get_input_string('_count', rcube_utils::INPUT_POST);
Expand Down Expand Up @@ -403,7 +403,7 @@ public function prefs_table($args)
'maxlength' => 30,
'folder_filter' => 'mail',
'folder_rights' => 'w',
'onchange' => "if ($(this).val() == 'INBOX') $(this).val('')",
'data-onchange' => ['reset_value_if_inbox', '__THIS__'],
'class' => 'custom-select',
]);
} else {
Expand Down
18 changes: 16 additions & 2 deletions plugins/enigma/enigma.js
Original file line number Diff line number Diff line change
Expand Up @@ -567,14 +567,15 @@ rcube_webmail.prototype.enigma_compose_handler = function (props) {
};

// Import attached keys/certs file
rcube_webmail.prototype.enigma_import_attachment = function (mime_id) {
$('[data-event-handle="enigma_import_attachment"]').on('click', function (event) {
var mime_id = event.target.dataset.part;
var lock = this.set_busy(true, 'loading'),
post = { _uid: this.env.uid, _mbox: this.env.mailbox, _part: mime_id };

this.http_post('plugin.enigmaimport', post, lock);

return false;
};
});

// password request popup
rcube_webmail.prototype.enigma_password_request = function (data) {
Expand Down Expand Up @@ -745,3 +746,16 @@ rcube_webmail.prototype.enigma_find_publickey = function (email) {
}
);
};

// Some event handlers.
$('[data-event-handle="enigma_import_upload"]').on('click', function (event) {
return window.rcmail.command('plugin.enigma-import', '', event.target, event);
});

$('[data-event-handle="enigma_import_search"]').on('click', function (event) {
return window.rcmail.command('plugin.enigma-import-search', '', event.target, event);
});

$('[data-event-handle="enigma_import_search"]').on('click', function (event) {
window.rcmail.command('menu-open', 'enigmamenu', event.target, event);
});
33 changes: 17 additions & 16 deletions plugins/enigma/lib/enigma_ui.php
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ public function password_prompt($status, $params = [])
}

if (preg_match('/^(send|plugin.enigmaimport|plugin.enigmakeys)$/', $this->rc->action)) {
$this->rc->output->command('enigma_password_request', $data);
$this->rc->output->add_js_call('enigma_password_request', $data);
} else {
$this->rc->output->set_env('enigma_password_request', $data);
}
Expand Down Expand Up @@ -254,7 +254,7 @@ private function key_list()

// Add rows
foreach ($list as $key) {
$this->rc->output->command('enigma_add_list_row', [
$this->rc->output->add_js_call('enigma_add_list_row', [
'name' => rcube::Q($key->name),
'id' => $key->id,
'flags' => $key->is_private() ? 'p' : '',
Expand All @@ -266,7 +266,7 @@ private function key_list()
$this->rc->output->set_env('search_request', $search);
$this->rc->output->set_env('pagecount', ceil($listsize / $pagesize));
$this->rc->output->set_env('current_page', $page);
$this->rc->output->command('set_rowcount', $this->get_rowcount_text($listsize, $size, $page));
$this->rc->output->add_js_call('set_rowcount', $this->get_rowcount_text($listsize, $size, $page));

$this->rc->output->send();
}
Expand Down Expand Up @@ -323,7 +323,7 @@ private function key_info()
$this->data = $res;
} else { // error
$this->rc->output->show_message('enigma.keyopenerror', 'error');
$this->rc->output->command('parent.enigma_loadframe');
$this->rc->output->add_js_call('parent.enigma_loadframe');
$this->rc->output->send('iframe');
}

Expand Down Expand Up @@ -528,14 +528,14 @@ private function key_import()

if (is_array($result)) {
if (rcube_utils::get_input_value('_generated', rcube_utils::INPUT_POST)) {
$this->rc->output->command('enigma_key_create_success');
$this->rc->output->add_js_call('enigma_key_create_success');
$this->rc->output->show_message('enigma.keygeneratesuccess', 'confirmation');
} else {
$this->rc->output->show_message('enigma.keysimportsuccess', 'confirmation',
['new' => $result['imported'], 'old' => $result['unchanged']]);

if ($result['imported'] && !empty($_POST['_refresh'])) {
$this->rc->output->command('enigma_list', 1, false);
$this->rc->output->add_js_call('enigma_list', 1, false);
}
}
} else {
Expand All @@ -550,13 +550,13 @@ private function key_import()
if (is_array($result)) {
// reload list if any keys has been added
if ($result['imported']) {
$this->rc->output->command('parent.enigma_list', 1);
$this->rc->output->add_js_call('parent.enigma_list', 1);
}

$this->rc->output->show_message('enigma.keysimportsuccess', 'confirmation',
['new' => $result['imported'], 'old' => $result['unchanged']]);

$this->rc->output->command('parent.enigma_import_success');
$this->rc->output->add_js_call('parent.enigma_import_success');
} elseif ($result instanceof enigma_error && $result->getCode() == enigma_error::BADPASS) {
$this->password_prompt($result);
} else {
Expand Down Expand Up @@ -611,7 +611,7 @@ public function tpl_key_import_form($attrib)
$max_filesize = rcmail_action::upload_init();
$upload_button = new html_button([
'class' => 'button import',
'onclick' => "return rcmail.command('plugin.enigma-import','',this,event)",
'data-event-handle' => 'enigma_import_upload',
]);

$form = html::div(null, html::p(null, rcube::Q($this->enigma->gettext('keyimporttext'), 'show'))
Expand Down Expand Up @@ -639,7 +639,7 @@ public function tpl_key_import_form($attrib)

$search_button = new html_button([
'class' => 'button search',
'onclick' => "return rcmail.command('plugin.enigma-import-search','',this,event)",
'data-event-handle' => 'enigma_import_search',
]);

$form = html::div(null,
Expand Down Expand Up @@ -710,7 +710,7 @@ private function key_generate()
]);

if ($result instanceof enigma_key) {
$this->rc->output->command('enigma_key_create_success');
$this->rc->output->add_js_call('enigma_key_create_success');
$this->rc->output->show_message('enigma.keygeneratesuccess', 'confirmation');
} else {
$this->rc->output->show_message('enigma.keygenerateerror', 'error');
Expand Down Expand Up @@ -820,12 +820,12 @@ private function key_delete()

if ($res !== true) {
$this->rc->output->show_message('enigma.keyremoveerror', 'error');
$this->rc->output->command('enigma_list');
$this->rc->output->add_js_call('enigma_list');
$this->rc->output->send();
}
}

$this->rc->output->command('enigma_list');
$this->rc->output->add_js_call('enigma_list');
$this->rc->output->show_message('enigma.keyremovesuccess', 'confirmation');
$this->rc->output->send();
}
Expand All @@ -848,7 +848,7 @@ private function compose_ui()
$this->enigma->add_button([
'type' => 'link',
'command' => 'plugin.enigma',
'onclick' => "rcmail.command('menu-open', 'enigmamenu', event.target, event)",
'data-event-handle' => 'enigma_menu_open',
'class' => 'button enigma',
'title' => 'encryptionoptions',
'label' => 'encryption',
Expand Down Expand Up @@ -1107,7 +1107,8 @@ public function message_output($p)
$p['content'] = html::p(['class' => 'enigmaattachment boxinformation aligned-buttons'],
html::span(null, rcube::Q($this->enigma->gettext('keyattfound'))) .
html::tag('button', [
'onclick' => 'return ' . rcmail_output::JS_OBJECT_NAME . ".enigma_import_attachment('" . rcube::JQ($part) . "')",
'data-event-handle' => 'enigma_import_attachment',
'data-part' => $part,
'title' => $this->enigma->gettext('keyattimport'),
'class' => 'import btn-sm',
], rcube::Q($this->rc->gettext('import'))
Expand Down Expand Up @@ -1190,7 +1191,7 @@ public function message_ready($p)

if (!empty($msg)) {
if (!empty($vars['email'])) {
$this->rc->output->command('enigma_key_not_found', [
$this->rc->output->add_js_call('enigma_key_not_found', [
'email' => $vars['email'],
'text' => $this->rc->gettext(['name' => $msg, 'vars' => $vars]),
'title' => $this->enigma->gettext('keynotfound'),
Expand Down
3 changes: 2 additions & 1 deletion plugins/help/help.php
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,8 @@ public function tablink($attrib)
// so button() will translate it correctly
$attrib['title'] = $attrib['label'];

$attrib['onclick'] = sprintf("return show_help_content('%s', event)", $attrib['action']);
$attrib['data-action'] = $attrib['action'];
$attrib['data-event-handle'] = 'call_show_help_content';

return $rcmail->output->button($attrib);
}
Expand Down
3 changes: 2 additions & 1 deletion plugins/jqueryui/jqueryui.php
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,8 @@ public static function miniColors()

$rcube->output->include_css('plugins/jqueryui/' . $css);
$rcube->output->include_script($script, 'head', false);
$rcube->output->add_script('$.fn.miniColors = $.fn.minicolors; $("input.colors").minicolors(' . $config_str . ')', 'docready');
$rcube->output->include_script('plugins/jqueryui/js/jqueryui-minicolors-init.js');
$rcube->output->add_js_call('jqueryui_minicolors_init', $config_str);
$rcube->output->set_env('minicolors_config', $config);
}

Expand Down
4 changes: 4 additions & 0 deletions plugins/jqueryui/js/jqueryui-minicolors-init.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
rcube_webmail.prototype.jqueryui_minicolors_init = function (config) {
$.fn.miniColors = $.fn.minicolors;
$("input.colors").minicolors(config);
}
Loading
Loading